diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..a3108f35b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,104 @@ +name: CI Pipeline + +on: + push: + branches: [ "**" ] # Run on every commit to any branch + pull_request: + branches: [ "**" ] # Run for PRs from any branch + workflow_dispatch: + +permissions: write-all + +jobs: + gradle_check: + name: Gradle Check + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + steps: + - uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@main + with: + java-version: '17' + distribution: 'temurin' + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@main + + - name: Run Gradle Check + run: ./gradlew check + + maven_verify: + name: Maven Verify + needs: gradle_check # ✅ Run only after Gradle check succeeds + runs-on: ${{ matrix.os }} + strategy: + matrix: +# os: [ ubuntu-latest, windows-latest, macos-latest ] + os: [ ubuntu-latest, macos-latest ] + steps: + - uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@main + with: + java-version: '17' + distribution: 'temurin' + + - name: Run Maven Verify + run: mvn --batch-mode verify + + gradle_publish: + name: Gradle Publish + needs: [ gradle_check, maven_verify ] # ✅ Run only after both succeed + if: github.ref == 'refs/heads/master' && github.repository == 'JSQLParser/JSqlParser' # ✅ Only for master branch of main repo + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@main + with: + java-version: '17' + distribution: 'temurin' + + - name: Build with Gradle + uses: gradle/actions/setup-gradle@main + + - name: Publish with Gradle + run: ./gradlew publish + env: + ossrhUsername: ${{ secrets.OSSRHUSERNAME }} + ossrhPassword: ${{ secrets.OSSRHPASSWORD }} + + - uses: actions/setup-python@main + + - name: Install XSLT Processor + run: sudo apt-get install -y xsltproc sphinx-common + + - name: Install Python dependencies + run: pip install manticore_sphinx_theme sphinx_javadoc_xml myst_parser sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments + + - name: Build Sphinx documentation with Gradle + run: FLOATING_TOC=false ./gradlew -DFLOATING_TOC=false gitChangelogTask renderRR xslt xmldoc sphinx + + - name: Configure GitHub Pages + uses: actions/configure-pages@main + + - name: Upload artifact + uses: actions/upload-pages-artifact@main + with: + path: 'build/sphinx' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@main diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml deleted file mode 100644 index 67ccc3166..000000000 --- a/.github/workflows/gradle.yml +++ /dev/null @@ -1,35 +0,0 @@ -# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle - -name: Gradle CI - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -permissions: - contents: read - -jobs: - check: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - - name: Build with Gradle - uses: gradle/gradle-build-action@v2.6.0 - with: - arguments: check - env: - ossrhUsername: ${{ secrets.OSSRHPASSWORD }} - ossrhPassword: ${{ secrets.OSSRHUSERNAME }} diff --git a/.github/workflows/gradle_publish.yml b/.github/workflows/gradle_publish.yml deleted file mode 100644 index 4e8cbddea..000000000 --- a/.github/workflows/gradle_publish.yml +++ /dev/null @@ -1,37 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle - -name: Gradle publish Snapshot - -on: - workflow_dispatch: - -permissions: - contents: read - -jobs: - publish: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Set up JDK 11 - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'temurin' - - name: Build with Gradle - uses: gradle/gradle-build-action@v2.6.0 - with: - arguments: publish - # arguments: build check publish - env: - ossrhUsername: ${{ secrets.OSSRHPASSWORD }} - ossrhPassword: ${{ secrets.OSSRHUSERNAME }} diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml deleted file mode 100644 index 3c265b631..000000000 --- a/.github/workflows/maven.yml +++ /dev/null @@ -1,36 +0,0 @@ -# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Maven CI - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - package: - - runs-on: ubuntu-latest - strategy: - matrix: - java: [11] - name: Java ${{ matrix.java }} building ... - - steps: - - uses: actions/checkout@v3 - - name: Set up Java ${{ matrix.java }} - uses: actions/setup-java@v3 - with: - java-version: ${{ matrix.java }} - distribution: 'temurin' - cache: maven - server-id: sonatype-nexus-snapshots - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - - name: Build with Maven - run: mvn -B package --file pom.xml -DdisableXmlReport=true -Djacoco.skip=true -Dpmd.skip=true - env: - MAVEN_USERNAME: ${{ secrets.OSSRHUSERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRHPASSWORD }} diff --git a/.github/workflows/maven_deploy.yml b/.github/workflows/maven_deploy.yml deleted file mode 100644 index 740e80cb1..000000000 --- a/.github/workflows/maven_deploy.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Maven deploy snapshot - -on: - push: - branches: [ "master" ] - -jobs: - deploy: - - runs-on: ubuntu-latest - strategy: - matrix: - java: [11] - name: Java ${{ matrix.java }} building ... - - steps: - - uses: actions/checkout@v3 - - name: Set up Java ${{ matrix.java }} - uses: actions/setup-java@v3 - with: - java-version: ${{ matrix.java }} - distribution: 'temurin' - cache: maven - server-id: sonatype-nexus-snapshots - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - - name: Build with Maven - run: mvn -B deploy --file pom.xml -DdisableXmlReport=true -Djacoco.skip=true -Dpmd.skip=true - env: - MAVEN_USERNAME: ${{ secrets.OSSRHUSERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRHPASSWORD }} diff --git a/.github/workflows/sphinx.yml b/.github/workflows/sphinx.yml deleted file mode 100644 index ad8bde188..000000000 --- a/.github/workflows/sphinx.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Sphinx Pages -on: - push: - branches: [ "master" ] - -permissions: write-all -jobs: - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/setup-python@v4 - - name: Install XSLT Processor - run: sudo apt-get install xsltproc sphinx-common - - name: Install dependencies - run: pip install furo myst_parser sphinx-prompt sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments - - name: Checkout project sources - uses: actions/checkout@v2 - with: - ref: master - fetch-depth: 0 - - name: Setup Gradle - uses: gradle/gradle-build-action@v2.4.2 - - name: Run build with Gradle Wrapper - run: FLOATING_TOC=false gradle --no-build-cache clean xmldoc sphinx - - name: Deploy - uses: actions/configure-pages@v2 - - name: Upload artifact - uses: actions/upload-pages-artifact@v1 - with: - # Upload entire repository - path: 'build/sphinx' - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v1 diff --git a/.gitignore b/.gitignore index 20db77d7c..955e7bf2d 100755 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,17 @@ # Generated by maven /target /build +/out # Sphinx Theme related stuff, which shall be downloaded separately /src/site/sphinx/_themes # Exclude the Auto-generated Changelog /src/site/sphinx/changelog.rst -/src/site/sphinx/javadoc_stable.rst /src/site/sphinx/syntax_stable.rst -/src/site/sphinx/javadoc_snapshot.rst /src/site/sphinx/syntax_snapshot.rst +/src/site/sphinx/javadoc_stable.xml +/src/site/sphinx/javadoc_snapshot.xml # Generated by javacc-maven-plugin /bin @@ -31,3 +32,6 @@ /nbproject/ /.gradle + +# Mac +.DS_Store diff --git a/README.md b/README.md index 2e147efc3..42122c891 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,22 @@ -# [JSqlParser 4.9 Website](https://jsqlparser.github.io/JSqlParser) drawing +# [JSqlParser 5.3 Website](https://jsqlparser.github.io/JSqlParser) drawing -![Build Status](https://github.com/JSQLParser/JSqlParser/actions/workflows/maven.yml/badge.svg) -[![Build Status (Legacy)](https://travis-ci.com/JSQLParser/JSqlParser.svg?branch=master)](https://travis-ci.com/JSQLParser/JSqlParser) [![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/6f9a2d7eb98f45969749e101322634a1)](https://www.codacy.com/gh/JSQLParser/JSqlParser/dashboard?utm_source=github.com&utm_medium=referral&utm_content=JSQLParser/JSqlParser&utm_campaign=Badge_Grade) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser/badge.svg)](http://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser) [![Javadocs](https://www.javadoc.io/badge/com.github.jsqlparser/jsqlparser.svg)](https://www.javadoc.io/doc/com.github.jsqlparser/jsqlparser) +[![CI](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml) +[![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/6f9a2d7eb98f45969749e101322634a1)](https://www.codacy.com/gh/JSQLParser/JSqlParser/dashboard?utm_source=github.com&utm_medium=referral&utm_content=JSQLParser/JSqlParser&utm_campaign=Badge_Grade) +[![Maven Central](https://img.shields.io/maven-central/v/com.github.jsqlparser/jsqlparser.svg?label=maven-central)](https://central.sonatype.com/artifact/com.github.jsqlparser/jsqlparser) [![Javadocs](https://www.javadoc.io/badge/com.github.jsqlparser/jsqlparser.svg)](https://www.javadoc.io/doc/com.github.jsqlparser/jsqlparser) [![Gitter](https://badges.gitter.im/JSQLParser/JSqlParser.svg)](https://gitter.im/JSQLParser/JSqlParser?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +A huge thank you to our sponsor, [Starlake.ai](https://starlake.ai/) who simplifies data ingestion, transformation, and orchestration, enabling faster delivery of high-quality data. Starlake has been instrumental in providing Piped SQL and numerous test cases for BigQuery, Redshift, DataBricks, and DuckDB. Show your support for ongoing development by visiting Starlake.ai and giving us a star! + ## Summary -Please visit the [WebSite](https://jsqlparser.github.io/JSqlParser). **JSqlParser** is a RDBMS agnostic SQL statement parser. It translates SQL statements into a traversable hierarchy of Java classes (see [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#parse-a-sql-statements)): +Please visit our [WebSite](https://jsqlparser.github.io/JSqlParser) for detailed information. **JSqlParser** is a RDBMS agnostic SQL statement parser. It translates SQL statements into a traversable hierarchy of Java classes (see [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#parse-a-sql-statements)): ```sql SELECT 1 FROM dual WHERE a = b -``` -```text +/* produces the following AST + SQL Text └─Statements: statement.select.PlainSelect ├─selectItems: statement.select.SelectItem @@ -22,6 +25,7 @@ SQL Text └─where: expression.operators.relational.EqualsTo ├─Column: a └─Column: b +*/ ``` ```java @@ -43,26 +47,68 @@ Column a = (Column) equalsTo.getLeftExpression(); Column b = (Column) equalsTo.getRightExpression(); Assertions.assertEquals("a", a.getColumnName()); Assertions.assertEquals("b", b.getColumnName()); -} ``` +## Support for `Piped SQL` + +Work is progressing for parsing `Piped SQL`, a much saner and more logical way to write queries in its semantic order. +```sql +FROM Produce +|> WHERE + item != 'bananas' + AND category IN ('fruit', 'nut') +|> AGGREGATE COUNT(*) AS num_items, SUM(sales) AS total_sales + GROUP BY item +|> ORDER BY item DESC; +``` + +For details, please see https://storage.googleapis.com/gweb-research2023-media/pubtools/1004848.pdf, https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax and https://duckdb.org/docs/sql/query_syntax/from.html#from-first-syntax + +## Java Version + +JSQLParser-4.9 was the last JDK8 compatible version. JSQLParser-5.0 and later depend on JDK11 and introduce API breaking changes to the AST Visitors. Please see the Migration Guide for the details. + +Building JSQLParser-5.1 and newer with Gradle will depend on a JDK17 toolchain due to the used plugins. -JSQLParser-4.9 is the last JDK8 compatible version and any future development will depend on JDK11. +JSQLParser-5.4 Snapshot and later use JavaCC-8 Snapshots for generating the parser. + +## Performance + +Unfortunately the released JSQLParser-5.2 shows a performance deterioration caused by commit [30cf5d7](https://github.com/JSQLParser/JSqlParser/commit/30cf5d7b930ae0a076f49deb5cc841d39e62b3dc) related to `FunctionAllColumns()`. +This has been resolved in JSQLParser 5.3-SNAPSHOT and JMH benchmarks have been added to avoid such regressions in the future. Further all `LOOKAHEAD` have been revised one by one, and we have gained back a very good performance of the Parser. + +As per March-2026, the productions `Condition()`, `RegularCondition()` and `AndExpression()` have been refactored successfully. Furthermore, we have overhauled Token definition and handling of Reserved Keywords. This resulted in a massive performance boost and seem to have solved most of the performance issues. + +```text +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 7.602 ± 0.135 ms/op <-- March/26 +JSQLParserBenchmark.parseSQLStatements 5.3 avgt 15 84.687 ± 3.321 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 86.592 ± 5.781 ms/op +``` ## [Supported Grammar and Syntax](https://jsqlparser.github.io/JSqlParser/syntax.html) **JSqlParser** aims to support the SQL standard as well as all major RDBMS. Any missing syntax or features can be added on demand. -| RDBMS | Statements | -|-----------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------| -| Oracle
MS SQL Server and Sybase
Postgres
MySQL and MariaDB
DB2
H2 and HSQLDB and Derby
SQLite | `SELECT`
`INSERT`, `UPDATE`, `UPSERT`, `MERGE`
`DELETE`, `TRUNCATE TABLE`
`CREATE ...`, `ALTER ....`, `DROP ...`
`WITH ...` | -| Salesforce SOQL | `INCLUDES`, `EXCLUDES` | +| RDBMS | Statements | +|-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| +| BigQuery
Snowflake
DuckDB
Redshift
Oracle
MS SQL Server and Sybase
Postgres
MySQL and MariaDB
DB2
H2 and HSQLDB and Derby
SQLite | `SELECT`
`INSERT`, `UPDATE`, `UPSERT`, `MERGE`
`DELETE`, `TRUNCATE TABLE`
`CREATE ...`, `ALTER ....`, `DROP ...`
`WITH ...` | +| PostgreSQL Row Level Security | `CREATE POLICY`
`ALTER TABLE ... ENABLE/DISABLE/FORCE/NO FORCE ROW LEVEL SECURITY` | +| Salesforce SOQL | `INCLUDES`, `EXCLUDES` | +| Piped SQL (also known as FROM SQL) | | **JSqlParser** can also be used to create SQL Statements from Java Code with a fluent API (see [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#build-a-sql-statements)). +## Sister Projects + +If you like JSqlParser then please check out its related projects: + +* [JSQLFormatter](https://manticore-projects.com/JSQLFormatter/index.html) for pretty printing and formatting SQL Text + +* [JSQLTranspiler](https://manticore-projects.com/JSQLTranspiler/index.html) for dialect specific rewriting, SQL Column resolution and Lineage, provided by [Starlake.ai](https://starlake.ai/) + ## Alternatives to JSqlParser? -[**General SQL Parser**](http://www.sqlparser.com/features/introduce.php?utm_source=github-jsqlparser&utm_medium=text-general) looks pretty good, with extended SQL syntax (like PL/SQL and T-SQL) and java + .NET APIs. The tool is commercial (license available online), with a free download option. -Alternatively the dual-licensed [JOOQ](https://www.jooq.org/doc/latest/manual/sql-building/sql-parser/) provides a hand-written Parser supporting a lot of RDBMS, translation between dialects, SQL transformation, can be used as a JDBC proxy for translation and transformation purposes. +Alternatively the dual-licensed [JOOQ](https://www.jooq.org/doc/latest/manual/sql-building/sql-parser/) provides a handwritten Parser supporting a lot of RDBMS, translation between dialects, SQL transformation, can be used as a JDBC proxy for translation and transformation purposes. ## [Documentation](https://jsqlparser.github.io/JSqlParser) 1. [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#parse-a-sql-statements) diff --git a/build.gradle b/build.gradle index f5e939cb9..a690cef6b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,13 @@ import se.bjurr.gitchangelog.plugin.gradle.GitChangelogTask +import com.nwalsh.gradle.saxon.SaxonXsltTask + +import java.time.Instant + +buildscript { + dependencies { + classpath group: 'net.sf.saxon', name: 'Saxon-HE', version: 'latest.release' + } +} plugins { id 'java' @@ -6,12 +15,13 @@ plugins { id 'signing' id "org.javacc.javacc" version "latest.release" - //id 'jacoco' + id 'jacoco' id 'com.github.kt3k.coveralls' version "latest.release" id "com.github.spotbugs" version "latest.release" id "com.diffplug.spotless" version "latest.release" id 'pmd' id 'checkstyle' + id 'eclipse' // download the RR tools which have no Maven Repository id "de.undercouch.download" version "latest.release" @@ -19,7 +29,8 @@ plugins { id "se.bjurr.gitchangelog.git-changelog-gradle-plugin" version "latest.release" id "me.champeau.jmh" version "latest.release" - id "com.nwalsh.gradle.saxon.saxon-gradle" version "0.9.6" + id "com.nwalsh.gradle.saxon.saxon-gradle" version "latest.release" + id 'biz.aQute.bnd.builder' version "latest.release" } def getVersion = { boolean considerSnapshot -> @@ -27,58 +38,106 @@ def getVersion = { boolean considerSnapshot -> Integer minor = 0 Integer patch = null Integer build = null - def commit = null - def snapshot = "" - new ByteArrayOutputStream().withStream { os -> - exec { - args = [ - "--no-pager" - , "describe" - , "--tags" - , "--always" - , "--dirty=-SNAPSHOT" - ] - executable "git" - standardOutput = os - } - def versionStr = os.toString().trim() - def pattern = /(?\d*)\.(?\d*)(\.(?\d*))?(-(?\d*)-(?[a-zA-Z\d]*))?/ - def matcher = versionStr =~ pattern - if (matcher.find()) { - major = matcher.group('major') as Integer - minor = matcher.group('minor') as Integer - patch = matcher.group('patch') as Integer - build = matcher.group('build') as Integer - commit = matcher.group('commit') - } + String commit = null + String snapshot = "" + + def versionStr = providers.exec { + commandLine "git", "--no-pager", "-C", project.projectDir, "describe", "--tags", "--always", "--dirty=-SNAPSHOT" + }.standardOutput.asText.get().trim() + + def pattern = /jsqlparser-(?\d*)\.(?\d*)(\.(?\d*))?(-(?\d*)-(?[a-zA-Z\d]*))?/ + def matcher = versionStr =~ pattern + + if (matcher.find()) { + major = matcher.group('major') as Integer ?: 0 + minor = matcher.group('minor') as Integer ?: 0 + patch = matcher.group('patch') as Integer ?: null + build = matcher.group('build') as Integer ?: null + commit = matcher.group('commit') ?: null + } - if (considerSnapshot && ( versionStr.endsWith('SNAPSHOT') || build!=null) ) { - minor++ - if (patch!=null) patch = 0 - snapshot = "-SNAPSHOT" - } + if (considerSnapshot && (versionStr.endsWith('SNAPSHOT') || build != null)) { + minor++ + if (patch != null) patch = 0 + snapshot = "-SNAPSHOT" } - return patch!=null + + return patch != null ? "${major}.${minor}.${patch}${snapshot}" - : "${major}.${minor}${snapshot}" + : "${major}.${minor}${snapshot}" } + // for publishing a release, call Gradle with Environment Variable RELEASE: // RELEASE=true gradle JSQLParser:publish version = getVersion( !System.getenv("RELEASE") ) group = 'com.github.jsqlparser' description = 'JSQLParser library' -archivesBaseName = "JSQLParser" + +tasks.register('generateBuildInfo') { + outputs.dir layout.buildDirectory.file("resources/main") + doLast { + def outputDir = new File( layout.buildDirectory.file("generated/sources/buildinfo/java/main").get().asFile, "net/sf/jsqlparser") + outputDir.mkdirs() + + def gitVersionStr = providers.exec { + commandLine "git", "--no-pager", "-C", project.projectDir, "describe", "--tags", "--always", "--dirty=-SNAPSHOT" + }.standardOutput.asText.get().trim() + + def gitCommitStr = providers.exec { + commandLine "git", "--no-pager", "-C", project.projectDir, "rev-parse", "--short", "HEAD" + }.standardOutput.asText.get().trim() + + def buildTime = Instant.now().toString() + + def content = """\ + |package net.sf.jsqlparser; + | + |public final class BuildInfo { + | public static final String NAME = "${project.name}"; + | public static final String VERSION = "${gitVersionStr}"; + | public static final String GIT_COMMIT = "${gitCommitStr ?: 'unknown'}"; + | public static final String BUILD_TIME = "${buildTime}"; + |} + """.stripMargin() + + new File(outputDir, "BuildInfo.java").text = content + } +} + +// Make sure the file is included in the compiled sources +sourceSets { + main { + java { + srcDir layout.buildDirectory.file("generated/sources/buildinfo/java/main").get().asFile + } + } +} + +tasks.withType(JavaCompile).configureEach { + mustRunAfter("generateBuildInfo") +} + +tasks.withType(Pmd).configureEach { + mustRunAfter("generateBuildInfo") +} + +tasks.withType(Checkstyle).configureEach { + exclude '**/module-info.java', '**/package-info.java' + + mustRunAfter("generateBuildInfo") +} repositories { gradlePluginPortal() - mavenLocal() mavenCentral() - // Sonatype OSSRH + // JavaCC 8 Snapshots maven { - url = uri('https://s01.oss.sonatype.org/content/repositories/snapshots/') + url = uri('https://central.sonatype.com/repository/maven-snapshots/') } + + maven { url "https://dev.saxonica.com/maven" } } configurations { @@ -95,27 +154,121 @@ dependencies { testImplementation 'com.h2database:h2:+' // for JaCoCo Reports - testImplementation 'org.junit.jupiter:junit-jupiter-api:+' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:+' - testImplementation 'org.junit.jupiter:junit-jupiter-params:+' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.11.4' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.4' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.4' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.4' // https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter - testImplementation 'org.mockito:mockito-junit-jupiter:+' + testImplementation 'org.mockito:mockito-junit-jupiter:5.18.0' // Performance Benchmark testImplementation 'org.openjdk.jmh:jmh-core:+' testImplementation 'org.openjdk.jmh:jmh-generator-annprocess:+' // Java Doc in XML Format - xmlDoclet 'com.manticore-projects.tools:xml-doclet:+' + xmlDoclet ('com.manticore-projects.tools:xml-doclet:+'){ changing = true } // enforce latest version of JavaCC - testImplementation 'net.java.dev.javacc:javacc:+' - javacc 'net.java.dev.javacc:javacc:+' + testImplementation('org.javacc:core:8.1.0-SNAPSHOT') { changing = true } + testImplementation('org.javacc.generator:java:8.1.0-SNAPSHOT') { changing = true } + + jmh 'org.openjdk.jmh:jmh-core:1.37' + jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37' + javacc('org.javacc:core:8.1.0-SNAPSHOT') { changing = true } + javacc('org.javacc.generator:java:8.1.0-SNAPSHOT') { changing = true } +} +configurations.configureEach { + resolutionStrategy.eachDependency { DependencyResolveDetails details -> + if (details.requested.group in ['org.javacc:core', 'org.javacc.generator']) { + // Check for updates every build + resolutionStrategy.cacheChangingModulesFor 30, 'seconds' + } + } } compileJavacc { - arguments = [grammar_encoding: 'UTF-8', static: 'false', java_template_type: 'modern'] + arguments = [ + grammar_encoding: 'UTF-8', + static: 'false', + java_template_type: 'modern', + // Comment this in to build the parser with tracing. + DEBUG_PARSER: 'false', + DEBUG_LOOKAHEAD: 'false' + ] +} + +// Post-process the generated CCJSqlParserTokenManager.java to split large static +// array initializers into separate methods, preventing the method from +// exceeding the JVM's 64KB bytecode limit (which breaks ASM-based tools like sbt-assembly). +tasks.register('splitTokenManagerStaticInit') { + dependsOn(compileJavacc) + + def tokenManagerFile = layout.buildDirectory.file( + "generated/javacc/net/sf/jsqlparser/parser/CCJSqlParserTokenManager.java" + ) + + inputs.file(tokenManagerFile) + outputs.file(tokenManagerFile) + + doLast { + def file = tokenManagerFile.get().asFile + if (!file.exists()) { + throw new GradleException("CCJSqlParserTokenManager.java not found at ${file}") + } + def content = file.text + + // Pattern matches static final array field declarations with inline initialization. + // We extract large ones and move their initialization into separate methods. + def fieldsToExtract = [ + // [regex-safe field name, array type for method return] + ['stringLiterals', 'int[]'], + ['jjstrLiteralImages', 'String[]'], + ['jjmatchKinds', 'int[]'], + ['jjnewLexState', 'int[]'], + ] + + fieldsToExtract.each { entry -> + def fieldName = entry[0] + def arrayType = entry[1] + + // Match: = { ... }; + // The field declaration may use 'public' or 'private' and 'static final' + def pattern = ~"(?s)((?:public|private)\\s+static\\s+final\\s+${java.util.regex.Pattern.quote(arrayType)}\\s+${fieldName}\\s*=\\s*)\\{(.*?)\\};" + def matcher = pattern.matcher(content) + if (matcher.find()) { + def prefix = matcher.group(1) + def body = matcher.group(2) + def methodName = "_init_${fieldName}" + def replacement = "${prefix}${methodName}();\n" + + " private static ${arrayType} ${methodName}() { return new ${arrayType} {${body}}; }" + content = matcher.replaceFirst(java.util.regex.Matcher.quoteReplacement(replacement)) + logger.lifecycle("splitTokenManagerStaticInit: extracted ${fieldName} initialization into ${methodName}()") + } + } + + // Handle int[][] arrays separately (jjcompositeState, jjnextStateSet) + def arrayArrayFields = ['jjcompositeState', 'jjnextStateSet'] + arrayArrayFields.each { fieldName -> + def pattern = ~"(?s)(private\\s+static\\s+final\\s+int\\[\\]\\[\\]\\s+${fieldName}\\s*=\\s*)\\{(.*?)\\};" + def matcher = pattern.matcher(content) + if (matcher.find()) { + def prefix = matcher.group(1) + def body = matcher.group(2) + def methodName = "_init_${fieldName}" + def replacement = "${prefix}${methodName}();\n" + + " private static int[][] ${methodName}() { return new int[][] {${body}}; }" + content = matcher.replaceFirst(java.util.regex.Matcher.quoteReplacement(replacement)) + logger.lifecycle("splitTokenManagerStaticInit: extracted ${fieldName} initialization into ${methodName}()") + } + } + + file.text = content + } +} + +tasks.withType(JavaCompile).configureEach { + dependsOn('splitTokenManagerStaticInit') } java { @@ -124,16 +277,13 @@ java { sourceCompatibility = '11' targetCompatibility = '11' + // needed for XML-Doclet to work (since Doclet changed again with Java 13) toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) + languageVersion.set(JavaLanguageVersion.of(17)) } } -compileJava { - options.release = 11 -} - javadoc { include("build/generated/javacc/net/sf/jsqlparser/parser/*.java" ) if(JavaVersion.current().isJava9Compatible()) { @@ -145,171 +295,178 @@ javadoc { jar { manifest { attributes ( - "Automatic-Module-Name": "net.sf.jsqlparser" + "Automatic-Module-Name": "net.sf.jsqlparser" ) } + + bundle { + properties.empty() + bnd( + "Created-By": System.properties.get('user.name'), + "Bundle-SymbolicName": "net.sf.jsqlparser", + "Import-Package": "*", + "Export-Package": "net.sf.jsqlparser.*", + "Automatic-Module-Name": "net.sf.jsqlparser" + ) + } + + dependsOn(generateBuildInfo) } tasks.register('xmldoc', Javadoc) { + dependsOn(compileJavacc) + def outFile = reporting.file( version.endsWith("-SNAPSHOT") ? "xmlDoclet/javadoc_snapshot.xml" : "xmlDoclet/javadoc_stable.xml" ) - def rstFile = reporting.file( - version.endsWith("-SNAPSHOT") - ? "xmlDoclet/javadoc_snapshot.rst" - : "xmlDoclet/javadoc_stable.rst" - ) - source = sourceSets.main.allJava - // beware: Gradle deletes this folder automatically and there is no switch-off + // add any generated Java sources + source += fileTree(layout.buildDirectory.dir("generated/javacc").get().asFile) { + include '**/*.java' + } + source += fileTree(layout.buildDirectory.dir("generated/jjtree").get().asFile) { + include '**/*.java' + } + + classpath = sourceSets.main.runtimeClasspath + destinationDir = reporting.file("xmlDoclet") options.docletpath = configurations.xmlDoclet.files as List - options.doclet = "com.github.markusbernhardt.xmldoclet.XmlDoclet" + options.doclet = "com.manticore.tools.xmldoclet.XmlDoclet" title = "API $version" - options.addBooleanOption("rst", true) - options.addBooleanOption("withFloatingToc", Boolean.parseBoolean(System.getenv().getOrDefault("FLOATING_TOC", "true"))) + options.addStringOption("basePackage", "net.sf.jsqlparser") options.addStringOption("filename", outFile.getName()) - dependsOn(compileJava) doLast { copy { - from rstFile - into "${projectDir}/src/site/sphinx/" + from outFile + into layout.projectDirectory.dir("src/site/sphinx/").asFile } } } test { - environment = [ 'EXPORT_TEST_TO_FILE': 'True' ] + environment = [ 'EXPORT_TEST_TO_FILE': 'False' ] useJUnitPlatform() // set heap size for the test JVM(s) - minHeapSize = "128m" - maxHeapSize = "1G" + minHeapSize = "1G" + maxHeapSize = "4G" + + // set JVM stack size + jvmArgs = ['-Xss2m', '--add-opens=java.base/java.lang=ALL-UNNAMED'] + + jacoco { + excludes = ['net/sf/jsqlparser/parser/CCJSqlParserTokenManager'] + } } coveralls { jacocoReportPath 'build/reports/jacoco/test/jacocoTestReport.xml' } -// -//jacocoTestReport { -// afterEvaluate { -// classDirectories.setFrom(files(classDirectories.files.collect { -// fileTree(dir: it, exclude: ' net/sf/jsqlparser/parser/CCJSqlParserTokenManager') -// })) -// } -// dependsOn test // tests are required to run before generating the report -// reports { -// xml.required = false -// csv.required = false -// html.outputLocation = layout.buildDirectory.dir('reports/jacoco') -// } -//} -//jacocoTestCoverageVerification { -// violationRules { -// rule { -// //element = 'CLASS' -// limit { -// //@todo: temporarily reduced it 80%, we need to bring that back to 84% accepting the Keywords PR -// minimum = 0.80 -// } -// excludes = [ -// 'net.sf.jsqlparser.util.validation.*', -// 'net.sf.jsqlparser.**.*Adapter', -// 'net.sf.jsqlparser.parser.JJTCCJSqlParserState', -// 'net.sf.jsqlparser.parser.TokenMgrError', -// 'net.sf.jsqlparser.parser.StreamProvider', -// 'net.sf.jsqlparser.parser.CCJSqlParserTokenManager', -// 'net.sf.jsqlparser.parser.ParseException', -// 'net.sf.jsqlparser.parser.SimpleNode', -// 'net.sf.jsqlparser.parser.SimpleCharStream', -// 'net.sf.jsqlparser.parser.StringProvider', -// 'net.sf.jsqlparser.parser.CCJSqlParserTokenManager' -// ] -// } + +jacocoTestReport { + dependsOn test // tests are required to run before generating the report + reports { + xml.required = false + csv.required = false + html.outputLocation = layout.buildDirectory.dir('reports/jacoco') + } +} +jacocoTestCoverageVerification { + // Jacoco can't handle the TokenManager class + afterEvaluate { + classDirectories.setFrom(files(classDirectories.files.collect { + fileTree(dir: it, exclude: [ + "**CCJSqlParserTokenManager**" + ]) + })) + } + violationRules { + rule { + //element = 'CLASS' + limit { + //@todo: temporarily reduced it 80%, we need to bring that back to 84% accepting the Keywords PR + minimum = 0.50 + } + excludes = [ + 'net.sf.jsqlparser.util.validation.*', + 'net.sf.jsqlparser.**.*Adapter', + 'net.sf.jsqlparser.parser.**' + ] + } + rule { + //element = 'CLASS' + limit { + counter = 'LINE' + value = 'MISSEDCOUNT' + + //@todo: temporarily increased to 7000, we need to bring that down to 5500 after accepting the Keywords PR + maximum = 20000 + } + excludes = [ + 'net.sf.jsqlparser.util.validation.*', + 'net.sf.jsqlparser.**.*Adapter', + 'net.sf.jsqlparser.parser.**' + ] + } // rule { -// //element = 'CLASS' +// element = 'CLASS' // limit { // counter = 'LINE' -// value = 'MISSEDCOUNT' -// -// //@todo: temporarily increased to 7000, we need to bring that down to 5500 after accepting the Keywords PR -// maximum = 7000 -// } -// excludes = [ +// value = 'MISSEDRATIO' +// maximum = 0.3 +// } +// excludes = [ // 'net.sf.jsqlparser.util.validation.*', // 'net.sf.jsqlparser.**.*Adapter', -// 'net.sf.jsqlparser.parser.JJTCCJSqlParserState', -// 'net.sf.jsqlparser.parser.TokenMgrError', -// 'net.sf.jsqlparser.parser.StreamProvider', -// 'net.sf.jsqlparser.parser.CCJSqlParserTokenManager', -// 'net.sf.jsqlparser.parser.ParseException', -// 'net.sf.jsqlparser.parser.SimpleNode', -// 'net.sf.jsqlparser.parser.SimpleCharStream', -// 'net.sf.jsqlparser.parser.StringProvider', -// 'net.sf.jsqlparser.parser.CCJSqlParserTokenManager' +// 'net.sf.jsqlparser.parser.**' // ] // } -//// rule { -//// element = 'CLASS' -//// limit { -//// counter = 'LINE' -//// value = 'MISSEDRATIO' -//// maximum = 0.3 -//// } -//// excludes = [ -//// 'net.sf.jsqlparser.util.validation.*', -//// 'net.sf.jsqlparser.**.*Adapter', -//// 'net.sf.jsqlparser.parser.JJTCCJSqlParserState', -//// 'net.sf.jsqlparser.parser.TokenMgrError', -//// 'net.sf.jsqlparser.parser.StreamProvider', -//// 'net.sf.jsqlparser.parser.CCJSqlParserTokenManager', -//// 'net.sf.jsqlparser.parser.ParseException', -//// 'net.sf.jsqlparser.parser.SimpleNode', -//// 'net.sf.jsqlparser.parser.SimpleCharStream', -//// 'net.sf.jsqlparser.parser.StringProvider', -//// ] -//// } -// } -//} + } +} spotbugsMain { reports { - html { - enabled = true - destination = file("build/reports/spotbugs/main/spotbugs.html") - stylesheet = 'fancy-hist.xsl' - } + html.required.set(true) + html.outputLocation.set( layout.buildDirectory.file("reports/spotbugs/main/spotbugs.html").get().asFile ) + html.stylesheet="fancy-hist.xsl" } } + spotbugs { // fail only on P1 and without the net.sf.jsqlparser.parser.* excludeFilter = file("config/spotbugs/spotBugsExcludeFilter.xml") +} - // do not run over the test, although we should do that eventually - spotbugsTest.enabled = false +// do not run over the test, although we should do that eventually +tasks.named('spotbugsTest').configure { + enabled = false } pmd { + // later versions throw NPE + toolVersion = '7.17.0' + consoleOutput = true sourceSets = [sourceSets.main] // clear the ruleset in order to use configured rules only ruleSets = [] - - //rulesMinimumPriority = 1 + rulesMinimumPriority = 2 ruleSetFiles = files("config/pmd/ruleset.xml") +} - pmdMain { - excludes = [ - "build/generated/*" - ] - } +tasks.named('pmdMain').configure { + excludes = [ + "build/generated/*" + , "**/net/sf/jsqlparser/parser/SimpleCharStream.java" + ] } checkstyle { @@ -317,6 +474,17 @@ checkstyle { configFile = rootProject.file('config/checkstyle/checkstyle.xml') } +tasks.withType(Checkstyle).configureEach { + reports { + xml.required = false + html.required = true + } + excludes = [ + "**/module-info.java" + , "net/sf/jsqlparser/parser/SimpleCharStream.java" + ] +} + spotless { // optional: limit format enforcement to just the files changed by this feature branch ratchetFrom 'origin/master' @@ -327,82 +495,81 @@ spotless { // define the steps to apply to those files trimTrailingWhitespace() - indentWithSpaces(4) // or spaces. Takes an integer argument if you don't like 4 + leadingTabsToSpaces(4) endWithNewline() } java { - indentWithSpaces(4) + leadingTabsToSpaces(4) eclipse().configFile('config/formatter/eclipse-java-google-style.xml') } } -tasks.withType(Checkstyle).configureEach { - reports { - xml.required = false - html.required = true - } - excludes = [ "**/module-info.java" ] -} tasks.register('renderRR') { dependsOn(compileJavacc) + doLast { - // these WAR files have been provided as a courtesy by Gunther Rademacher - // and belong to the RR - Railroad Diagram Generator Project - // https://github.com/GuntherRademacher/rr - // - // Hosting at manticore-projects.com is temporary until a better solution is found - // Please do not use these files without Gunther's permission + def rrDir = layout.buildDirectory.dir("rr").get().asFile + + // Download convert.war download.run { src 'http://manticore-projects.com/download/convert.war' - dest "$buildDir/rr/convert.war" + dest new File(rrDir, "convert.war") overwrite false onlyIfModified true } + // Download rr.war download.run { src 'http://manticore-projects.com/download/rr.war' - dest "$buildDir/rr/rr.war" + dest new File(rrDir, "rr.war") overwrite false onlyIfModified true tempAndMove true } - javaexec { - standardOutput = new FileOutputStream("${buildDir}/rr/JSqlParserCC.ebnf") - main = "-jar" - args = [ - "$buildDir/rr/convert.war", - "$buildDir/generated/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jj" - ] + // Convert JJ file to EBNF + def ebnfFile = new File(rrDir, "JSqlParserCC.ebnf") + def jjFile = layout.buildDirectory.dir("generated/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jj").get().asFile.absolutePath + + def convertProc = new ProcessBuilder('java', '-jar', + new File(rrDir, "convert.war").absolutePath, + jjFile) + .redirectOutput(ebnfFile) + .redirectErrorStream(true) + .start() + if (convertProc.waitFor() != 0) { + throw new GradleException("Failed to convert JJ to EBNF") } - javaexec { - main = "-jar" - args = [ - "$buildDir/rr/rr.war", - "-noepsilon", - "-color:#4D88FF", - "-offset:0", - "-width:800", - //"-png", - //"-out:${buildDir}/rr/JSqlParserCC.zip", - "-out:${buildDir}/rr/JSqlParserCC.xhtml", - "${buildDir}/rr/JSqlParserCC.ebnf" - ] + // Generate RR diagrams + def rrProc = new ProcessBuilder('java', '-jar', + new File(rrDir, "rr.war").absolutePath, + "-noepsilon", + "-color:#4D88FF", + "-offset:0", + "-width:800", + "-out:${new File(rrDir, "JSqlParserCC.xhtml")}", + new File(rrDir, "JSqlParserCC.ebnf").absolutePath) + .redirectErrorStream(true) + .start() + rrProc.inputStream.eachLine { logger.info(it) } + if (rrProc.waitFor() != 0) { + throw new GradleException("Failed to generate RR diagrams") } } } + tasks.register('gitChangelogTask', GitChangelogTask) { - fromRepo = file("$projectDir") - file = new File("${projectDir}/src/site/sphinx/changelog.rst") - fromRef = "4.0" + fromRepo.set( file("$projectDir").toString() ) + file.set( new File("${projectDir}/src/site/sphinx/changelog.rst") ) + fromRevision.set( "4.0") //toRef = "1.1"; // switch off the formatter since the indentation matters for Mark-down // @formatter:off - templateContent =""" + templateContent.set (""" ************************ Changelog ************************ @@ -429,38 +596,38 @@ Version {{name}} {{/issues}} {{/tags}} -""" +""") // @formatter:on } tasks.register('updateKeywords', JavaExec) { group = "Execution" - description = "Run the main class with JavaExecTask" + description = "Generate the Reserved Keywords documentation" classpath = sourceSets.main.runtimeClasspath args = [ file('src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt').absolutePath , file('src/site/sphinx/keywords.rst').absolutePath ] - main("net.sf.jsqlparser.parser.ParserKeywordsUtils") + mainClass.set("net.sf.jsqlparser.parser.ParserKeywordsUtils") dependsOn(compileJava) } -xslt { +tasks.register('xslt', SaxonXsltTask) { def outFile = version.endsWith("-SNAPSHOT") - ? file("src/site/sphinx/syntax_snapshot.rst") - : file("src/site/sphinx/syntax_stable.rst") + ? file("src/site/sphinx/syntax_snapshot.rst") + : file("src/site/sphinx/syntax_stable.rst") dependsOn(renderRR) - stylesheet 'src/main/resources/rr/xhtml2rst.xsl' + stylesheet file('src/main/resources/rr/xhtml2rst.xsl') - parameters ( - "withFloatingToc": System.getenv().getOrDefault("FLOATING_TOC", "true"), + parameters( + "withFloatingToc": System.getProperty("FLOATING_TOC", "false"), "isSnapshot": Boolean.toString(version.endsWith("-SNAPSHOT")) ) // Transform every .xml file in the "input" directory. - input "$buildDir/rr/JSqlParserCC.xhtml" + input layout.buildDirectory.file("rr/JSqlParserCC.xhtml").get() output outFile } @@ -491,7 +658,7 @@ tasks.register('sphinx', Exec) { , "-Drelease=${getVersion(false)}" , "-Drst_prolog=$PROLOG" , "${projectDir}/src/site/sphinx" - , "${project.buildDir}/sphinx" + , layout.buildDirectory.file("sphinx").get().asFile ] executable "sphinx-build" @@ -515,6 +682,7 @@ publishing { artifactId = 'jsqlparser' from components.java + versionMapping { usage('java-api') { fromResolutionOf('runtimeClasspath') @@ -523,54 +691,61 @@ publishing { fromResolutionResult() } } + pom { - name = 'JSQLParser library' - description = 'Parse SQL Statements into Abstract Syntax Trees (AST)' - url = 'https://github.com/JSQLParser/JSqlParser' + name.set('JSQLParser library') + description.set('Parse SQL Statements into Abstract Syntax Trees (AST)') + url.set('https://github.com/JSQLParser/JSqlParser') + licenses { license { - name = 'GNU Library or Lesser General Public License (LGPL) V2.1' - url = 'http://www.gnu.org/licenses/lgpl-2.1.html' + name.set('GNU Library or Lesser General Public License (LGPL) V2.1') + url.set('http://www.gnu.org/licenses/lgpl-2.1.html') } license { - name = 'The Apache Software License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + name.set('The Apache Software License, Version 2.0') + url.set('http://www.apache.org/licenses/LICENSE-2.0.txt') } } + developers { developer { - id = 'twa' - name = 'Tobias Warneke' - email = 't.warneke@gmx.net' + id.set('twa') + name.set('Tobias Warneke') + email.set('t.warneke@gmx.net') } developer { - id = 'are' - name = 'Andreas Reichel' - email = 'andreas@manticore-projects.com' + id.set('are') + name.set('Andreas Reichel') + email.set('andreas@manticore-projects.com') } } + scm { - connection = 'scm:git:https://github.com/JSQLParser/JSqlParser.git' - developerConnection = 'scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git' - url = 'https://github.com/JSQLParser/JSqlParser.git' + connection.set('scm:git:https://github.com/JSQLParser/JSqlParser.git') + developerConnection.set('scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git') + url.set('https://github.com/JSQLParser/JSqlParser.git') } } } } + repositories { maven { - name "ossrh" - def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - def snapshotsRepoUrl= "https://oss.sonatype.org/content/repositories/snapshots/" - url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + name = "ossrh" + def releasesRepoUrl = "https://central.sonatype.com/repository/maven-releases" + def snapshotsRepoUrl = "https://central.sonatype.com/repository/maven-snapshots/" + url(version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl) + credentials { - username = System.getenv("ossrhUsername") - password = System.getenv("ossrhPassword") + username = providers.environmentVariable("ossrhUsername").orNull + password = providers.environmentVariable("ossrhPassword").orNull } } } } + signing { //def signingKey = findProperty("signingKey") //def signingPassword = findProperty("signingPassword") @@ -588,12 +763,13 @@ tasks.withType(JavaCompile).configureEach { remotes { webServer { - host = findProperty("${project.name}.host") - user = findProperty("${project.name}.username") - identity = new File("${System.properties['user.home']}/.ssh/id_rsa") + host = findProperty("${project.name}.host") ?: "defaultHost" // Provide default if not found + user = findProperty("${project.name}.username") ?: "defaultUsername" // Provide default if not found + identity = file("${System.getProperty('user.home')}/.ssh/id_rsa") } } + tasks.register('upload') { doFirst { if (findProperty("${project.name}.host") == null) { @@ -610,12 +786,24 @@ tasks.register('upload') { session(remotes.webServer) { def versionStable = getVersion(false) execute "mkdir -p download/${project.name}-${versionStable}" - for (File file: fileTree(include:['*.jar'], dir:"${project.buildDir}/libs").collect()) { + for (File file: fileTree(include:['*.jar'], dir: layout.buildDirectory.dir("libs").get()).collect()) { put from: file, into: "download/${project.name}-${versionStable}" } } } } + + dependsOn(check, assemble, gitChangelogTask, renderRR, xslt, xmldoc) +} + +check { + dependsOn jacocoTestCoverageVerification } -upload.dependsOn(check, assemble, gitChangelogTask, renderRR, xslt, xmldoc) +jmh { + includes = ['.*JSQLParserBenchmark.*'] + warmupIterations = 2 + fork = 3 + iterations = 5 + timeOnIteration = '1s' +} \ No newline at end of file diff --git a/config/pmd/ruleset.xml b/config/pmd/ruleset.xml index acca2d6e9..45804d4c0 100644 --- a/config/pmd/ruleset.xml +++ b/config/pmd/ruleset.xml @@ -20,14 +20,15 @@ under the License. - The default ruleset used by the Maven PMD Plugin, when no other ruleset is specified. - It contains the rules of the old (pre PMD 6.0.0) rulesets java-basic, java-empty, java-imports, - java-unnecessary, java-unusedcode. + Custom PMD ruleset, compatible with PMD 7.x. - This ruleset might be used as a starting point for an own customized ruleset [0]. + Based on the old (pre PMD 6.0.0) rulesets java-basic, java-empty, java-imports, + java-unnecessary, java-unusedcode, migrated for PMD 7. - [0] https://pmd.github.io/latest/pmd_userdocs_making_rulesets.html - + This ruleset might be used as a starting point for an own customized ruleset [0]. + + [0] https://pmd.github.io/latest/pmd_userdocs_making_rulesets.html + @@ -46,6 +47,14 @@ under the License. + + + + + + @@ -63,14 +72,15 @@ under the License. - - + + + @@ -80,16 +90,10 @@ under the License. + + - - - - - - - - - + @@ -97,15 +101,14 @@ under the License. - - - + + - + - + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 522c7558e..8b590d14c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx1G -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -Xss8m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError org.gradle.caching=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c4..d997cfc60 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3fa8f862f..dbc3ce4a0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0adc8e1a5..f640dbced 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob//platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -145,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -170,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -202,16 +202,15 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 6689b85be..c4bdd3ab8 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,92 +1,93 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/nb-configuration.xml b/nb-configuration.xml index 8771b5deb..2c751cae4 100644 --- a/nb-configuration.xml +++ b/nb-configuration.xml @@ -19,7 +19,7 @@ LF false true - JDK_1.8 + JDK_11 false none 4 diff --git a/pom.xml b/pom.xml index 92c47c42d..5ac0c4666 100644 --- a/pom.xml +++ b/pom.xml @@ -2,11 +2,11 @@ 4.0.0 com.github.jsqlparser jsqlparser - 4.10-SNAPSHOT - JSQLParser library + 5.4-SNAPSHOT + JSQLParser library 2004 - JSQLParser + JSQLParser bundle https://github.com/JSQLParser/JSqlParser @@ -24,65 +24,121 @@ + + + javacc8-snapshots + + true + + false + https://central.sonatype.com/repository/maven-snapshots/ + + + ossrh-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + true + false + + + + + javacc8-snapshots + + true + + false + https://central.sonatype.com/repository/maven-snapshots/ + + + ossrh-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + true + false + + + - net.java.dev.javacc - javacc - [7.0.13,) + org.javacc + core + 8.1.0-SNAPSHOT + pom + test + + + org.javacc.generator + java + 8.1.0-SNAPSHOT test - commons-io commons-io - [2.15.1,) + 2.18.0 test - org.junit.jupiter - junit-jupiter - [5.10.2,) - test + org.junit.jupiter + junit-jupiter + 5.11.4 + test org.mockito mockito-core - [5.11.0,) + 5.15.2 test org.mockito mockito-junit-jupiter - [5.11.0,) + 5.15.2 test org.assertj assertj-core - [3.25.3,) + (3.27.7,) test org.apache.commons commons-lang3 - [3.14.0,) + [3.18.0,) test com.h2database h2 - [2.2.224,) + [2.3.232,) test org.hamcrest - hamcrest-all - 1.3 + hamcrest + 2.2 + test + + + + + org.openjdk.jmh + jmh-core + 1.37 test + + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + provided + + @@ -95,11 +151,13 @@ sonatype-nexus-staging - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + https://central.sonatype.com/repository/maven-releases sonatype-nexus-snapshots - https://oss.sonatype.org/content/repositories/snapshots/ + https://central.sonatype.com/repository/maven-snapshots/ + false + true @@ -121,7 +179,7 @@ org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.5.0 net.sf.jsqlparser.parser.ParserKeywordsUtils @@ -133,8 +191,9 @@ org.apache.maven.plugins maven-pmd-plugin - 3.21.2 + 3.26.0 + 2 ${project.basedir}/config/pmd/ruleset.xml @@ -142,6 +201,7 @@ **/*Bean.java **/generated/*.java + **/net/sf/jsqlparser/parser/SimpleCharStream.java target/generated-sources @@ -174,7 +234,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.2.0 + 3.6.0 add-source @@ -193,20 +253,31 @@ maven-compiler-plugin - 3.10.1 + 3.14.0 11 11 true ${project.build.sourceEncoding} true + 2000m + + -J-Xss4M + + true + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + + org.javacc.plugin javacc-maven-plugin - 3.0.3 - + 3.8.0 javacc @@ -214,26 +285,31 @@ jjtree-javacc + + + -CODE_GENERATOR="Java" + -GRAMMAR_ENCODING="UTF-8" + + + -GRAMMAR_ENCODING="UTF-8" + -CODE_GENERATOR="Java" + + - net.java.dev.javacc - javacc - 7.0.13 + org.javacc.generator + java + 8.1.0-SNAPSHOT + + + org.javacc + core + 8.1.0-SNAPSHOT - - org.apache.maven.plugins - maven-eclipse-plugin - 2.9 - - - /target/generated-sources/javacc - - - org.apache.maven.plugins maven-resources-plugin @@ -269,32 +345,23 @@ org.apache.maven.plugins maven-release-plugin - - 3.0.0-M7 + --> + 3.1.1 true false forked-path sign-release-artifacts - org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.3.1 attach-sources @@ -307,7 +374,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.4.1 + 3.11.2 attach-javadocs @@ -315,6 +382,10 @@ ${javadoc.opts} net.sf.jsqlparser.parser none + true + 2g + 800m + -J-Xss4m jar @@ -325,7 +396,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.2 @@ -334,41 +405,6 @@ - - maven-site-plugin - 3.12.1 - - - attach-descriptor - - attach-descriptor - - - - - en - - - - org.eluder.coveralls - coveralls-maven-plugin - 4.3.0 - - - org.codehaus.mojo - cobertura-maven-plugin - 2.7 - - xml - - - net/sf/jsqlparser/parser/*.class - net/sf/jsqlparser/JSQLParserException.class - - - - - org.apache.felix maven-bundle-plugin @@ -378,7 +414,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.5.2 false @@ -386,13 +422,14 @@ --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED + -Xmx2G -Xms800m -Xss4m org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.13 @@ -411,7 +448,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.28.0 + 2.44.4 origin/master @@ -452,28 +489,40 @@ + + org.sonatype.central + central-publishing-maven-plugin + 0.10.0 + true + + sonatype-nexus + + - + org.apache.maven.plugins maven-surefire-report-plugin - 3.0.0-M7 + 3.5.2 ${project.reporting.outputDirectory}/testresults + -Xmx2G -Xms800m -Xss4m org.apache.maven.plugins maven-javadoc-plugin - 3.4.1 + 3.11.2 true - 800m none - + 2g + 800m + -J-Xss2m + `'ü'` public StringValue getStringValue() { return new StringValue( diff --git a/src/main/java/net/sf/jsqlparser/expression/HighExpression.java b/src/main/java/net/sf/jsqlparser/expression/HighExpression.java new file mode 100644 index 000000000..4d3a9cd63 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/HighExpression.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class HighExpression extends ASTNodeAccessImpl implements Expression { + private Expression expression; + + public HighExpression() { + // empty constructor + } + + public HighExpression(Expression expression) { + this.expression = expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return "HIGH " + expression.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/IntervalExpression.java b/src/main/java/net/sf/jsqlparser/expression/IntervalExpression.java index 26584c63d..9c028c769 100644 --- a/src/main/java/net/sf/jsqlparser/expression/IntervalExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/IntervalExpression.java @@ -15,9 +15,9 @@ public class IntervalExpression extends ASTNodeAccessImpl implements Expression { + private final boolean intervalKeyword; private String parameter = null; private String intervalType = null; - private final boolean intervalKeyword; private Expression expression = null; public IntervalExpression() { @@ -28,6 +28,13 @@ public IntervalExpression(boolean intervalKeyword) { this.intervalKeyword = intervalKeyword; } + public IntervalExpression(int value, String type) { + this.parameter = null; + this.intervalKeyword = true; + this.expression = new LongValue(value); + this.intervalType = type; + } + public boolean isUsingIntervalKeyword() { return intervalKeyword; } @@ -64,8 +71,8 @@ public String toString() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public IntervalExpression withParameter(String parameter) { diff --git a/src/main/java/net/sf/jsqlparser/expression/Inverse.java b/src/main/java/net/sf/jsqlparser/expression/Inverse.java new file mode 100644 index 000000000..b50d8be8f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/Inverse.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class Inverse extends ASTNodeAccessImpl implements Expression { + private Expression expression; + + public Inverse() { + // empty constructor + } + + public Inverse(Expression expression) { + this.expression = expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return "INVERSE (" + expression.toString() + ")"; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JdbcNamedParameter.java b/src/main/java/net/sf/jsqlparser/expression/JdbcNamedParameter.java index 9e8d83792..84aa0b34e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JdbcNamedParameter.java +++ b/src/main/java/net/sf/jsqlparser/expression/JdbcNamedParameter.java @@ -39,8 +39,8 @@ public void setName(String name) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java b/src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java index aaedebc68..f512c47fc 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java +++ b/src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java @@ -67,8 +67,8 @@ public void setUseFixedIndex(boolean useFixedIndex) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateFunction.java b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateFunction.java index 497c8dbc5..20bfa272e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateFunction.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateFunction.java @@ -11,21 +11,19 @@ import java.util.List; import java.util.Objects; + import net.sf.jsqlparser.statement.select.OrderByElement; /** - * * @author Andreas Reichel */ public class JsonAggregateFunction extends FilterOverImpl implements Expression { + private final OrderByClause expressionOrderBy = new OrderByClause(); private JsonFunctionType functionType; - private Expression expression = null; - private final OrderByClause expressionOrderBy = new OrderByClause(); - private boolean usingKeyKeyword = false; - private String key; + private Object key; private boolean usingValueKeyword = false; private Object value; @@ -70,11 +68,6 @@ public void setType(JsonFunctionType type) { "The Type of the JSON Aggregate Function must not be null"); } - public JsonAggregateFunction withType(JsonFunctionType type) { - this.setType(type); - return this; - } - public void setType(String typeName) { this.functionType = JsonFunctionType .valueOf(Objects @@ -83,6 +76,11 @@ public void setType(String typeName) { .toUpperCase()); } + public JsonAggregateFunction withType(JsonFunctionType type) { + this.setType(type); + return this; + } + public JsonAggregateFunction withType(String typeName) { this.setType(typeName); return this; @@ -114,15 +112,15 @@ public JsonAggregateFunction withUsingKeyKeyword(boolean usingKeyKeyword) { return this; } - public String getKey() { + public Object getKey() { return key; } - public void setKey(String key) { + public void setKey(Object key) { this.key = key; } - public JsonAggregateFunction withKey(String key) { + public JsonAggregateFunction withKey(Object key) { this.setKey(key); return this; } @@ -181,8 +179,8 @@ public JsonAggregateFunction withExpressionOrderByElements( } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } // avoid countless Builder --> String conversion @@ -190,6 +188,7 @@ public void accept(ExpressionVisitor expressionVisitor) { public StringBuilder append(StringBuilder builder) { switch (functionType) { case OBJECT: + case MYSQL_OBJECT: appendObject(builder); break; case ARRAY: @@ -211,6 +210,8 @@ public StringBuilder appendObject(StringBuilder builder) { builder.append("KEY "); } builder.append(key).append(" VALUE ").append(value); + } else if (functionType == JsonFunctionType.MYSQL_OBJECT) { + builder.append(key).append(", ").append(value); } else { builder.append(key).append(":").append(value); } diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateOnNullType.java b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateOnNullType.java index d9e2b4c51..898dad7c0 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateOnNullType.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateOnNullType.java @@ -26,7 +26,6 @@ package net.sf.jsqlparser.expression; /** - * * @author Andreas Reichel */ public enum JsonAggregateOnNullType { diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateUniqueKeysType.java b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateUniqueKeysType.java index aa1370595..097aad552 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateUniqueKeysType.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateUniqueKeysType.java @@ -26,7 +26,6 @@ package net.sf.jsqlparser.expression; /** - * * @author Andreas Reichel */ public enum JsonAggregateUniqueKeysType { diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonExpression.java b/src/main/java/net/sf/jsqlparser/expression/JsonExpression.java index 9fe2811cf..f258e855c 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonExpression.java @@ -18,10 +18,9 @@ import java.util.Map; public class JsonExpression extends ASTNodeAccessImpl implements Expression { + private final List> idents = new ArrayList<>(); private Expression expr; - private final List> idents = new ArrayList<>(); - public JsonExpression() { } @@ -30,14 +29,14 @@ public JsonExpression(Expression expr) { this.expr = expr; } - public JsonExpression(Expression expr, List> idents) { + public JsonExpression(Expression expr, List> idents) { this.expr = expr; this.idents.addAll(idents); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public Expression getExpression() { @@ -48,26 +47,26 @@ public void setExpression(Expression expr) { this.expr = expr; } - public void addIdent(String ident, String operator) { + public void addIdent(Expression ident, String operator) { idents.add(new AbstractMap.SimpleEntry<>(ident, operator)); } - public void addAllIdents(Collection> idents) { + public void addAllIdents(Collection> idents) { this.idents.addAll(idents); } - public List> getIdentList() { + public List> getIdentList() { return idents; } - public Map.Entry getIdent(int index) { + public Map.Entry getIdent(int index) { return idents.get(index); } @Deprecated - public List getIdents() { - ArrayList l = new ArrayList<>(); - for (Map.Entry ident : idents) { + public List getIdents() { + ArrayList l = new ArrayList<>(); + for (Map.Entry ident : idents) { l.add(ident.getKey()); } @@ -77,7 +76,7 @@ public List getIdents() { @Deprecated public List getOperators() { ArrayList l = new ArrayList<>(); - for (Map.Entry ident : idents) { + for (Map.Entry ident : idents) { l.add(ident.getValue()); } return l; @@ -87,7 +86,7 @@ public List getOperators() { public String toString() { StringBuilder b = new StringBuilder(); b.append(expr.toString()); - for (Map.Entry ident : idents) { + for (Map.Entry ident : idents) { b.append(ident.getValue()).append(ident.getKey()); } return b.toString(); diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java index 9d09b9711..3cc409873 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java @@ -11,251 +11,598 @@ import java.util.ArrayList; import java.util.Objects; + import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.create.table.ColDataType; /** + * Represents a JSON-Function.
+ * Currently supported are the types in {@link JsonFunctionType}.
+ *
+ * For JSON_OBJECT the parameters are available from {@link #getKeyValuePairs()}
+ *
+ * For JSON_ARRAY the parameters are availble from {@link #getExpressions()}.
* * @author Andreas Reichel */ - public class JsonFunction extends ASTNodeAccessImpl implements Expression { - private JsonFunctionType functionType; - private final ArrayList keyValuePairs = new ArrayList<>(); - private final ArrayList expressions = new ArrayList<>(); - private JsonAggregateOnNullType onNullType; - private JsonAggregateUniqueKeysType uniqueKeysType; - - public ArrayList getKeyValuePairs() { - return keyValuePairs; - } - - public ArrayList getExpressions() { - return expressions; - } - - public JsonKeyValuePair getKeyValuePair(int i) { - return keyValuePairs.get(i); - } - - public JsonFunctionExpression getExpression(int i) { - return expressions.get(i); - } - - public boolean add(JsonKeyValuePair keyValuePair) { - return keyValuePairs.add(keyValuePair); - } - - public void add(int i, JsonKeyValuePair keyValuePair) { - keyValuePairs.add(i, keyValuePair); - } - - public boolean add(JsonFunctionExpression expression) { - return expressions.add(expression); - } - - public void add(int i, JsonFunctionExpression expression) { - expressions.add(i, expression); - } - - public boolean isEmpty() { - return keyValuePairs.isEmpty(); - } - - public JsonAggregateOnNullType getOnNullType() { - return onNullType; - } - - public void setOnNullType(JsonAggregateOnNullType onNullType) { - this.onNullType = onNullType; - } - - public JsonFunction withOnNullType(JsonAggregateOnNullType onNullType) { - this.setOnNullType(onNullType); - return this; - } - - public JsonAggregateUniqueKeysType getUniqueKeysType() { - return uniqueKeysType; - } - - public void setUniqueKeysType(JsonAggregateUniqueKeysType uniqueKeysType) { - this.uniqueKeysType = uniqueKeysType; - } - - public JsonFunction withUniqueKeysType(JsonAggregateUniqueKeysType uniqueKeysType) { - this.setUniqueKeysType(uniqueKeysType); - return this; - } - - public JsonFunctionType getType() { - return functionType; - } - - public void setType(JsonFunctionType type) { - this.functionType = - Objects.requireNonNull(type, "The Type of the JSON Aggregate Function must not be null"); - } - - public JsonFunction withType(JsonFunctionType type) { - this.setType(type); - return this; - } - - public void setType(String typeName) { - this.functionType = JsonFunctionType.valueOf( - Objects.requireNonNull(typeName, "The Type of the JSON Aggregate Function must not be null") - .toUpperCase()); - } - - public JsonFunction withType(String typeName) { - this.setType(typeName); - return this; - } - - @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); - } - - // avoid countless Builder --> String conversion - public StringBuilder append(StringBuilder builder) { - switch (functionType) { - case OBJECT: - appendObject(builder); - break; - case POSTGRES_OBJECT: - appendPostgresObject(builder); - break; - case MYSQL_OBJECT: - appendMySqlObject(builder); - break; - case ARRAY: - appendArray(builder); - break; - default: - // this should never happen really - } - return builder; - } - - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) - public StringBuilder appendObject(StringBuilder builder) { - builder.append("JSON_OBJECT( "); - int i = 0; - for (JsonKeyValuePair keyValuePair : keyValuePairs) { - if (i > 0) { - builder.append(", "); - } - if (keyValuePair.isUsingValueKeyword()) { - if (keyValuePair.isUsingKeyKeyword()) { - builder.append("KEY "); + public enum JsonOnResponseBehaviorType { + ERROR, NULL, DEFAULT, EMPTY, EMPTY_ARRAY, EMPTY_OBJECT, TRUE, FALSE, UNKNOWN + } + + public enum JsonWrapperType { + WITHOUT, WITH + } + + public enum JsonWrapperMode { + CONDITIONAL, UNCONDITIONAL + } + + public enum JsonQuotesType { + KEEP, OMIT + } + + public enum ScalarsType { + ALLOW, DISALLOW + } + + public static class JsonOnResponseBehavior { + private JsonOnResponseBehaviorType type; + private Expression expression; + + public JsonOnResponseBehavior(JsonOnResponseBehaviorType type) { + this(type, null); + } + + public JsonOnResponseBehavior(JsonOnResponseBehaviorType type, Expression expression) { + this.type = type; + this.expression = expression; + } + + public JsonOnResponseBehaviorType getType() { + return type; + } + + public void setType(JsonOnResponseBehaviorType type) { + this.type = type; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public StringBuilder append(StringBuilder builder) { + switch (type) { + case ERROR: + builder.append("ERROR"); + break; + case NULL: + builder.append("NULL"); + break; + case DEFAULT: + builder.append("DEFAULT ").append(expression); + break; + case EMPTY: + builder.append("EMPTY "); + break; + case EMPTY_ARRAY: + builder.append("EMPTY ARRAY"); + break; + case EMPTY_OBJECT: + builder.append("EMPTY OBJECT"); + break; + case TRUE: + builder.append("TRUE"); + break; + case FALSE: + builder.append("FALSE"); + break; + case UNKNOWN: + builder.append("UNKNOWN"); + break; + default: + throw new IllegalStateException("Unhandled JsonOnResponseBehavior: " + type); + // this should never happen + } + return builder; } - builder.append(keyValuePair.getKey()).append(" VALUE ").append(keyValuePair.getValue()); - } else { - builder.append(keyValuePair.getKey()).append(":").append(keyValuePair.getValue()); - } - - if (keyValuePair.isUsingFormatJson()) { - builder.append(" FORMAT JSON"); - } - i++; - } - - if (onNullType != null) { - switch (onNullType) { - case NULL: - builder.append(" NULL ON NULL"); - break; - case ABSENT: - builder.append(" ABSENT On NULL"); - break; - default: - // this should never happen - } - } - - if (uniqueKeysType != null) { - switch (uniqueKeysType) { - case WITH: - builder.append(" WITH UNIQUE KEYS"); - break; - case WITHOUT: - builder.append(" WITHOUT UNIQUE KEYS"); - break; - default: - // this should never happen - } - } - - builder.append(" ) "); - - return builder; - } - - - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) - public StringBuilder appendPostgresObject(StringBuilder builder) { - builder.append("JSON_OBJECT( "); - for (JsonKeyValuePair keyValuePair : keyValuePairs) { - builder.append(keyValuePair.getKey()); - if (keyValuePair.getValue()!=null) { - builder.append(", ").append(keyValuePair.getValue()); - } - } - builder.append(" ) "); - - return builder; - } - - public StringBuilder appendMySqlObject(StringBuilder builder) { - builder.append("JSON_OBJECT( "); - int i=0; - for (JsonKeyValuePair keyValuePair : keyValuePairs) { - if (i>0) { - builder.append(", "); - } - builder.append(keyValuePair.getKey()); - builder.append(", ").append(keyValuePair.getValue()); - i++; - } - builder.append(" ) "); - - return builder; - } - - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) - public StringBuilder appendArray(StringBuilder builder) { - builder.append("JSON_ARRAY( "); - int i = 0; - - for (JsonFunctionExpression expr : expressions) { - if (i > 0) { - builder.append(", "); - } - expr.append(builder); - i++; - } - - if (onNullType != null) { - switch (onNullType) { - case NULL: - builder.append(" NULL ON NULL "); - break; - case ABSENT: - builder.append(" ABSENT ON NULL "); - break; - default: - // "ON NULL" was omitted - } - } - builder.append(") "); - - return builder; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - return append(builder).toString(); - } + + @Override + public String toString() { + return append(new StringBuilder()).toString(); + } + } + + private final ArrayList keyValuePairs = new ArrayList<>(); + private final ArrayList expressions = new ArrayList<>(); + private final ArrayList passingExpressions = new ArrayList<>(); + private final ArrayList additionalQueryPathArguments = new ArrayList<>(); + private JsonFunctionType functionType; + private JsonAggregateOnNullType onNullType; + private JsonAggregateUniqueKeysType uniqueKeysType; + + private boolean isStrict = false; + private JsonFunctionExpression inputExpression; + private Expression jsonPathExpression; + private ColDataType returningType; + private boolean returningFormatJson; + private String returningEncoding; + private JsonOnResponseBehavior onEmptyBehavior; + private JsonOnResponseBehavior onErrorBehavior; + private JsonWrapperType wrapperType; + private JsonWrapperMode wrapperMode; + private boolean wrapperArray; + private JsonQuotesType quotesType; + private boolean quotesOnScalarString; + private ScalarsType scalarsType; + + public JsonFunction() {} + + public JsonFunction(JsonFunctionType functionType) { + this.functionType = functionType; + } + + /** + * Returns the Parameters of an JSON_OBJECT
+ * The KeyValuePairs may not have both key and value set, in some cases only the Key is set. + * + * @see net.sf.jsqlparser.parser.feature.Feature#allowCommaAsKeyValueSeparator + * + * @return A List of KeyValuePairs, never NULL + */ + public ArrayList getKeyValuePairs() { + return keyValuePairs; + } + + /** + * Returns the parameters of JSON_ARRAY
+ * + * @return A List of {@link JsonFunctionExpression}s, never NULL + */ + public ArrayList getExpressions() { + return expressions; + } + + public JsonKeyValuePair getKeyValuePair(int i) { + return keyValuePairs.get(i); + } + + public JsonFunctionExpression getExpression(int i) { + return expressions.get(i); + } + + public boolean add(JsonKeyValuePair keyValuePair) { + return keyValuePairs.add(keyValuePair); + } + + public void add(int i, JsonKeyValuePair keyValuePair) { + keyValuePairs.add(i, keyValuePair); + } + + public boolean add(JsonFunctionExpression expression) { + return expressions.add(expression); + } + + public void add(int i, JsonFunctionExpression expression) { + expressions.add(i, expression); + } + + public ArrayList getPassingExpressions() { + return passingExpressions; + } + + public boolean addPassingExpression(Expression expression) { + return passingExpressions.add(expression); + } + + public ArrayList getAdditionalQueryPathArguments() { + return additionalQueryPathArguments; + } + + public boolean addAdditionalQueryPathArgument(String argument) { + return additionalQueryPathArguments.add(argument); + } + + public JsonFunctionExpression getInputExpression() { + return inputExpression; + } + + public void setInputExpression(JsonFunctionExpression inputExpression) { + this.inputExpression = inputExpression; + } + + public Expression getJsonPathExpression() { + return jsonPathExpression; + } + + public void setJsonPathExpression(Expression jsonPathExpression) { + this.jsonPathExpression = jsonPathExpression; + } + + public ColDataType getReturningType() { + return returningType; + } + + public void setReturningType(ColDataType returningType) { + this.returningType = returningType; + } + + public boolean isReturningFormatJson() { + return returningFormatJson; + } + + public void setReturningFormatJson(boolean returningFormatJson) { + this.returningFormatJson = returningFormatJson; + } + + public String getReturningEncoding() { + return returningEncoding; + } + + public void setReturningEncoding(String returningEncoding) { + this.returningEncoding = returningEncoding; + } + + public JsonOnResponseBehavior getOnEmptyBehavior() { + return onEmptyBehavior; + } + + public void setOnEmptyBehavior(JsonOnResponseBehavior onEmptyBehavior) { + this.onEmptyBehavior = onEmptyBehavior; + } + + public JsonOnResponseBehavior getOnErrorBehavior() { + return onErrorBehavior; + } + + public void setOnErrorBehavior(JsonOnResponseBehavior onErrorBehavior) { + this.onErrorBehavior = onErrorBehavior; + } + + public JsonWrapperType getWrapperType() { + return wrapperType; + } + + public void setWrapperType(JsonWrapperType wrapperType) { + this.wrapperType = wrapperType; + } + + public JsonWrapperMode getWrapperMode() { + return wrapperMode; + } + + public void setWrapperMode(JsonWrapperMode wrapperMode) { + this.wrapperMode = wrapperMode; + } + + public boolean isWrapperArray() { + return wrapperArray; + } + + public void setWrapperArray(boolean wrapperArray) { + this.wrapperArray = wrapperArray; + } + + public JsonQuotesType getQuotesType() { + return quotesType; + } + + public void setQuotesType(JsonQuotesType quotesType) { + this.quotesType = quotesType; + } + + public boolean isQuotesOnScalarString() { + return quotesOnScalarString; + } + + public void setQuotesOnScalarString(boolean quotesOnScalarString) { + this.quotesOnScalarString = quotesOnScalarString; + } + + public ScalarsType getScalarsType() { + return scalarsType; + } + + public void setScalarsType(ScalarsType type) { + this.scalarsType = type; + } + + public boolean isEmpty() { + return keyValuePairs.isEmpty(); + } + + public JsonAggregateOnNullType getOnNullType() { + return onNullType; + } + + public void setOnNullType(JsonAggregateOnNullType onNullType) { + this.onNullType = onNullType; + } + + public JsonFunction withOnNullType(JsonAggregateOnNullType onNullType) { + this.setOnNullType(onNullType); + return this; + } + + public JsonAggregateUniqueKeysType getUniqueKeysType() { + return uniqueKeysType; + } + + public void setUniqueKeysType(JsonAggregateUniqueKeysType uniqueKeysType) { + this.uniqueKeysType = uniqueKeysType; + } + + public JsonFunction withUniqueKeysType(JsonAggregateUniqueKeysType uniqueKeysType) { + this.setUniqueKeysType(uniqueKeysType); + return this; + } + + public JsonFunctionType getType() { + return functionType; + } + + public void setType(JsonFunctionType type) { + this.functionType = + Objects.requireNonNull(type, + "The Type of the JSON Aggregate Function must not be null"); + } + + public void setType(String typeName) { + this.functionType = JsonFunctionType.valueOf( + Objects.requireNonNull(typeName, + "The Type of the JSON Aggregate Function must not be null") + .toUpperCase()); + } + + public JsonFunction withType(JsonFunctionType type) { + this.setType(type); + return this; + } + + public JsonFunction withType(String typeName) { + this.setType(typeName); + return this; + } + + public boolean isStrict() { + return isStrict; + } + + public void setStrict(boolean strict) { + isStrict = strict; + } + + public JsonFunction withStrict(boolean strict) { + this.setStrict(strict); + return this; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + // avoid countless Builder --> String conversion + public StringBuilder append(StringBuilder builder) { + switch (functionType) { + case OBJECT: + case POSTGRES_OBJECT: + case MYSQL_OBJECT: + appendObject(builder); + break; + case ARRAY: + appendArray(builder); + break; + case VALUE: + appendValue(builder); + break; + case QUERY: + appendQuery(builder); + break; + case EXISTS: + appendExists(builder); + break; + default: + // this should never happen really + } + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendObject(StringBuilder builder) { + builder.append("JSON_OBJECT( "); + int i = 0; + for (JsonKeyValuePair keyValuePair : keyValuePairs) { + if (i > 0) { + builder.append(", "); + } + keyValuePair.append(builder); + i++; + } + + appendOnNullType(builder); + if (isStrict) { + builder.append(" STRICT"); + } + appendUniqueKeys(builder); + appendReturningClause(builder, true); + + builder.append(" ) "); + + return builder; + } + + private void appendOnNullType(StringBuilder builder) { + if (onNullType != null) { + switch (onNullType) { + case NULL: + builder.append(" NULL ON NULL"); + break; + case ABSENT: + builder.append(" ABSENT ON NULL"); + break; + default: + // this should never happen + } + } + } + + private void appendUniqueKeys(StringBuilder builder) { + if (uniqueKeysType != null) { + switch (uniqueKeysType) { + case WITH: + builder.append(" WITH UNIQUE KEYS"); + break; + case WITHOUT: + builder.append(" WITHOUT UNIQUE KEYS"); + break; + default: + // this should never happen + } + } + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendArray(StringBuilder builder) { + builder.append("JSON_ARRAY( "); + int i = 0; + + for (JsonFunctionExpression expr : expressions) { + if (i > 0) { + builder.append(", "); + } + expr.append(builder); + i++; + } + + appendOnNullType(builder); + appendReturningClause(builder, true); + builder.append(") "); + + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendValue(StringBuilder builder) { + builder.append("JSON_VALUE("); + appendValueOrQueryPrefix(builder); + + if (returningType != null) { + builder.append(" RETURNING ").append(returningType); + } + + appendOnResponseClause(builder, onEmptyBehavior, "EMPTY"); + appendOnResponseClause(builder, onErrorBehavior, "ERROR"); + + builder.append(")"); + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendQuery(StringBuilder builder) { + builder.append("JSON_QUERY("); + appendValueOrQueryPrefix(builder); + + appendReturningClause(builder, true); + + appendWrapperClause(builder); + appendQuotesClause(builder); + appendOnResponseClause(builder, onEmptyBehavior, "EMPTY"); + appendOnResponseClause(builder, onErrorBehavior, "ERROR"); + + for (String additionalQueryPathArgument : additionalQueryPathArguments) { + builder.append(", ").append(additionalQueryPathArgument); + } + + builder.append(")"); + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendExists(StringBuilder builder) { + builder.append("JSON_EXISTS("); + appendValueOrQueryPrefix(builder); + appendOnResponseClause(builder, onErrorBehavior, "ERROR"); + builder.append(")"); + return builder; + } + + private void appendValueOrQueryPrefix(StringBuilder builder) { + if (inputExpression != null) { + inputExpression.append(builder); + } + + if (jsonPathExpression != null) { + if (inputExpression != null) { + builder.append(", "); + } + builder.append(jsonPathExpression); + } + + if (!passingExpressions.isEmpty()) { + builder.append(" PASSING "); + boolean comma = false; + for (Expression passingExpression : passingExpressions) { + if (comma) { + builder.append(", "); + } else { + comma = true; + } + builder.append(passingExpression); + } + } + } + + private void appendOnResponseClause(StringBuilder builder, JsonOnResponseBehavior behavior, + String clause) { + if (behavior != null) { + builder.append(" "); + behavior.append(builder); + builder.append(" ON ").append(clause); + } + } + + private void appendReturningClause(StringBuilder builder, boolean formatJsonAllowed) { + if (returningType != null) { + builder.append(" RETURNING ").append(returningType); + if (formatJsonAllowed && returningFormatJson) { + builder.append(" FORMAT JSON"); + if (returningEncoding != null) { + builder.append(" ENCODING ").append(returningEncoding); + } + } + } + } + + private void appendWrapperClause(StringBuilder builder) { + if (wrapperType != null) { + builder.append(" ").append(wrapperType); + if (wrapperMode != null) { + builder.append(" ").append(wrapperMode); + } + if (wrapperArray) { + builder.append(" ARRAY"); + } + builder.append(" WRAPPER"); + } + } + + private void appendQuotesClause(StringBuilder builder) { + if (quotesType != null) { + builder.append(" ").append(quotesType).append(" QUOTES"); + if (quotesOnScalarString) { + builder.append(" ON SCALAR STRING"); + } + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + return append(builder).toString(); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java index e23aa2751..738c09fc2 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java @@ -14,7 +14,6 @@ import java.util.Objects; /** - * * @author Andreas Reichel */ @@ -22,10 +21,12 @@ public class JsonFunctionExpression implements Serializable { private final Expression expression; private boolean usingFormatJson = false; + private String encoding; public JsonFunctionExpression(Expression expression) { this.expression = Objects.requireNonNull(expression, "The EXPRESSION must not be null"); } + public Expression getExpression() { return expression; } @@ -37,14 +38,34 @@ public boolean isUsingFormatJson() { public void setUsingFormatJson(boolean usingFormatJson) { this.usingFormatJson = usingFormatJson; } - + public JsonFunctionExpression withUsingFormatJson(boolean usingFormatJson) { this.setUsingFormatJson(usingFormatJson); return this; } - + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public JsonFunctionExpression withEncoding(String encoding) { + this.setEncoding(encoding); + return this; + } + public StringBuilder append(StringBuilder builder) { - return builder.append(getExpression()).append(isUsingFormatJson() ? " FORMAT JSON" : ""); + builder.append(getExpression()); + if (isUsingFormatJson()) { + builder.append(" FORMAT JSON"); + if (encoding != null) { + builder.append(" ENCODING ").append(encoding); + } + } + return builder; } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java index 4502b3ca6..ebd497e79 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java @@ -11,11 +11,22 @@ package net.sf.jsqlparser.expression; /** - * * @author Andreas Reichel */ public enum JsonFunctionType { - OBJECT, ARRAY, POSTGRES_OBJECT, MYSQL_OBJECT; + OBJECT, ARRAY, VALUE, QUERY, EXISTS, + + /** + * Not used anymore + */ + @Deprecated + POSTGRES_OBJECT, + + /** + * Not used anymore + */ + @Deprecated + MYSQL_OBJECT; public static JsonFunctionType from(String type) { return Enum.valueOf(JsonFunctionType.class, type.toUpperCase()); diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java index b85274caa..18fb4752d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java @@ -14,114 +14,168 @@ import java.util.Objects; /** - * * @author Andreas Reichel */ public class JsonKeyValuePair implements Serializable { - private final String key; - private boolean usingKeyKeyword = false; - private final Object value; - private boolean usingValueKeyword = false; - private boolean usingFormatJson = false; - - public JsonKeyValuePair(String key, Object value, boolean usingKeyKeyword, - boolean usingValueKeyword) { - this.key = Objects.requireNonNull(key, "The KEY of the Pair must not be null"); - this.value = value; - this.usingKeyKeyword = usingKeyKeyword; - this.usingValueKeyword = usingValueKeyword; - } - - public boolean isUsingKeyKeyword() { - return usingKeyKeyword; - } - - public void setUsingKeyKeyword(boolean usingKeyKeyword) { - this.usingKeyKeyword = usingKeyKeyword; - } - - public JsonKeyValuePair withUsingKeyKeyword(boolean usingKeyKeyword) { - this.setUsingKeyKeyword(usingKeyKeyword); - return this; - } - - public boolean isUsingValueKeyword() { - return usingValueKeyword; - } - - public void setUsingValueKeyword(boolean usingValueKeyword) { - this.usingValueKeyword = usingValueKeyword; - } - - public JsonKeyValuePair withUsingValueKeyword(boolean usingValueKeyword) { - this.setUsingValueKeyword(usingValueKeyword); - return this; - } - - public boolean isUsingFormatJson() { - return usingFormatJson; - } - - public void setUsingFormatJson(boolean usingFormatJson) { - this.usingFormatJson = usingFormatJson; - } - - public JsonKeyValuePair withUsingFormatJson(boolean usingFormatJson) { - this.setUsingFormatJson(usingFormatJson); - return this; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 83 * hash + Objects.hashCode(this.key); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final JsonKeyValuePair other = (JsonKeyValuePair) obj; - return Objects.equals(this.key, other.key); - } - - public String getKey() { - return key; - } - - public Object getValue() { - return value; - } - - public StringBuilder append(StringBuilder builder) { - if (isUsingValueKeyword()) { - if (isUsingKeyKeyword()) { - builder.append("KEY "); - } - builder.append(getKey()).append(" VALUE ").append(getValue()); - } else { - builder.append(getKey()).append(":").append(getValue()); - } - - if (isUsingFormatJson()) { - builder.append(" FORMAT JSON"); - } - - return builder; - } - - @Override - public String toString() { - return append(new StringBuilder()).toString(); - } + private final Object key; + private final Object value; + private boolean usingKeyKeyword; + private JsonKeyValuePairSeparator separator; + private boolean usingFormatJson = false; + private String encoding; + + /** + * Please use the Constructor with {@link JsonKeyValuePairSeparator} parameter. + */ + @Deprecated + public JsonKeyValuePair(Object key, Object value, boolean usingKeyKeyword, + boolean usingValueKeyword) { + this(key, value, usingKeyKeyword, usingValueKeyword ? JsonKeyValuePairSeparator.VALUE + : JsonKeyValuePairSeparator.COLON); + } + + public JsonKeyValuePair(Object key, Object value, boolean usingKeyKeyword, + JsonKeyValuePairSeparator separator) { + this.key = Objects.requireNonNull(key, "The KEY of the Pair must not be null"); + this.value = value; + this.usingKeyKeyword = usingKeyKeyword; + this.separator = + Objects.requireNonNull(separator, "The KeyValuePairSeparator must not be NULL"); + } + + public boolean isUsingKeyKeyword() { + return usingKeyKeyword; + } + + public void setUsingKeyKeyword(boolean usingKeyKeyword) { + this.usingKeyKeyword = usingKeyKeyword; + } + + public JsonKeyValuePair withUsingKeyKeyword(boolean usingKeyKeyword) { + this.setUsingKeyKeyword(usingKeyKeyword); + return this; + } + + /** + * Use {@link #getSeparator()} + */ + @Deprecated + public boolean isUsingValueKeyword() { + return separator == JsonKeyValuePairSeparator.VALUE; + } + + /** + * Use {@link #setSeparator(JsonKeyValuePairSeparator)} + */ + @Deprecated + public void setUsingValueKeyword(boolean usingValueKeyword) { + separator = usingValueKeyword ? JsonKeyValuePairSeparator.VALUE + : JsonKeyValuePairSeparator.COLON; + } + + /** + * Use {@link #withSeparator(JsonKeyValuePairSeparator)} + */ + @Deprecated + public JsonKeyValuePair withUsingValueKeyword(boolean usingValueKeyword) { + this.setUsingValueKeyword(usingValueKeyword); + return this; + } + + public JsonKeyValuePairSeparator getSeparator() { + return separator; + } + + public void setSeparator(JsonKeyValuePairSeparator separator) { + this.separator = separator; + } + + public JsonKeyValuePair withSeparator(JsonKeyValuePairSeparator separator) { + this.setSeparator(separator); + return this; + } + + public boolean isUsingFormatJson() { + return usingFormatJson; + } + + public void setUsingFormatJson(boolean usingFormatJson) { + this.usingFormatJson = usingFormatJson; + } + + public JsonKeyValuePair withUsingFormatJson(boolean usingFormatJson) { + this.setUsingFormatJson(usingFormatJson); + return this; + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public JsonKeyValuePair withEncoding(String encoding) { + this.setEncoding(encoding); + return this; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.key); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final JsonKeyValuePair other = (JsonKeyValuePair) obj; + return Objects.equals(this.key, other.key); + } + + public Object getKey() { + return key; + } + + public Object getValue() { + return value; + } + + public StringBuilder append(StringBuilder builder) { + if (isUsingKeyKeyword() && getSeparator() == JsonKeyValuePairSeparator.VALUE) { + builder.append("KEY "); + } + builder.append(getKey()); + + if (getValue() != null) { + builder.append(getSeparator().getSeparatorString()); + builder.append(getValue()); + } + + if (isUsingFormatJson()) { + builder.append(" FORMAT JSON"); + if (encoding != null) { + builder.append(" ENCODING ").append(encoding); + } + } + + return builder; + } + + @Override + public String toString() { + return append(new StringBuilder()).toString(); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java new file mode 100644 index 000000000..e4e998aa5 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java @@ -0,0 +1,33 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +/** + * Describes the string used to separate the key from the value. + */ +public enum JsonKeyValuePairSeparator { + VALUE(" VALUE "), COLON(":"), + + // Used in MySQL dialect + COMMA(","), + + // Is used in case they KeyValuePair has only a key and no value + NOT_USED(""); + + private final String separator; + + JsonKeyValuePairSeparator(String separator) { + this.separator = separator; + } + + public String getSeparatorString() { + return separator; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonTableFunction.java b/src/main/java/net/sf/jsqlparser/expression/JsonTableFunction.java new file mode 100644 index 000000000..5ee166e6f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonTableFunction.java @@ -0,0 +1,864 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.create.table.ColDataType; + +public class JsonTableFunction extends Function { + + private Expression jsonInputExpression; + private Expression jsonPathExpression; + private String pathName; + private final List passingClauses = new ArrayList<>(); + private JsonTableColumnsClause columnsClause; + private JsonTablePlanClause planClause; + private JsonTableOnErrorClause onErrorClause; + private JsonTableParsingTypeClause parsingTypeClause; + private JsonTableOnEmptyClause onEmptyClause; + private boolean formatJson; + + public enum JsonTablePlanOperator { + COMMA(", "), INNER(" INNER "), OUTER(" OUTER "), CROSS(" CROSS "), UNION(" UNION "); + + private final String display; + + JsonTablePlanOperator(String display) { + this.display = display; + } + + public String getDisplay() { + return display; + } + } + + public enum JsonTableOnErrorType { + ERROR, NULL, EMPTY, TRUE, FALSE + } + + public enum JsonTableOnEmptyType { + ERROR, NULL, EMPTY, TRUE, FALSE + } + + public enum JsonTableParsingType { + STRICT, LAX + } + + public static class JsonTablePassingClause extends ASTNodeAccessImpl implements Serializable { + private Expression valueExpression; + private String parameterName; + + public JsonTablePassingClause() {} + + public JsonTablePassingClause(Expression valueExpression, String parameterName) { + this.valueExpression = valueExpression; + this.parameterName = parameterName; + } + + public Expression getValueExpression() { + return valueExpression; + } + + public JsonTablePassingClause setValueExpression(Expression valueExpression) { + this.valueExpression = valueExpression; + return this; + } + + public String getParameterName() { + return parameterName; + } + + public JsonTablePassingClause setParameterName(String parameterName) { + this.parameterName = parameterName; + return this; + } + + public void collectExpressions(List expressions) { + if (valueExpression != null) { + expressions.add(valueExpression); + } + } + + @Override + public String toString() { + return valueExpression + " AS " + parameterName; + } + } + + public static class JsonTableWrapperClause extends ASTNodeAccessImpl implements Serializable { + private boolean beforePathExpression; + private JsonFunction.JsonWrapperType wrapperType; + private JsonFunction.JsonWrapperMode wrapperMode; + private boolean array; + + /** + * Creates a wrapper clause. Depending on the dialect, this clause can come before or after + * the PATH expression. + *
    + *
  • Trino: after PATH
  • + *
  • Oracle: before PATH
  • + *
+ * + * @param beforePathExpression A flag to determine wether the clause is rendered before or + * after the PATH expression + */ + public JsonTableWrapperClause(boolean beforePathExpression) { + this.beforePathExpression = beforePathExpression; + } + + public boolean isBeforePathExpression() { + return beforePathExpression; + } + + public JsonFunction.JsonWrapperType getWrapperType() { + return wrapperType; + } + + public JsonTableWrapperClause setWrapperType(JsonFunction.JsonWrapperType wrapperType) { + this.wrapperType = wrapperType; + return this; + } + + public JsonFunction.JsonWrapperMode getWrapperMode() { + return wrapperMode; + } + + public JsonTableWrapperClause setWrapperMode(JsonFunction.JsonWrapperMode wrapperMode) { + this.wrapperMode = wrapperMode; + return this; + } + + public boolean isArray() { + return array; + } + + public JsonTableWrapperClause setArray(boolean array) { + this.array = array; + return this; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(wrapperType); + if (wrapperMode != null) { + builder.append(" ").append(wrapperMode); + } + if (array) { + builder.append(" ARRAY"); + } + builder.append(" WRAPPER"); + return builder.toString(); + } + } + + public static class JsonTableQuotesClause extends ASTNodeAccessImpl implements Serializable { + private JsonFunction.JsonQuotesType quotesType; + private boolean onScalarString; + + public JsonFunction.JsonQuotesType getQuotesType() { + return quotesType; + } + + public JsonTableQuotesClause setQuotesType(JsonFunction.JsonQuotesType quotesType) { + this.quotesType = quotesType; + return this; + } + + public boolean isOnScalarString() { + return onScalarString; + } + + public JsonTableQuotesClause setOnScalarString(boolean onScalarString) { + this.onScalarString = onScalarString; + return this; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(quotesType).append(" QUOTES"); + if (onScalarString) { + builder.append(" ON SCALAR STRING"); + } + return builder.toString(); + } + } + + public static class JsonTableOnErrorClause extends ASTNodeAccessImpl implements Serializable { + private JsonTableOnErrorType type; + private boolean beforeColumns = true; + + public JsonTableOnErrorClause(boolean beforeColumns) { + this.beforeColumns = beforeColumns; + } + + public boolean isBeforeColumns() { + return beforeColumns; + } + + public JsonTableOnErrorType getType() { + return type; + } + + public JsonTableOnErrorClause setType(JsonTableOnErrorType type) { + this.type = type; + return this; + } + + @Override + public String toString() { + return type + " ON ERROR"; + } + } + + public static class JsonTableOnEmptyClause extends ASTNodeAccessImpl implements Serializable { + private JsonTableOnEmptyType type; + + public JsonTableOnEmptyType getType() { + return type; + } + + public JsonTableOnEmptyClause setType(JsonTableOnEmptyType type) { + this.type = type; + return this; + } + + @Override + public String toString() { + return type + " ON EMPTY"; + } + } + + public static class JsonTableParsingTypeClause extends ASTNodeAccessImpl + implements Serializable { + private JsonTableParsingType type; + + public JsonTableParsingType getType() { + return type; + } + + public JsonTableParsingTypeClause setType(JsonTableParsingType type) { + this.type = type; + return this; + } + + @Override + public String toString() { + return "TYPE(" + type + ")"; + } + } + + public static class JsonTablePlanTerm extends ASTNodeAccessImpl implements Serializable { + private JsonTablePlanExpression nestedPlanExpression; + private String name; + private Expression expression; + + public JsonTablePlanExpression getNestedPlanExpression() { + return nestedPlanExpression; + } + + public JsonTablePlanTerm setNestedPlanExpression( + JsonTablePlanExpression nestedPlanExpression) { + this.nestedPlanExpression = nestedPlanExpression; + return this; + } + + public String getName() { + return name; + } + + public JsonTablePlanTerm setName(String name) { + this.name = name; + return this; + } + + public Expression getExpression() { + return expression; + } + + public JsonTablePlanTerm setExpression(Expression expression) { + this.expression = expression; + return this; + } + + public void collectExpressions(List expressions) { + if (expression != null) { + expressions.add(expression); + } + if (nestedPlanExpression != null) { + nestedPlanExpression.collectExpressions(expressions); + } + } + + @Override + public String toString() { + if (nestedPlanExpression != null) { + return "(" + nestedPlanExpression + ")"; + } + if (name != null) { + return name; + } + return expression != null ? expression.toString() : ""; + } + } + + public static class JsonTablePlanExpression extends ASTNodeAccessImpl implements Serializable { + private final List terms = new ArrayList<>(); + private final List operators = new ArrayList<>(); + + public List getTerms() { + return terms; + } + + public JsonTablePlanExpression addTerm(JsonTablePlanTerm term) { + terms.add(term); + return this; + } + + public List getOperators() { + return operators; + } + + public JsonTablePlanExpression addOperator(JsonTablePlanOperator operator) { + operators.add(operator); + return this; + } + + public void collectExpressions(List expressions) { + for (JsonTablePlanTerm term : terms) { + if (term != null) { + term.collectExpressions(expressions); + } + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (!terms.isEmpty()) { + builder.append(terms.get(0)); + } + for (int i = 0; i < operators.size() && i + 1 < terms.size(); i++) { + builder.append(operators.get(i).getDisplay()).append(terms.get(i + 1)); + } + return builder.toString(); + } + } + + public static class JsonTablePlanClause extends ASTNodeAccessImpl implements Serializable { + private boolean defaultPlan; + private JsonTablePlanExpression planExpression; + + public boolean isDefaultPlan() { + return defaultPlan; + } + + public JsonTablePlanClause setDefaultPlan(boolean defaultPlan) { + this.defaultPlan = defaultPlan; + return this; + } + + public JsonTablePlanExpression getPlanExpression() { + return planExpression; + } + + public JsonTablePlanClause setPlanExpression(JsonTablePlanExpression planExpression) { + this.planExpression = planExpression; + return this; + } + + public void collectExpressions(List expressions) { + if (planExpression != null) { + planExpression.collectExpressions(expressions); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("PLAN"); + if (defaultPlan) { + builder.append(" DEFAULT"); + } + builder.append(" (").append(planExpression).append(")"); + return builder.toString(); + } + } + + public abstract static class JsonTableColumnDefinition extends ASTNodeAccessImpl + implements Serializable { + public abstract void collectExpressions(List expressions); + } + + public static class JsonTableNestedColumnDefinition extends JsonTableColumnDefinition { + private boolean pathKeyword; + private Expression pathExpression; + private String pathName; + private JsonTableColumnsClause columnsClause; + + public boolean isPathKeyword() { + return pathKeyword; + } + + public JsonTableNestedColumnDefinition setPathKeyword(boolean pathKeyword) { + this.pathKeyword = pathKeyword; + return this; + } + + public Expression getPathExpression() { + return pathExpression; + } + + public JsonTableNestedColumnDefinition setPathExpression(Expression pathExpression) { + this.pathExpression = pathExpression; + return this; + } + + public String getPathName() { + return pathName; + } + + public JsonTableNestedColumnDefinition setPathName(String pathName) { + this.pathName = pathName; + return this; + } + + public JsonTableColumnsClause getColumnsClause() { + return columnsClause; + } + + public JsonTableNestedColumnDefinition setColumnsClause( + JsonTableColumnsClause columnsClause) { + this.columnsClause = columnsClause; + return this; + } + + @Override + public void collectExpressions(List expressions) { + if (pathExpression != null) { + expressions.add(pathExpression); + } + if (columnsClause != null) { + columnsClause.collectExpressions(expressions); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("NESTED"); + if (pathKeyword) { + builder.append(" PATH"); + } + builder.append(" ").append(pathExpression); + if (pathName != null) { + builder.append(" AS ").append(pathName); + } + builder.append(" ").append(columnsClause); + return builder.toString(); + } + } + + public static class JsonTableValueColumnDefinition extends JsonTableColumnDefinition { + private String columnName; + private boolean forOrdinality; + private ColDataType dataType; + private boolean formatJson; + private boolean exists; + private boolean onEmptyAfterOnError; + private String encoding; + private Expression pathExpression; + private JsonTableWrapperClause wrapperClause; + private JsonTableQuotesClause quotesClause; + private JsonFunction.JsonOnResponseBehavior onEmptyBehavior; + private JsonFunction.JsonOnResponseBehavior onErrorBehavior; + private JsonFunction.ScalarsType scalarsType; + + public String getColumnName() { + return columnName; + } + + public JsonTableValueColumnDefinition setColumnName(String columnName) { + this.columnName = columnName; + return this; + } + + public boolean isExists() { + return exists; + } + + public JsonTableValueColumnDefinition setExistsKeyword(boolean exists) { + this.exists = exists; + return this; + } + + public JsonTableValueColumnDefinition setOnEmptyAfterOnError(boolean b) { + this.onEmptyAfterOnError = b; + return this; + } + + public boolean isForOrdinality() { + return forOrdinality; + } + + public JsonTableValueColumnDefinition setForOrdinality(boolean forOrdinality) { + this.forOrdinality = forOrdinality; + return this; + } + + public ColDataType getDataType() { + return dataType; + } + + public JsonTableValueColumnDefinition setDataType(ColDataType dataType) { + this.dataType = dataType; + return this; + } + + public boolean isFormatJson() { + return formatJson; + } + + public JsonTableValueColumnDefinition setFormatJson(boolean formatJson) { + this.formatJson = formatJson; + return this; + } + + public String getEncoding() { + return encoding; + } + + public JsonTableValueColumnDefinition setEncoding(String encoding) { + this.encoding = encoding; + return this; + } + + public Expression getPathExpression() { + return pathExpression; + } + + public JsonTableValueColumnDefinition setPathExpression(Expression pathExpression) { + this.pathExpression = pathExpression; + return this; + } + + public JsonTableWrapperClause getWrapperClause() { + return wrapperClause; + } + + public JsonTableValueColumnDefinition setWrapperClause( + JsonTableWrapperClause wrapperClause) { + this.wrapperClause = wrapperClause; + return this; + } + + public JsonTableQuotesClause getQuotesClause() { + return quotesClause; + } + + public JsonTableValueColumnDefinition setQuotesClause(JsonTableQuotesClause quotesClause) { + this.quotesClause = quotesClause; + return this; + } + + public JsonFunction.JsonOnResponseBehavior getOnEmptyBehavior() { + return onEmptyBehavior; + } + + public JsonTableValueColumnDefinition setOnEmptyBehavior( + JsonFunction.JsonOnResponseBehavior onEmptyBehavior) { + this.onEmptyBehavior = onEmptyBehavior; + return this; + } + + public JsonFunction.JsonOnResponseBehavior getOnErrorBehavior() { + return onErrorBehavior; + } + + public JsonTableValueColumnDefinition setOnErrorBehavior( + JsonFunction.JsonOnResponseBehavior onErrorBehavior) { + this.onErrorBehavior = onErrorBehavior; + return this; + } + + public void setScalarsType(JsonFunction.ScalarsType scalarsType) { + this.scalarsType = scalarsType; + } + + public JsonFunction.ScalarsType getScalarsType() { + return scalarsType; + } + + @Override + public void collectExpressions(List expressions) { + if (pathExpression != null) { + expressions.add(pathExpression); + } + if (onEmptyBehavior != null && onEmptyBehavior.getExpression() != null) { + expressions.add(onEmptyBehavior.getExpression()); + } + if (onErrorBehavior != null && onErrorBehavior.getExpression() != null) { + expressions.add(onErrorBehavior.getExpression()); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(columnName); + if (forOrdinality) { + builder.append(" FOR ORDINALITY"); + return builder.toString(); + } + if (exists) { + builder.append(" EXISTS"); + } + if (dataType != null) { + builder.append(" ").append(dataType); + } + if (formatJson) { + builder.append(" FORMAT JSON"); + if (encoding != null) { + builder.append(" ENCODING ").append(encoding); + } + } + if (scalarsType != null) { + builder.append(" "); + builder.append(scalarsType); + builder.append(" SCALARS"); + } + if (wrapperClause != null && wrapperClause.isBeforePathExpression()) { + builder.append(" ").append(wrapperClause); + } + if (pathExpression != null) { + builder.append(" PATH ").append(pathExpression); + } + if (wrapperClause != null && !wrapperClause.isBeforePathExpression()) { + builder.append(" ").append(wrapperClause); + } + if (quotesClause != null) { + builder.append(" ").append(quotesClause); + } + if (onEmptyBehavior != null && !onEmptyAfterOnError) { + builder.append(" ").append(onEmptyBehavior).append(" ON EMPTY"); + } + if (onErrorBehavior != null) { + builder.append(" ").append(onErrorBehavior).append(" ON ERROR"); + } + if (onEmptyBehavior != null && onEmptyAfterOnError) { + builder.append(" ").append(onEmptyBehavior).append(" ON EMPTY"); + } + return builder.toString(); + } + } + + public static class JsonTableColumnsClause extends ASTNodeAccessImpl implements Serializable { + private final List columnDefinitions = new ArrayList<>(); + + public List getColumnDefinitions() { + return columnDefinitions; + } + + public JsonTableColumnsClause addColumnDefinition( + JsonTableColumnDefinition columnDefinition) { + columnDefinitions.add(columnDefinition); + return this; + } + + public void collectExpressions(List expressions) { + for (JsonTableColumnDefinition columnDefinition : columnDefinitions) { + if (columnDefinition != null) { + columnDefinition.collectExpressions(expressions); + } + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("COLUMNS ("); + boolean first = true; + for (JsonTableColumnDefinition columnDefinition : columnDefinitions) { + if (!first) { + builder.append(", "); + } + builder.append(columnDefinition); + first = false; + } + builder.append(")"); + return builder.toString(); + } + } + + public JsonTableFunction() { + setName("JSON_TABLE"); + } + + public boolean getFormatJson() { + return formatJson; + } + + public JsonTableFunction setFormatJson(boolean formatJson) { + this.formatJson = formatJson; + return this; + } + + public Expression getJsonInputExpression() { + return jsonInputExpression; + } + + public JsonTableFunction setJsonInputExpression(Expression jsonInputExpression) { + this.jsonInputExpression = jsonInputExpression; + return this; + } + + public Expression getJsonPathExpression() { + return jsonPathExpression; + } + + public JsonTableFunction setJsonPathExpression(Expression jsonPathExpression) { + this.jsonPathExpression = jsonPathExpression; + return this; + } + + public String getPathName() { + return pathName; + } + + public JsonTableFunction setPathName(String pathName) { + this.pathName = pathName; + return this; + } + + public List getPassingClauses() { + return passingClauses; + } + + public JsonTableFunction addPassingClause(JsonTablePassingClause passingClause) { + passingClauses.add(Objects.requireNonNull(passingClause, "passingClause")); + return this; + } + + public JsonTableColumnsClause getColumnsClause() { + return columnsClause; + } + + public JsonTableFunction setColumnsClause(JsonTableColumnsClause columnsClause) { + this.columnsClause = columnsClause; + return this; + } + + public JsonTablePlanClause getPlanClause() { + return planClause; + } + + public JsonTableFunction setPlanClause(JsonTablePlanClause planClause) { + this.planClause = planClause; + return this; + } + + public JsonTableOnErrorClause getOnErrorClause() { + return onErrorClause; + } + + public JsonTableFunction setOnErrorClause(JsonTableOnErrorClause onErrorClause) { + this.onErrorClause = onErrorClause; + return this; + } + + public JsonTableParsingTypeClause getParsingTypeClause() { + return parsingTypeClause; + } + + public JsonTableFunction setParsingTypeClause(JsonTableParsingTypeClause parsingTypeClause) { + this.parsingTypeClause = parsingTypeClause; + return this; + } + + public JsonTableOnEmptyClause getOnEmptyClause() { + return onEmptyClause; + } + + public JsonTableFunction setOnEmptyClause(JsonTableOnEmptyClause onEmptyClause) { + this.onEmptyClause = onEmptyClause; + return this; + } + + public List getAllExpressions() { + List expressions = new ArrayList<>(); + if (jsonInputExpression != null) { + expressions.add(jsonInputExpression); + } + if (jsonPathExpression != null) { + expressions.add(jsonPathExpression); + } + for (JsonTablePassingClause passingClause : passingClauses) { + passingClause.collectExpressions(expressions); + } + if (columnsClause != null) { + columnsClause.collectExpressions(expressions); + } + if (planClause != null) { + planClause.collectExpressions(expressions); + } + return expressions; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("JSON_TABLE("); + builder.append(jsonInputExpression); + if (formatJson) { + builder.append(" FORMAT JSON"); + } + if (jsonPathExpression != null) { + builder.append(", ").append(jsonPathExpression); + } + if (pathName != null) { + builder.append(" AS ").append(pathName); + } + if (!passingClauses.isEmpty()) { + builder.append(" PASSING "); + boolean first = true; + for (JsonTablePassingClause passingClause : passingClauses) { + if (!first) { + builder.append(", "); + } + builder.append(passingClause); + first = false; + } + } + if (onErrorClause != null && onErrorClause.isBeforeColumns()) { + builder.append(" ").append(onErrorClause); + } + if (parsingTypeClause != null) { + builder.append(" ").append(parsingTypeClause); + } + if (onEmptyClause != null) { + builder.append(" ").append(onEmptyClause); + } + builder.append(" ").append(columnsClause); + if (planClause != null) { + builder.append(" ").append(planClause); + } + if (onErrorClause != null && !onErrorClause.isBeforeColumns()) { + builder.append(" ").append(onErrorClause); + } + builder.append(")"); + return builder.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/KeepExpression.java b/src/main/java/net/sf/jsqlparser/expression/KeepExpression.java index 2712a0e46..b8e493244 100644 --- a/src/main/java/net/sf/jsqlparser/expression/KeepExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/KeepExpression.java @@ -14,6 +14,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; + import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import net.sf.jsqlparser.statement.select.OrderByElement; @@ -24,8 +25,8 @@ public class KeepExpression extends ASTNodeAccessImpl implements Expression { private boolean first = false; @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public List getOrderByElements() { @@ -94,13 +95,15 @@ public KeepExpression withFirst(boolean first) { } public KeepExpression addOrderByElements(OrderByElement... orderByElements) { - List collection = Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); Collections.addAll(collection, orderByElements); return this.withOrderByElements(collection); } public KeepExpression addOrderByElements(Collection orderByElements) { - List collection = Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); collection.addAll(orderByElements); return this.withOrderByElements(collection); } diff --git a/src/main/java/net/sf/jsqlparser/expression/KeyExpression.java b/src/main/java/net/sf/jsqlparser/expression/KeyExpression.java new file mode 100644 index 000000000..2bb063875 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/KeyExpression.java @@ -0,0 +1,44 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import java.util.Objects; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +/** + * Dialect specific expression for constructs such as {@code KEY chain.entity}. + */ +public class KeyExpression extends ASTNodeAccessImpl implements Expression { + private final Expression expression; + + public KeyExpression(Expression expression) { + this.expression = Objects.requireNonNull(expression, + "The EXPRESSION of the KEY expression must not be null"); + } + + public Expression getExpression() { + return expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("KEY ").append(expression); + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/LambdaExpression.java b/src/main/java/net/sf/jsqlparser/expression/LambdaExpression.java index a9207b214..e2819060f 100644 --- a/src/main/java/net/sf/jsqlparser/expression/LambdaExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/LambdaExpression.java @@ -9,9 +9,11 @@ */ package net.sf.jsqlparser.expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class LambdaExpression extends ASTNodeAccessImpl implements Expression { @@ -19,7 +21,7 @@ public class LambdaExpression extends ASTNodeAccessImpl implements Expression { private Expression expression; public LambdaExpression(String identifier, Expression expression) { - this.identifiers = Arrays.asList(identifier); + this.identifiers = Collections.singletonList(identifier); this.expression = expression; } @@ -28,6 +30,15 @@ public LambdaExpression(List identifiers, Expression expression) { this.expression = expression; } + public static LambdaExpression from(ExpressionList expressionList, + Expression expression) { + List identifiers = new ArrayList<>(expressionList.size()); + for (Expression variable : expressionList) { + identifiers.add(variable.toString()); + } + return new LambdaExpression(identifiers, expression); + } + public List getIdentifiers() { return identifiers; } @@ -66,7 +77,7 @@ public String toString() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/LongValue.java b/src/main/java/net/sf/jsqlparser/expression/LongValue.java index 730a8871e..eeba186cc 100644 --- a/src/main/java/net/sf/jsqlparser/expression/LongValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/LongValue.java @@ -41,22 +41,22 @@ public LongValue(long value) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public long getValue() { return Long.parseLong(stringValue); } - public BigInteger getBigIntegerValue() { - return new BigInteger(stringValue); - } - public void setValue(long d) { stringValue = String.valueOf(d); } + public BigInteger getBigIntegerValue() { + return new BigInteger(stringValue); + } + public LongValue withValue(long d) { setValue(d); return this; diff --git a/src/main/java/net/sf/jsqlparser/expression/LowExpression.java b/src/main/java/net/sf/jsqlparser/expression/LowExpression.java new file mode 100644 index 000000000..2d2882a53 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/LowExpression.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class LowExpression extends ASTNodeAccessImpl implements Expression { + private Expression expression; + + public LowExpression() { + // empty constructor + } + + public LowExpression(Expression expression) { + this.expression = expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return "LOW " + expression.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/MySQLGroupConcat.java b/src/main/java/net/sf/jsqlparser/expression/MySQLGroupConcat.java index 49161bbee..aa4a53357 100644 --- a/src/main/java/net/sf/jsqlparser/expression/MySQLGroupConcat.java +++ b/src/main/java/net/sf/jsqlparser/expression/MySQLGroupConcat.java @@ -59,8 +59,8 @@ public void setSeparator(String separator) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/NextValExpression.java b/src/main/java/net/sf/jsqlparser/expression/NextValExpression.java index 4838bbcf4..a56723851 100644 --- a/src/main/java/net/sf/jsqlparser/expression/NextValExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/NextValExpression.java @@ -1,8 +1,8 @@ -/* - +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2019 JSQLParser + * Copyright (C) 2004 - 2024 JSQLParser * %% * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% @@ -11,11 +11,13 @@ import java.util.List; import java.util.regex.Pattern; + import net.sf.jsqlparser.parser.ASTNodeAccessImpl; public class NextValExpression extends ASTNodeAccessImpl implements Expression { - public static final Pattern NEXT_VALUE_PATTERN = Pattern.compile("NEXT\\s+VALUE\\s+FOR", Pattern.CASE_INSENSITIVE); + public static final Pattern NEXT_VALUE_PATTERN = + Pattern.compile("NEXT\\s+VALUE\\s+FOR", Pattern.CASE_INSENSITIVE); private final List nameList; private boolean usingNextValueFor = false; @@ -63,7 +65,7 @@ public String toString() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/NotExpression.java b/src/main/java/net/sf/jsqlparser/expression/NotExpression.java index d61ae2bb9..bb2769fdd 100644 --- a/src/main/java/net/sf/jsqlparser/expression/NotExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/NotExpression.java @@ -42,8 +42,8 @@ public final void setExpression(Expression expression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/NullValue.java b/src/main/java/net/sf/jsqlparser/expression/NullValue.java index b6397030f..fb096eff6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/NullValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/NullValue.java @@ -14,8 +14,8 @@ public class NullValue extends ASTNodeAccessImpl implements Expression { @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/NumericBind.java b/src/main/java/net/sf/jsqlparser/expression/NumericBind.java index 8f5ac4088..f38ff15d4 100644 --- a/src/main/java/net/sf/jsqlparser/expression/NumericBind.java +++ b/src/main/java/net/sf/jsqlparser/expression/NumericBind.java @@ -24,8 +24,8 @@ public void setBindId(int bindId) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/OracleHierarchicalExpression.java b/src/main/java/net/sf/jsqlparser/expression/OracleHierarchicalExpression.java index a3644e441..693128d03 100644 --- a/src/main/java/net/sf/jsqlparser/expression/OracleHierarchicalExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/OracleHierarchicalExpression.java @@ -13,10 +13,10 @@ public class OracleHierarchicalExpression extends ASTNodeAccessImpl implements Expression { + boolean connectFirst = false; private Expression startExpression; private Expression connectExpression; private boolean noCycle = false; - boolean connectFirst = false; public Expression getStartExpression() { return startExpression; @@ -51,8 +51,8 @@ public void setConnectFirst(boolean connectFirst) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override @@ -65,11 +65,11 @@ public String toString() { } b.append(connectExpression.toString()); if (startExpression != null) { - b.append(" START WITH ").append(startExpression.toString()); + b.append(" START WITH ").append(startExpression); } } else { if (startExpression != null) { - b.append(" START WITH ").append(startExpression.toString()); + b.append(" START WITH ").append(startExpression); } b.append(" CONNECT BY "); if (isNoCycle()) { diff --git a/src/main/java/net/sf/jsqlparser/expression/OracleHint.java b/src/main/java/net/sf/jsqlparser/expression/OracleHint.java index c229e880e..4ab164f98 100644 --- a/src/main/java/net/sf/jsqlparser/expression/OracleHint.java +++ b/src/main/java/net/sf/jsqlparser/expression/OracleHint.java @@ -24,7 +24,7 @@ public class OracleHint extends ASTNodeAccessImpl implements Expression { private static final Pattern SINGLE_LINE = Pattern.compile("--\\+ *([^ ].*[^ ])"); private static final Pattern MULTI_LINE = - Pattern.compile("\\/\\*\\+ *([^ ].*[^ ]) *\\*+\\/", Pattern.MULTILINE | Pattern.DOTALL); + Pattern.compile("/\\*\\+ *([^ ].*[^ ]) *\\*+/", Pattern.MULTILINE | Pattern.DOTALL); private String value; private boolean singleLine = false; @@ -33,6 +33,17 @@ public static boolean isHintMatch(String comment) { return SINGLE_LINE.matcher(comment).find() || MULTI_LINE.matcher(comment).find(); } + public static OracleHint getHintFromSelectBody(Select selectBody) { + + if (selectBody instanceof PlainSelect) { + return ((PlainSelect) selectBody).getOracleHint(); + } else if (selectBody instanceof ParenthesedSelect) { + return getHintFromSelectBody(((ParenthesedSelect) selectBody).getSelect()); + } else { + return null; + } + } + public final void setComment(String comment) { Matcher m; m = SINGLE_LINE.matcher(comment); @@ -65,8 +76,8 @@ public void setSingleLine(boolean singleLine) { } @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override @@ -87,15 +98,4 @@ public OracleHint withSingleLine(boolean singleLine) { this.setSingleLine(singleLine); return this; } - - public static OracleHint getHintFromSelectBody(Select selectBody) { - - if (selectBody instanceof PlainSelect) { - return ((PlainSelect) selectBody).getOracleHint(); - } else if (selectBody instanceof ParenthesedSelect) { - return getHintFromSelectBody(((ParenthesedSelect) selectBody).getSelect()); - } else { - return null; - } - } } diff --git a/src/main/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameter.java b/src/main/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameter.java index 51a7a433c..0dd76b5f6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameter.java +++ b/src/main/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameter.java @@ -10,10 +10,10 @@ package net.sf.jsqlparser.expression; import java.util.Objects; + import net.sf.jsqlparser.parser.ASTNodeAccessImpl; /** - * * @author Andreas Reichel */ public class OracleNamedFunctionParameter extends ASTNodeAccessImpl implements Expression { @@ -21,8 +21,10 @@ public class OracleNamedFunctionParameter extends ASTNodeAccessImpl implements E private final Expression expression; public OracleNamedFunctionParameter(String name, Expression expression) { - this.name = Objects.requireNonNull(name, "The NAME of the OracleNamedFunctionParameter must not be null."); - this.expression = Objects.requireNonNull(expression, "The EXPRESSION of the OracleNamedFunctionParameter must not be null."); + this.name = Objects.requireNonNull(name, + "The NAME of the OracleNamedFunctionParameter must not be null."); + this.expression = Objects.requireNonNull(expression, + "The EXPRESSION of the OracleNamedFunctionParameter must not be null."); } public String getName() { @@ -34,18 +36,18 @@ public Expression getExpression() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } - + public StringBuilder appendTo(StringBuilder builder) { builder.append(name) - .append(" => ") - .append(expression); - + .append(" => ") + .append(expression); + return builder; } - + @Override public String toString() { return appendTo(new StringBuilder()).toString(); diff --git a/src/main/java/net/sf/jsqlparser/expression/OrderByClause.java b/src/main/java/net/sf/jsqlparser/expression/OrderByClause.java index 7c71ddfa0..fbf21de87 100644 --- a/src/main/java/net/sf/jsqlparser/expression/OrderByClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/OrderByClause.java @@ -15,6 +15,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; + import net.sf.jsqlparser.statement.select.OrderByElement; public class OrderByClause implements Serializable { @@ -46,13 +47,15 @@ public OrderByClause withOrderByElements(List orderByElements) { } public OrderByClause addOrderByElements(OrderByElement... orderByElements) { - List collection = Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); Collections.addAll(collection, orderByElements); return this.withOrderByElements(collection); } public OrderByClause addOrderByElements(Collection orderByElements) { - List collection = Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); collection.addAll(orderByElements); return this.withOrderByElements(collection); } diff --git a/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java b/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java index f9e41b4bc..09ccd6183 100644 --- a/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java +++ b/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java @@ -12,36 +12,30 @@ import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -public class OverlapsCondition extends ASTNodeAccessImpl implements Expression{ +public class OverlapsCondition extends ASTNodeAccessImpl implements Expression { + private final ExpressionList left; + private final ExpressionList right; - - private ExpressionList left; - private ExpressionList right; - - - public OverlapsCondition(ExpressionList left, ExpressionList right) { + public OverlapsCondition(ExpressionList left, ExpressionList right) { this.left = left; this.right = right; } - public ExpressionList getLeft() { + public ExpressionList getLeft() { return left; } - public ExpressionList getRight() { + public ExpressionList getRight() { return right; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return String.format("%s OVERLAPS %s" - , left.toString() - , right.toString() - ); + return String.format("%s OVERLAPS %s", left.toString(), right.toString()); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java b/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java index 0b0f70663..6ad41e994 100644 --- a/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java @@ -14,37 +14,51 @@ import java.io.Serializable; -public class PartitionByClause implements Serializable { - ExpressionList partitionExpressionList; +public class PartitionByClause extends ExpressionList implements Serializable { boolean brackets = false; - public ExpressionList getPartitionExpressionList() { - return partitionExpressionList; + @Deprecated + public ExpressionList getPartitionExpressionList() { + return this; } - - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + + @Deprecated + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) { - this.partitionExpressionList = partitionExpressionList; + @Deprecated + public void setPartitionExpressionList(ExpressionList partitionExpressionList, + boolean brackets) { + setExpressions(partitionExpressionList, brackets); + } + + public PartitionByClause setExpressions(ExpressionList partitionExpressionList, + boolean brackets) { + clear(); + if (partitionExpressionList != null) { + addAll(partitionExpressionList); + } this.brackets = brackets; + return this; } public void toStringPartitionBy(StringBuilder b) { - if (partitionExpressionList != null && !partitionExpressionList.getExpressions().isEmpty()) { + if (!isEmpty()) { b.append("PARTITION BY "); - b.append(PlainSelect. - getStringList(partitionExpressionList.getExpressions(), true, brackets)); + b.append(PlainSelect.getStringList(this, true, + brackets)); b.append(" "); } } - + public boolean isBrackets() { return brackets; } - public PartitionByClause withPartitionExpressionList(ExpressionList partitionExpressionList) { + @Deprecated + public PartitionByClause withPartitionExpressionList( + ExpressionList partitionExpressionList) { this.setPartitionExpressionList(partitionExpressionList); return this; } diff --git a/src/main/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameter.java b/src/main/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameter.java new file mode 100644 index 000000000..573ad60f2 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameter.java @@ -0,0 +1,55 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2021 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.Objects; + +/** + * @author Andreas Reichel + */ +public class PostgresNamedFunctionParameter extends ASTNodeAccessImpl implements Expression { + private final String name; + private final Expression expression; + + public PostgresNamedFunctionParameter(String name, Expression expression) { + this.name = Objects.requireNonNull(name, + "The NAME of the PostgresNamedFunctionParameter must not be null."); + this.expression = Objects.requireNonNull(expression, + "The EXPRESSION of the PostgresNamedFunctionParameter must not be null."); + } + + public String getName() { + return name; + } + + public Expression getExpression() { + return expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append(name) + .append(" := ") + .append(expression); + + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java b/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java new file mode 100644 index 000000000..2db468dbb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java @@ -0,0 +1,66 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; + +import java.io.Serializable; + +public class PreferringClause implements Serializable { + private Expression preferring; + private PartitionByClause partitionBy; + + public PreferringClause(Expression preferring) { + this.preferring = preferring; + } + + public void setPartitionExpressionList(ExpressionList expressionList, + boolean brackets) { + if (this.partitionBy == null) { + this.partitionBy = new PartitionByClause(); + } + partitionBy.setExpressions(expressionList, brackets); + } + + public void toStringPreferring(StringBuilder b) { + b.append("PREFERRING "); + b.append(preferring.toString()); + + if (partitionBy != null) { + b.append(" "); + partitionBy.toStringPartitionBy(b); + } + } + + public Expression getPreferring() { + return preferring; + } + + public PreferringClause setPreferring(Expression preferring) { + this.preferring = preferring; + return this; + } + + public PartitionByClause getPartitionBy() { + return partitionBy; + } + + public PreferringClause setPartitionBy(PartitionByClause partitionBy) { + this.partitionBy = partitionBy; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + toStringPreferring(sb); + return sb.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/RangeExpression.java b/src/main/java/net/sf/jsqlparser/expression/RangeExpression.java index 69cba377d..dd05827d6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/RangeExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/RangeExpression.java @@ -44,7 +44,7 @@ public String toString() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/RawFunction.java b/src/main/java/net/sf/jsqlparser/expression/RawFunction.java new file mode 100644 index 000000000..1c2d5b874 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/RawFunction.java @@ -0,0 +1,41 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +/** + * Function with a raw argument body preserved as-is for deparsing. + */ +public class RawFunction extends Function { + private String rawArguments; + + public RawFunction() {} + + public RawFunction(String name, String rawArguments) { + setName(name); + this.rawArguments = rawArguments; + } + + public String getRawArguments() { + return rawArguments; + } + + public void setRawArguments(String rawArguments) { + this.rawArguments = rawArguments; + } + + @Override + public String toString() { + String name = getName(); + if (rawArguments == null) { + return name + "()"; + } + return name + "(" + rawArguments + ")"; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/RowConstructor.java b/src/main/java/net/sf/jsqlparser/expression/RowConstructor.java index 6eabf3b70..2f5844ea0 100644 --- a/src/main/java/net/sf/jsqlparser/expression/RowConstructor.java +++ b/src/main/java/net/sf/jsqlparser/expression/RowConstructor.java @@ -36,8 +36,13 @@ public String toString() { return (name != null ? name : "") + super.toString(); } - public RowConstructor withName(String name) { + public RowConstructor withName(String name) { this.setName(name); return this; } + + @Override + public K accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/RowGetExpression.java b/src/main/java/net/sf/jsqlparser/expression/RowGetExpression.java index 16376a470..0aaefa1aa 100644 --- a/src/main/java/net/sf/jsqlparser/expression/RowGetExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/RowGetExpression.java @@ -21,8 +21,8 @@ public RowGetExpression(Expression expression, String columnName) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/SQLServerHints.java b/src/main/java/net/sf/jsqlparser/expression/SQLServerHints.java index 84b7c2f38..34d14964b 100644 --- a/src/main/java/net/sf/jsqlparser/expression/SQLServerHints.java +++ b/src/main/java/net/sf/jsqlparser/expression/SQLServerHints.java @@ -18,8 +18,7 @@ public class SQLServerHints implements Serializable { private Boolean noLock; private String indexName; - public SQLServerHints() { - } + public SQLServerHints() {} public SQLServerHints withNoLock() { this.noLock = true; diff --git a/src/main/java/net/sf/jsqlparser/expression/SignedExpression.java b/src/main/java/net/sf/jsqlparser/expression/SignedExpression.java index dabc2f9c5..725d449e8 100644 --- a/src/main/java/net/sf/jsqlparser/expression/SignedExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/SignedExpression.java @@ -48,8 +48,8 @@ public final void setExpression(Expression expression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/SpannerInterleaveIn.java b/src/main/java/net/sf/jsqlparser/expression/SpannerInterleaveIn.java index 18cb16ac4..0bf49925d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/SpannerInterleaveIn.java +++ b/src/main/java/net/sf/jsqlparser/expression/SpannerInterleaveIn.java @@ -16,14 +16,6 @@ public class SpannerInterleaveIn { - public enum OnDelete { - CASCADE, NO_ACTION; - - public static OnDelete from(String action) { - return Enum.valueOf(OnDelete.class, action.toUpperCase()); - } - } - private Table table; private OnDelete onDelete; @@ -77,4 +69,12 @@ public SpannerInterleaveIn withOnDelete(OnDelete action) { this.setOnDelete(action); return this; } + + public enum OnDelete { + CASCADE, NO_ACTION; + + public static OnDelete from(String action) { + return Enum.valueOf(OnDelete.class, action.toUpperCase()); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/StringValue.java b/src/main/java/net/sf/jsqlparser/expression/StringValue.java index 743efea46..a16536fab 100644 --- a/src/main/java/net/sf/jsqlparser/expression/StringValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/StringValue.java @@ -20,11 +20,11 @@ */ public final class StringValue extends ASTNodeAccessImpl implements Expression { - private String value = ""; - private String prefix = null; - public static final List ALLOWED_PREFIXES = Arrays.asList("N", "U", "E", "R", "B", "RB", "_utf8", "Q"); + private String value = ""; + private String prefix = null; + private String quoteStr = "'"; public StringValue() { // empty constructor @@ -36,6 +36,11 @@ public StringValue(String escapedValue) { && escapedValue.endsWith("'")) { value = escapedValue.substring(1, escapedValue.length() - 1); return; + } else if (escapedValue.length() >= 4 && escapedValue.startsWith("$$") + && escapedValue.endsWith("$$")) { + value = escapedValue.substring(2, escapedValue.length() - 2); + quoteStr = "$$"; + return; } if (escapedValue.length() > 2) { @@ -57,10 +62,27 @@ public String getValue() { return value; } + public void setValue(String string) { + value = string; + } + public String getPrefix() { return prefix; } + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getQuoteStr() { + return quoteStr; + } + + public StringValue setQuoteStr(String quoteStr) { + this.quoteStr = quoteStr; + return this; + } + public String getNotExcapedValue() { StringBuilder buffer = new StringBuilder(value); int index = 0; @@ -73,22 +95,14 @@ public String getNotExcapedValue() { return buffer.toString(); } - public void setValue(String string) { - value = string; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return (prefix != null ? prefix : "") + "'" + value + "'"; + return (prefix != null ? prefix : "") + quoteStr + value + quoteStr; } public StringValue withPrefix(String prefix) { diff --git a/src/main/java/net/sf/jsqlparser/expression/StructType.java b/src/main/java/net/sf/jsqlparser/expression/StructType.java index a9b88ab7c..4bd38a693 100644 --- a/src/main/java/net/sf/jsqlparser/expression/StructType.java +++ b/src/main/java/net/sf/jsqlparser/expression/StructType.java @@ -19,26 +19,26 @@ /* * STRUCT - * + * * Type Declaration Meaning STRUCT Simple struct with a single unnamed 64-bit integer field. * STRUCT Simple struct with a single parameterized string field named x. STRUCT> A struct with a nested struct named x inside it. The struct x has two * fields, y and z, both of which are 64-bit integers. STRUCT> A struct * containing an array named inner_array that holds 64-bit integer elements. - * + * * STRUCT( expr1 [AS field_name] [, ... ]) - * + * * Syntax Output Type STRUCT(1,2,3) STRUCT STRUCT() STRUCT<> STRUCT('abc') * STRUCT STRUCT(1, t.str_col) STRUCT STRUCT(1 AS a, 'abc' AS b) * STRUCT STRUCT(str_col AS abc) STRUCT - * - * + * + * * Struct Literals - * + * * Example Output Type (1, 2, 3) STRUCT (1, 'abc') STRUCT * STRUCT(1 AS foo, 'abc' AS bar) STRUCT STRUCT(1, 'abc') * STRUCT STRUCT(1) STRUCT STRUCT(1) STRUCT - * + * */ public class StructType extends ASTNodeAccessImpl implements Expression { private Dialect dialect = Dialect.BIG_QUERY;; @@ -188,8 +188,8 @@ public String toString() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public enum Dialect { diff --git a/src/main/java/net/sf/jsqlparser/expression/TimeKeyExpression.java b/src/main/java/net/sf/jsqlparser/expression/TimeKeyExpression.java index f2c4cfa65..759da0e7a 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TimeKeyExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/TimeKeyExpression.java @@ -24,8 +24,8 @@ public TimeKeyExpression(final String value) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public String getStringValue() { diff --git a/src/main/java/net/sf/jsqlparser/expression/TimeValue.java b/src/main/java/net/sf/jsqlparser/expression/TimeValue.java index f87970fa1..2b3f74394 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TimeValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/TimeValue.java @@ -25,15 +25,15 @@ public TimeValue() { } public TimeValue(String value) { - if (value == null || value.length() == 0) { + if (value == null || value.isEmpty()) { throw new IllegalArgumentException("value can neither be null nor empty."); } this.value = Time.valueOf(value.substring(1, value.length() - 1)); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public Time getValue() { diff --git a/src/main/java/net/sf/jsqlparser/expression/TimestampValue.java b/src/main/java/net/sf/jsqlparser/expression/TimestampValue.java index c6e84a4ea..a06082304 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TimestampValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/TimestampValue.java @@ -19,26 +19,26 @@ */ public final class TimestampValue extends ASTNodeAccessImpl implements Expression { + private static final char QUOTATION = '\''; private Timestamp value; private String rawValue; - private static final char QUOTATION = '\''; public TimestampValue() { // empty constructor } public TimestampValue(String value) { - // if (value == null) { - // throw new IllegalArgumentException("null string"); - // } else { - // setRawValue(value); - // } - setRawValue(Objects.requireNonNull(value, "The Timestamp string value must not be null.")); + // if (value == null) { + // throw new IllegalArgumentException("null string"); + // } else { + // setRawValue(value); + // } + setRawValue(Objects.requireNonNull(value, "The Timestamp string value must not be null.")); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public Timestamp getValue() { diff --git a/src/main/java/net/sf/jsqlparser/expression/TimezoneExpression.java b/src/main/java/net/sf/jsqlparser/expression/TimezoneExpression.java index 1cc10c924..a67572ace 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TimezoneExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/TimezoneExpression.java @@ -17,8 +17,8 @@ public class TimezoneExpression extends ASTNodeAccessImpl implements Expression { - private Expression leftExpression; private final ExpressionList timezoneExpressions = new ExpressionList<>(); + private Expression leftExpression; public TimezoneExpression() { leftExpression = null; @@ -39,8 +39,8 @@ public TimezoneExpression setLeftExpression(Expression expression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public List getTimezoneExpressions() { diff --git a/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java b/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java index 6b656aa2d..b68f1dfb7 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java +++ b/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java @@ -12,17 +12,35 @@ import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import net.sf.jsqlparser.statement.create.table.ColDataType; +import java.util.Objects; + public class TranscodingFunction extends ASTNodeAccessImpl implements Expression { + private String keyword = "CONVERT"; private boolean isTranscodeStyle = true; private ColDataType colDataType; private Expression expression; private String transcodingName; + public TranscodingFunction(String keyword, Expression expression, String transcodingName) { + this.keyword = Objects.requireNonNullElse(keyword, "CONVERT").toUpperCase(); + this.expression = expression; + this.transcodingName = transcodingName; + } + public TranscodingFunction(Expression expression, String transcodingName) { this.expression = expression; this.transcodingName = transcodingName; } + public TranscodingFunction(String keyword, ColDataType colDataType, Expression expression, + String transcodingName) { + this.keyword = Objects.requireNonNullElse(keyword, "CONVERT").toUpperCase(); + this.colDataType = colDataType; + this.expression = expression; + this.transcodingName = transcodingName; + this.isTranscodeStyle = false; + } + public TranscodingFunction(ColDataType colDataType, Expression expression, String transcodingName) { this.colDataType = colDataType; @@ -35,6 +53,15 @@ public TranscodingFunction() { this(null, null); } + public String getKeyword() { + return keyword; + } + + public TranscodingFunction setKeyword(String keyword) { + this.keyword = Objects.requireNonNullElse(keyword, "CONVERT").toUpperCase(); + return this; + } + public Expression getExpression() { return expression; } @@ -80,21 +107,23 @@ public TranscodingFunction setTranscodeStyle(boolean transcodeStyle) { return this; } - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public StringBuilder appendTo(StringBuilder builder) { if (isTranscodeStyle) { return builder - .append("CONVERT( ") + .append(keyword) + .append("( ") .append(expression) .append(" USING ") .append(transcodingName) .append(" )"); } else { return builder - .append("CONVERT( ") + .append(keyword) + .append("( ") .append(colDataType) .append(", ") .append(expression) diff --git a/src/main/java/net/sf/jsqlparser/expression/TrimFunction.java b/src/main/java/net/sf/jsqlparser/expression/TrimFunction.java index def6ec3d1..e8ea0305d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TrimFunction.java +++ b/src/main/java/net/sf/jsqlparser/expression/TrimFunction.java @@ -12,10 +12,6 @@ import net.sf.jsqlparser.parser.ASTNodeAccessImpl; public class TrimFunction extends ASTNodeAccessImpl implements Expression { - public enum TrimSpecification { - LEADING, TRAILING, BOTH - } - private TrimSpecification trimSpecification; private Expression expression; private Expression fromExpression; @@ -92,8 +88,8 @@ public TrimFunction withUsingFromKeyword(boolean useFromKeyword) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public StringBuilder appendTo(StringBuilder builder) { @@ -121,4 +117,8 @@ public StringBuilder appendTo(StringBuilder builder) { public String toString() { return appendTo(new StringBuilder()).toString(); } + + public enum TrimSpecification { + LEADING, TRAILING, BOTH + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/UserVariable.java b/src/main/java/net/sf/jsqlparser/expression/UserVariable.java index f7abde5f8..b0599a3c5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/UserVariable.java +++ b/src/main/java/net/sf/jsqlparser/expression/UserVariable.java @@ -24,7 +24,7 @@ public UserVariable() { } public UserVariable(String name) { - this.name = name; + setName(name); } public String getName() { @@ -32,12 +32,20 @@ public String getName() { } public void setName(String name) { - this.name = name; + if (name.startsWith("@@")) { + this.name = name.substring(2); + doubleAdd = true; + } else if (name.startsWith("@")) { + this.name = name.substring(1); + doubleAdd = false; + } else { + this.name = name; + } } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public boolean isDoubleAdd() { diff --git a/src/main/java/net/sf/jsqlparser/expression/VariableAssignment.java b/src/main/java/net/sf/jsqlparser/expression/VariableAssignment.java index a92f639e2..2ad773205 100644 --- a/src/main/java/net/sf/jsqlparser/expression/VariableAssignment.java +++ b/src/main/java/net/sf/jsqlparser/expression/VariableAssignment.java @@ -50,9 +50,9 @@ public String toString() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } - + } diff --git a/src/main/java/net/sf/jsqlparser/expression/WhenClause.java b/src/main/java/net/sf/jsqlparser/expression/WhenClause.java index 7f13fb523..5ed58de11 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WhenClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/WhenClause.java @@ -27,8 +27,8 @@ public WhenClause(Expression whenExpression, Expression thenExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public Expression getThenExpression() { diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java b/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java index b15ec6fcb..60760baee 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java @@ -11,6 +11,7 @@ import java.io.Serializable; import java.util.List; + import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.statement.select.OrderByElement; @@ -50,12 +51,13 @@ public ExpressionList getPartitionExpressionList() { return partitionBy.getPartitionExpressionList(); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) { - partitionBy.setPartitionExpressionList(partitionExpressionList, brackets); + public void setPartitionExpressionList(ExpressionList partitionExpressionList, + boolean brackets) { + partitionBy.setExpressions(partitionExpressionList, brackets); } public String getWindowName() { @@ -65,7 +67,7 @@ public String getWindowName() { public void setWindowName(String windowName) { this.windowName = windowName; } - + public WindowDefinition withWindowName(String windowName) { setWindowName(windowName); return this; diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowElement.java b/src/main/java/net/sf/jsqlparser/expression/WindowElement.java index 89c85e79a..97260ce97 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowElement.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowElement.java @@ -13,14 +13,6 @@ public class WindowElement implements Serializable { - public enum Type { - ROWS, RANGE; - - public static Type from(String type) { - return Enum.valueOf(Type.class, type.toUpperCase()); - } - } - private Type type; private WindowOffset offset; private WindowRange range; @@ -77,4 +69,12 @@ public WindowElement withRange(WindowRange range) { return this; } + public enum Type { + ROWS, RANGE; + + public static Type from(String type) { + return Enum.valueOf(Type.class, type.toUpperCase()); + } + } + } diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowOffset.java b/src/main/java/net/sf/jsqlparser/expression/WindowOffset.java index 843f14150..0303b4f06 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowOffset.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowOffset.java @@ -13,14 +13,6 @@ public class WindowOffset implements Serializable { - public enum Type { - PRECEDING, FOLLOWING, CURRENT, EXPR; - - public static Type from(String type) { - return Enum.valueOf(Type.class, type.toUpperCase()); - } - } - private Expression expression; private Type type; @@ -83,4 +75,12 @@ public E getExpression(Class type) { return type.cast(getExpression()); } + public enum Type { + PRECEDING, FOLLOWING, CURRENT, EXPR; + + public static Type from(String type) { + return Enum.valueOf(Type.class, type.toUpperCase()); + } + } + } diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowRange.java b/src/main/java/net/sf/jsqlparser/expression/WindowRange.java index 5c2568258..fc5f0af36 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowRange.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowRange.java @@ -34,12 +34,10 @@ public void setStart(WindowOffset start) { @Override public String toString() { - StringBuilder buffer = new StringBuilder(); - buffer.append(" BETWEEN"); - buffer.append(start); - buffer.append(" AND"); - buffer.append(end); - return buffer.toString(); + return " BETWEEN" + + start + + " AND" + + end; } public WindowRange withStart(WindowOffset start) { diff --git a/src/main/java/net/sf/jsqlparser/expression/XMLSerializeExpr.java b/src/main/java/net/sf/jsqlparser/expression/XMLSerializeExpr.java index 89f59242b..d2534e62d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/XMLSerializeExpr.java +++ b/src/main/java/net/sf/jsqlparser/expression/XMLSerializeExpr.java @@ -10,7 +10,9 @@ package net.sf.jsqlparser.expression; import java.util.List; + import static java.util.stream.Collectors.joining; + import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import net.sf.jsqlparser.statement.create.table.ColDataType; import net.sf.jsqlparser.statement.select.OrderByElement; @@ -22,8 +24,8 @@ public class XMLSerializeExpr extends ASTNodeAccessImpl implements Expression { private ColDataType dataType; @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public Expression getExpression() { @@ -49,11 +51,12 @@ public ColDataType getDataType() { public void setDataType(ColDataType dataType) { this.dataType = dataType; } - + @Override public String toString() { return "xmlserialize(xmlagg(xmltext(" + expression + ")" - + (orderByElements != null ? " ORDER BY " + orderByElements.stream().map(item -> item.toString()).collect(joining(", ")) : "") + + (orderByElements != null ? " ORDER BY " + orderByElements.stream() + .map(OrderByElement::toString).collect(joining(", ")) : "") + ") AS " + dataType + ")"; } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Addition.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Addition.java index 0492a5540..fca4fd08d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Addition.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Addition.java @@ -22,8 +22,8 @@ public Addition(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseAnd.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseAnd.java index 4104bfda1..f5eac9390 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseAnd.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseAnd.java @@ -22,8 +22,8 @@ public BitwiseAnd(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseLeftShift.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseLeftShift.java index 21e08f0ee..0f2094ce9 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseLeftShift.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseLeftShift.java @@ -22,8 +22,8 @@ public BitwiseLeftShift(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseOr.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseOr.java index dad377195..2d11d9e6f 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseOr.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseOr.java @@ -22,8 +22,8 @@ public BitwiseOr(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseRightShift.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseRightShift.java index bbcaccc48..13b5dbdd3 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseRightShift.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseRightShift.java @@ -22,8 +22,8 @@ public BitwiseRightShift(Expression leftExpression, Expression rightExpression) } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseXor.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseXor.java index 6837eedaa..89cbcb64a 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseXor.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseXor.java @@ -22,8 +22,8 @@ public BitwiseXor(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Concat.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Concat.java index 39960b35f..1ad8bb119 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Concat.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Concat.java @@ -22,8 +22,8 @@ public Concat(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Division.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Division.java index c07b71235..a963d63f3 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Division.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Division.java @@ -22,8 +22,8 @@ public Division(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/IntegerDivision.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/IntegerDivision.java index 351ad764b..73489eb8d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/IntegerDivision.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/IntegerDivision.java @@ -22,8 +22,8 @@ public IntegerDivision(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Modulo.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Modulo.java index 31831a51b..63482d2a2 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Modulo.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Modulo.java @@ -25,8 +25,8 @@ public Modulo(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Multiplication.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Multiplication.java index 7fdf26900..774db570b 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Multiplication.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Multiplication.java @@ -22,8 +22,8 @@ public Multiplication(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Subtraction.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Subtraction.java index cff5b4041..dc2b74c7b 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Subtraction.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Subtraction.java @@ -22,8 +22,8 @@ public Subtraction(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/AndExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/AndExpression.java index 38152158b..0d9d36377 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/AndExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/AndExpression.java @@ -25,17 +25,17 @@ public AndExpression(Expression leftExpression, Expression rightExpression) { setRightExpression(rightExpression); } - public void setUseOperator(boolean useOperator) { - this.useOperator = useOperator; - } - public boolean isUseOperator() { return useOperator; } + public void setUseOperator(boolean useOperator) { + this.useOperator = useOperator; + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/OrExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/OrExpression.java index 11503b475..f08cc7de2 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/OrExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/OrExpression.java @@ -35,8 +35,8 @@ public OrExpression withRightExpression(Expression expression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/XorExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/XorExpression.java index 00e93fc5a..9bab8b53f 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/XorExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/XorExpression.java @@ -35,8 +35,8 @@ public XorExpression withRightExpression(Expression expression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Between.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Between.java index e220a1dcb..8998863ef 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Between.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Between.java @@ -22,47 +22,70 @@ public class Between extends ASTNodeAccessImpl implements Expression { private boolean not = false; private Expression betweenExpressionStart; private Expression betweenExpressionEnd; + private boolean usingSymmetric = false; + private boolean usingAsymmetric = false; public Expression getBetweenExpressionEnd() { return betweenExpressionEnd; } + public void setBetweenExpressionEnd(Expression expression) { + betweenExpressionEnd = expression; + } + public Expression getBetweenExpressionStart() { return betweenExpressionStart; } + public void setBetweenExpressionStart(Expression expression) { + betweenExpressionStart = expression; + } + public Expression getLeftExpression() { return leftExpression; } + public void setLeftExpression(Expression expression) { + leftExpression = expression; + } + public boolean isNot() { return not; } - public void setBetweenExpressionEnd(Expression expression) { - betweenExpressionEnd = expression; + public void setNot(boolean b) { + not = b; } - public void setBetweenExpressionStart(Expression expression) { - betweenExpressionStart = expression; + public boolean isUsingSymmetric() { + return usingSymmetric; } - public void setLeftExpression(Expression expression) { - leftExpression = expression; + public Between setUsingSymmetric(boolean usingSymmetric) { + this.usingSymmetric = usingSymmetric; + return this; } - public void setNot(boolean b) { - not = b; + public boolean isUsingAsymmetric() { + return usingAsymmetric; + } + + public Between setUsingAsymmetric(boolean usingAsymmetric) { + this.usingAsymmetric = usingAsymmetric; + return this; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return leftExpression + " " + (not ? "NOT " : "") + "BETWEEN " + betweenExpressionStart + " AND " + return leftExpression + " " + (not ? "NOT " : "") + "BETWEEN " + + (usingSymmetric ? "SYMMETRIC " : "") + (usingAsymmetric ? "ASYMMETRIC " : "") + + betweenExpressionStart + + " AND " + betweenExpressionEnd; } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ContainedBy.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ContainedBy.java index b0a5abcbb..15562a408 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ContainedBy.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ContainedBy.java @@ -18,8 +18,8 @@ public ContainedBy() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Contains.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Contains.java index c362dc2be..dbfda1027 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Contains.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Contains.java @@ -18,8 +18,8 @@ public Contains() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/CosineSimilarity.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/CosineSimilarity.java new file mode 100644 index 000000000..00aad962d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/CosineSimilarity.java @@ -0,0 +1,28 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class CosineSimilarity extends ComparisonOperator { + + public CosineSimilarity() { + super("<=>"); + } + + public CosineSimilarity(String operator) { + super(operator); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/DoubleAnd.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/DoubleAnd.java index c060cbc52..372e123b1 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/DoubleAnd.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/DoubleAnd.java @@ -18,7 +18,7 @@ public DoubleAnd() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/EqualsTo.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/EqualsTo.java index e9e33ac60..8f80f1be8 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/EqualsTo.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/EqualsTo.java @@ -25,8 +25,8 @@ public EqualsTo(Expression left, Expression right) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExcludesExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExcludesExpression.java index bd9c1de75..847ff087c 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExcludesExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExcludesExpression.java @@ -29,15 +29,15 @@ public Expression getLeftExpression() { return leftExpression; } + public final void setLeftExpression(Expression expression) { + leftExpression = expression; + } + public ExcludesExpression withLeftExpression(Expression expression) { this.setLeftExpression(expression); return this; } - public final void setLeftExpression(Expression expression) { - leftExpression = expression; - } - public Expression getRightExpression() { return rightExpression; } @@ -47,8 +47,8 @@ public void setRightExpression(Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExistsExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExistsExpression.java index 099fb054f..c8d83f1d5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExistsExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExistsExpression.java @@ -35,8 +35,8 @@ public void setNot(boolean b) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public String getStringExpression() { diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExpressionList.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExpressionList.java index 090d2707b..5efb04359 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExpressionList.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExpressionList.java @@ -11,7 +11,7 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; -import net.sf.jsqlparser.parser.SimpleNode; +import net.sf.jsqlparser.parser.Node; import java.io.Serializable; import java.util.ArrayList; @@ -24,7 +24,7 @@ */ public class ExpressionList extends ArrayList implements Expression, Serializable { - private transient SimpleNode node; + private transient Node node; public ExpressionList(Collection expressions) { addAll(expressions); @@ -94,18 +94,19 @@ public String toString() { return appendTo(new StringBuilder()).toString(); } - @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); - } @Override - public SimpleNode getASTNode() { + public Node getASTNode() { return node; } @Override - public void setASTNode(SimpleNode node) { + public void setASTNode(Node node) { this.node = node; } + + @Override + public K accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearch.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearch.java index 83c1f7b3a..0bf79f0ec 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearch.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearch.java @@ -9,6 +9,10 @@ */ package net.sf.jsqlparser.expression.operators.relational; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.expression.JdbcNamedParameter; @@ -17,11 +21,6 @@ import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import net.sf.jsqlparser.schema.Column; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.Optional; - public class FullTextSearch extends ASTNodeAccessImpl implements Expression { private ExpressionList _matchColumns; @@ -32,41 +31,45 @@ public FullTextSearch() { } + public ExpressionList getMatchColumns() { + return this._matchColumns; + } + public void setMatchColumns(ExpressionList columns) { this._matchColumns = columns; } - public ExpressionList getMatchColumns() { - return this._matchColumns; + public Expression getAgainstValue() { + return this._againstValue; } - public void setAgainstValue(StringValue val) { + public void setAgainstValue(Expression val) { this._againstValue = val; } + public void setAgainstValue(StringValue val) { + setAgainstValue((Expression) val); + } + public void setAgainstValue(JdbcNamedParameter val) { - this._againstValue = val; + setAgainstValue((Expression) val); } public void setAgainstValue(JdbcParameter val) { - this._againstValue = val; + setAgainstValue((Expression) val); } - public Expression getAgainstValue() { - return this._againstValue; + public String getSearchModifier() { + return this._searchModifier; } public void setSearchModifier(String val) { this._searchModifier = val; } - public String getSearchModifier() { - return this._searchModifier; - } - @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override @@ -92,6 +95,10 @@ public FullTextSearch withMatchColumns(ExpressionList matchColumns) { } public FullTextSearch withAgainstValue(StringValue againstValue) { + return withAgainstValue((Expression) againstValue); + } + + public FullTextSearch withAgainstValue(Expression againstValue) { this.setAgainstValue(againstValue); return this; } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GeometryDistance.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GeometryDistance.java index 8fceadd3f..9f8438ab6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GeometryDistance.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GeometryDistance.java @@ -22,7 +22,7 @@ public GeometryDistance(String operator) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThan.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThan.java index 5b94c6301..3599ba45d 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThan.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThan.java @@ -23,8 +23,8 @@ public GreaterThan(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThanEquals.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThanEquals.java index 506c60efb..39d1c8c97 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThanEquals.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThanEquals.java @@ -27,8 +27,8 @@ public GreaterThanEquals(Expression leftExpression, Expression rightExpression) } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java index af6ad913d..743d8a0aa 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java @@ -29,6 +29,11 @@ public InExpression(Expression leftExpression, Expression rightExpression) { this.rightExpression = rightExpression; } + @Override + public int getOldOracleJoinSyntax() { + return oldOracleJoinSyntax; + } + @Override public void setOldOracleJoinSyntax(int oldOracleJoinSyntax) { this.oldOracleJoinSyntax = oldOracleJoinSyntax; @@ -39,24 +44,19 @@ public void setOldOracleJoinSyntax(int oldOracleJoinSyntax) { } } - @Override - public int getOldOracleJoinSyntax() { - return oldOracleJoinSyntax; - } - public Expression getLeftExpression() { return leftExpression; } + public final void setLeftExpression(Expression expression) { + leftExpression = expression; + } + public InExpression withLeftExpression(Expression expression) { this.setLeftExpression(expression); return this; } - public final void setLeftExpression(Expression expression) { - leftExpression = expression; - } - public boolean isGlobal() { return global; } @@ -83,8 +83,8 @@ public void setRightExpression(Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } private String getLeftExpressionString() { diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IncludesExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IncludesExpression.java index 9bc621d96..b0b260e72 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IncludesExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IncludesExpression.java @@ -30,15 +30,15 @@ public Expression getLeftExpression() { return leftExpression; } + public final void setLeftExpression(Expression expression) { + leftExpression = expression; + } + public IncludesExpression withLeftExpression(Expression expression) { this.setLeftExpression(expression); return this; } - public final void setLeftExpression(Expression expression) { - leftExpression = expression; - } - public Expression getRightExpression() { return rightExpression; } @@ -48,8 +48,8 @@ public void setRightExpression(Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsBooleanExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsBooleanExpression.java index 68ce5eed4..3c8336533 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsBooleanExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsBooleanExpression.java @@ -23,14 +23,14 @@ public Expression getLeftExpression() { return leftExpression; } - public boolean isNot() { - return not; - } - public void setLeftExpression(Expression expression) { leftExpression = expression; } + public boolean isNot() { + return not; + } + public void setNot(boolean b) { not = b; } @@ -44,8 +44,8 @@ public void setIsTrue(boolean isTrue) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsDistinctExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsDistinctExpression.java index 4cff4ac0e..60add6b6e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsDistinctExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsDistinctExpression.java @@ -25,8 +25,8 @@ public void setNot(boolean b) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpression.java index 3e0f880da..393f9f194 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpression.java @@ -12,6 +12,7 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; public class IsNullExpression extends ASTNodeAccessImpl implements Expression { @@ -26,18 +27,23 @@ public IsNullExpression(Expression leftExpression) { this.leftExpression = leftExpression; } - public Expression getLeftExpression() { - return leftExpression; + public IsNullExpression(String columnName, boolean not) { + this.leftExpression = new Column(columnName); + this.not = not; } - public boolean isNot() { - return not; + public Expression getLeftExpression() { + return leftExpression; } public void setLeftExpression(Expression expression) { leftExpression = expression; } + public boolean isNot() { + return not; + } + public void setNot(boolean b) { not = b; } @@ -60,8 +66,8 @@ public IsNullExpression setUseNotNull(boolean useNotNull) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpression.java new file mode 100644 index 000000000..506d6e246 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpression.java @@ -0,0 +1,60 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class IsUnknownExpression extends ASTNodeAccessImpl implements Expression { + + private Expression leftExpression; + private boolean isNot = false; + + public Expression getLeftExpression() { + return leftExpression; + } + + public void setLeftExpression(Expression expression) { + leftExpression = expression; + } + + public boolean isNot() { + return isNot; + } + + public void setNot(boolean isNot) { + this.isNot = isNot; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return leftExpression + " IS" + (isNot ? " NOT" : "") + " UNKNOWN"; + } + + public IsUnknownExpression withLeftExpression(Expression leftExpression) { + this.setLeftExpression(leftExpression); + return this; + } + + public IsUnknownExpression withNot(boolean isNot) { + this.setNot(isNot); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/JsonOperator.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/JsonOperator.java index 5525b1e05..94237e8f6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/JsonOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/JsonOperator.java @@ -15,15 +15,15 @@ public class JsonOperator extends BinaryExpression { - private String op; //"@>" + private String op; // "@>" public JsonOperator(String op) { this.op = op; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java index f98121402..f450de1c1 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java @@ -14,14 +14,6 @@ import net.sf.jsqlparser.expression.ExpressionVisitor; public class LikeExpression extends BinaryExpression { - public enum KeyWord { - LIKE, ILIKE, RLIKE, REGEXP, SIMILAR_TO; - - public static KeyWord from(String keyword) { - return Enum.valueOf(KeyWord.class, keyword.toUpperCase().replaceAll("\\s+", "_")); - } - } - private boolean not = false; private boolean useBinary = false; private Expression escapeExpression = null; @@ -45,8 +37,8 @@ public LikeExpression setUseBinary(boolean useBinary) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Deprecated @@ -123,4 +115,12 @@ public LikeExpression withLeftExpression(Expression arg0) { public LikeExpression withRightExpression(Expression arg0) { return (LikeExpression) super.withRightExpression(arg0); } + + public enum KeyWord { + LIKE, ILIKE, RLIKE, REGEXP_LIKE, REGEXP, SIMILAR_TO, MATCH_ANY, MATCH_ALL, MATCH_PHRASE, MATCH_PHRASE_PREFIX, MATCH_REGEXP; + + public static KeyWord from(String keyword) { + return Enum.valueOf(KeyWord.class, keyword.toUpperCase().replaceAll("\\s+", "_")); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Matches.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Matches.java index 4c2e1cb4b..1388fa51f 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Matches.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Matches.java @@ -15,8 +15,8 @@ public class Matches extends OldOracleJoinBinaryExpression { @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MemberOfExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MemberOfExpression.java index 590606629..d602e6278 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MemberOfExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MemberOfExpression.java @@ -57,7 +57,7 @@ public String toString() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThan.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThan.java index 3eff279af..3f6ddd267 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThan.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThan.java @@ -23,8 +23,8 @@ public MinorThan(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThanEquals.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThanEquals.java index a3ca0dd15..5318a0d27 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThanEquals.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThanEquals.java @@ -27,8 +27,8 @@ public MinorThanEquals(Expression leftExpression, Expression rightExpression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/NotEqualsTo.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/NotEqualsTo.java index 397a4fb84..c6e1ef3cb 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/NotEqualsTo.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/NotEqualsTo.java @@ -39,8 +39,8 @@ public NotEqualsTo withRightExpression(Expression expression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/OldOracleJoinBinaryExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/OldOracleJoinBinaryExpression.java index e607ee36c..46b093b7d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/OldOracleJoinBinaryExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/OldOracleJoinBinaryExpression.java @@ -12,24 +12,17 @@ import net.sf.jsqlparser.expression.BinaryExpression; import net.sf.jsqlparser.expression.Expression; -public abstract class OldOracleJoinBinaryExpression extends BinaryExpression implements SupportsOldOracleJoinSyntax { +public abstract class OldOracleJoinBinaryExpression extends BinaryExpression + implements SupportsOldOracleJoinSyntax { private int oldOracleJoinSyntax = NO_ORACLE_JOIN; private int oraclePriorPosition = NO_ORACLE_PRIOR; - @Override - public void setOldOracleJoinSyntax(int oldOracleJoinSyntax) { - this.oldOracleJoinSyntax = oldOracleJoinSyntax; - if (oldOracleJoinSyntax < 0 || oldOracleJoinSyntax > 2) { - throw new IllegalArgumentException("unknown join type for oracle found (type=" + oldOracleJoinSyntax + ")"); - } - } - @Override public String toString() { - return //(isNot() ? "NOT " : "") - (oraclePriorPosition == ORACLE_PRIOR_START ? "PRIOR " : "") + return // (isNot() ? "NOT " : "") + (oraclePriorPosition == ORACLE_PRIOR_START ? "PRIOR " : "") + getLeftExpression() + (oldOracleJoinSyntax == ORACLE_JOIN_RIGHT ? "(+)" : "") + " " + getStringExpression() + " " @@ -43,6 +36,15 @@ public int getOldOracleJoinSyntax() { return oldOracleJoinSyntax; } + @Override + public void setOldOracleJoinSyntax(int oldOracleJoinSyntax) { + this.oldOracleJoinSyntax = oldOracleJoinSyntax; + if (oldOracleJoinSyntax < 0 || oldOracleJoinSyntax > 2) { + throw new IllegalArgumentException( + "unknown join type for oracle found (type=" + oldOracleJoinSyntax + ")"); + } + } + @Override public int getOraclePriorPosition() { return oraclePriorPosition; diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ParenthesedExpressionList.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ParenthesedExpressionList.java index 13efb57c8..dc71ea6ad 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ParenthesedExpressionList.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ParenthesedExpressionList.java @@ -22,6 +22,7 @@ public ParenthesedExpressionList(ExpressionList expressions) { addAll(expressions); } + @SafeVarargs public ParenthesedExpressionList(T... expressions) { addAll(Arrays.asList(expressions)); } @@ -31,7 +32,7 @@ public ParenthesedExpressionList(Collection expressions) { } public static ParenthesedExpressionList from(ExpressionList expressions) { - return new ParenthesedExpressionList(expressions); + return new ParenthesedExpressionList<>(expressions); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Plus.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Plus.java new file mode 100644 index 000000000..e3362d950 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Plus.java @@ -0,0 +1,30 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class Plus extends BinaryExpression { + public Plus(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + + @Override + public String getStringExpression() { + return "PLUS"; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/PriorTo.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/PriorTo.java new file mode 100644 index 000000000..267f158fd --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/PriorTo.java @@ -0,0 +1,30 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class PriorTo extends BinaryExpression { + public PriorTo(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + + @Override + public String getStringExpression() { + return "PRIOR TO"; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperator.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperator.java index bffafc71d..786f60407 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperator.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.expression.operators.relational; import java.util.Objects; + import net.sf.jsqlparser.expression.BinaryExpression; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; @@ -19,7 +20,8 @@ public class RegExpMatchOperator extends BinaryExpression { private RegExpMatchOperatorType operatorType; public RegExpMatchOperator(RegExpMatchOperatorType operatorType) { - this.operatorType = Objects.requireNonNull(operatorType, "The provided RegExpMatchOperatorType must not be NULL."); + this.operatorType = Objects.requireNonNull(operatorType, + "The provided RegExpMatchOperatorType must not be NULL."); } public RegExpMatchOperatorType getOperatorType() { @@ -27,8 +29,8 @@ public RegExpMatchOperatorType getOperatorType() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperatorType.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperatorType.java index 8d324a4ab..c22f05eee 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperatorType.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperatorType.java @@ -13,8 +13,5 @@ * PostgresSQL match operators. */ public enum RegExpMatchOperatorType { - MATCH_CASESENSITIVE, - MATCH_CASEINSENSITIVE, - NOT_MATCH_CASESENSITIVE, - NOT_MATCH_CASEINSENSITIVE + MATCH_CASESENSITIVE, MATCH_CASEINSENSITIVE, NOT_MATCH_CASESENSITIVE, NOT_MATCH_CASEINSENSITIVE } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/SimilarToExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/SimilarToExpression.java index ae460e42b..0818d75c0 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/SimilarToExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/SimilarToExpression.java @@ -27,8 +27,8 @@ public void setNot(boolean b) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override @@ -38,7 +38,8 @@ public String getStringExpression() { @Override public String toString() { - String retval = getLeftExpression() + " " + (not ? "NOT " : "") + getStringExpression() + " " + getRightExpression(); + String retval = getLeftExpression() + " " + (not ? "NOT " : "") + getStringExpression() + + " " + getRightExpression(); if (escape != null) { retval += " ESCAPE " + "'" + escape + "'"; } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLLeftJoin.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLLeftJoin.java index e654bab2d..aa1b90e16 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLLeftJoin.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLLeftJoin.java @@ -18,7 +18,7 @@ public TSQLLeftJoin() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLRightJoin.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLRightJoin.java index a38ad4a9a..fcb3e9dc4 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLRightJoin.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLRightJoin.java @@ -18,7 +18,7 @@ public TSQLRightJoin() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java index 6b4993ed9..53eb89bb7 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java +++ b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java @@ -13,7 +13,7 @@ public interface ASTNodeAccess extends Serializable { - SimpleNode getASTNode(); + Node getASTNode(); - void setASTNode(SimpleNode node); + void setASTNode(Node node); } diff --git a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java index 8ecbca8bc..6ef61996b 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java +++ b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java @@ -14,15 +14,15 @@ public class ASTNodeAccessImpl implements ASTNodeAccess { - private transient SimpleNode node; + private transient Node node; @Override - public SimpleNode getASTNode() { + public Node getASTNode() { return node; } @Override - public void setASTNode(SimpleNode node) { + public void setASTNode(Node node) { this.node = node; } @@ -30,10 +30,10 @@ public StringBuilder appendTo(StringBuilder builder) { // don't add spaces around the following punctuation final Set punctuation = new TreeSet<>(Set.of(".", "[", "]")); - SimpleNode simpleNode = getASTNode(); - if (simpleNode != null) { - Token token = simpleNode.jjtGetFirstToken(); - Token lastToken = simpleNode.jjtGetLastToken(); + Node Node = getASTNode(); + if (Node != null) { + Token token = Node.jjtGetFirstToken(); + Token lastToken = Node.jjtGetLastToken(); Token prevToken = null; while (token.next != null && token.absoluteEnd <= lastToken.absoluteEnd) { if (!punctuation.contains(token.image) @@ -49,20 +49,25 @@ public StringBuilder appendTo(StringBuilder builder) { } public ASTNodeAccess getParent() { - SimpleNode parent = (SimpleNode) node.jjtGetParent(); + Node parent = (Node) node.jjtGetParent(); while (parent.jjtGetValue() == null) { - parent = (SimpleNode) parent.jjtGetParent(); + parent = (Node) parent.jjtGetParent(); } return ASTNodeAccess.class.cast(parent.jjtGetValue()); } public T getParent(Class clazz) { - SimpleNode parent = (SimpleNode) node.jjtGetParent(); + Node parent = (Node) node.jjtGetParent(); while (parent.jjtGetValue() == null || !clazz.isInstance(parent.jjtGetValue())) { - parent = (SimpleNode) parent.jjtGetParent(); + parent = (Node) parent.jjtGetParent(); } return clazz.cast(parent.jjtGetValue()); } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } } diff --git a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java index 3c414d852..45580cb5e 100644 --- a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java +++ b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java @@ -21,6 +21,10 @@ public abstract class AbstractJSqlParser

{ protected boolean errorRecovery = false; protected List parseErrors = new ArrayList<>(); + public enum Dialect { + ORACLE, EXASOL + } + public P withSquareBracketQuotation() { return withFeature(Feature.allowSquareBracketQuotation, true); } @@ -57,6 +61,14 @@ public P withTimeOut(long timeOutMillSeconds) { return withFeature(Feature.timeOut, timeOutMillSeconds); } + public P withDialect(Dialect dialect) { + return withFeature(Feature.dialect, dialect.name()); + } + + public P withAllowedNestingDepth(int allowedNestingDepth) { + return withFeature(Feature.allowedNestingDepth, allowedNestingDepth); + } + public P withBackslashEscapeCharacter() { return withFeature(Feature.allowBackslashEscapeCharacter, true); } @@ -65,6 +77,14 @@ public P withBackslashEscapeCharacter(boolean allowBackslashEscapeCharacter) { return withFeature(Feature.allowBackslashEscapeCharacter, allowBackslashEscapeCharacter); } + public P withUnparenthesizedSubSelects() { + return withFeature(Feature.allowUnparenthesizedSubSelects, true); + } + + public P withUnparenthesizedSubSelects(boolean allowUnparenthesizedSubSelects) { + return withFeature(Feature.allowUnparenthesizedSubSelects, allowUnparenthesizedSubSelects); + } + public P withFeature(Feature f, boolean enabled) { getConfiguration().setValue(f, enabled); return me(); @@ -75,8 +95,21 @@ public P withFeature(Feature f, long value) { return me(); } + public P withFeature(Feature f, String value) { + getConfiguration().setValue(f, value); + return me(); + } + public abstract FeatureConfiguration getConfiguration(); + public FeatureConfiguration setValue(Feature feature, Object value) { + return getConfiguration().setValue(feature, value); + } + + public Object getValue(Feature feature) { + return getConfiguration().getValue(feature); + } + public abstract P me(); public boolean getAsBoolean(Feature f) { @@ -87,6 +120,18 @@ public Long getAsLong(Feature f) { return getConfiguration().getAsLong(f); } + public int getAsInt(Feature f) { + return getConfiguration().getAsInt(f); + } + + public Integer getAsInteger(Feature f) { + return getConfiguration().getAsInteger(f); + } + + public String getAsString(Feature f) { + return getConfiguration().getAsString(f); + } + public void setErrorRecovery(boolean errorRecovery) { this.errorRecovery = errorRecovery; } diff --git a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java index 0acc825c5..bdb25eeb4 100644 --- a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java +++ b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java @@ -40,17 +40,16 @@ @SuppressWarnings("PMD.CyclomaticComplexity") public final class CCJSqlParserUtil { public final static Logger LOGGER = Logger.getLogger(CCJSqlParserUtil.class.getName()); + static { LOGGER.setLevel(Level.OFF); } - public final static int ALLOWED_NESTING_DEPTH = 10; - private CCJSqlParserUtil() {} public static Statement parse(Reader statementReader) throws JSQLParserException { ExecutorService executorService = Executors.newSingleThreadExecutor(); - Statement statement = null; + Statement statement; CCJSqlParser parser = new CCJSqlParser(new StreamProvider(statementReader)); try { statement = parseStatement(parser, executorService); @@ -66,9 +65,9 @@ public static Statement parse(String sql) throws JSQLParserException { /** * Parses an sql statement while allowing via consumer to configure the used parser before. - * + *

* For instance to activate SQLServer bracket quotation on could use: - * + *

* {@code * CCJSqlParserUtil.parse("select * from [mytable]", parser -> parser.withSquareBracketQuotation(true)); * } @@ -86,7 +85,7 @@ public static Statement parse(String sql, Consumer consumer) } ExecutorService executorService = Executors.newSingleThreadExecutor(); - Statement statement = null; + Statement statement; try { statement = parse(sql, executorService, consumer); } finally { @@ -102,20 +101,22 @@ public static Statement parse(String sql, ExecutorService executorService, return null; } - Statement statement = null; + Statement statement; // first, try to parse fast and simple CCJSqlParser parser = newParser(sql); if (consumer != null) { consumer.accept(parser); } - boolean allowComplex = parser.getConfiguration().getAsBoolean(Feature.allowComplexParsing); + boolean allowComplex = parser.getAsBoolean(Feature.allowComplexParsing); + int allowedNestingDepth = parser.getAsInt(Feature.allowedNestingDepth); LOGGER.info("Allowed Complex Parsing: " + allowComplex); try { LOGGER.info("Trying SIMPLE parsing " + (allowComplex ? "first" : "only")); statement = parseStatement(parser.withAllowComplexParsing(false), executorService); } catch (JSQLParserException ex) { LOGGER.info("Nesting Depth" + getNestingDepth(sql)); - if (allowComplex && getNestingDepth(sql) <= ALLOWED_NESTING_DEPTH) { + if (allowComplex + && (allowedNestingDepth < 0 || getNestingDepth(sql) <= allowedNestingDepth)) { LOGGER.info("Trying COMPLEX parsing when SIMPLE parsing failed"); // beware: the parser must not be reused, but needs to be re-initiated parser = newParser(sql); @@ -222,23 +223,21 @@ public static Expression parseExpression(String expressionStr, boolean allowPart } catch (JSQLParserException ex1) { // when fast simple parsing fails, try complex parsing but only if it has a chance to // succeed - if (getNestingDepth(expressionStr) <= ALLOWED_NESTING_DEPTH) { - CCJSqlParser parser = newParser(expressionStr).withAllowComplexParsing(true); - if (consumer != null) { - consumer.accept(parser); - } - try { - expression = parser.Expression(); - if (!allowPartialParse - && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { - throw new JSQLParserException( - "could only parse partial expression " + expression.toString()); - } - } catch (JSQLParserException ex) { - throw ex; - } catch (ParseException ex) { - throw new JSQLParserException(ex); + CCJSqlParser parser = newParser(expressionStr).withAllowComplexParsing(true); + if (consumer != null) { + consumer.accept(parser); + } + try { + expression = parser.Expression(); + if (!allowPartialParse + && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { + throw new JSQLParserException( + "could only parse partial expression " + expression.toString()); } + } catch (JSQLParserException ex) { + throw ex; + } catch (ParseException ex) { + throw new JSQLParserException(ex); } } return expression; @@ -301,24 +300,22 @@ public static Expression parseCondExpression(String conditionalExpressionStr, throw new JSQLParserException(ex); } } catch (JSQLParserException ex1) { - if (getNestingDepth(conditionalExpressionStr) <= ALLOWED_NESTING_DEPTH) { - CCJSqlParser parser = - newParser(conditionalExpressionStr).withAllowComplexParsing(true); - if (consumer != null) { - consumer.accept(parser); - } - try { - expression = parser.Expression(); - if (!allowPartialParse - && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { - throw new JSQLParserException( - "could only parse partial expression " + expression.toString()); - } - } catch (JSQLParserException ex) { - throw ex; - } catch (ParseException ex) { - throw new JSQLParserException(ex); + CCJSqlParser parser = + newParser(conditionalExpressionStr).withAllowComplexParsing(true); + if (consumer != null) { + consumer.accept(parser); + } + try { + expression = parser.Expression(); + if (!allowPartialParse + && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { + throw new JSQLParserException( + "could only parse partial expression " + expression.toString()); } + } catch (JSQLParserException ex) { + throw ex; + } catch (ParseException ex) { + throw new JSQLParserException(ex); } } return expression; @@ -334,7 +331,7 @@ public static Expression parseCondExpression(String conditionalExpressionStr, public static Statement parseStatement(CCJSqlParser parser, ExecutorService executorService) throws JSQLParserException { - Statement statement = null; + Statement statement; Future future = executorService.submit(new Callable() { @Override public Statement call() throws ParseException { @@ -342,7 +339,7 @@ public Statement call() throws ParseException { } }); try { - statement = future.get(parser.getConfiguration().getAsLong(Feature.timeOut), + statement = future.get(parser.getAsLong(Feature.timeOut), TimeUnit.MILLISECONDS); } catch (TimeoutException ex) { parser.interrupted = true; @@ -397,7 +394,8 @@ public static Statements parseStatements(String sqls, ExecutorService executorSe if (consumer != null) { consumer.accept(parser); } - boolean allowComplex = parser.getConfiguration().getAsBoolean(Feature.allowComplexParsing); + boolean allowComplex = parser.getAsBoolean(Feature.allowComplexParsing); + int allowedNestingDepth = parser.getAsInt(Feature.allowedNestingDepth); // first, try to parse fast and simple try { @@ -405,7 +403,8 @@ public static Statements parseStatements(String sqls, ExecutorService executorSe } catch (JSQLParserException ex) { // when fast simple parsing fails, try complex parsing but only if it has a chance to // succeed - if (allowComplex && getNestingDepth(sqls) <= ALLOWED_NESTING_DEPTH) { + if (allowComplex + && (allowedNestingDepth < 0 || getNestingDepth(sqls) <= allowedNestingDepth)) { // beware: parser must not be re-used but needs to be re-initiated parser = newParser(sqls); if (consumer != null) { @@ -434,7 +433,7 @@ public Statements call() throws ParseException { } }); try { - statements = future.get(parser.getConfiguration().getAsLong(Feature.timeOut), + statements = future.get(parser.getAsLong(Feature.timeOut), TimeUnit.MILLISECONDS); } catch (TimeoutException ex) { parser.interrupted = true; @@ -450,17 +449,14 @@ public static void streamStatements(StatementListener listener, InputStream is, throws JSQLParserException { try { CCJSqlParser parser = newParser(is, encoding); - while (true) { + do { Statement stmt = parser.SingleStatement(); listener.accept(stmt); if (parser.getToken(1).kind == CCJSqlParserTokenManager.ST_SEMICOLON) { parser.getNextToken(); } - if (parser.getToken(1).kind == CCJSqlParserTokenManager.EOF) { - break; - } - } + } while (parser.getToken(1).kind != CCJSqlParserTokenManager.EOF); } catch (Exception ex) { throw new JSQLParserException(ex); } diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java index d1a50ca0e..5bdb93830 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -10,351 +10,215 @@ package net.sf.jsqlparser.parser; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; -import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; +import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; +/** + * Utilities for querying the parser's reserved and non-reserved keyword sets. + * + *

+ * Non-reserved keywords are derived from the generated {@link CCJSqlParserConstants} token + * table using the {@code MIN_NON_RESERVED_WORD} / {@code MAX_NON_RESERVED_WORD} sentinels. + * + *

+ * Reserved keywords are determined by scanning the Grammar file for all simple string token + * definitions ({@code }) and subtracting the non-reserved set. + */ public class ParserKeywordsUtils { - public final static CharsetEncoder CHARSET_ENCODER = StandardCharsets.US_ASCII.newEncoder(); - - public final static int RESTRICTED_FUNCTION = 1; - public final static int RESTRICTED_SCHEMA = 2; - public final static int RESTRICTED_TABLE = 4; - public final static int RESTRICTED_COLUMN = 8; - public final static int RESTRICTED_EXPRESSION = 16; - public final static int RESTRICTED_ALIAS = 32; - public final static int RESTRICTED_SQL2016 = 64; - - public final static int RESTRICTED_JSQLPARSER = 128 - | RESTRICTED_FUNCTION - | RESTRICTED_SCHEMA - | RESTRICTED_TABLE - | RESTRICTED_COLUMN - | RESTRICTED_EXPRESSION - | RESTRICTED_ALIAS - | RESTRICTED_SQL2016; + private static final CharsetEncoder ASCII_ENCODER = StandardCharsets.US_ASCII.newEncoder(); - // Classification follows http://www.h2database.com/html/advanced.html#keywords - public final static Object[][] ALL_RESERVED_KEYWORDS = { - {"ABSENT", RESTRICTED_JSQLPARSER}, - {"ALL", RESTRICTED_SQL2016}, - {"AND", RESTRICTED_SQL2016}, - {"ANY", RESTRICTED_JSQLPARSER}, - {"AS", RESTRICTED_SQL2016}, - {"BETWEEN", RESTRICTED_SQL2016}, - {"BOTH", RESTRICTED_SQL2016}, - {"CASEWHEN", RESTRICTED_ALIAS}, - {"CHECK", RESTRICTED_SQL2016}, - {"CONNECT", RESTRICTED_ALIAS}, - {"CONNECT_BY_ROOT", RESTRICTED_JSQLPARSER}, - {"CONSTRAINT", RESTRICTED_SQL2016}, - {"CREATE", RESTRICTED_ALIAS}, - {"CROSS", RESTRICTED_SQL2016}, - {"CURRENT", RESTRICTED_JSQLPARSER}, - {"DISTINCT", RESTRICTED_SQL2016}, - {"DOUBLE", RESTRICTED_ALIAS}, - {"ELSE", RESTRICTED_JSQLPARSER}, - {"EXCEPT", RESTRICTED_SQL2016}, - {"EXCLUDES", RESTRICTED_JSQLPARSER}, - {"EXISTS", RESTRICTED_SQL2016}, - {"FETCH", RESTRICTED_SQL2016}, - {"FINAL", RESTRICTED_JSQLPARSER}, - {"FOR", RESTRICTED_SQL2016}, - {"FORCE", RESTRICTED_SQL2016}, - {"FOREIGN", RESTRICTED_SQL2016}, - {"FROM", RESTRICTED_SQL2016}, - {"FULL", RESTRICTED_SQL2016}, - {"GLOBAL", RESTRICTED_ALIAS}, - {"GROUP", RESTRICTED_SQL2016}, - {"GROUPING", RESTRICTED_ALIAS}, - {"QUALIFY", RESTRICTED_ALIAS}, - {"HAVING", RESTRICTED_SQL2016}, - {"IF", RESTRICTED_SQL2016}, - {"IIF", RESTRICTED_ALIAS}, - {"IGNORE", RESTRICTED_ALIAS}, - {"ILIKE", RESTRICTED_SQL2016}, - {"IN", RESTRICTED_SQL2016}, - {"INCLUDES", RESTRICTED_JSQLPARSER}, - {"INNER", RESTRICTED_SQL2016}, - {"INTERSECT", RESTRICTED_SQL2016}, - {"INTERVAL", RESTRICTED_SQL2016}, - {"INTO", RESTRICTED_JSQLPARSER}, - {"IS", RESTRICTED_SQL2016}, - {"JOIN", RESTRICTED_JSQLPARSER}, - {"LATERAL", RESTRICTED_SQL2016}, - {"LEFT", RESTRICTED_SQL2016}, - {"LIKE", RESTRICTED_SQL2016}, - {"LIMIT", RESTRICTED_SQL2016}, - {"MINUS", RESTRICTED_SQL2016}, - {"NATURAL", RESTRICTED_SQL2016}, - {"NOCYCLE", RESTRICTED_JSQLPARSER}, - {"NOT", RESTRICTED_SQL2016}, - {"NULL", RESTRICTED_SQL2016}, - {"OFFSET", RESTRICTED_SQL2016}, - {"ON", RESTRICTED_SQL2016}, - {"ONLY", RESTRICTED_JSQLPARSER}, - {"OPTIMIZE", RESTRICTED_ALIAS}, - {"OR", RESTRICTED_SQL2016}, - {"ORDER", RESTRICTED_SQL2016}, - {"OUTER", RESTRICTED_JSQLPARSER}, - {"OUTPUT", RESTRICTED_JSQLPARSER}, - {"OPTIMIZE ", RESTRICTED_JSQLPARSER}, - {"PIVOT", RESTRICTED_JSQLPARSER}, - {"PROCEDURE", RESTRICTED_ALIAS}, - {"PUBLIC", RESTRICTED_ALIAS}, - {"RETURNING", RESTRICTED_JSQLPARSER}, - {"RIGHT", RESTRICTED_SQL2016}, - {"SAMPLE", RESTRICTED_ALIAS}, - {"SEL", RESTRICTED_ALIAS}, - {"SELECT", RESTRICTED_ALIAS}, - {"SEMI", RESTRICTED_JSQLPARSER}, - {"SET", RESTRICTED_JSQLPARSER}, - {"SOME", RESTRICTED_JSQLPARSER}, - {"START", RESTRICTED_JSQLPARSER}, - {"TABLES", RESTRICTED_ALIAS}, - {"TOP", RESTRICTED_SQL2016}, - {"TRAILING", RESTRICTED_SQL2016}, - {"UNBOUNDED", RESTRICTED_JSQLPARSER}, - {"UNION", RESTRICTED_SQL2016}, - {"UNIQUE", RESTRICTED_SQL2016}, - {"UNPIVOT", RESTRICTED_JSQLPARSER}, - {"USE", RESTRICTED_JSQLPARSER}, - {"USING", RESTRICTED_SQL2016}, - {"SQL_CACHE", RESTRICTED_JSQLPARSER}, - {"SQL_CALC_FOUND_ROWS", RESTRICTED_JSQLPARSER}, - {"SQL_NO_CACHE", RESTRICTED_JSQLPARSER}, - {"STRAIGHT_JOIN", RESTRICTED_JSQLPARSER}, - {"TABLESAMPLE", RESTRICTED_ALIAS}, - {"VALUE", RESTRICTED_JSQLPARSER}, - {"VALUES", RESTRICTED_SQL2016}, - {"VARYING", RESTRICTED_JSQLPARSER}, - {"WHEN", RESTRICTED_SQL2016}, - {"WHERE", RESTRICTED_SQL2016}, - {"WINDOW", RESTRICTED_SQL2016}, - {"WITH", RESTRICTED_SQL2016}, - {"XOR", RESTRICTED_JSQLPARSER}, - {"XMLSERIALIZE", RESTRICTED_JSQLPARSER}, + /** Matches a pure keyword image: word characters, at least two characters, pure US-ASCII. */ + private static final Pattern KEYWORD_PATTERN = Pattern.compile("[A-Za-z_][A-Za-z_0-9]+"); - // add keywords from the composite token definitions: - // tk= | tk= | tk= - // we will use the composite tokens instead, which are always hit first before the - // simple keywords - // @todo: figure out a way to remove these composite tokens, as they do more harm than - // good - {"SEL", RESTRICTED_JSQLPARSER}, - {"SELECT", RESTRICTED_JSQLPARSER}, - {"DATE", RESTRICTED_JSQLPARSER}, - {"TIME", RESTRICTED_JSQLPARSER}, - {"TIMESTAMP", RESTRICTED_JSQLPARSER}, - {"YEAR", RESTRICTED_JSQLPARSER}, - {"MONTH", RESTRICTED_JSQLPARSER}, - {"DAY", RESTRICTED_JSQLPARSER}, - {"HOUR", RESTRICTED_JSQLPARSER}, - {"MINUTE", RESTRICTED_JSQLPARSER}, - {"SECOND", RESTRICTED_JSQLPARSER}, - {"SUBSTR", RESTRICTED_JSQLPARSER}, - {"SUBSTRING", RESTRICTED_JSQLPARSER}, - {"TRIM", RESTRICTED_JSQLPARSER}, - {"POSITION", RESTRICTED_JSQLPARSER}, - {"OVERLAY", RESTRICTED_JSQLPARSER}, - {"NEXTVAL", RESTRICTED_COLUMN}, - - // @todo: Object Names should not start with Hex-Prefix, we shall not find that Token - {"0x", RESTRICTED_JSQLPARSER} - }; + /** + * Matches simple token definitions in the grammar: {@code }. Group 1 captures + * the string value. Only matches definitions where the value is a plain quoted string — + * compound regex tokens like {@code } won't match. + */ + private static final Pattern SIMPLE_TOKEN_PATTERN = + Pattern.compile("", Pattern.MULTILINE); - @SuppressWarnings({"PMD.ExcessiveMethodLength"}) - public static List getReservedKeywords(int restriction) { - ArrayList keywords = new ArrayList<>(); - for (Object[] data : ALL_RESERVED_KEYWORDS) { - int value = (int) data[1]; + private ParserKeywordsUtils() { + // utility class + } - // test if bit is not set - if ((value & restriction) == restriction || (restriction & value) == value) { - keywords.add((String) data[0]); + /** + * Returns the set of non-reserved keywords, i.e. tokens whose kind lies between + * {@code MIN_NON_RESERVED_WORD} and {@code MAX_NON_RESERVED_WORD}. These keywords can be used + * as unquoted identifiers. + */ + public static TreeSet getNonReservedKeywords() { + TreeSet keywords = new TreeSet<>(); + String[] images = CCJSqlParserConstants.tokenImage; + + for (int kind = CCJSqlParserConstants.MIN_NON_RESERVED_WORD + + 1; kind < CCJSqlParserConstants.MAX_NON_RESERVED_WORD; kind++) { + String image = extractKeyword(images[kind]); + if (image != null && isKeywordImage(image)) { + keywords.add(image); } } - return keywords; } /** - * @param args with: Grammar File, Keyword Documentation File - * @throws Exception + * Returns the set of reserved keywords by scanning the Grammar file for all simple + * string token definitions and subtracting the non-reserved keywords. + * + * @param grammarFile the {@code .jjt} grammar file + * @return reserved keyword strings + * @throws IOException if reading the grammar file fails */ - public static void main(String[] args) throws Exception { - if (args.length < 2) { - throw new IllegalArgumentException("No filename provided as parameters ARGS[0]"); - } - - File grammarFile = new File(args[0]); - if (grammarFile.exists() && grammarFile.canRead() && grammarFile.canWrite()) { - buildGrammarForRelObjectName(grammarFile); - buildGrammarForRelObjectNameWithoutValue(grammarFile); - } else { - throw new FileNotFoundException("Can't read file " + args[0]); - } - - File keywordDocumentationFile = new File(args[1]); - keywordDocumentationFile.createNewFile(); - if (keywordDocumentationFile.canWrite()) { - writeKeywordsDocumentationFile(keywordDocumentationFile); - } else { - throw new FileNotFoundException("Can't read file " + args[1]); - } + public static TreeSet getReservedKeywords(File grammarFile) throws IOException { + TreeSet allSimple = getAllSimpleKeywords(grammarFile); + allSimple.removeAll(getNonReservedKeywords()); + return allSimple; } - public static TreeSet getAllKeywordsUsingRegex(File file) throws IOException { - Pattern tokenBlockPattern = Pattern.compile( - "TOKEN\\s*:\\s*/\\*.*\\*/*(?:\\r?\\n|\\r)\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}", - Pattern.MULTILINE); - Pattern tokenStringValuePattern = Pattern.compile("\"(\\w{2,})\"", Pattern.MULTILINE); - - TreeSet allKeywords = new TreeSet<>(); - - Path path = file.toPath(); - Charset charset = Charset.defaultCharset(); - String content = new String(Files.readAllBytes(path), charset); - - Matcher tokenBlockmatcher = tokenBlockPattern.matcher(content); - while (tokenBlockmatcher.find()) { - String tokenBlock = tokenBlockmatcher.group(0); - Matcher tokenStringValueMatcher = tokenStringValuePattern.matcher(tokenBlock); - while (tokenStringValueMatcher.find()) { - String tokenValue = tokenStringValueMatcher.group(1); - // test if pure US-ASCII - if (CHARSET_ENCODER.canEncode(tokenValue) && tokenValue.matches("[A-Za-z]+")) { - allKeywords.add(tokenValue); - } + /** + * Returns all simple string keywords defined in the grammar file. Scans for + * {@code } patterns and collects the string values. + * + * @param grammarFile the {@code .jjt} grammar file + * @return all simple keyword strings + * @throws IOException if reading the grammar file fails + */ + public static TreeSet getAllSimpleKeywords(File grammarFile) throws IOException { + TreeSet keywords = new TreeSet<>(); + String content = Files.readString(grammarFile.toPath(), StandardCharsets.UTF_8); + + Matcher matcher = SIMPLE_TOKEN_PATTERN.matcher(content); + while (matcher.find()) { + String value = matcher.group(1); + if (isKeywordImage(value) && ASCII_ENCODER.canEncode(value)) { + keywords.add(value); } } - return allKeywords; + return keywords; } + /** + * Checks whether the given token kind is a non-reserved keyword that can be used as an unquoted + * identifier. + */ + public static boolean isNonReservedKeyword(int tokenKind) { + return tokenKind > CCJSqlParserConstants.MIN_NON_RESERVED_WORD + && tokenKind < CCJSqlParserConstants.MAX_NON_RESERVED_WORD; + } - public static void buildGrammarForRelObjectNameWithoutValue(File file) throws Exception { - Pattern methodBlockPattern = Pattern.compile( - "String\\W*RelObjectNameWithoutValue\\W*\\(\\W*\\)\\W*:\\s*\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}\\s*\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}", - Pattern.MULTILINE); - - TreeSet allKeywords = getAllKeywords(file); - - for (String reserved : getReservedKeywords(RESTRICTED_JSQLPARSER)) { - allKeywords.remove(reserved); - } + /** + * Writes a reStructuredText documentation file listing all reserved keywords. + * + * @param grammarFile the {@code .jjt} grammar file + * @param rstFile the output {@code .rst} file to write + * @throws IOException if reading or writing fails + */ + public static void writeKeywordsDocumentationFile(File grammarFile, File rstFile) + throws IOException { + TreeSet reserved = getReservedKeywords(grammarFile); StringBuilder builder = new StringBuilder(); - builder.append("String RelObjectNameWithoutValue() :\n" - + "{ Token tk = null; }\n" - + "{\n" - // @todo: find a way to avoid those hardcoded compound tokens - + " ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= \n" - + " "); - - for (String keyword : allKeywords) { - builder.append(" | tk=\"").append(keyword).append("\""); - } - - builder.append(" )\n" + " { return tk.image; }\n" + "}"); + builder.append("***********************\n"); + builder.append("Reserved Keywords\n"); + builder.append("***********************\n"); + builder.append("\n"); - replaceInFile(file, methodBlockPattern, builder.toString()); - } + builder.append( + "The following Keywords are **reserved** in JSQLParser-|JSQLPARSER_VERSION| and must not be used for **Naming Objects**: \n"); + builder.append("\n"); - public static void buildGrammarForRelObjectName(File file) throws Exception { - // Pattern pattern = - // Pattern.compile("String\\W*RelObjectName\\W*\\(\\W*\\)\\W*:\\s*\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}\\s*\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}", - // Pattern.MULTILINE); - TreeSet allKeywords = new TreeSet<>(); - for (String reserved : getReservedKeywords(RESTRICTED_ALIAS)) { - allKeywords.add(reserved); - } + builder.append("+---------------------------+\n"); + builder.append("| **Keyword** |\n"); + builder.append("+---------------------------+\n"); - for (String reserved : getReservedKeywords(RESTRICTED_JSQLPARSER & ~RESTRICTED_ALIAS)) { - allKeywords.remove(reserved); + for (String keyword : reserved) { + builder.append("| ").append(rightPadding(keyword, ' ', 25)).append(" |\n"); + builder.append("+---------------------------+\n"); } - StringBuilder builder = new StringBuilder(); - builder.append("String RelObjectName() :\n" - + "{ Token tk = null; String result = null; }\n" - + "{\n" - + " (result = RelObjectNameWithoutValue()\n" - + " "); - - for (String keyword : allKeywords) { - builder.append(" | tk=\"").append(keyword).append("\""); + try (FileWriter fileWriter = new FileWriter(rstFile)) { + fileWriter.append(builder); + fileWriter.flush(); } - - builder.append(" )\n" + " { return tk!=null ? tk.image : result; }\n" + "}"); - - // @todo: Needs fine-tuning, we are not replacing this part yet - // replaceInFile(file, pattern, builder.toString()); - } - - public static TreeSet getAllKeywords(File file) throws Exception { - return getAllKeywordsUsingRegex(file); - } - - private static void replaceInFile(File file, Pattern pattern, String replacement) - throws IOException { - Path path = file.toPath(); - Charset charset = Charset.defaultCharset(); - - String content = new String(Files.readAllBytes(path), charset); - content = pattern.matcher(content).replaceAll(replacement); - Files.write(file.toPath(), content.getBytes(charset)); } public static String rightPadding(String input, char ch, int length) { return String.format("%" + (-length) + "s", input).replace(' ', ch); } - public static void writeKeywordsDocumentationFile(File file) throws IOException { - StringBuilder builder = new StringBuilder(); - builder.append("***********************\n"); - builder.append("Restricted Keywords\n"); - builder.append("***********************\n"); - builder.append("\n"); - - builder.append( - "The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and must not be used for **Naming Objects**: \n"); - builder.append("\n"); + /** + * Entry point for the {@code updateKeywords} Gradle/Maven task. + * + *

+ * Usage: {@code java net.sf.jsqlparser.parser.ParserKeywordsUtils } + * + * @param args {@code args[0]}: path to the grammar file, {@code args[1]}: path to the output + * RST file + * @throws Exception if reading or writing fails + */ + public static void main(String[] args) throws Exception { + if (args.length < 2) { + throw new IllegalArgumentException( + "Usage: ParserKeywordsUtils "); + } - builder.append("+----------------------+-------------+-----------+\n"); - builder.append("| **Keyword** | JSQL Parser | SQL:2016 |\n"); - builder.append("+----------------------+-------------+-----------+\n"); + File grammarFile = new File(args[0]); + if (!grammarFile.canRead()) { + throw new IOException("Cannot read grammar file: " + grammarFile); + } - for (Object[] keywordDefinition : ALL_RESERVED_KEYWORDS) { - builder.append("| ").append(rightPadding(keywordDefinition[0].toString(), ' ', 20)) - .append(" | "); + File rstFile = new File(args[1]); + rstFile.getParentFile().mkdirs(); + writeKeywordsDocumentationFile(grammarFile, rstFile); - int value = (int) keywordDefinition[1]; - int restriction = RESTRICTED_JSQLPARSER; - String s = (value & restriction) == restriction || (restriction & value) == value - ? "Yes" - : ""; - builder.append(rightPadding(s, ' ', 11)).append(" | "); + System.out.println("Reserved keywords: " + getReservedKeywords(grammarFile).size()); + System.out.println("Non-reserved keywords: " + getNonReservedKeywords().size()); + System.out.println("Written to: " + rstFile.getAbsolutePath()); + } - restriction = RESTRICTED_SQL2016; - s = (value & restriction) == restriction || (restriction & value) == value - ? "Yes" - : ""; - builder.append(rightPadding(s, ' ', 9)).append(" | "); + /** + * Extracts the keyword string from a {@code tokenImage} entry. + * + *

+ * JavaCC renders inline BNF token declarations as {@code } in {@code tokenImage}. + * Stripping the {@code K_} prefix and angle brackets yields the keyword string. + * + * @return the keyword string, or {@code null} if the entry is not a {@code K_} token + */ + private static String extractKeyword(String tokenImage) { + if (tokenImage == null || tokenImage.length() < 5) { + return null; + } - builder.append("\n"); - builder.append("+----------------------+-------------+-----------+\n"); + // Format: → ACTION + if (tokenImage.charAt(0) == '<' + && tokenImage.charAt(tokenImage.length() - 1) == '>' + && tokenImage.startsWith(" 2048) { bufpos = maxNextCharInd = 0; @@ -122,22 +146,13 @@ protected void FillBuff() throws IOException { int i; try { - if (inputStream instanceof StringProvider) { - i = ((StringProvider) inputStream)._string.length(); - if (maxNextCharInd == i) { - throw new IOException(); - } - maxNextCharInd = i; + if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) { + inputStream.close(); + throw new java.io.IOException(); } else { - if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) { - inputStream.close(); - throw new IOException(); - } else { - maxNextCharInd += i; - } + maxNextCharInd += i; } - return; - } catch (IOException e) { + } catch (java.io.IOException e) { --bufpos; backup(0); if (tokenBegin == -1) { @@ -149,14 +164,14 @@ protected void FillBuff() throws IOException { /** * Start. - * @return the character read - * @throws IOException */ - public char BeginToken() throws IOException { + public char BeginToken() throws java.io.IOException { tokenBegin = -1; char c = readChar(); tokenBegin = bufpos; + absoluteTokenBegin = totalCharsRead; + return c; } @@ -184,7 +199,7 @@ protected void UpdateLineColumn(char c) { break; case '\t': column--; - column += tabSize - (column % tabSize); + column += tabSize - column % tabSize; break; default: break; @@ -194,20 +209,10 @@ protected void UpdateLineColumn(char c) { bufcolumn[bufpos] = column; } - private char readChar(int pos) { - if (this.inputStream instanceof StringProvider) { - return ((StringProvider) inputStream)._string.charAt(pos); - } else { - return buffer[pos]; - } - } - /** * Read a character. - * @return the character read - * @throws IOException */ - public char readChar() throws IOException { + public char readChar() throws java.io.IOException { if (inBuf > 0) { --inBuf; @@ -216,7 +221,8 @@ public char readChar() throws IOException { } totalCharsRead++; - return readChar(bufpos); + + return buffer[bufpos]; } if (++bufpos >= maxNextCharInd) { @@ -225,55 +231,55 @@ public char readChar() throws IOException { totalCharsRead++; - char c = readChar(bufpos); + char c = buffer[bufpos]; UpdateLineColumn(c); return c; } - + @Deprecated /** - * @return the column - * @deprecated @see #getEndColumn + * @deprecated + * @see #getEndColumn */ - @Deprecated + public int getColumn() { return bufcolumn[bufpos]; } - + @Deprecated /** - * @return the line - * @deprecated @see #getEndLine + * @deprecated + * @see #getEndLine */ - @Deprecated + public int getLine() { return bufline[bufpos]; } /** - * @return get token end column number. + * Get token end column number. */ public int getEndColumn() { return bufcolumn[bufpos]; } /** - * @return get token end line number. + * Get token end line number. */ public int getEndLine() { return bufline[bufpos]; } /** - * @return get token beginning column number. + * Get token beginning column number. */ public int getBeginColumn() { return bufcolumn[tokenBegin]; } /** - * @return get token beginning line number. + * Get token beginning line number. */ public int getBeginLine() { return bufline[tokenBegin]; @@ -281,7 +287,6 @@ public int getBeginLine() { /** * Backup a number of characters. - * @param amount */ public void backup(int amount) { @@ -293,77 +298,19 @@ public void backup(int amount) { } /** - * Constructor - * @param dstream - * @param startline - * @param startcolumn - * @param buffersize + * Reinitialise. */ - public SimpleCharStream(Provider dstream, int startline, - int startcolumn, int buffersize) { + public void ReInit(Provider dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; - isStringProvider = dstream instanceof StringProvider; line = startline; column = startcolumn - 1; - if (isStringProvider) { - int bs = ((StringProvider) inputStream)._string.length(); - available = bufsize = bs; - bufline = new int[bs]; - bufcolumn = new int[bs]; - } else { + if (buffer == null || buffersize != buffer.length) { available = bufsize = buffersize; buffer = new char[buffersize]; bufline = new int[buffersize]; bufcolumn = new int[buffersize]; } - } - - /** - * Constructor - * @param dstream - * @param startline - * @param startcolumn - */ - public SimpleCharStream(Provider dstream, int startline, - int startcolumn) { - this(dstream, startline, startcolumn, 4096); - } - - /** - * Constructor - * @param dstream - */ - public SimpleCharStream(Provider dstream) { - this(dstream, 1, 1, 4096); - } - - /** - * Reinitialise. - * @param dstream - * @param startline - * @param startcolumn - * @param buffersize - */ - public void ReInit(Provider dstream, int startline, - int startcolumn, int buffersize) { - inputStream = dstream; - isStringProvider = dstream instanceof StringProvider; - line = startline; - column = startcolumn - 1; - if (isStringProvider) { - int bs = ((StringProvider) inputStream)._string.length(); - available = bufsize = bs; - bufline = new int[bs]; - bufcolumn = new int[bs]; - } else { - if (buffer == null || buffersize != buffer.length) { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - } prevCharIsLF = prevCharIsCR = false; tokenBegin = inBuf = maxNextCharInd = 0; bufpos = -1; @@ -371,69 +318,42 @@ public void ReInit(Provider dstream, int startline, /** * Reinitialise. - * @param dstream - * @param startline - * @param startcolumn */ - public void ReInit(Provider dstream, int startline, - int startcolumn) { + public void ReInit(Provider dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } - /** - * Reinitialise. - * @param dstream - */ + /** + * Reinitialise. + */ public void ReInit(Provider dstream) { ReInit(dstream, 1, 1, 4096); } + /** - * @return get token literal value. + * Get token literal value. */ public String GetImage() { - if (isStringProvider) { - String data = ((StringProvider) inputStream)._string; - if (bufpos >= tokenBegin) { - return data.substring(tokenBegin, bufpos + 1); - } else { - return data.substring(tokenBegin, bufsize) - + data.substring(0, bufpos + 1); - } + if (bufpos >= tokenBegin) { + return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); } else { - if (bufpos >= tokenBegin) { - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - } else { - return new String(buffer, tokenBegin, bufsize - tokenBegin) - + new String(buffer, 0, bufpos + 1); - } + return new String(buffer, tokenBegin, bufsize - tokenBegin) + + new String(buffer, 0, bufpos + 1); } } /** - * @param len - * @return get the suffix. + * Get the suffix. */ public char[] GetSuffix(int len) { - char[] ret = new char[len]; - if (isStringProvider) { - String str = ((StringProvider) inputStream)._string; - if ((bufpos + 1) >= len) { - str.getChars(bufpos - len + 1, bufpos - len + 1 + len, ret, 0); - } else { - str.getChars(bufsize - (len - bufpos - 1), bufsize - (len - bufpos - 1) + len - bufpos - 1, ret, 0); - str.getChars(0, bufpos + 1, ret, len - bufpos - 1); - } + if ((bufpos + 1) >= len) { + System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); } else { - if ((bufpos + 1) >= len) { - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - } else { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } + System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1); + System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); } return ret; @@ -450,11 +370,8 @@ public void Done() { /** * Method to adjust line and column numbers for the start of a token. - * @param newLine - * @param newCol */ public void adjustBeginLineColumn(int newLine, int newCol) { - int nl = newLine; int start = tokenBegin; int len; @@ -466,12 +383,12 @@ public void adjustBeginLineColumn(int newLine, int newCol) { int i = 0; int j = 0; - int k = 0; - int nextColDiff = 0; + int k; + int nextColDiff; int columnDiff = 0; while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { - bufline[j] = nl; + bufline[j] = newLine; nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; bufcolumn[j] = newCol + columnDiff; columnDiff = nextColDiff; @@ -479,14 +396,14 @@ public void adjustBeginLineColumn(int newLine, int newCol) { } if (i < len) { - bufline[j] = nl++; + bufline[j] = newLine++; bufcolumn[j] = newCol + columnDiff; while (i++ < len) { if (bufline[j = start % bufsize] != bufline[++start % bufsize]) { - bufline[j] = nl++; + bufline[j] = newLine++; } else { - bufline[j] = nl; + bufline[j] = newLine; } } } @@ -503,4 +420,4 @@ void setTrackLineColumn(boolean tlc) { trackLineColumn = tlc; } } -/* JavaCC - OriginalChecksum=47e65cd0a1ed785f7a51c9e0c60893c9 (do not edit this line) */ +/* JavaCC - OriginalChecksum=0cd74e5ad7a4ccb9188541ab8f8b35eb (do not edit this line) */ diff --git a/src/main/java/net/sf/jsqlparser/parser/StatementListener.java b/src/main/java/net/sf/jsqlparser/parser/StatementListener.java index d48901f39..3e26a0018 100644 --- a/src/main/java/net/sf/jsqlparser/parser/StatementListener.java +++ b/src/main/java/net/sf/jsqlparser/parser/StatementListener.java @@ -12,7 +12,6 @@ import net.sf.jsqlparser.statement.Statement; /** - * * @author Tobias Warneke (t.warneke@gmx.net) */ public interface StatementListener { diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java index 011919338..d786f5170 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -110,7 +110,7 @@ public enum Feature { limitOffset, /** * "OFFSET offset" - * + * * @see Offset */ offset, @@ -127,7 +127,7 @@ public enum Feature { fetch, /** * "FETCH FIRST row_count (ROW | ROWS) ONLY" - * + * * @see Fetch#isFetchParamFirst() */ fetchFirst, @@ -465,7 +465,6 @@ public enum Feature { executeUsing, /** * SQL "REPLACE" statement is allowed - * */ @Deprecated replace, @@ -787,7 +786,43 @@ public enum Feature { /** * allows Backslash '\' as Escape Character */ - allowBackslashEscapeCharacter(false),; + allowBackslashEscapeCharacter(false), + + /** + * allows sub selects without parentheses, e.g. `select * from dual where 1 = select 1` + */ + allowUnparenthesizedSubSelects(false), + + /** + * maximum nesting depth for trying complex parsing, can bet set to -1 to ignore + */ + allowedNestingDepth(10), + + dialect(null), + + /** + * "IMPORT" + */ + imprt, + + /** + * "EXPORT" + */ + export, + + /** + * MySQL allows a ',' as a separator between key and value entries. We allow that by default, + * but it can be disabled here + */ + allowCommaAsKeyValueSeparator(true), + + /** + * DB2 and Oracle allow Expressions as JSON_OBJECT key values. This clashes with Informix and + * Snowflake Json-Extraction syntax + */ + allowExpressionAsJsonObjectKey(false) + + ; private final Object value; private final boolean configurable; diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java index dc72652ba..0106431cc 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java @@ -19,12 +19,12 @@ public class FeatureConfiguration { private static final Logger LOG = Logger.getLogger(FeatureConfiguration.class.getName()); - private Map featureEnabled = new EnumMap<>(Feature.class); + private final Map featureEnabled = new EnumMap<>(Feature.class); public FeatureConfiguration() { // set default-value for all switchable features EnumSet.allOf(Feature.class).stream().filter(Feature::isConfigurable) - .forEach(f -> setValue(f, f.getDefaultValue())); + .forEach(f -> setValue(f, f.getDefaultValue())); } /** @@ -46,8 +46,7 @@ public FeatureConfiguration setValue(Feature feature, Object value) { /** * @param feature * @return the configured feature value - can be null - * @throws IllegalStateException - if given {@link Feature#isConfigurable()} == - * false + * @throws IllegalStateException - if given {@link Feature#isConfigurable()} == false */ public Object getValue(Feature feature) { if (feature.isConfigurable()) { @@ -65,6 +64,14 @@ public Long getAsLong(Feature f) { return Long.valueOf(String.valueOf(getValue(f))); } + public int getAsInt(Feature f) { + return Integer.parseInt(String.valueOf(getValue(f))); + } + + public Integer getAsInteger(Feature f) { + return Integer.parseInt(String.valueOf(getValue(f))); + } + public String getAsString(Feature f) { Object value = getValue(f); return value == null ? null : String.valueOf(value); diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/FeatureSet.java b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureSet.java index 7ebefec9e..551e0c575 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/FeatureSet.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureSet.java @@ -12,6 +12,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; + import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed; public interface FeatureSet { @@ -19,8 +20,8 @@ public interface FeatureSet { Set getFeatures(); /** - * @return true if the feature is identical to one of the features - * contained in this set, false otherwise + * @return true if the feature is identical to one of the features contained in + * this set, false otherwise */ default boolean contains(Feature feature) { return getFeatures().contains(feature); @@ -35,8 +36,7 @@ default Set getFeaturesClone() { /** * @param features - * @return all features within this feature set which are not contained in given - * set + * @return all features within this feature set which are not contained in given set */ default Set getNotContained(Collection features) { Set f = getFeaturesClone(); @@ -46,8 +46,7 @@ default Set getNotContained(Collection features) { /** * @param features - * @return all features within this feature set which are contained in given - * set too. + * @return all features within this feature set which are contained in given set too. */ default Set retainAll(Collection features) { Set f = getFeaturesClone(); diff --git a/src/main/java/net/sf/jsqlparser/schema/Column.java b/src/main/java/net/sf/jsqlparser/schema/Column.java index a4d94eb8e..33240ac52 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Column.java +++ b/src/main/java/net/sf/jsqlparser/schema/Column.java @@ -15,7 +15,9 @@ import net.sf.jsqlparser.expression.ArrayConstructor; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.ReturningReferenceType; /** * A column. It can have the table name it belongs to. @@ -27,6 +29,12 @@ public class Column extends ASTNodeAccessImpl implements Expression, MultiPartNa private String commentText; private ArrayConstructor arrayConstructor; private String tableDelimiter = "."; + private int oldOracleJoinSyntax = SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN; + private ReturningReferenceType returningReferenceType = null; + private String returningQualifier = null; + + // holds the physical table when resolved against an actual schema information + private Table resolvedTable = null; public Column() {} @@ -49,7 +57,8 @@ public Column(List nameParts, List delimiters) { } public Column(String columnName) { - this(null, columnName); + this(); + setColumnName(columnName); } public ArrayConstructor getArrayConstructor() { @@ -91,6 +100,30 @@ public Table getTable() { return table; } + public String getTableName() { + return table != null ? table.getName() : null; + } + + public String getUnquotedTableName() { + return table != null ? table.getUnquotedName() : null; + } + + public String getSchemaName() { + return table != null ? table.getSchemaName() : null; + } + + public String getUnquotedSchemaName() { + return table != null ? table.getUnquotedSchemaName() : null; + } + + public String getCatalogName() { + return table != null ? table.getCatalogName() : null; + } + + public String getUnquotedCatalogName() { + return table != null ? table.getUnquotedCatalogName() : null; + } + public void setTable(Table table) { this.table = table; } @@ -99,8 +132,60 @@ public String getColumnName() { return columnName; } - public void setColumnName(String string) { - columnName = string; + public String getUnquotedColumnName() { + return MultiPartName.unquote(columnName); + } + + public void setColumnName(String name) { + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + // however, some people believe that Dots in Names are a good idea, so provide a switch-off + boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null || + !List + .of("0", "N", "n", "FALSE", "false", "OFF", "off") + .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + + setName(name, splitNamesOnDelimiter); + } + + public void setName(String name, boolean splitNamesOnDelimiter) { + if (MultiPartName.isQuoted(name) && name.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(name).split("\\."); + switch (parts.length) { + case 3: + this.table = new Table("\"" + parts[0] + "\".\"" + parts[1] + "\""); + this.columnName = "\"" + parts[2] + "\""; + break; + case 2: + this.table = new Table("\"" + parts[0] + "\""); + this.columnName = "\"" + parts[1] + "\""; + break; + case 1: + this.columnName = "\"" + parts[0] + "\""; + break; + default: + throw new RuntimeException("Invalid column name: " + name); + } + } else if (name.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(name).split("\\."); + switch (parts.length) { + case 3: + this.table = new Table(parts[0] + "." + parts[1]); + this.columnName = parts[2]; + break; + case 2: + this.table = new Table(parts[0]); + this.columnName = parts[1]; + break; + case 1: + this.columnName = parts[0]; + break; + default: + throw new RuntimeException("Invalid column name: " + name); + } + } else { + this.columnName = name; + } } public String getTableDelimiter() { @@ -111,15 +196,30 @@ public void setTableDelimiter(String tableDelimiter) { this.tableDelimiter = tableDelimiter; } + public int getOldOracleJoinSyntax() { + return oldOracleJoinSyntax; + } + + public void setOldOracleJoinSyntax(int oldOracleJoinSyntax) { + this.oldOracleJoinSyntax = oldOracleJoinSyntax; + } + @Override public String getFullyQualifiedName() { return getFullyQualifiedName(false); } + @Override + public String getUnquotedName() { + return MultiPartName.unquote(columnName); + } + public String getFullyQualifiedName(boolean aliases) { StringBuilder fqn = new StringBuilder(); - if (table != null) { + if (returningQualifier != null) { + fqn.append(returningQualifier); + } else if (table != null) { if (table.getAlias() != null && aliases) { fqn.append(table.getAlias().getName()); } else { @@ -152,13 +252,15 @@ public String getName(boolean aliases) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return getFullyQualifiedName(true); + return getFullyQualifiedName(true) + + (oldOracleJoinSyntax != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN ? "(+)" : "") + + (commentText != null ? " /* " + commentText + "*/ " : ""); } public Column withTable(Table table) { @@ -181,11 +283,63 @@ public Column withTableDelimiter(String delimiter) { return this; } - public void setCommentText(String commentText) { - this.commentText = commentText; + public Column withOldOracleJoinSyntax(int oldOracleJoinSyntax) { + this.setOldOracleJoinSyntax(oldOracleJoinSyntax); + return this; + } + + public ReturningReferenceType getReturningReferenceType() { + return returningReferenceType; + } + + public Column setReturningReferenceType(ReturningReferenceType returningReferenceType) { + this.returningReferenceType = returningReferenceType; + return this; + } + + public String getReturningQualifier() { + return returningQualifier; + } + + public Column setReturningQualifier(String returningQualifier) { + this.returningQualifier = returningQualifier; + return this; + } + + public Column withReturningReference(ReturningReferenceType returningReferenceType, + String returningQualifier) { + this.returningReferenceType = returningReferenceType; + this.returningQualifier = returningQualifier; + return this; } public String getCommentText() { return commentText; } + + public void setCommentText(String commentText) { + this.commentText = commentText; + } + + /** + * Gets the actual table when resolved against a physical schema information. + * + * @return the actual table when resolved against a physical schema information + */ + public Table getResolvedTable() { + return resolvedTable; + } + + /** + * Sets resolved table. + * + * @param resolvedTable the resolved table + * @return this column + */ + public Column setResolvedTable(Table resolvedTable) { + // clone, not reference + this.resolvedTable = + resolvedTable != null ? new Table(resolvedTable.getFullyQualifiedName()) : null; + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/schema/Database.java b/src/main/java/net/sf/jsqlparser/schema/Database.java index 00f65f8e8..c566b744f 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Database.java +++ b/src/main/java/net/sf/jsqlparser/schema/Database.java @@ -57,6 +57,11 @@ public String getFullyQualifiedName() { return fqn; } + @Override + public String getUnquotedName() { + return MultiPartName.unquote(databaseName); + } + @Override public String toString() { return getFullyQualifiedName(); diff --git a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java index 57960855b..ce954780d 100644 --- a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java +++ b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java @@ -9,7 +9,52 @@ */ package net.sf.jsqlparser.schema; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public interface MultiPartName { + Pattern LEADING_TRAILING_QUOTES_PATTERN = Pattern.compile("^[\"\\[`]+|[\"\\]`]+$"); + Pattern BACKTICK_PATTERN = Pattern.compile("`([^`]*)`"); + + /** + * Removes leading and trailing quotes from a SQL quoted identifier + * + * @param quotedIdentifier the quoted identifier + * @return the pure identifier without quotes + */ + static String unquote(String quotedIdentifier) { + return quotedIdentifier != null + ? LEADING_TRAILING_QUOTES_PATTERN.matcher(quotedIdentifier).replaceAll("") + : null; + } + + static boolean isQuoted(String identifier) { + return identifier != null && LEADING_TRAILING_QUOTES_PATTERN.matcher(identifier).find(); + } String getFullyQualifiedName(); + + String getUnquotedName(); + + + static String replaceBackticksWithDoubleQuotes(String input) { + if (input == null || input.isEmpty()) { + return input; + } + + Matcher matcher = BACKTICK_PATTERN.matcher(input); + StringBuilder sb = new StringBuilder(); + int lastEnd = 0; + + while (matcher.find()) { + sb.append(input, lastEnd, matcher.start()); // text before match + sb.append('"').append(matcher.group(1)).append('"'); // replace with double quotes + lastEnd = matcher.end(); + } + + sb.append(input.substring(lastEnd)); // append remaining text + return sb.toString(); + } + + } diff --git a/src/main/java/net/sf/jsqlparser/schema/Partition.java b/src/main/java/net/sf/jsqlparser/schema/Partition.java new file mode 100644 index 000000000..2666a6e81 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/schema/Partition.java @@ -0,0 +1,66 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.schema; + +import net.sf.jsqlparser.expression.Expression; + +import java.util.Collection; +import java.util.Objects; + +public class Partition { + protected Column column; + protected Expression value; + + public Partition() { + + } + + public Partition(Column column, Expression value) { + this.column = column; + this.value = value; + } + + public static void appendPartitionsTo(StringBuilder builder, + Collection partitions) { + int j = 0; + for (Partition partition : partitions) { + partition.appendTo(builder, j); + j++; + } + } + + public Column getColumn() { + return column; + } + + public void setColumn(Column column) { + this.column = Objects.requireNonNull(column); + } + + public Expression getValue() { + return value; + } + + public void setValue(Expression value) { + this.value = Objects.requireNonNull(value); + } + + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPath"}) + void appendTo(StringBuilder builder, int j) { + if (j > 0) { + builder.append(", "); + } + builder.append(column.getColumnName()); + if (value != null) { + builder.append(" = ").append(value); + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/schema/Sequence.java b/src/main/java/net/sf/jsqlparser/schema/Sequence.java index 0997eefb8..764294db6 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Sequence.java +++ b/src/main/java/net/sf/jsqlparser/schema/Sequence.java @@ -9,13 +9,12 @@ */ package net.sf.jsqlparser.schema; -import net.sf.jsqlparser.parser.ASTNodeAccessImpl; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; /** * Represents the database type for a {@code SEQUENCE} @@ -29,6 +28,7 @@ public class Sequence extends ASTNodeAccessImpl implements MultiPartName { private List partItems = new ArrayList<>(); private List parameters; + private String dataType; public Sequence() {} @@ -37,12 +37,25 @@ public Sequence(List partItems) { Collections.reverse(this.partItems); } + public List getParameters() { + return parameters; + } + public void setParameters(List parameters) { this.parameters = parameters; } - public List getParameters() { - return parameters; + public String getDataType() { + return dataType; + } + + public void setDataType(String dataType) { + this.dataType = dataType; + } + + public Sequence withDataType(String dataType) { + this.setDataType(dataType); + return this; } public Database getDatabase() { @@ -121,9 +134,17 @@ public String getFullyQualifiedName() { return fqn.toString(); } + @Override + public String getUnquotedName() { + return MultiPartName.unquote(partItems.get(NAME_IDX)); + } + @Override public String toString() { StringBuilder sql = new StringBuilder(getFullyQualifiedName()); + if (dataType != null) { + sql.append(" AS ").append(dataType); + } if (parameters != null) { for (Sequence.Parameter parameter : parameters) { sql.append(" ").append(parameter.formatParameter()); @@ -153,7 +174,7 @@ public Sequence addParameters(Collection parameters) { * The available parameters to a sequence */ public enum ParameterType { - INCREMENT_BY, START_WITH, RESTART_WITH, MAXVALUE, NOMAXVALUE, MINVALUE, NOMINVALUE, CYCLE, NOCYCLE, CACHE, NOCACHE, ORDER, NOORDER, KEEP, NOKEEP, SESSION, GLOBAL; + INCREMENT_BY, INCREMENT, START_WITH, START, RESTART_WITH, MAXVALUE, NOMAXVALUE, MINVALUE, NOMINVALUE, CYCLE, NOCYCLE, CACHE, NOCACHE, ORDER, NOORDER, KEEP, NOKEEP, SESSION, GLOBAL; public static ParameterType from(String type) { return Enum.valueOf(ParameterType.class, type.toUpperCase()); @@ -184,8 +205,12 @@ public String formatParameter() { switch (option) { case INCREMENT_BY: return prefix("INCREMENT BY"); + case INCREMENT: + return prefix("INCREMENT"); case START_WITH: return prefix("START WITH"); + case START: + return prefix("START"); case RESTART_WITH: if (value != null) { return prefix("RESTART WITH"); diff --git a/src/main/java/net/sf/jsqlparser/schema/Server.java b/src/main/java/net/sf/jsqlparser/schema/Server.java index 3dca6cd2c..9ac9bd2d2 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Server.java +++ b/src/main/java/net/sf/jsqlparser/schema/Server.java @@ -13,8 +13,8 @@ public final class Server implements MultiPartName { - public static final Pattern SERVER_PATTERN = Pattern. - compile("\\[([^\\]]+?)(?:\\\\([^\\]]+))?\\]"); + public static final Pattern SERVER_PATTERN = + Pattern.compile("\\[([^\\]]+?)(?:\\\\([^\\]]+))?\\]"); private String serverName; @@ -57,8 +57,8 @@ public void setInstanceName(String instanceName) { @Override public String getFullyQualifiedName() { - if (serverName != null && !serverName.isEmpty() && instanceName != null && !instanceName. - isEmpty()) { + if (serverName != null && !serverName.isEmpty() && instanceName != null + && !instanceName.isEmpty()) { return String.format("[%s\\%s]", serverName, instanceName); } else if (serverName != null && !serverName.isEmpty()) { return String.format("[%s]", serverName); @@ -69,6 +69,11 @@ public String getFullyQualifiedName() { } } + @Override + public String getUnquotedName() { + return MultiPartName.unquote(serverName); + } + @Override public String toString() { return getFullyQualifiedName(); diff --git a/src/main/java/net/sf/jsqlparser/schema/Synonym.java b/src/main/java/net/sf/jsqlparser/schema/Synonym.java index b2b958302..b052588c8 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Synonym.java +++ b/src/main/java/net/sf/jsqlparser/schema/Synonym.java @@ -23,8 +23,7 @@ public class Synonym extends ASTNodeAccessImpl implements MultiPartName { private static final int SERVER_IDX = 3; private List partItems = new ArrayList<>(); - public Synonym() { - } + public Synonym() {} public Synonym(List partItems) { this.partItems = new ArrayList<>(partItems); @@ -107,6 +106,11 @@ public String getFullyQualifiedName() { return fqn.toString(); } + @Override + public String getUnquotedName() { + return MultiPartName.unquote(partItems.get(NAME_IDX)); + } + @Override public String toString() { StringBuilder sql = new StringBuilder(getFullyQualifiedName()); diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 983f5e011..1de14a8a5 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -10,12 +10,15 @@ package net.sf.jsqlparser.schema; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; + import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.MySQLIndexHint; import net.sf.jsqlparser.expression.SQLServerHints; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.ErrorDestination; import net.sf.jsqlparser.statement.select.FromItem; import net.sf.jsqlparser.statement.select.FromItemVisitor; import net.sf.jsqlparser.statement.select.IntoTableVisitor; @@ -26,11 +29,9 @@ /** * A table. It can have an alias and the schema name it belongs to. */ -public class Table extends ASTNodeAccessImpl implements FromItem, MultiPartName { +public class Table extends ASTNodeAccessImpl + implements ErrorDestination, FromItem, MultiPartName, Cloneable { - // private Database database; - // private String schemaName; - // private String name; private static final int NAME_IDX = 0; private static final int SCHEMA_IDX = 1; @@ -43,8 +44,14 @@ public class Table extends ASTNodeAccessImpl implements FromItem, MultiPartName private List partDelimiters = new ArrayList<>(); + // holds the various `time travel` syntax for BigQuery, RedShift, Snowflake or RedShift + private String timeTravelStr = null; + private Alias alias; + // thank you, Google! + private String timeTravelStrAfterAlias = null; + private SampleClause sampleClause; private Pivot pivot; @@ -55,46 +62,86 @@ public class Table extends ASTNodeAccessImpl implements FromItem, MultiPartName private SQLServerHints sqlServerHints; + // holds the physical table when resolved against an actual schema information + private Table resolvedTable = null; + public Table() {} + /** + * Instantiates a new Table. + * + * Sets the table name, splitting it into parts (catalog, schema, name) on `.` dots when quoted + * unless the system property `SPLIT_NAMES_ON_DELIMITER` points to `FALSE` + * + * @param name the table name, optionally quoted + */ public Table(String name) { setName(name); } + public Table(String name, boolean splitNamesOnDelimiter) { + setName(name, splitNamesOnDelimiter); + } + public Table(String schemaName, String name) { - setName(name); setSchemaName(schemaName); + setName(name); } public Table(Database database, String schemaName, String name) { + setDatabase(database); + setSchemaName(schemaName); setName(name); + } + + public Table(String catalogName, String schemaName, String tableName) { setSchemaName(schemaName); - setDatabase(database); + setDatabase(new Database(catalogName)); + setName(tableName); } public Table(List partItems) { - this.partItems = new ArrayList<>(partItems); - Collections.reverse(this.partItems); + if (partItems.size() == 1) { + setName(partItems.get(0)); + } else { + this.partItems = new ArrayList<>(partItems); + Collections.reverse(this.partItems); + } } public Table(List partItems, List partDelimiters) { - if (partDelimiters.size() != partItems.size() - 1) { - throw new IllegalArgumentException( - "the length of the delimiters list must be 1 less than nameParts"); + if (partItems.size() == 1) { + setName(partItems.get(0)); + } else { + if (partDelimiters.size() != partItems.size() - 1) { + throw new IllegalArgumentException( + "the length of the delimiters list must be 1 less than nameParts"); + } + this.partItems = new ArrayList<>(partItems); + this.partDelimiters = new ArrayList<>(partDelimiters); + Collections.reverse(this.partItems); + Collections.reverse(this.partDelimiters); } - this.partItems = new ArrayList<>(partItems); - this.partDelimiters = new ArrayList<>(partDelimiters); - Collections.reverse(this.partItems); - Collections.reverse(this.partDelimiters); + } + + public String getCatalogName() { + return getIndex(DATABASE_IDX); } public Database getDatabase() { return new Database(getIndex(DATABASE_IDX)); } - public Table withDatabase(Database database) { - setDatabase(database); - return this; + public String getDatabaseName() { + return getIndex(DATABASE_IDX); + } + + public String getUnquotedCatalogName() { + return MultiPartName.unquote(getDatabaseName()); + } + + public String getUnquotedDatabaseName() { + return MultiPartName.unquote(getDatabaseName()); } public void setDatabase(Database database) { @@ -104,17 +151,74 @@ public void setDatabase(Database database) { } } + public Table setDatabaseName(String databaseName) { + this.setDatabase(new Database(databaseName)); + return this; + } + + public Table withDatabase(Database database) { + setDatabase(database); + return this; + } + public String getSchemaName() { return getIndex(SCHEMA_IDX); } - public Table withSchemaName(String schemaName) { - setSchemaName(schemaName); + public String getUnquotedSchemaName() { + return MultiPartName.unquote(getSchemaName()); + } + + public Table setSchemaName(String schemaName) { + if (schemaName == null) { + setIndex(SCHEMA_IDX, null); + return this; + } + + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + // however, some people believe that Dots in Names are a good idea, so provide a switch-off + boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null || + !List + .of("0", "N", "n", "FALSE", "false", "OFF", "off") + .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + + if (MultiPartName.isQuoted(schemaName) && schemaName.contains(".") + && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(schemaName).split("\\."); + switch (parts.length) { + case 2: + setIndex(DATABASE_IDX, "\"" + parts[0] + "\""); + setIndex(SCHEMA_IDX, "\"" + parts[1] + "\""); + break; + case 1: + setIndex(SCHEMA_IDX, "\"" + parts[0] + "\""); + break; + default: + throw new RuntimeException("Invalid schema name: " + schemaName); + } + } else if (schemaName.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(schemaName).split("\\."); + switch (parts.length) { + case 2: + setIndex(DATABASE_IDX, parts[0]); + setIndex(SCHEMA_IDX, parts[1]); + break; + case 1: + setIndex(SCHEMA_IDX, parts[0]); + break; + default: + throw new RuntimeException("Invalid schema name: " + schemaName); + } + } else { + this.setIndex(SCHEMA_IDX, schemaName); + } return this; } - public void setSchemaName(String schemaName) { - setIndex(SCHEMA_IDX, schemaName); + public Table withSchemaName(String schemaName) { + setSchemaName(schemaName); + return this; } public String getName() { @@ -128,11 +232,46 @@ public String getName() { return name; } + + /** + * Sets the table name, splitting it into parts (catalog, schema, name) on `.` dots when quoted + * unless the system property `SPLIT_NAMES_ON_DELIMITER` points to `FALSE` + * + * @param name the table name, optionally quoted + */ + public void setName(String name) { + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + // however, some people believe that Dots in Names are a good idea, so provide a switch-off + boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null || + !List + .of("0", "N", "n", "FALSE", "false", "OFF", "off") + .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + + setName(name, splitNamesOnDelimiter); + } + + public void setName(String name, boolean splitNamesOnDelimiter) { + if (MultiPartName.isQuoted(name) && name.contains(".") && splitNamesOnDelimiter) { + partItems.clear(); + for (String unquotedIdentifier : MultiPartName.unquote(name).split("\\.")) { + partItems.add("\"" + unquotedIdentifier + "\""); + } + Collections.reverse(partItems); + } else if (name.contains(".") && splitNamesOnDelimiter) { + partItems.clear(); + partItems.addAll(Arrays.asList(MultiPartName.unquote(name).split("\\."))); + Collections.reverse(partItems); + } else { + setIndex(NAME_IDX, name); + } + } + public String getDBLinkName() { String name = getIndex(NAME_IDX); if (name != null && name.contains("@")) { int pos = name.lastIndexOf('@'); - if (pos > 0 && name.length() > 1) { + if (pos > 0) { name = name.substring(pos + 1); } } @@ -144,10 +283,6 @@ public Table withName(String name) { return this; } - public void setName(String name) { - setIndex(NAME_IDX, name); - } - @Override public Alias getAlias() { return alias; @@ -158,6 +293,19 @@ public void setAlias(Alias alias) { this.alias = alias; } + public String getTimeTravelStrAfterAlias() { + return timeTravelStrAfterAlias; + } + + public Table setTimeTravelStrAfterAlias(String timeTravelStrAfterAlias) { + this.timeTravelStrAfterAlias = timeTravelStrAfterAlias; + return this; + } + + public void setNameParts(List nameParts) { + this.partItems = nameParts; + } + private void setIndex(int idx, String value) { int size = partItems.size(); for (int i = 0; i < idx - size + 1; i++) { @@ -183,6 +331,13 @@ private String getIndex(int idx) { public String getFullyQualifiedName() { StringBuilder fqn = new StringBuilder(); + // remove any leading empty items + // only middle items can be suppressed (e.g. dbo..MY_TABLE ) + while (!partItems.isEmpty() && (partItems.get(partItems.size() - 1) == null + || partItems.get(partItems.size() - 1).isEmpty())) { + partItems.remove(partItems.size() - 1); + } + for (int i = partItems.size() - 1; i >= 0; i--) { String part = partItems.get(i); if (part == null) { @@ -198,12 +353,26 @@ public String getFullyQualifiedName() { } @Override - public void accept(FromItemVisitor fromItemVisitor) { - fromItemVisitor.visit(this); + public String getUnquotedName() { + return MultiPartName.unquote(getName()); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + public T accept(IntoTableVisitor intoTableVisitor, S context) { + return intoTableVisitor.visit(this, context); + } + + public String getTimeTravel() { + return timeTravelStr; } - public void accept(IntoTableVisitor intoTableVisitor) { - intoTableVisitor.visit(this); + public Table setTimeTravel(String timeTravelStr) { + this.timeTravelStr = timeTravelStr; + return this; } @Override @@ -258,10 +427,19 @@ public Table setSampleClause(SampleClause sampleClause) { public StringBuilder appendTo(StringBuilder builder) { builder.append(getFullyQualifiedName()); + + if (timeTravelStr != null) { + builder.append(" ").append(timeTravelStr); + } + if (alias != null) { builder.append(alias); } + if (timeTravelStrAfterAlias != null) { + builder.append(" ").append(timeTravelStrAfterAlias); + } + if (sampleClause != null) { sampleClause.appendTo(builder); } @@ -316,4 +494,74 @@ public List getNameParts() { public List getNamePartDelimiters() { return partDelimiters; } + + /** + * Gets the actual table when resolved against a physical schema information. + * + * @return the actual table when resolved against a physical schema information + */ + public Table getResolvedTable() { + return resolvedTable; + } + + /** + * Sets resolved table. + * + * @param resolvedTable the resolved table + * @return this table + */ + public Table setResolvedTable(Table resolvedTable) { + // clone, not reference + if (resolvedTable != null) { + this.resolvedTable = new Table(resolvedTable.getFullyQualifiedName()); + } + return this; + } + + /** + * Sets a table's catalog and schema only when not set. Useful for setting CURRENT_SCHEMA() and + * CURRENT_DATABASE() + * + * @param currentCatalogName the catalog name + * @param currentSchemaName the schema name + * @return the provided table + */ + public Table setUnsetCatalogAndSchema(String currentCatalogName, String currentSchemaName) { + String databaseName = getDatabaseName(); + if (databaseName == null || databaseName.isEmpty()) { + setDatabaseName(currentCatalogName); + } + + String schemaName = getSchemaName(); + if (schemaName == null || schemaName.isEmpty()) { + setSchemaName(currentSchemaName); + } + return this; + } + + /** + * Sets a tables' catalog and schema only when not set. Useful for setting CURRENT_SCHEMA() and + * CURRENT_DATABASE() + * + * @param currentCatalogName the current catalog name + * @param currentSchemaName the current schema name + * @param tables the tables + * @return the tables + */ + public static Table[] setUnsetCatalogAndSchema(String currentCatalogName, + String currentSchemaName, Table... tables) { + for (Table t : tables) { + if (t != null) { + t.setUnsetCatalogAndSchema(currentCatalogName, currentSchemaName); + } + } + return tables; + } + + @Override + public Table clone() { + Table clone = new Table(this.getFullyQualifiedName()); + clone.setResolvedTable(this.resolvedTable != null ? this.resolvedTable.clone() : null); + return clone; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/Block.java b/src/main/java/net/sf/jsqlparser/statement/Block.java index cbbbb3c87..83b9a2347 100644 --- a/src/main/java/net/sf/jsqlparser/statement/Block.java +++ b/src/main/java/net/sf/jsqlparser/statement/Block.java @@ -31,8 +31,8 @@ public void setSemicolonAfterEnd(boolean hasSemicolonAfterEnd) { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public StringBuilder appendTo(StringBuilder builder) { diff --git a/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java b/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java new file mode 100644 index 000000000..08c7f4d1d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java @@ -0,0 +1,91 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class CSVColumn { + private Long startIndex; + private Long endIndex; + private StringValue format; + private String delimit; + + public CSVColumn(Long startIndex, Long endIndex) { + this.startIndex = startIndex; + this.endIndex = endIndex; + } + + public CSVColumn(Long index) { + this(index, null); + } + + public Long getStartIndex() { + return startIndex; + } + + public void setStartIndex(Long startIndex) { + this.startIndex = startIndex; + } + + public Long getIndex() { + return getStartIndex(); + } + + public void setIndex(Long index) { + setStartIndex(index); + } + + public Long getEndIndex() { + return endIndex; + } + + public void setEndIndex(Long endIndex) { + this.endIndex = endIndex; + } + + public StringValue getFormat() { + return format; + } + + public void setFormat(StringValue format) { + this.format = format; + } + + public String getDelimit() { + return delimit; + } + + public void setDelimit(String delimit) { + this.delimit = delimit; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(startIndex); + if (endIndex != null) { + sql.append(" .. "); + sql.append(endIndex); + } else if (format != null || delimit != null) { + if (format != null) { + sql.append(" FORMAT = "); + sql.append(format); + } + + if (delimit != null) { + sql.append(" DELIMIT = "); + sql.append(delimit); + } + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java b/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java new file mode 100644 index 000000000..697368f83 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java @@ -0,0 +1,75 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class CSVFileDestination implements ErrorDestination { + private ConnectionDefinition connectionDefinition; + private boolean local; + private boolean secure; + private StringValue file; + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public boolean isLocal() { + return local; + } + + public void setLocal(boolean local) { + this.local = local; + } + + public boolean isSecure() { + return secure; + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public StringValue getFile() { + return file; + } + + public void setFile(StringValue file) { + this.file = file; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (local) { + sql.append("LOCAL "); + if (secure) { + sql.append("SECURE "); + } + } + + sql.append("CSV"); + + if (connectionDefinition != null) { + sql.append(" "); + sql.append(connectionDefinition); + } + + sql.append(" FILE "); + sql.append(file); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java b/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java new file mode 100644 index 000000000..7aabbb060 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java @@ -0,0 +1,67 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class CertificateVerification implements Serializable { + private Boolean ignoreCertificate; + private StringValue publicKey; + + public StringValue getPublicKey() { + return publicKey; + } + + public void setPublicKey(StringValue publicKey) { + this.publicKey = publicKey; + } + + public Boolean getIgnoreCertificate() { + return ignoreCertificate; + } + + public void setIgnoreCertificate(Boolean ignoreCertificate) { + this.ignoreCertificate = ignoreCertificate; + } + + public Boolean getVerifyCertificate() { + return !ignoreCertificate; + } + + public void setVerifyCertificate(Boolean verifyCertificate) { + this.ignoreCertificate = !verifyCertificate; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (ignoreCertificate != null) { + if (ignoreCertificate) { + sql.append("IGNORE "); + } else { + sql.append("VERIFY "); + } + sql.append("CERTIFICATE"); + } + + if (publicKey != null) { + if (ignoreCertificate != null) { + sql.append(" "); + } + sql.append("PUBLIC KEY "); + sql.append(publicKey); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java b/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java new file mode 100644 index 000000000..82b65fbd7 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java @@ -0,0 +1,37 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +public class CloudConnectionDefinition extends ConnectionDefinition { + private String storage; + + public String getStorage() { + return storage; + } + + public void setStorage(String storage) { + this.storage = storage; + } + + @Override + public void setCertificateVerification(CertificateVerification certificateVerification) {} + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("AT CLOUD "); + sql.append(storage); + sql.append(" "); + appendConnectionDefinition(sql); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/Commit.java b/src/main/java/net/sf/jsqlparser/statement/Commit.java index f33a36ae1..7ce465053 100644 --- a/src/main/java/net/sf/jsqlparser/statement/Commit.java +++ b/src/main/java/net/sf/jsqlparser/statement/Commit.java @@ -11,10 +11,10 @@ public class Commit implements Statement { @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } - + @Override public String toString() { return "COMMIT"; diff --git a/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java b/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java new file mode 100644 index 000000000..f2887cf82 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java @@ -0,0 +1,91 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class ConnectionDefinition implements Serializable { + private String connectionObjectName; + private StringValue connectionDefinition; + private UserIdentification userIdentification; + private CertificateVerification certificateVerification; + + public String getConnectionObjectName() { + return connectionObjectName; + } + + public void setConnectionObjectName(String connectionObjectName) { + this.connectionObjectName = connectionObjectName; + } + + public StringValue getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(StringValue connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public void setConnection(String connectionObjectName) { + this.connectionObjectName = connectionObjectName; + } + + public void setConnection(StringValue connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public UserIdentification getUserIdentification() { + return userIdentification; + } + + public void setUserIdentification(UserIdentification userIdentification) { + this.userIdentification = userIdentification; + } + + public CertificateVerification getCertificateVerification() { + return certificateVerification; + } + + public void setCertificateVerification(CertificateVerification certificateVerification) { + this.certificateVerification = certificateVerification; + } + + protected StringBuilder appendConnectionDefinition(StringBuilder sql) { + if (connectionObjectName != null) { + sql.append(connectionObjectName); + } else if (connectionDefinition != null) { + sql.append(connectionDefinition); + } + + if (userIdentification != null) { + sql.append(" "); + sql.append(userIdentification); + } + + if (certificateVerification != null) { + sql.append(" "); + sql.append(certificateVerification); + } + + return sql; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("AT "); + appendConnectionDefinition(sql); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java b/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java new file mode 100644 index 000000000..f0e0d0cf1 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java @@ -0,0 +1,60 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.util.List; + +public class ConnectionFileDefinition { + private ConnectionDefinition connectionDefinition; + private List filePaths; + + public ConnectionFileDefinition(List filePaths) { + this(null, filePaths); + } + + public ConnectionFileDefinition(ConnectionDefinition connectionDefinition, + List filePaths) { + this.connectionDefinition = connectionDefinition; + this.filePaths = filePaths; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public List getFilePaths() { + return filePaths; + } + + public void setFilePaths(List filePaths) { + this.filePaths = filePaths; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (connectionDefinition != null) { + sql.append(connectionDefinition); + } + + for (StringValue filePath : filePaths) { + sql.append(" FILE ").append(filePath); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CreateFunctionalStatement.java b/src/main/java/net/sf/jsqlparser/statement/CreateFunctionalStatement.java index 6a6e3c1d2..536a2b68f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/CreateFunctionalStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/CreateFunctionalStatement.java @@ -32,17 +32,14 @@ protected CreateFunctionalStatement(String kind) { protected CreateFunctionalStatement(String kind, List functionDeclarationParts) { this(false, kind, functionDeclarationParts); } - - protected CreateFunctionalStatement(boolean orReplace, String kind, List functionDeclarationParts) { + + protected CreateFunctionalStatement(boolean orReplace, String kind, + List functionDeclarationParts) { this.orReplace = orReplace; this.kind = kind; this.functionDeclarationParts = functionDeclarationParts; } - public void setFunctionDeclarationParts(List functionDeclarationParts) { - this.functionDeclarationParts = functionDeclarationParts; - } - /** * @return the declaration parts after {@code CREATE FUNCTION|PROCEDURE} */ @@ -50,20 +47,23 @@ public List getFunctionDeclarationParts() { return functionDeclarationParts; } + public void setFunctionDeclarationParts(List functionDeclarationParts) { + this.functionDeclarationParts = functionDeclarationParts; + } + /** * @return the kind of functional statement */ public String getKind() { return kind; } - + public void setOrReplace(boolean orReplace) { this.orReplace = orReplace; } /** - * @return a whitespace appended String with the declaration parts with some - * minimal formatting. + * @return a whitespace appended String with the declaration parts with some minimal formatting. */ public String formatDeclaration() { StringBuilder declaration = new StringBuilder(); @@ -85,30 +85,35 @@ public String formatDeclaration() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } @Override public String toString() { - return "CREATE " - + (orReplace?"OR REPLACE ":"") + return "CREATE " + + (orReplace ? "OR REPLACE " : "") + kind + " " + formatDeclaration(); } - public CreateFunctionalStatement withFunctionDeclarationParts(List functionDeclarationParts) { + public CreateFunctionalStatement withFunctionDeclarationParts( + List functionDeclarationParts) { this.setFunctionDeclarationParts(functionDeclarationParts); return this; } - public CreateFunctionalStatement addFunctionDeclarationParts(String... functionDeclarationParts) { - List collection = Optional.ofNullable(getFunctionDeclarationParts()).orElseGet(ArrayList::new); + public CreateFunctionalStatement addFunctionDeclarationParts( + String... functionDeclarationParts) { + List collection = + Optional.ofNullable(getFunctionDeclarationParts()).orElseGet(ArrayList::new); Collections.addAll(collection, functionDeclarationParts); return this.withFunctionDeclarationParts(collection); } - public CreateFunctionalStatement addFunctionDeclarationParts(Collection functionDeclarationParts) { - List collection = Optional.ofNullable(getFunctionDeclarationParts()).orElseGet(ArrayList::new); + public CreateFunctionalStatement addFunctionDeclarationParts( + Collection functionDeclarationParts) { + List collection = + Optional.ofNullable(getFunctionDeclarationParts()).orElseGet(ArrayList::new); collection.addAll(functionDeclarationParts); return this.withFunctionDeclarationParts(collection); } diff --git a/src/main/java/net/sf/jsqlparser/statement/DBMSType.java b/src/main/java/net/sf/jsqlparser/statement/DBMSType.java new file mode 100644 index 000000000..4b3d667da --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/DBMSType.java @@ -0,0 +1,52 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class DBMSType implements SourceDestinationType { + private final Kind dbmsType; + private StringValue jdbcDriverDefinition; + + public DBMSType(String dbmsType) { + this(dbmsType, null); + } + + public DBMSType(String dbmsType, String jdbcDriverDefinition) { + this.dbmsType = Kind.valueOf(dbmsType.toUpperCase()); + if (jdbcDriverDefinition != null) { + this.jdbcDriverDefinition = new StringValue(jdbcDriverDefinition); + } + } + + private enum Kind { + EXA, ORA, JDBC + } + + public StringValue getJDBCDriverDefinition() { + return jdbcDriverDefinition; + } + + public void setJDBCDriverDefinition(StringValue jdbcDriverDefinition) { + this.jdbcDriverDefinition = jdbcDriverDefinition; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(dbmsType); + if (jdbcDriverDefinition != null) { + sql.append(" DRIVER = ").append(jdbcDriverDefinition); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/DeclareStatement.java b/src/main/java/net/sf/jsqlparser/statement/DeclareStatement.java index 282220a1a..27537bc5f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/DeclareStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/DeclareStatement.java @@ -15,6 +15,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; + import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.UserVariable; import net.sf.jsqlparser.statement.create.table.ColDataType; @@ -28,17 +29,16 @@ public final class DeclareStatement implements Statement { private List typeDefExprList = new ArrayList<>(); private List columnDefinitions = new ArrayList<>(); - public DeclareStatement() { + public DeclareStatement() {} + + public UserVariable getUserVariable() { + return userVariable; } public void setUserVariable(UserVariable userVariable) { this.userVariable = userVariable; } - public UserVariable getUserVariable() { - return userVariable; - } - /** * @return the {@link DeclareType} * @deprecated use {@link #getDeclareType()} @@ -55,30 +55,38 @@ public DeclareType getDeclareType() { return declareType; } + public void setDeclareType(DeclareType declareType) { + this.declareType = declareType; + } + public String getTypeName() { return typeName; } - public void setDeclareType(DeclareType declareType) { - this.declareType = declareType; + public void setTypeName(String typeName) { + this.typeName = typeName; } public void addType(ColDataType colDataType, Expression defaultExpr) { addTypeDefExprList(new TypeDefExpr(colDataType, defaultExpr)); } - public void addType(UserVariable userVariable, ColDataType colDataType, Expression defaultExpr) { + public void addType(UserVariable userVariable, ColDataType colDataType, + Expression defaultExpr) { addTypeDefExprList(new TypeDefExpr(userVariable, colDataType, defaultExpr)); } public DeclareStatement addTypeDefExprList(TypeDefExpr... typeDefExpressions) { - List collection = Optional.ofNullable(getTypeDefExprList()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getTypeDefExprList()).orElseGet(ArrayList::new); Collections.addAll(collection, typeDefExpressions); return this.withTypeDefExprList(collection); } - public DeclareStatement addTypeDefExprList(Collection typeDefExpressions) { - List collection = Optional.ofNullable(getTypeDefExprList()).orElseGet(ArrayList::new); + public DeclareStatement addTypeDefExprList( + Collection typeDefExpressions) { + List collection = + Optional.ofNullable(getTypeDefExprList()).orElseGet(ArrayList::new); collection.addAll(typeDefExpressions); return this.withTypeDefExprList(collection); } @@ -88,33 +96,31 @@ public DeclareStatement withTypeDefExprList(List typeDefExpressions return this; } - public void setTypeDefExprList(List expr) { - this.typeDefExprList = expr; + public List getTypeDefExprList() { + return this.typeDefExprList; } - public List getTypeDefExprList() { - return this.typeDefExprList ; + public void setTypeDefExprList(List expr) { + this.typeDefExprList = expr; } public void addColumnDefinition(ColumnDefinition colDef) { columnDefinitions.add(colDef); } - public void setColumnDefinitions(List columnDefinitions) { - this.columnDefinitions = columnDefinitions; - } - public List getColumnDefinitions() { return columnDefinitions; } + public void setColumnDefinitions(List columnDefinitions) { + this.columnDefinitions = columnDefinitions; + } + public List getTypeDefinitions() { return typeDefExprList; } - public void setTypeName(String typeName) { - this.typeName = typeName; - } + @Override public String toString() { @@ -153,8 +159,8 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public DeclareStatement withUserVariable(UserVariable userVariable) { @@ -178,14 +184,17 @@ public DeclareStatement withColumnDefinitions(List columnDefin } public DeclareStatement addColumnDefinitions(ColumnDefinition... statements) { - List collection = Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); Collections.addAll(collection, statements); return this.withColumnDefinitions(collection); } - public DeclareStatement addColumnDefinitions(Collection columnDefinitions) { - List collection = Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); + public DeclareStatement addColumnDefinitions( + Collection columnDefinitions) { + List collection = + Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); collection.addAll(columnDefinitions); return this.withColumnDefinitions(collection); } @@ -200,10 +209,23 @@ public TypeDefExpr(ColDataType colDataType, Expression defaultExpr) { this(null, colDataType, defaultExpr); } - public TypeDefExpr(UserVariable userVariable, ColDataType colDataType, Expression defaultExpr) { + public TypeDefExpr(UserVariable userVariable, ColDataType colDataType, + Expression defaultExpr) { this.userVariable = userVariable; this.colDataType = colDataType; this.defaultExpr = defaultExpr; } + + public UserVariable getUserVariable() { + return userVariable; + } + + public ColDataType getColDataType() { + return colDataType; + } + + public Expression getDefaultExpr() { + return defaultExpr; + } } } diff --git a/src/main/java/net/sf/jsqlparser/statement/DeclareType.java b/src/main/java/net/sf/jsqlparser/statement/DeclareType.java index c63c686a4..5208a333a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/DeclareType.java +++ b/src/main/java/net/sf/jsqlparser/statement/DeclareType.java @@ -10,7 +10,6 @@ package net.sf.jsqlparser.statement; /** - * * @author tobens */ public enum DeclareType { diff --git a/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java b/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java index 8a2ab01d4..10a92764c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java @@ -38,8 +38,8 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public DescribeStatement withTable(Table table) { diff --git a/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java b/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java new file mode 100644 index 000000000..92db1a3dc --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java @@ -0,0 +1,90 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.Expression; + +import java.io.Serializable; + +public class ErrorClause implements Serializable { + private ErrorDestination errorDestination; + private Expression expression; + private RejectClause rejectClause; + private boolean replace; + private boolean truncate; + + public ErrorDestination getErrorDestination() { + return errorDestination; + } + + public void setErrorDestination(ErrorDestination errorDestination) { + this.errorDestination = errorDestination; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public RejectClause getRejectClause() { + return rejectClause; + } + + public void setRejectClause(RejectClause rejectClause) { + this.rejectClause = rejectClause; + } + + public boolean isReplace() { + return replace; + } + + public void setReplace(boolean replace) { + this.replace = replace; + } + + public boolean isTruncate() { + return truncate; + } + + public void setTruncate(boolean truncate) { + this.truncate = truncate; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (errorDestination != null) { + sql.append("ERRORS INTO "); + sql.append(errorDestination); + if (expression != null) { + sql.append(" ("); + sql.append(expression); + sql.append(")"); + } + + if (replace) { + sql.append(" REPLACE"); + } else if (truncate) { + sql.append(" TRUNCATE"); + } + } + + if (rejectClause != null) { + sql.append(" "); + sql.append(rejectClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java b/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java new file mode 100644 index 000000000..258a39ebb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java @@ -0,0 +1,13 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +public interface ErrorDestination { +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ExplainStatement.java b/src/main/java/net/sf/jsqlparser/statement/ExplainStatement.java index 01e7c2f18..544aedf67 100644 --- a/src/main/java/net/sf/jsqlparser/statement/ExplainStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/ExplainStatement.java @@ -11,21 +11,41 @@ import java.io.Serializable; import java.util.LinkedHashMap; +import java.util.List; import java.util.stream.Collectors; import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.select.Select; /** * An {@code EXPLAIN} statement */ public class ExplainStatement implements Statement { - - private Select select; + private String keyword; + private Statement statement; private LinkedHashMap options; private Table table; + public ExplainStatement(String keyword) { + this.keyword = keyword; + } + public ExplainStatement() { - // empty constructor + this("EXPLAIN"); + } + + public ExplainStatement(String keyword, Table table) { + this.keyword = keyword; + this.table = table; + } + + public ExplainStatement(String keyword, Statement statement, ListAndreas Reichel */ public class IfElseStatement implements Statement { - private final Expression condition; - private final Statement ifStatement; - private Statement elseStatement; - private boolean usingSemicolonForIfStatement = false; - private boolean usingSemicolonForElseStatement = false; - - public IfElseStatement(Expression condition, Statement ifStatement) { - this.condition = - Objects.requireNonNull(condition, "The CONDITION of the IfElseStatement must not be null."); - this.ifStatement = Objects.requireNonNull(ifStatement, - "The IF Statement of the IfElseStatement must not be null."); - } - - public Expression getCondition() { - return condition; - } - - public Statement getIfStatement() { - return ifStatement; - } - - public void setElseStatement(Statement elseStatement) { - this.elseStatement = elseStatement; - } - - public Statement getElseStatement() { - return elseStatement; - } - - public void setUsingSemicolonForElseStatement(boolean usingSemicolonForElseStatement) { - this.usingSemicolonForElseStatement = usingSemicolonForElseStatement; - } - - public boolean isUsingSemicolonForElseStatement() { - return usingSemicolonForElseStatement; - } - - public void setUsingSemicolonForIfStatement(boolean usingSemicolonForIfStatement) { - this.usingSemicolonForIfStatement = usingSemicolonForIfStatement; - } - - public boolean isUsingSemicolonForIfStatement() { - return usingSemicolonForIfStatement; - } - - public StringBuilder appendTo(StringBuilder builder) { - builder.append("IF ").append(condition).append(" ").append(ifStatement) - .append(usingSemicolonForIfStatement ? ";" : ""); - - if (elseStatement != null) { - builder.append(" ELSE ").append(elseStatement) - .append(usingSemicolonForElseStatement ? ";" : ""); + private final Expression condition; + private final Statement ifStatement; + private Statement elseStatement; + private boolean usingSemicolonForIfStatement = false; + private boolean usingSemicolonForElseStatement = false; + + public IfElseStatement(Expression condition, Statement ifStatement) { + this.condition = + Objects.requireNonNull(condition, + "The CONDITION of the IfElseStatement must not be null."); + this.ifStatement = Objects.requireNonNull(ifStatement, + "The IF Statement of the IfElseStatement must not be null."); + } + + public Expression getCondition() { + return condition; + } + + public Statement getIfStatement() { + return ifStatement; + } + + public Statement getElseStatement() { + return elseStatement; + } + + public void setElseStatement(Statement elseStatement) { + this.elseStatement = elseStatement; + } + + public boolean isUsingSemicolonForElseStatement() { + return usingSemicolonForElseStatement; + } + + public void setUsingSemicolonForElseStatement(boolean usingSemicolonForElseStatement) { + this.usingSemicolonForElseStatement = usingSemicolonForElseStatement; + } + + public boolean isUsingSemicolonForIfStatement() { + return usingSemicolonForIfStatement; + } + + public void setUsingSemicolonForIfStatement(boolean usingSemicolonForIfStatement) { + this.usingSemicolonForIfStatement = usingSemicolonForIfStatement; + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("IF ").append(condition).append(" ").append(ifStatement) + .append(usingSemicolonForIfStatement ? ";" : ""); + + if (elseStatement != null) { + builder.append(" ELSE ").append(elseStatement) + .append(usingSemicolonForElseStatement ? ";" : ""); + } + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } - return builder; - } - - @Override - public String toString() { - return appendTo(new StringBuilder()).toString(); - } - - @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); - } } diff --git a/src/main/java/net/sf/jsqlparser/statement/LikeClause.java b/src/main/java/net/sf/jsqlparser/statement/LikeClause.java new file mode 100644 index 000000000..448b4de72 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/LikeClause.java @@ -0,0 +1,142 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.ImportColumn; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.io.Serializable; +import java.util.List; + +/** + * Exasol Like Clause + * + * @see Like Clause in CREATE + * TABLE + * @see Like Clause in IMPORT + */ +public class LikeClause implements ImportColumn, Serializable { + private Table table; + private List> columnsList; + + private Boolean includingDefaults; + private Boolean includingIdentity; + private Boolean includingComments; + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public List> getColumnsList() { + return columnsList; + } + + public void setColumnsList(List> columnsList) { + this.columnsList = columnsList; + } + + public Boolean isIncludingDefaults() { + return includingDefaults; + } + + public void setIncludingDefaults(Boolean includingDefaults) { + this.includingDefaults = includingDefaults; + } + + public Boolean isExcludingDefaults() { + return includingDefaults == null ? null : !includingDefaults; + } + + public void setExcludingDefaults(Boolean excludingDefaults) { + this.includingDefaults = !excludingDefaults; + } + + public Boolean isIncludingIdentity() { + return includingIdentity; + } + + public void setIncludingIdentity(Boolean includingIdentity) { + this.includingIdentity = includingIdentity; + } + + public Boolean isExcludingIdentity() { + return includingIdentity == null ? null : !includingIdentity; + } + + public void setExcludingIdentity(Boolean excludingIdentity) { + this.includingIdentity = !excludingIdentity; + } + + public Boolean isIncludingComments() { + return includingComments; + } + + public void setIncludingComments(Boolean includingComments) { + this.includingComments = includingComments; + } + + public Boolean isExcludingComments() { + return includingComments == null ? null : !includingComments; + } + + public void setExcludingComments(Boolean excludingComments) { + this.includingComments = !excludingComments; + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append(" LIKE "); + builder.append(table); + if (columnsList != null) { + builder.append(" "); + PlainSelect.appendStringListTo(builder, columnsList, true, true); + } + + if (includingDefaults != null) { + if (includingDefaults) { + builder.append(" INCLUDING "); + } else { + builder.append(" EXCLUDING "); + } + builder.append(" DEFAULTS "); + } + + if (includingIdentity != null) { + if (includingIdentity) { + builder.append(" INCLUDING "); + } else { + builder.append(" EXCLUDING "); + } + builder.append(" IDENTITY "); + } + + if (includingComments != null) { + if (includingComments) { + builder.append(" INCLUDING "); + } else { + builder.append(" EXCLUDING "); + } + builder.append(" COMMENTS "); + } + + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ParenthesedStatement.java b/src/main/java/net/sf/jsqlparser/statement/ParenthesedStatement.java new file mode 100644 index 000000000..bd76f2282 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ParenthesedStatement.java @@ -0,0 +1,31 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.Alias; + +public interface ParenthesedStatement extends Statement { + + T accept(StatementVisitor statementVisitor, S context); + + default void accept(StatementVisitor statementVisitor) { + this.accept(statementVisitor, null); + } + + Alias getAlias(); + + void setAlias(Alias alias); + + default ParenthesedStatement withAlias(Alias alias) { + setAlias(alias); + return this; + } + +} diff --git a/src/main/java/net/sf/jsqlparser/statement/PurgeObjectType.java b/src/main/java/net/sf/jsqlparser/statement/PurgeObjectType.java index c9fecb849..4cb2755ba 100644 --- a/src/main/java/net/sf/jsqlparser/statement/PurgeObjectType.java +++ b/src/main/java/net/sf/jsqlparser/statement/PurgeObjectType.java @@ -10,7 +10,6 @@ package net.sf.jsqlparser.statement; /** - * * @author Andreas Reichel */ public enum PurgeObjectType { diff --git a/src/main/java/net/sf/jsqlparser/statement/PurgeStatement.java b/src/main/java/net/sf/jsqlparser/statement/PurgeStatement.java index bfcfff14d..2dca9fbab 100644 --- a/src/main/java/net/sf/jsqlparser/statement/PurgeStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/PurgeStatement.java @@ -11,13 +11,14 @@ package net.sf.jsqlparser.statement; import java.util.Objects; + import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.create.table.Index; /** - * * @author Andreas Reichel - * @see Purge + * @see Purge */ public class PurgeStatement implements Statement { @@ -27,34 +28,38 @@ public class PurgeStatement implements Statement { public PurgeStatement(Table table) { this.purgeObjectType = PurgeObjectType.TABLE; - this.object = Objects.requireNonNull(table, "The TABLE of the PURGE TABLE statement must not be null."); + this.object = Objects.requireNonNull(table, + "The TABLE of the PURGE TABLE statement must not be null."); } - + public PurgeStatement(Index index) { this.purgeObjectType = PurgeObjectType.INDEX; - this.object = Objects.requireNonNull(index, "The INDEX of the PURGE INDEX statement must not be null."); + this.object = Objects.requireNonNull(index, + "The INDEX of the PURGE INDEX statement must not be null."); } - + public PurgeStatement(PurgeObjectType purgeObjectType) { this.purgeObjectType = purgeObjectType; this.object = null; } - + public PurgeStatement(PurgeObjectType purgeObjectType, String tableSpaceName, String userName) { this.purgeObjectType = purgeObjectType; - this.object = Objects.requireNonNull(tableSpaceName, "The TABLESPACE NAME of the PURGE TABLESPACE statement must not be null."); + this.object = Objects.requireNonNull(tableSpaceName, + "The TABLESPACE NAME of the PURGE TABLESPACE statement must not be null."); this.userName = userName; } - - @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } - - @SuppressWarnings({"PMD.MissingBreakInSwitch", "PMD.SwitchStmtsShouldHaveDefault", "PMD.CyclomaticComplexity"}) + + @SuppressWarnings({"PMD.MissingBreakInSwitch", "PMD.SwitchStmtsShouldHaveDefault", + "PMD.CyclomaticComplexity"}) public StringBuilder appendTo(StringBuilder builder) { builder.append("PURGE "); - + switch (purgeObjectType) { case RECYCLEBIN: case DBA_RECYCLEBIN: @@ -63,16 +68,16 @@ public StringBuilder appendTo(StringBuilder builder) { case TABLE: case INDEX: builder.append(purgeObjectType); - if (object!=null) { + if (object != null) { builder.append(" ").append(object); } break; case TABLESPACE: builder.append(purgeObjectType); - if (object!=null) { + if (object != null) { builder.append(" ").append(object); } - if (userName!=null && userName.length()>0) { + if (userName != null && userName.length() > 0) { builder.append(" USER ").append(userName); } break; diff --git a/src/main/java/net/sf/jsqlparser/statement/ReferentialAction.java b/src/main/java/net/sf/jsqlparser/statement/ReferentialAction.java index 16dc9427d..5691aed25 100644 --- a/src/main/java/net/sf/jsqlparser/statement/ReferentialAction.java +++ b/src/main/java/net/sf/jsqlparser/statement/ReferentialAction.java @@ -62,9 +62,8 @@ public int hashCode() { @Override public String toString() { - return new StringBuilder(" ON ").append(getType().name()).append(" ") - .append(getAction().getAction()) - .toString(); + return " ON " + getType().name() + " " + + getAction().getAction(); } @Override diff --git a/src/main/java/net/sf/jsqlparser/statement/RejectClause.java b/src/main/java/net/sf/jsqlparser/statement/RejectClause.java new file mode 100644 index 000000000..5ca9f9714 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/RejectClause.java @@ -0,0 +1,53 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.LongValue; + +import java.io.Serializable; + +public class RejectClause implements Serializable { + private LongValue limit; + private boolean errors; + + public LongValue getLimit() { + return limit; + } + + public void setLimit(LongValue limit) { + this.limit = limit; + } + + public boolean isErrors() { + return errors; + } + + public void setErrors(boolean errors) { + this.errors = errors; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("REJECT LIMIT "); + if (limit != null) { + sql.append(limit); + } else { + sql.append("UNLIMITED"); + } + + if (errors) { + sql.append(" ERRORS"); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ResetStatement.java b/src/main/java/net/sf/jsqlparser/statement/ResetStatement.java index 956ffd027..dc769a9e8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/ResetStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/ResetStatement.java @@ -25,7 +25,7 @@ public ResetStatement(String name) { public void add(String name) { this.name = name; } - + public String getName() { return name; } @@ -41,8 +41,8 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/ReturningClause.java b/src/main/java/net/sf/jsqlparser/statement/ReturningClause.java index 3c7525b46..4c55daba8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/ReturningClause.java +++ b/src/main/java/net/sf/jsqlparser/statement/ReturningClause.java @@ -9,10 +9,18 @@ */ package net.sf.jsqlparser.statement; -import net.sf.jsqlparser.statement.select.SelectItem; - import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.MultiPartName; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.select.AllTableColumns; +import net.sf.jsqlparser.statement.select.SelectItem; /** * RETURNING clause according to > { - enum Keyword { - RETURN, RETURNING; - - public static Keyword from(String keyword) { - return Enum.valueOf(Keyword.class, keyword.toUpperCase()); - } - } - - private Keyword keyword; - /** * List of output targets like Table or UserVariable */ private final List dataItems; + private final List outputAliases; + private Keyword keyword; public ReturningClause(Keyword keyword, List> selectItems, List dataItems) { + this(keyword, selectItems, null, dataItems); + } + + public ReturningClause(Keyword keyword, List> selectItems, + List outputAliases, List dataItems) { this.keyword = keyword; this.addAll(selectItems); + this.outputAliases = outputAliases; this.dataItems = dataItems; + normalizeReturningReferences(); } public ReturningClause(String keyword, List> selectItems, @@ -48,12 +55,17 @@ public ReturningClause(String keyword, List> selectItems, this(Keyword.from(keyword), selectItems, dataItems); } + public ReturningClause(String keyword, List> selectItems, + List outputAliases, List dataItems) { + this(Keyword.from(keyword), selectItems, outputAliases, dataItems); + } + public ReturningClause(Keyword keyword, List> selectItems) { - this(keyword, selectItems, null); + this(keyword, selectItems, null, null); } public ReturningClause(String keyword, List> selectItems) { - this(Keyword.valueOf(keyword), selectItems, null); + this(Keyword.from(keyword), selectItems, null, null); } public Keyword getKeyword() { @@ -69,8 +81,22 @@ public List getDataItems() { return dataItems; } + public List getOutputAliases() { + return outputAliases; + } + public StringBuilder appendTo(StringBuilder builder) { builder.append(" ").append(keyword).append(" "); + if (outputAliases != null && !outputAliases.isEmpty()) { + builder.append("WITH ("); + for (int i = 0; i < outputAliases.size(); i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(outputAliases.get(i)); + } + builder.append(") "); + } for (int i = 0; i < size(); i++) { if (i > 0) { builder.append(", "); @@ -78,7 +104,7 @@ public StringBuilder appendTo(StringBuilder builder) { builder.append(get(i)); } - if (dataItems != null && dataItems.size() > 0) { + if (dataItems != null && !dataItems.isEmpty()) { builder.append(" INTO "); for (int i = 0; i < dataItems.size(); i++) { if (i > 0) { @@ -94,4 +120,132 @@ public StringBuilder appendTo(StringBuilder builder) { public String toString() { return appendTo(new StringBuilder()).toString(); } + + private void normalizeReturningReferences() { + Map qualifierMap = buildQualifierMap(); + if (qualifierMap.isEmpty()) { + return; + } + + ReturningReferenceNormalizer normalizer = new ReturningReferenceNormalizer(qualifierMap); + forEach(selectItem -> { + if (selectItem != null && selectItem.getExpression() != null) { + selectItem.getExpression().accept(normalizer, null); + } + }); + } + + private Map buildQualifierMap() { + LinkedHashMap qualifierMap = new LinkedHashMap<>(); + + if (outputAliases == null || outputAliases.isEmpty()) { + qualifierMap.put(QualifierKey.from("OLD"), ReturningReferenceType.OLD); + qualifierMap.put(QualifierKey.from("NEW"), ReturningReferenceType.NEW); + return qualifierMap; + } + + for (ReturningOutputAlias outputAlias : outputAliases) { + if (outputAlias == null || outputAlias.getAlias() == null + || outputAlias.getReferenceType() == null) { + continue; + } + qualifierMap.put(QualifierKey.from(outputAlias.getAlias()), + outputAlias.getReferenceType()); + } + return qualifierMap; + } + + private static class ReturningReferenceNormalizer extends ExpressionVisitorAdapter { + private final Map qualifierMap; + + ReturningReferenceNormalizer(Map qualifierMap) { + this.qualifierMap = qualifierMap; + } + + @Override + public Void visit(Column column, S context) { + Table table = column.getTable(); + String qualifier = extractSimpleQualifier(table); + if (qualifier == null) { + return null; + } + ReturningReferenceType referenceType = qualifierMap.get(QualifierKey.from(qualifier)); + if (referenceType != null) { + column.withReturningReference(referenceType, qualifier); + column.setTable(null); + } + return null; + } + + @Override + public Void visit(AllTableColumns allTableColumns, S context) { + Table table = allTableColumns.getTable(); + String qualifier = extractSimpleQualifier(table); + if (qualifier == null) { + return null; + } + ReturningReferenceType referenceType = qualifierMap.get(QualifierKey.from(qualifier)); + if (referenceType != null) { + allTableColumns.withReturningReference(referenceType, qualifier); + allTableColumns.setTable(null); + } + return null; + } + + private String extractSimpleQualifier(Table table) { + if (table == null || table.getSchemaName() != null || table.getDatabaseName() != null) { + return null; + } + String qualifier = table.getName(); + if (qualifier == null || qualifier.contains("@")) { + return null; + } + return qualifier; + } + } + + private static class QualifierKey { + private final boolean quoted; + private final String normalizedIdentifier; + + private QualifierKey(boolean quoted, String normalizedIdentifier) { + this.quoted = quoted; + this.normalizedIdentifier = normalizedIdentifier; + } + + static QualifierKey from(String identifier) { + boolean quoted = MultiPartName.isQuoted(identifier); + String unquoted = MultiPartName.unquote(identifier); + if (!quoted && unquoted != null) { + unquoted = unquoted.toUpperCase(Locale.ROOT); + } + return new QualifierKey(quoted, unquoted); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof QualifierKey)) { + return false; + } + QualifierKey that = (QualifierKey) o; + return quoted == that.quoted + && Objects.equals(normalizedIdentifier, that.normalizedIdentifier); + } + + @Override + public int hashCode() { + return Objects.hash(quoted, normalizedIdentifier); + } + } + + public enum Keyword { + RETURN, RETURNING; + + public static Keyword from(String keyword) { + return Enum.valueOf(Keyword.class, keyword.toUpperCase()); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/ReturningOutputAlias.java b/src/main/java/net/sf/jsqlparser/statement/ReturningOutputAlias.java new file mode 100644 index 000000000..d0c42de34 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ReturningOutputAlias.java @@ -0,0 +1,66 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import java.util.Objects; + +public class ReturningOutputAlias { + private ReturningReferenceType referenceType; + private String alias; + + public ReturningOutputAlias(ReturningReferenceType referenceType, String alias) { + this.referenceType = referenceType; + this.alias = alias; + } + + public ReturningReferenceType getReferenceType() { + return referenceType; + } + + public ReturningOutputAlias setReferenceType(ReturningReferenceType referenceType) { + this.referenceType = referenceType; + return this; + } + + public String getAlias() { + return alias; + } + + public ReturningOutputAlias setAlias(String alias) { + this.alias = alias; + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + return builder.append(referenceType).append(" AS ").append(alias); + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ReturningOutputAlias)) { + return false; + } + ReturningOutputAlias that = (ReturningOutputAlias) o; + return referenceType == that.referenceType && Objects.equals(alias, that.alias); + } + + @Override + public int hashCode() { + return Objects.hash(referenceType, alias); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ReturningReferenceType.java b/src/main/java/net/sf/jsqlparser/statement/ReturningReferenceType.java new file mode 100644 index 000000000..06079904a --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ReturningReferenceType.java @@ -0,0 +1,30 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.schema.MultiPartName; + +public enum ReturningReferenceType { + OLD, NEW; + + public static ReturningReferenceType from(String name) { + String unquoted = MultiPartName.unquote(name); + if (unquoted == null) { + return null; + } + if ("OLD".equalsIgnoreCase(unquoted)) { + return OLD; + } + if ("NEW".equalsIgnoreCase(unquoted)) { + return NEW; + } + return null; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/RollbackStatement.java b/src/main/java/net/sf/jsqlparser/statement/RollbackStatement.java index ef566bc03..0c6f66769 100644 --- a/src/main/java/net/sf/jsqlparser/statement/RollbackStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/RollbackStatement.java @@ -26,87 +26,89 @@ package net.sf.jsqlparser.statement; /** - * * @author are */ public class RollbackStatement implements Statement { - private boolean usingWorkKeyword=false; - private boolean usingSavepointKeyword=false; - private String savepointName=null; - private String forceDistributedTransactionIdentifier=null; + private boolean usingWorkKeyword = false; + private boolean usingSavepointKeyword = false; + private String savepointName = null; + private String forceDistributedTransactionIdentifier = null; public boolean isUsingWorkKeyword() { return usingWorkKeyword; } - public RollbackStatement withUsingWorkKeyword(boolean usingWorkKeyword) { + public void setUsingWorkKeyword(boolean usingWorkKeyword) { this.usingWorkKeyword = usingWorkKeyword; - return this; } - - public void setUsingWorkKeyword(boolean usingWorkKeyword) { + + public RollbackStatement withUsingWorkKeyword(boolean usingWorkKeyword) { this.usingWorkKeyword = usingWorkKeyword; + return this; } public boolean isUsingSavepointKeyword() { return usingSavepointKeyword; } - - public RollbackStatement withUsingSavepointKeyword(boolean usingSavepointKeyword) { + + public void setUsingSavepointKeyword(boolean usingSavepointKeyword) { this.usingSavepointKeyword = usingSavepointKeyword; - return this; } - public void setUsingSavepointKeyword(boolean usingSavepointKeyword) { + public RollbackStatement withUsingSavepointKeyword(boolean usingSavepointKeyword) { this.usingSavepointKeyword = usingSavepointKeyword; + return this; } public String getSavepointName() { return savepointName; } - - public RollbackStatement withSavepointName(String savepointName) { + + public void setSavepointName(String savepointName) { this.savepointName = savepointName; - return this; } - public void setSavepointName(String savepointName) { + public RollbackStatement withSavepointName(String savepointName) { this.savepointName = savepointName; + return this; } public String getForceDistributedTransactionIdentifier() { return forceDistributedTransactionIdentifier; } - - public RollbackStatement withForceDistributedTransactionIdentifier(String forceDistributedTransactionIdentifier) { + + public void setForceDistributedTransactionIdentifier( + String forceDistributedTransactionIdentifier) { this.forceDistributedTransactionIdentifier = forceDistributedTransactionIdentifier; - return this; } - public void setForceDistributedTransactionIdentifier(String forceDistributedTransactionIdentifier) { + public RollbackStatement withForceDistributedTransactionIdentifier( + String forceDistributedTransactionIdentifier) { this.forceDistributedTransactionIdentifier = forceDistributedTransactionIdentifier; + return this; } @Override public String toString() { - return "ROLLBACK " - + ( usingWorkKeyword - ? "WORK " - : "" ) - + (savepointName!=null && savepointName.trim().length()!=0 - ? "TO " + (usingSavepointKeyword - ? "SAVEPOINT " - : "") + savepointName - : forceDistributedTransactionIdentifier!=null && forceDistributedTransactionIdentifier.trim().length()!=0 - ? "FORCE " + forceDistributedTransactionIdentifier - : "" - + return "ROLLBACK " + + (usingWorkKeyword + ? "WORK " + : "") + + (savepointName != null && !savepointName.trim().isEmpty() + ? "TO " + (usingSavepointKeyword + ? "SAVEPOINT " + : "") + savepointName + : forceDistributedTransactionIdentifier != null + && !forceDistributedTransactionIdentifier.trim().isEmpty() + ? "FORCE " + forceDistributedTransactionIdentifier + : "" + ); } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/SavepointStatement.java b/src/main/java/net/sf/jsqlparser/statement/SavepointStatement.java index fd08d2999..390c7f438 100644 --- a/src/main/java/net/sf/jsqlparser/statement/SavepointStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/SavepointStatement.java @@ -13,22 +13,23 @@ import java.util.Objects; /** - * * @author Andreas Reichel */ public class SavepointStatement implements Statement { private String savepointName; + public SavepointStatement(String savepointName) { + this.savepointName = + Objects.requireNonNull(savepointName, "The Savepoint Name must not be NULL."); + } + public String getSavepointName() { return savepointName; } public void setSavepointName(String savepointName) { - this.savepointName = Objects.requireNonNull(savepointName, "The Savepoint Name must not be NULL."); - } - - public SavepointStatement(String savepointName) { - this.savepointName = Objects.requireNonNull(savepointName, "The Savepoint Name must not be NULL."); + this.savepointName = + Objects.requireNonNull(savepointName, "The Savepoint Name must not be NULL."); } @Override @@ -37,7 +38,7 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/ScriptSourceDestination.java b/src/main/java/net/sf/jsqlparser/statement/ScriptSourceDestination.java new file mode 100644 index 000000000..c1193b037 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ScriptSourceDestination.java @@ -0,0 +1,99 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.export.ExportIntoItem; +import net.sf.jsqlparser.statement.imprt.ImportFromItem; + +import java.io.Serializable; +import java.util.List; + +public class ScriptSourceDestination implements ImportFromItem, ExportIntoItem, Serializable { + private Table script; + private ConnectionDefinition connectionDefinition; + private List properties; + private List values; + private ErrorClause errorClause; + + public Table getScript() { + return script; + } + + public void setScript(Table script) { + this.script = script; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public List getProperties() { + return properties; + } + + public void setProperties(List properties) { + this.properties = properties; + } + + public List getValues() { + return values; + } + + public void setValues(List values) { + this.values = values; + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("SCRIPT "); + sql.append(script); + + if (connectionDefinition != null) { + sql.append(" "); + sql.append(connectionDefinition); + } + + if (properties != null && values != null) { + sql.append(" WITH"); + + int max = Math.min(properties.size(), values.size()); + for (int i = 0; i < max; i++) { + sql.append(" "); + sql.append(properties.get(i)); + sql.append(" = "); + sql.append(values.get(i)); + } + } + + if (errorClause != null) { + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java new file mode 100644 index 000000000..161054397 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/SessionStatement.java @@ -0,0 +1,131 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +public class SessionStatement implements Statement { + public enum Action { + START, APPLY, DROP, SHOW, DESCRIBE; + + public static Action from(String flag) { + return Enum.valueOf(Action.class, flag.toUpperCase()); + } + } + + final private Action action; + final private String id; + final private LinkedHashMap options = new LinkedHashMap<>(); + + public SessionStatement(Action action, String id) { + this.action = action; + this.id = id; + } + + public SessionStatement(String action, String id) { + this(Action.from(action), id); + } + + public SessionStatement(String action) { + this(action, null); + } + + + public Action getAction() { + return action; + } + + public String getId() { + return id; + } + + public int size() { + return options.size(); + } + + public String putOption(String key, String value) { + return options.put(key.replaceAll("[\"']", "").toLowerCase(), value.toLowerCase()); + } + + public boolean hasOptions() { + return !options.isEmpty(); + } + + public void clearOptions() { + options.clear(); + } + + public boolean removeOption(String key, String value) { + return options.remove(key, value); + } + + public boolean containsOption(String value) { + return options.containsValue(value); + } + + public String removeOption(String key) { + return options.remove(key); + } + + public String getOption(String key) { + return options.get(key); + } + + public Set getOptionKeySet() { + return options.keySet(); + } + + public Map getOptions() { + return options; + } + + public Set> getOptionEntrySet() { + return options.entrySet(); + } + + public boolean hasOption(String key) { + return options.containsKey(key); + } + + public String getOptionOrDefault(String key, String defaultValue) { + return options.getOrDefault(key, defaultValue); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public void accept(StatementVisitor statementVisitor) { + Statement.super.accept(statementVisitor); + } + + @Override + public String toString() { + StringBuilder builder = + new StringBuilder("SESSION " + action + " " + (id != null ? id : "")); + if (!options.isEmpty()) { + builder.append(" WITH "); + int i = 0; + for (Map.Entry e : options.entrySet()) { + if (i++ > 0) { + builder.append(", "); + } + builder.append(e.getKey()).append("=").append(e.getValue()); + } + } + builder.append(";"); + + return builder.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/SetStatement.java b/src/main/java/net/sf/jsqlparser/statement/SetStatement.java index f276f4956..16878f773 100644 --- a/src/main/java/net/sf/jsqlparser/statement/SetStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/SetStatement.java @@ -21,8 +21,8 @@ public final class SetStatement implements Statement { - private String effectParameter; private final List values = new ArrayList<>(); + private String effectParameter; public SetStatement() { // empty constructor @@ -52,6 +52,10 @@ public boolean isUseEqual() { return isUseEqual(0); } + public SetStatement setUseEqual(boolean useEqual) { + return setUseEqual(0, useEqual); + } + public SetStatement withUseEqual(int idx, boolean useEqual) { this.setUseEqual(idx, useEqual); return this; @@ -67,23 +71,18 @@ public SetStatement withUseEqual(boolean useEqual) { return this; } - public SetStatement setUseEqual(boolean useEqual) { - return setUseEqual(0, useEqual); - } - - public Object getName() { return getName(0); } - public Object getName(int idx) { - return values.get(idx).name; - } - public void setName(String name) { setName(0, name); } + public Object getName(int idx) { + return values.get(idx).name; + } + public void setName(int idx, String name) { values.get(idx).name = name; } @@ -96,14 +95,14 @@ public List getExpressions() { return getExpressions(0); } - public void setExpressions(int idx, ExpressionList expressions) { - values.get(idx).expressions = expressions; - } - public void setExpressions(ExpressionList expressions) { setExpressions(0, expressions); } + public void setExpressions(int idx, ExpressionList expressions) { + values.get(idx).expressions = expressions; + } + private String toString(NameExpr ne) { return ne.name + (ne.useEqual ? " = " : " ") + PlainSelect.getStringList(ne.expressions, true, false); @@ -146,8 +145,21 @@ public void clear() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + public String getEffectParameter() { + return effectParameter; + } + + public void setEffectParameter(String effectParameter) { + this.effectParameter = effectParameter; + } + + public SetStatement withEffectParameter(String effectParameter) { + this.effectParameter = effectParameter; + return this; } static class NameExpr implements Serializable { @@ -155,6 +167,12 @@ static class NameExpr implements Serializable { ExpressionList expressions; boolean useEqual; + public NameExpr(Object name, ExpressionList expressions, boolean useEqual) { + this.name = name; + this.expressions = expressions; + this.useEqual = useEqual; + } + public Object getName() { return name; } @@ -178,24 +196,5 @@ public boolean isUseEqual() { public void setUseEqual(boolean useEqual) { this.useEqual = useEqual; } - - public NameExpr(Object name, ExpressionList expressions, boolean useEqual) { - this.name = name; - this.expressions = expressions; - this.useEqual = useEqual; - } - } - - public String getEffectParameter() { - return effectParameter; - } - - public void setEffectParameter(String effectParameter) { - this.effectParameter = effectParameter; - } - - public SetStatement withEffectParameter(String effectParameter) { - this.effectParameter = effectParameter; - return this; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/ShowColumnsStatement.java b/src/main/java/net/sf/jsqlparser/statement/ShowColumnsStatement.java index 8915d81fd..51f1ed26d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/ShowColumnsStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/ShowColumnsStatement.java @@ -35,8 +35,8 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public ShowColumnsStatement withTableName(String tableName) { diff --git a/src/main/java/net/sf/jsqlparser/statement/ShowStatement.java b/src/main/java/net/sf/jsqlparser/statement/ShowStatement.java index f6bc84518..c5f1729cc 100644 --- a/src/main/java/net/sf/jsqlparser/statement/ShowStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/ShowStatement.java @@ -35,8 +35,8 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public ShowStatement withName(String name) { diff --git a/src/main/java/net/sf/jsqlparser/statement/SourceDestinationType.java b/src/main/java/net/sf/jsqlparser/statement/SourceDestinationType.java new file mode 100644 index 000000000..743d21378 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/SourceDestinationType.java @@ -0,0 +1,13 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +public interface SourceDestinationType { +} diff --git a/src/main/java/net/sf/jsqlparser/statement/Statement.java b/src/main/java/net/sf/jsqlparser/statement/Statement.java index fee483c09..380092ab6 100644 --- a/src/main/java/net/sf/jsqlparser/statement/Statement.java +++ b/src/main/java/net/sf/jsqlparser/statement/Statement.java @@ -12,5 +12,9 @@ import net.sf.jsqlparser.Model; public interface Statement extends Model { - void accept(StatementVisitor statementVisitor); + T accept(StatementVisitor statementVisitor, S context); + + default void accept(StatementVisitor statementVisitor) { + accept(statementVisitor, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index 46d4e0d96..9ebab53a8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java @@ -17,6 +17,7 @@ import net.sf.jsqlparser.statement.analyze.Analyze; import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; @@ -24,106 +25,337 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; -public interface StatementVisitor { +public interface StatementVisitor { - void visit(Analyze analyze); + T visit(Analyze analyze, S context); - void visit(SavepointStatement savepointStatement); + default void visit(Analyze analyze) { + this.visit(analyze, null); + } - void visit(RollbackStatement rollbackStatement); + T visit(SavepointStatement savepointStatement, S context); - void visit(Comment comment); + default void visit(SavepointStatement savepointStatement) { + this.visit(savepointStatement, null); + } - void visit(Commit commit); + T visit(RollbackStatement rollbackStatement, S context); - void visit(Delete delete); + default void visit(RollbackStatement rollbackStatement) { + this.visit(rollbackStatement, null); + } - void visit(Update update); + T visit(Comment comment, S context); - void visit(Insert insert); + default void visit(Comment comment) { + this.visit(comment, null); + } - void visit(Drop drop); + T visit(Commit commit, S context); - void visit(Truncate truncate); + default void visit(Commit commit) { + this.visit(commit, null); + } - void visit(CreateIndex createIndex); + T visit(Delete delete, S context); - void visit(CreateSchema aThis); + default void visit(Delete delete) { + this.visit(delete, null); + } - void visit(CreateTable createTable); + T visit(Update update, S context); - void visit(CreateView createView); + default void visit(Update update) { + this.visit(update, null); + } - void visit(AlterView alterView); + T visit(Insert insert, S context); - void visit(RefreshMaterializedViewStatement materializedView); + default void visit(Insert insert) { + this.visit(insert, null); + } - void visit(Alter alter); + T visit(Drop drop, S context); - void visit(Statements stmts); + default void visit(Drop drop) { + this.visit(drop, null); + } - void visit(Execute execute); + T visit(Truncate truncate, S context); - void visit(SetStatement set); + default void visit(Truncate truncate) { + this.visit(truncate, null); + } - void visit(ResetStatement reset); + T visit(CreateIndex createIndex, S context); - void visit(ShowColumnsStatement set); + default void visit(CreateIndex createIndex) { + this.visit(createIndex, null); + } - void visit(ShowIndexStatement showIndex); + T visit(CreateSchema createSchema, S context); - void visit(ShowTablesStatement showTables); + default void visit(CreateSchema createSchema) { + this.visit(createSchema, null); + } - void visit(Merge merge); + T visit(CreateTable createTable, S context); - void visit(Select select); + default void visit(CreateTable createTable) { + this.visit(createTable, null); + } - void visit(Upsert upsert); + T visit(CreateView createView, S context); - void visit(UseStatement use); + default void visit(CreateView createView) { + this.visit(createView, null); + } - void visit(Block block); + T visit(AlterView alterView, S context); - void visit(DescribeStatement describe); + default void visit(AlterView alterView) { + this.visit(alterView, null); + } - void visit(ExplainStatement aThis); + T visit(RefreshMaterializedViewStatement materializedView, S context); - void visit(ShowStatement aThis); + default void visit(RefreshMaterializedViewStatement materializedView) { + this.visit(materializedView, null); + } - void visit(DeclareStatement aThis); + T visit(Alter alter, S context); - void visit(Grant grant); + default void visit(Alter alter) { + this.visit(alter, null); + } - void visit(CreateSequence createSequence); + T visit(Statements statements, S context); - void visit(AlterSequence alterSequence); + default void visit(Statements statements) { + this.visit(statements, null); + } - void visit(CreateFunctionalStatement createFunctionalStatement); + T visit(Execute execute, S context); - void visit(CreateSynonym createSynonym); + default void visit(Execute execute) { + this.visit(execute, null); + } - void visit(AlterSession alterSession); + T visit(SetStatement set, S context); - void visit(IfElseStatement aThis); + default void visit(SetStatement set) { + this.visit(set, null); + } - void visit(RenameTableStatement renameTableStatement); + T visit(ResetStatement reset, S context); - void visit(PurgeStatement purgeStatement); + default void visit(ResetStatement reset) { + this.visit(reset, null); + } - void visit(AlterSystemStatement alterSystemStatement); + T visit(ShowColumnsStatement showColumns, S context); + + default void visit(ShowColumnsStatement showColumns) { + this.visit(showColumns, null); + } + + T visit(ShowIndexStatement showIndex, S context); + + default void visit(ShowIndexStatement showIndex) { + this.visit(showIndex, null); + } + + T visit(ShowTablesStatement showTables, S context); + + default void visit(ShowTablesStatement showTables) { + this.visit(showTables, null); + } + + T visit(Merge merge, S context); + + default void visit(Merge merge) { + this.visit(merge, null); + } + + T visit(Select select, S context); + + default void visit(Select select) { + this.visit(select, null); + } + + T visit(Upsert upsert, S context); + + default void visit(Upsert upsert) { + this.visit(upsert, null); + } + + T visit(UseStatement use, S context); + + default void visit(UseStatement use) { + this.visit(use, null); + } + + T visit(Block block, S context); + + default void visit(Block block) { + this.visit(block, null); + } + + T visit(DescribeStatement describe, S context); + + default void visit(DescribeStatement describe) { + this.visit(describe, null); + } + + T visit(ExplainStatement explainStatement, S context); + + default void visit(ExplainStatement explainStatement) { + this.visit(explainStatement, null); + } + + T visit(ShowStatement showStatement, S context); + + default void visit(ShowStatement showStatement) { + this.visit(showStatement, null); + } + + T visit(DeclareStatement declareStatement, S context); + + default void visit(DeclareStatement declareStatement) { + this.visit(declareStatement, null); + } + + T visit(Grant grant, S context); + + default void visit(Grant grant) { + this.visit(grant, null); + } + + T visit(CreateSequence createSequence, S context); + + default void visit(CreateSequence createSequence) { + this.visit(createSequence, null); + } + + T visit(AlterSequence alterSequence, S context); + + default void visit(AlterSequence alterSequence) { + this.visit(alterSequence, null); + } + + T visit(CreateFunctionalStatement createFunctionalStatement, S context); + + default void visit(CreateFunctionalStatement createFunctionalStatement) { + this.visit(createFunctionalStatement, null); + } + + T visit(CreateSynonym createSynonym, S context); + + default void visit(CreateSynonym createSynonym) { + this.visit(createSynonym, null); + } + + T visit(AlterSession alterSession, S context); + + default void visit(AlterSession alterSession) { + this.visit(alterSession, null); + } + + T visit(IfElseStatement ifElseStatement, S context); + + default void visit(IfElseStatement ifElseStatement) { + this.visit(ifElseStatement, null); + } + + T visit(RenameTableStatement renameTableStatement, S context); + + default void visit(RenameTableStatement renameTableStatement) { + this.visit(renameTableStatement, null); + } + + T visit(PurgeStatement purgeStatement, S context); + + default void visit(PurgeStatement purgeStatement) { + this.visit(purgeStatement, null); + } + + T visit(AlterSystemStatement alterSystemStatement, S context); + + default void visit(AlterSystemStatement alterSystemStatement) { + this.visit(alterSystemStatement, null); + } + + T visit(UnsupportedStatement unsupportedStatement, S context); + + default void visit(UnsupportedStatement unsupportedStatement) { + this.visit(unsupportedStatement, null); + } + + T visit(ParenthesedInsert parenthesedInsert, S context); + + default void visit(ParenthesedInsert parenthesedInsert) { + this.visit(parenthesedInsert, null); + } + + T visit(ParenthesedUpdate parenthesedUpdate, S context); + + default void visit(ParenthesedUpdate parenthesedUpdate) { + this.visit(parenthesedUpdate, null); + } + + T visit(ParenthesedDelete parenthesedDelete, S context); + + default void visit(ParenthesedDelete parenthesedDelete) { + this.visit(parenthesedDelete, null); + } + + T visit(SessionStatement sessionStatement, S context); + + default void visit(SessionStatement sessionStatement) { + this.visit(sessionStatement, null); + } + + T visit(Import imprt, S context); + + default void visit(Import imprt) { + this.visit(imprt, null); + } + + T visit(Export export, S context); + + default void visit(Export export) { + this.visit(export, null); + } + + T visit(LockStatement lock, S context); + + default void visit(LockStatement lock) { + this.visit(lock, null); + } + + T visit(CreatePolicy createPolicy, S context); + + default void visit(CreatePolicy createPolicy) { + this.visit(createPolicy, null); + } - void visit(UnsupportedStatement unsupportedStatement); } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index 72d2a540a..3b12c01c0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -9,6 +9,10 @@ */ package net.sf.jsqlparser.statement; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Partition; import net.sf.jsqlparser.statement.alter.Alter; import net.sf.jsqlparser.statement.alter.AlterSession; import net.sf.jsqlparser.statement.alter.AlterSystemStatement; @@ -17,6 +21,7 @@ import net.sf.jsqlparser.statement.analyze.Analyze; import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; @@ -24,208 +29,449 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.InsertConflictAction; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; import net.sf.jsqlparser.statement.merge.Merge; +import net.sf.jsqlparser.statement.merge.MergeOperationVisitor; +import net.sf.jsqlparser.statement.merge.MergeOperationVisitorAdapter; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; +import net.sf.jsqlparser.statement.select.FromItemVisitor; +import net.sf.jsqlparser.statement.select.FromItemVisitorAdapter; +import net.sf.jsqlparser.statement.select.PivotVisitor; +import net.sf.jsqlparser.statement.select.PivotVisitorAdapter; import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectItemVisitor; +import net.sf.jsqlparser.statement.select.SelectItemVisitorAdapter; +import net.sf.jsqlparser.statement.select.SelectVisitor; +import net.sf.jsqlparser.statement.select.SelectVisitorAdapter; +import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; +import java.util.List; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class StatementVisitorAdapter implements StatementVisitor { +public class StatementVisitorAdapter implements StatementVisitor { + private final ExpressionVisitor expressionVisitor; + private final PivotVisitor pivotVisitor; + private final SelectItemVisitor selectItemVisitor; + private final FromItemVisitor fromItemVisitor; + private final SelectVisitor selectVisitor; + private final MergeOperationVisitor mergeOperationVisitor; + + public StatementVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(); + this.pivotVisitor = new PivotVisitorAdapter<>(this.expressionVisitor); + this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); + this.fromItemVisitor = new FromItemVisitorAdapter<>(); + + this.selectVisitor = new SelectVisitorAdapter<>(this.expressionVisitor, this.pivotVisitor, + this.selectItemVisitor, this.fromItemVisitor); + this.mergeOperationVisitor = new MergeOperationVisitorAdapter<>(); + } - @Override - public void visit(Comment comment) { + public StatementVisitorAdapter(ExpressionVisitor expressionVisitor, + PivotVisitor pivotVisitor, SelectItemVisitor selectItemVisitor, + FromItemVisitor fromItemVisitor, SelectVisitor selectVisitor, + MergeOperationVisitor mergeOperationVisitor) { + this.expressionVisitor = expressionVisitor; + this.pivotVisitor = pivotVisitor; + this.selectItemVisitor = selectItemVisitor; + this.fromItemVisitor = fromItemVisitor; + this.selectVisitor = selectVisitor; + this.mergeOperationVisitor = mergeOperationVisitor; + } + public StatementVisitorAdapter(SelectVisitorAdapter selectVisitor) { + this.selectVisitor = selectVisitor; + this.expressionVisitor = selectVisitor.getExpressionVisitor(); + this.pivotVisitor = selectVisitor.getPivotVisitor(); + this.selectItemVisitor = selectVisitor.getSelectItemVisitor(); + this.fromItemVisitor = selectVisitor.getFromItemVisitor(); + this.mergeOperationVisitor = new MergeOperationVisitorAdapter<>(); } @Override - public void visit(Commit commit) { + public T visit(Comment comment, S context) { + return null; } @Override - public void visit(Select select) { + public T visit(Commit commit, S context) { + return null; } @Override - public void visit(Delete delete) { - + public T visit(Select select, S context) { + return select.accept(selectVisitor, context); } @Override - public void visit(Update update) { + public T visit(Delete delete, S context) { + visitWithItems(delete.getWithItemsList(), context); + fromItemVisitor.visitTables(delete.getTables(), context); + selectVisitor.visitOutputClause(delete.getOutputClause(), context); + fromItemVisitor.visitFromItem(delete.getTable(), context); + fromItemVisitor.visitTables(delete.getUsingList(), context); + fromItemVisitor.visitJoins(delete.getJoins(), context); + expressionVisitor.visitExpression(delete.getWhere(), context); + + expressionVisitor.visitPreferringClause(delete.getPreferringClause(), context); + + expressionVisitor.visitOrderBy(delete.getOrderByElements(), context); + + expressionVisitor.visitLimit(delete.getLimit(), context); + + return null; + } + private void visitWithItems(List> withItemsList, S context) { + if (withItemsList != null) { + for (WithItem item : withItemsList) { + item.accept(this, context); + } + } } @Override - public void visit(Insert insert) { + public T visit(ParenthesedDelete delete, S context) { + delete.getDelete().accept(this, context); + return null; + } + @Override + public T visit(SessionStatement sessionStatement, S context) { + return null; } @Override - public void visit(Drop drop) { + public T visit(Update update, S context) { + visitWithItems(update.getWithItemsList(), context); + fromItemVisitor.visitFromItem(update.getTable(), context); + fromItemVisitor.visitJoins(update.getStartJoins(), context); + expressionVisitor.visitUpdateSets(update.getUpdateSets(), context); + selectVisitor.visitOutputClause(update.getOutputClause(), context); + fromItemVisitor.visitFromItem(update.getFromItem(), context); + fromItemVisitor.visitJoins(update.getJoins(), context); + expressionVisitor.visitExpression(update.getWhere(), context); + expressionVisitor.visitPreferringClause(update.getPreferringClause(), context); + expressionVisitor.visitOrderBy(update.getOrderByElements(), context); + expressionVisitor.visitLimit(update.getLimit(), context); + visitReturningClause(update.getReturningClause(), context); + return null; + } + @Override + public T visit(ParenthesedUpdate update, S context) { + return update.getUpdate().accept(this, context); } @Override - public void visit(Truncate truncate) { + public T visit(Insert insert, S context) { + visitWithItems(insert.getWithItemsList(), context); + + insert.getTable().accept(fromItemVisitor, context); + + if (insert.getColumns() != null) { + for (Column column : insert.getColumns()) { + column.accept(expressionVisitor, context); + } + } + if (insert.getPartitions() != null) { + for (Partition partition : insert.getPartitions()) { + partition.getColumn().accept(expressionVisitor, context); + if (partition.getValue() != null) { + partition.getValue().accept(expressionVisitor, context); + } + } + } + + selectVisitor.visitOutputClause(insert.getOutputClause(), context); + + if (insert.getSelect() != null) { + insert.getSelect().accept(selectVisitor, null); + } + + expressionVisitor.visitUpdateSets(insert.getSetUpdateSets(), context); + + expressionVisitor.visitUpdateSets(insert.getDuplicateUpdateSets(), context); + + final InsertConflictAction conflictAction = insert.getConflictAction(); + if (conflictAction != null) { + expressionVisitor.visitExpression(conflictAction.getWhereExpression(), context); + expressionVisitor.visitUpdateSets(conflictAction.getUpdateSets(), context); + } + + visitReturningClause(insert.getReturningClause(), context); + return null; + } + + private T visitReturningClause(ReturningClause returningClause, S context) { + if (returningClause != null) { + returningClause.forEach(selectItem -> selectItem.accept(selectItemVisitor, context)); + // @todo: verify why this is a list of strings and not columns + } + return null; + } + + @Override + public T visit(ParenthesedInsert insert, S context) { + insert.getInsert().accept(this, context); + return null; } @Override - public void visit(CreateIndex createIndex) { + public T visit(Drop drop, S context) { + if (drop.getType().equalsIgnoreCase("table")) { + fromItemVisitor.visitFromItem(drop.getName(), context); + } + // @todo: handle schemas + return null; } @Override - public void visit(CreateSchema aThis) {} + public T visit(Truncate truncate, S context) { + return truncate.getTable().accept(fromItemVisitor, context); + } @Override - public void visit(CreateTable createTable) { + public T visit(CreateIndex createIndex, S context) { + return null; } @Override - public void visit(CreateView createView) { + public T visit(CreateSchema createSchema, S context) { + return null; + } + @Override + public T visit(CreateTable createTable, S context) { + return createTable.getTable().accept(fromItemVisitor, context); + } + + @Override + public T visit(CreateView createView, S context) { + return null; } @Override - public void visit(Alter alter) { + public T visit(Alter alter, S context) { + return null; } @Override - public void visit(Statements stmts) { - for (Statement statement : stmts.getStatements()) { - statement.accept(this); + public T visit(Statements statements, S context) { + for (Statement statement : statements) { + statement.accept(this, context); } + return null; } @Override - public void visit(Execute execute) { + public T visit(Execute execute, S context) { + return null; } @Override - public void visit(SetStatement set) { + public T visit(LockStatement lock, S context) { + return null; } @Override - public void visit(ResetStatement reset) { + public T visit(CreatePolicy createPolicy, S context) { + return null; } @Override - public void visit(Merge merge) { + public T visit(SetStatement set, S context) { + return null; } @Override - public void visit(AlterView alterView) {} + public T visit(ResetStatement reset, S context) { + + return null; + } @Override - public void visit(Upsert upsert) {} + public T visit(Merge merge, S context) { + visitWithItems(merge.getWithItemsList(), context); + fromItemVisitor.visitFromItem(merge.getTable(), context); + fromItemVisitor.visitFromItem(merge.getFromItem(), context); + expressionVisitor.visitExpression(merge.getOnCondition(), context); + mergeOperationVisitor.visit(merge.getOperations(), context); + selectVisitor.visitOutputClause(merge.getOutputClause(), context); + return null; + } @Override - public void visit(UseStatement use) {} + public T visit(AlterView alterView, S context) { + return null; + } @Override - public void visit(Block block) {} + public T visit(Upsert upsert, S context) { + return null; + } + + @Override + public T visit(UseStatement use, S context) { + return null; + } @Override - public void visit(DescribeStatement describe) {} + public T visit(Block block, S context) { + return null; + } + + @Override + public T visit(DescribeStatement describe, S context) { + return null; + } @Override - public void visit(ExplainStatement aThis) {} + public T visit(ExplainStatement explainStatement, S context) { + return null; + } @Override - public void visit(ShowStatement aThis) {} + public T visit(ShowStatement showStatement, S context) { + return null; + } @Override - public void visit(ShowColumnsStatement set) {} + public T visit(ShowColumnsStatement showColumnsStatement, S context) { + return null; + } @Override - public void visit(ShowIndexStatement set) {} + public T visit(ShowIndexStatement showIndexStatement, S context) { + return null; + } @Override - public void visit(ShowTablesStatement showTables) {} + public T visit(ShowTablesStatement showTables, S context) { + return null; + } @Override - public void visit(DeclareStatement aThis) {} + public T visit(DeclareStatement declareStatement, S context) { + return null; + } @Override - public void visit(Grant grant) {} + public T visit(Grant grant, S context) { + return null; + } @Override - public void visit(CreateSequence createSequence) {} + public T visit(CreateSequence createSequence, S context) { + return null; + } @Override - public void visit(AlterSequence alterSequence) {} + public T visit(AlterSequence alterSequence, S context) { + return null; + } @Override - public void visit(CreateFunctionalStatement createFunctionalStatement) {} + public T visit(CreateFunctionalStatement createFunctionalStatement, S context) { + return null; + } @Override - public void visit(CreateSynonym createSynonym) {} + public T visit(CreateSynonym createSynonym, S context) { + return null; + } @Override - public void visit(Analyze analyze) { + public T visit(Analyze analyze, S context) { + return null; } @Override - public void visit(SavepointStatement savepointStatement) { - // @todo: do something usefull here + public T visit(SavepointStatement savepointStatement, S context) { + // @todo: do something usefully here + return null; } @Override - public void visit(RollbackStatement rollbackStatement) { - // @todo: do something usefull here + public T visit(RollbackStatement rollbackStatement, S context) { + // @todo: do something usefully here + return null; } @Override - public void visit(AlterSession alterSession) { - // @todo: do something usefull here + public T visit(AlterSession alterSession, S context) { + // @todo: do something usefully here + return null; } @Override - public void visit(IfElseStatement ifElseStatement) { - ifElseStatement.getIfStatement().accept(this); + public T visit(IfElseStatement ifElseStatement, S context) { + ifElseStatement.getIfStatement().accept(this, context); if (ifElseStatement.getElseStatement() != null) { - ifElseStatement.getElseStatement().accept(this); + ifElseStatement.getElseStatement().accept(this, context); } + return null; } @Override - public void visit(RenameTableStatement renameTableStatement) { - // @todo: do something usefull here + public T visit(RenameTableStatement renameTableStatement, S context) { + return null; } @Override - public void visit(PurgeStatement purgeStatement) { - // @todo: do something usefull here + public T visit(PurgeStatement purgeStatement, S context) { + return null; } @Override - public void visit(AlterSystemStatement alterSystemStatement) {} + public T visit(AlterSystemStatement alterSystemStatement, S context) { + return null; + } @Override - public void visit(UnsupportedStatement unsupportedStatement) { + public T visit(UnsupportedStatement unsupportedStatement, S context) { + + return null; + } + @Override + public T visit(RefreshMaterializedViewStatement materializedView, S context) { + return null; } @Override - public void visit(RefreshMaterializedViewStatement materializedView) { + public T visit(Import imprt, S context) { + return null; + } + @Override + public T visit(Export export, S context) { + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/Statements.java b/src/main/java/net/sf/jsqlparser/statement/Statements.java index 5f66f2d6f..0c8571c35 100644 --- a/src/main/java/net/sf/jsqlparser/statement/Statements.java +++ b/src/main/java/net/sf/jsqlparser/statement/Statements.java @@ -26,8 +26,8 @@ public void setStatements(List statements) { this.addAll(statements); } - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public E get(Class type, int index) { diff --git a/src/main/java/net/sf/jsqlparser/statement/UnsupportedStatement.java b/src/main/java/net/sf/jsqlparser/statement/UnsupportedStatement.java index 9b47a9e2a..f64a89fac 100644 --- a/src/main/java/net/sf/jsqlparser/statement/UnsupportedStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/UnsupportedStatement.java @@ -15,7 +15,6 @@ import java.util.Objects; /** - * * @author Andreas Reichel */ @@ -35,8 +34,8 @@ public UnsupportedStatement(String upfront, List declarations) { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } @SuppressWarnings({"PMD.MissingBreakInSwitch", "PMD.SwitchStmtsShouldHaveDefault", diff --git a/src/main/java/net/sf/jsqlparser/statement/UseStatement.java b/src/main/java/net/sf/jsqlparser/statement/UseStatement.java index f0a80e4d7..b4b606849 100644 --- a/src/main/java/net/sf/jsqlparser/statement/UseStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/UseStatement.java @@ -49,8 +49,8 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public UseStatement withName(String name) { diff --git a/src/main/java/net/sf/jsqlparser/statement/UserIdentification.java b/src/main/java/net/sf/jsqlparser/statement/UserIdentification.java new file mode 100644 index 000000000..d951931d9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/UserIdentification.java @@ -0,0 +1,48 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class UserIdentification implements Serializable { + private StringValue user; + private StringValue password; + + public StringValue getUser() { + return user; + } + + public void setUser(StringValue user) { + this.user = user; + } + + public StringValue getPassword() { + return password; + } + + public void setPassword(StringValue password) { + this.password = password; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("USER "); + sql.append(user); + + sql.append(" IDENTIFIED BY "); + sql.append(password); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/Alter.java b/src/main/java/net/sf/jsqlparser/statement/alter/Alter.java index 0aabfc181..7c00077e2 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/Alter.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/Alter.java @@ -15,6 +15,7 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; + import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; @@ -73,8 +74,8 @@ public void setAlterExpressions(List alterExpressions) { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java index 0a99c97d5..43615abdb 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java @@ -18,28 +18,32 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.statement.ReferentialAction; import net.sf.jsqlparser.statement.ReferentialAction.Action; import net.sf.jsqlparser.statement.ReferentialAction.Type; import net.sf.jsqlparser.statement.create.table.ColDataType; import net.sf.jsqlparser.statement.create.table.ColumnDefinition; import net.sf.jsqlparser.statement.create.table.Index; +import net.sf.jsqlparser.statement.create.table.PartitionDefinition; import net.sf.jsqlparser.statement.select.PlainSelect; @SuppressWarnings({"PMD.CyclomaticComplexity"}) public class AlterExpression implements Serializable { + private final Set referentialActions = new LinkedHashSet<>(2); private AlterOperation operation; private String optionalSpecifier; private String newTableName; private String columnName; - private String columnOldName; // private ColDataType dataType; - + private String columnOldName; private List colDataTypeList; private List columnDropNotNullList; - private List columnDropDefaultList; + private List columnSetDefaultList; + private List columnSetVisibilityList; private List pkColumns; private List ukColumns; @@ -49,29 +53,79 @@ public class AlterExpression implements Serializable { private String constraintName; private boolean usingIfExists; - private Set referentialActions = new LinkedHashSet<>(2); - + /** + * @deprecated Use {@link #setIndex(Index)} with a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated private List fkColumns; + + /** + * @deprecated Use {@link #setIndex(Index)} with a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated private String fkSourceSchema; + /** + * @deprecated Use {@link #setIndex(Index)} with a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated private String fkSourceTable; + + /** + * @deprecated Use {@link #setIndex(Index)} with a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated private List fkSourceColumns; private boolean uk; + private boolean ukTypeSpecified; private boolean useEqual; + private List partitions; + private List partitionDefinitions; private List constraints; private List parameters; + + private ConvertType convertType; + private boolean hasEqualForCharacterSet; + private boolean hasEqualForCollate; + + private String characterSet; + private String collation; + private boolean defaultCollateSpecified; + private String lockOption; + private String algorithmOption; + private String engineOption; private String commentText; + private String tableOption; private boolean hasColumn = false; + private boolean hasColumns = false; private boolean useBrackets = false; - private String truncatePartitionName = null; - private boolean useIfNotExists = false; + private String partitionType; + private Expression partitionExpression; + private List partitionColumns; + private int coalescePartitionNumber; + + private String exchangePartitionTableName; + private boolean exchangePartitionWithValidation; + private boolean exchangePartitionWithoutValidation; + + private int keyBlockSize; + + private String constraintSymbol; + private boolean enforced; + private String constraintType; + private boolean invisible; + public Index getOldIndex() { return oldIndex; } @@ -84,6 +138,10 @@ public boolean hasColumn() { return hasColumn; } + public boolean hasColumns() { + return hasColumns; + } + public boolean useBrackets() { return useBrackets; } @@ -96,10 +154,24 @@ public void hasColumn(boolean hasColumn) { this.hasColumn = hasColumn; } + public void hasColumns(boolean hasColumns) { + this.hasColumns = hasColumns; + } + + /** + * @deprecated Use {@link #getIndex()} with + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated public String getFkSourceSchema() { return fkSourceSchema; } + /** + * @deprecated Use {@link #setIndex(Index)} with a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated public void setFkSourceSchema(String fkSourceSchema) { this.fkSourceSchema = fkSourceSchema; } @@ -112,6 +184,14 @@ public void setCommentText(String commentText) { this.commentText = commentText; } + public String getTableOption() { + return tableOption; + } + + public void setTableOption(String tableOption) { + this.tableOption = tableOption; + } + public AlterOperation getOperation() { return operation; } @@ -131,11 +211,19 @@ public void setOptionalSpecifier(String optionalSpecifier) { /** * @param type * @param action + * @deprecated Standalone FK fields are deprecated. Use a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} via + * {@link #setIndex(Index)} instead. */ + @Deprecated public void setReferentialAction(Type type, Action action) { setReferentialAction(type, action, true); } + /** + * @deprecated Standalone FK fields are deprecated. + */ + @Deprecated public AlterExpression withReferentialAction(Type type, Action action) { setReferentialAction(type, action); return this; @@ -143,7 +231,9 @@ public AlterExpression withReferentialAction(Type type, Action action) { /** * @param type + * @deprecated Standalone FK fields are deprecated. */ + @Deprecated public void removeReferentialAction(Type type) { setReferentialAction(type, null, false); } @@ -151,7 +241,9 @@ public void removeReferentialAction(Type type) { /** * @param type * @return + * @deprecated Standalone FK fields are deprecated. */ + @Deprecated public ReferentialAction getReferentialAction(Type type) { return referentialActions.stream() .filter(ra -> type.equals(ra.getType())) @@ -232,18 +324,38 @@ public void setOnDeleteSetNull(boolean onDeleteSetNull) { setReferentialAction(Type.DELETE, Action.SET_NULL, onDeleteSetNull); } + /** + * @deprecated Use {@link #getIndex()} with + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated public List getFkColumns() { return fkColumns; } + /** + * @deprecated Use {@link #setIndex(Index)} with a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated public void setFkColumns(List fkColumns) { this.fkColumns = fkColumns; } + /** + * @deprecated Use {@link #getIndex()} with + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated public String getFkSourceTable() { return fkSourceTable; } + /** + * @deprecated Use {@link #setIndex(Index)} with a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated public void setFkSourceTable(String fkSourceTable) { this.fkSourceTable = fkSourceTable; } @@ -270,6 +382,10 @@ public void addColDropNotNull(ColumnDropNotNull columnDropNotNull) { columnDropNotNullList.add(columnDropNotNull); } + public List getColumnDropDefaultList() { + return columnDropDefaultList; + } + public void addColDropDefault(ColumnDropDefault columnDropDefault) { if (columnDropDefaultList == null) { columnDropDefaultList = new ArrayList<>(); @@ -277,10 +393,42 @@ public void addColDropDefault(ColumnDropDefault columnDropDefault) { columnDropDefaultList.add(columnDropDefault); } + public void addColSetDefault(ColumnSetDefault columnSetDefault) { + if (columnSetDefaultList == null) { + columnSetDefaultList = new ArrayList<>(); + } + columnSetDefaultList.add(columnSetDefault); + } + + public List getColumnSetDefaultList() { + return columnSetDefaultList; + } + + public void addColSetVisibility(ColumnSetVisibility columnSetVisibility) { + if (columnSetVisibilityList == null) { + columnSetVisibilityList = new ArrayList<>(); + } + columnSetVisibilityList.add(columnSetVisibility); + } + + public List getColumnSetVisibilityList() { + return columnSetVisibilityList; + } + + /** + * @deprecated Use {@link #getIndex()} with + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated public List getFkSourceColumns() { return fkSourceColumns; } + /** + * @deprecated Use {@link #setIndex(Index)} with a + * {@link net.sf.jsqlparser.statement.create.table.ForeignKeyIndex} instead. + */ + @Deprecated public void setFkSourceColumns(List fkSourceColumns) { this.fkSourceColumns = fkSourceColumns; } @@ -390,6 +538,62 @@ public List getParameters() { return parameters; } + public ConvertType getConvertType() { + return convertType; + } + + public void setConvertType(ConvertType convertType) { + this.convertType = convertType; + } + + public String getCharacterSet() { + return characterSet; + } + + public void setCharacterSet(String characterSet) { + this.characterSet = characterSet; + } + + public String getCollation() { + return collation; + } + + public void setCollation(String collation) { + this.collation = collation; + } + + public void setDefaultCollateSpecified(boolean value) { + this.defaultCollateSpecified = value; + } + + public boolean isDefaultCollateSpecified() { + return defaultCollateSpecified; + } + + public String getLockOption() { + return lockOption; + } + + public void setLockOption(String lockOption) { + this.lockOption = lockOption; + } + + public String getAlgorithmOption() { + return algorithmOption; + } + + public void setAlgorithmOption(String algorithmOption) { + this.algorithmOption = algorithmOption; + } + + public String getEngineOption() { + return engineOption; + } + + public void setEngineOption(String engineOption) { + this.engineOption = engineOption; + } + public boolean getUseEqual() { return useEqual; } @@ -404,19 +608,15 @@ public boolean getUk() { public void setUk(boolean uk) { this.uk = uk; + this.ukTypeSpecified = true; } - public String getTruncatePartitionName() { - return truncatePartitionName; + public boolean isUkTypeSpecified() { + return ukTypeSpecified; } - public void setTruncatePartitionName(String truncatePartitionName) { - this.truncatePartitionName = truncatePartitionName; - } - - public AlterExpression withTruncatePartitionName(String truncatePartitionName) { - this.truncatePartitionName = truncatePartitionName; - return this; + public void setUkTypeSpecified(boolean ukTypeSpecified) { + this.ukTypeSpecified = ukTypeSpecified; } public boolean isUseIfNotExists() { @@ -432,16 +632,293 @@ public AlterExpression withUserIfNotExists(boolean userIfNotExists) { return this; } - @Override - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", - "PMD.ExcessiveMethodLength", "PMD.SwitchStmtsShouldHaveDefault"}) - public String toString() { + public void setPartitionType(String partitionType) { + this.partitionType = partitionType; + } + + public String getPartitionType() { + return partitionType; + } + + public void setPartitionExpression(Expression partitionExpression) { + this.partitionExpression = partitionExpression; + } + + public Expression getPartitionExpression() { + return partitionExpression; + } + + public void setPartitionColumns(List partitionColumns) { + this.partitionColumns = partitionColumns; + } + + public List getPartitionColumns() { + return partitionColumns; + } + + public void setExchangePartitionTableName(String exchangePartitionTableName) { + this.exchangePartitionTableName = exchangePartitionTableName; + } + public String getExchangePartitionTableName() { + return exchangePartitionTableName; + } + + public void setCoalescePartitionNumber(int coalescePartitionNumber) { + this.coalescePartitionNumber = coalescePartitionNumber; + } + + public int getCoalescePartitionNumber() { + return coalescePartitionNumber; + } + + public void setExchangePartitionWithValidation(boolean exchangePartitionWithValidation) { + this.exchangePartitionWithValidation = exchangePartitionWithValidation; + } + + public boolean isExchangePartitionWithValidation() { + return exchangePartitionWithValidation; + } + + public void setExchangePartitionWithoutValidation(boolean exchangePartitionWithoutValidation) { + this.exchangePartitionWithoutValidation = exchangePartitionWithoutValidation; + } + + public boolean isExchangePartitionWithoutValidation() { + return exchangePartitionWithoutValidation; + } + + public void setKeyBlockSize(int keyBlockSize) { + this.keyBlockSize = keyBlockSize; + } + + public int getKeyBlockSize() { + return keyBlockSize; + } + + public String getConstraintSymbol() { + return constraintSymbol; + } + + public void setConstraintSymbol(String constraintSymbol) { + this.constraintSymbol = constraintSymbol; + } + + public boolean isEnforced() { + return enforced; + } + + public void setEnforced(boolean enforced) { + this.enforced = enforced; + } + + public String getConstraintType() { + return constraintType; + } + + public void setConstraintType(String constraintType) { + this.constraintType = constraintType; + } + + public boolean isInvisible() { + return invisible; + } + + public void setInvisible(boolean invisible) { + this.invisible = invisible; + } + + @Override + public final String toString() { StringBuilder b = new StringBuilder(); + appendBody(b); + appendCommonTail(b); + return b.toString(); + } + /** + * Appends the main body of this ALTER expression to the builder. Subclasses override this for + * type-specific rendering. + */ + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", + "PMD.ExcessiveMethodLength", "PMD.SwitchStmtsShouldHaveDefault"}) + protected void appendBody(StringBuilder b) { if (operation == AlterOperation.UNSPECIFIC) { b.append(optionalSpecifier); - } else if (getOldIndex() != null) { + } else if (constraintType != null && constraintSymbol != null + && (operation == AlterOperation.ALTER || operation == AlterOperation.ADD)) { + toStringConstraintAlter(b); + } else if (operation == AlterOperation.ALTER + && (columnDropDefaultList != null && !columnDropDefaultList.isEmpty() + || columnSetDefaultList != null && !columnSetDefaultList.isEmpty() + || columnSetVisibilityList != null && !columnSetVisibilityList.isEmpty())) { + toStringAlterColumn(b); + } else if (isSimpleKeywordOperation()) { + toStringSimpleKeyword(b); + } else if (isRenameOperation()) { + toStringRename(b); + } else if (isDropSpecialOperation()) { + toStringDropSpecial(b); + } else if (operation == AlterOperation.CONVERT || operation == AlterOperation.COLLATE) { + toStringConvert(b); + } else if (isPartitionOperation()) { + toStringPartition(b); + } else { + toStringGeneral(b); + } + } + + /** + * Appends the common tail (parameters, index comment) shared by all ALTER expressions. + */ + protected void appendCommonTail(StringBuilder b) { + if (parameters != null && !parameters.isEmpty()) { + b.append(' ').append(PlainSelect.getStringList(parameters, false, false)); + } + if (index != null && index.getCommentText() != null) { + b.append(" COMMENT ").append(index.getCommentText()); + } + } + + protected boolean isSimpleKeywordOperation() { + switch (operation) { + case SET_TABLE_OPTION: + case DISCARD_TABLESPACE: + case IMPORT_TABLESPACE: + case DISABLE_KEYS: + case ENABLE_KEYS: + case ENGINE: + case ALGORITHM: + case KEY_BLOCK_SIZE: + case LOCK: + return true; + default: + return false; + } + } + + protected boolean isRenameOperation() { + return getOldIndex() != null || operation == AlterOperation.RENAME_TABLE; + } + + protected boolean isDropSpecialOperation() { + switch (operation) { + case DROP_PRIMARY_KEY: + case DROP_UNIQUE: + case DROP_FOREIGN_KEY: + return true; + case DROP: + return columnName == null && pkColumns != null && !pkColumns.isEmpty(); + default: + return false; + } + } + + protected boolean isPartitionOperation() { + switch (operation) { + case DISCARD_PARTITION: + case IMPORT_PARTITION: + case TRUNCATE_PARTITION: + case COALESCE_PARTITION: + case REORGANIZE_PARTITION: + case EXCHANGE_PARTITION: + case ANALYZE_PARTITION: + case CHECK_PARTITION: + case OPTIMIZE_PARTITION: + case REBUILD_PARTITION: + case REPAIR_PARTITION: + case REMOVE_PARTITIONING: + case PARTITION_BY: + return true; + default: + return false; + } + } + + protected void toStringConstraintAlter(StringBuilder b) { + if (operation == AlterOperation.ALTER) { + b.append("ALTER ").append(constraintType).append(" ").append(constraintSymbol); + if (invisible) { + b.append(" INVISIBLE"); + } else if (!isEnforced()) { + b.append(" NOT ENFORCED"); + } else if (enforced) { + b.append(" ENFORCED"); + } + } else { + b.append("ADD CONSTRAINT ").append(constraintType).append(" ").append(constraintSymbol) + .append(" "); + if (index != null && index.getColumnsNames() != null) { + b.append(" ") + .append(PlainSelect.getStringList(index.getColumnsNames(), true, true)); + } + } + } + + protected void toStringAlterColumn(StringBuilder b) { + b.append("ALTER "); + if (hasColumn) { + b.append("COLUMN "); + } + if (columnDropDefaultList != null && !columnDropDefaultList.isEmpty()) { + b.append(PlainSelect.getStringList(columnDropDefaultList)); + } else if (columnSetDefaultList != null && !columnSetDefaultList.isEmpty()) { + b.append(PlainSelect.getStringList(columnSetDefaultList)); + } else { + b.append(PlainSelect.getStringList(columnSetVisibilityList)); + } + } + + protected void toStringSimpleKeyword(StringBuilder b) { + switch (operation) { + case SET_TABLE_OPTION: + b.append(tableOption); + break; + case DISCARD_TABLESPACE: + b.append("DISCARD TABLESPACE"); + break; + case IMPORT_TABLESPACE: + b.append("IMPORT TABLESPACE"); + break; + case DISABLE_KEYS: + b.append("DISABLE KEYS"); + break; + case ENABLE_KEYS: + b.append("ENABLE KEYS"); + break; + case ENGINE: + b.append("ENGINE "); + if (useEqual) { + b.append("= "); + } + b.append(engineOption); + break; + case ALGORITHM: + b.append("ALGORITHM "); + if (useEqual) { + b.append("= "); + } + b.append(algorithmOption); + break; + case KEY_BLOCK_SIZE: + b.append("KEY_BLOCK_SIZE "); + if (useEqual) { + b.append("= "); + } + b.append(keyBlockSize); + break; + case LOCK: + b.append("LOCK "); + if (useEqual) { + b.append("= "); + } + b.append(lockOption); + break; + } + } + + protected void toStringRename(StringBuilder b) { + if (getOldIndex() != null) { b.append("RENAME"); switch (operation) { case RENAME_KEY: @@ -455,135 +932,261 @@ public String toString() { break; } b.append(getOldIndex().getName()).append(" TO ").append(getIndex().getName()); - } else if (operation == AlterOperation.RENAME_TABLE) { - - b.append("RENAME TO ").append(newTableName); - } else if (operation == AlterOperation.DROP_PRIMARY_KEY) { - - b.append("DROP PRIMARY KEY "); - } else if (operation == AlterOperation.DROP_UNIQUE) { - - b.append("DROP UNIQUE (").append(PlainSelect.getStringList(pkColumns)).append(')'); - } else if (operation == AlterOperation.DROP_FOREIGN_KEY) { - - b.append("DROP FOREIGN KEY (").append(PlainSelect.getStringList(pkColumns)).append(')'); - } else if (operation == AlterOperation.DROP && columnName == null && pkColumns != null - && !pkColumns.isEmpty()) { - // Oracle Multi Column Drop - b.append("DROP (").append(PlainSelect.getStringList(pkColumns)).append(')'); - } else if (operation == AlterOperation.TRUNCATE_PARTITION - && truncatePartitionName != null) { - b.append("TRUNCATE PARTITION ").append(truncatePartitionName); } else { - if (operation == AlterOperation.COMMENT_WITH_EQUAL_SIGN) { - b.append("COMMENT =").append(" "); - } else { - b.append(operation).append(" "); - } - if (commentText != null) { - if (columnName != null) { - b.append(columnName).append(" COMMENT "); - } - b.append(commentText); - } else if (columnName != null) { - if (hasColumn) { - b.append("COLUMN "); + b.append("RENAME TO ").append(newTableName); + } + } + + protected void toStringDropSpecial(StringBuilder b) { + switch (operation) { + case DROP_PRIMARY_KEY: + b.append("DROP PRIMARY KEY "); + break; + case DROP_UNIQUE: + b.append("DROP UNIQUE (").append(PlainSelect.getStringList(pkColumns)).append(')'); + break; + case DROP_FOREIGN_KEY: + b.append("DROP FOREIGN KEY (").append(PlainSelect.getStringList(pkColumns)) + .append(')'); + break; + default: + // Oracle Multi Column Drop + b.append("DROP (").append(PlainSelect.getStringList(pkColumns)).append(')'); + break; + } + } + + protected void toStringConvert(StringBuilder b) { + if (operation == AlterOperation.CONVERT) { + if (convertType == ConvertType.CONVERT_TO) { + b.append("CONVERT TO CHARACTER SET "); + } else if (convertType == ConvertType.DEFAULT_CHARACTER_SET) { + b.append("DEFAULT CHARACTER SET "); + if (hasEqualForCharacterSet) { + b.append("= "); } - if (usingIfExists) { - b.append("IF EXISTS "); + } else if (convertType == ConvertType.CHARACTER_SET) { + b.append("CHARACTER SET "); + if (hasEqualForCharacterSet) { + b.append("= "); } - if (operation == AlterOperation.RENAME) { - b.append(columnOldName).append(" TO "); + } + if (getCharacterSet() != null) { + b.append(getCharacterSet()); + } + if (getCollation() != null) { + b.append(" COLLATE "); + if (hasEqualForCollate) { + b.append("= "); } - b.append(columnName); - } else if (getColDataTypeList() != null) { - if (operation == AlterOperation.CHANGE) { - if (optionalSpecifier != null) { - b.append(optionalSpecifier).append(" "); - } - b.append(columnOldName).append(" "); - } else if (colDataTypeList.size() > 1) { - b.append("("); - } else { - if (hasColumn) { - b.append("COLUMN "); - } - if (useIfNotExists - && operation == AlterOperation.ADD) { - b.append("IF NOT EXISTS "); - } + b.append(getCollation()); + } + } else { + if (isDefaultCollateSpecified()) { + b.append("DEFAULT "); + } + b.append("COLLATE "); + if (hasEqualForCollate) { + b.append("= "); + } + if (getCollation() != null) { + b.append(getCollation()); + } + } + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + protected void toStringPartition(StringBuilder b) { + switch (operation) { + case DISCARD_PARTITION: + b.append("DISCARD PARTITION ").append(PlainSelect.getStringList(partitions)); + if (tableOption != null) { + b.append(" ").append(tableOption); } - if (useBrackets && colDataTypeList.size() == 1) { - b.append(" ( "); + break; + case IMPORT_PARTITION: + b.append("IMPORT PARTITION ").append(PlainSelect.getStringList(partitions)); + if (tableOption != null) { + b.append(" ").append(tableOption); } - b.append(PlainSelect.getStringList(colDataTypeList)); - if (useBrackets && colDataTypeList.size() == 1) { - b.append(" ) "); + break; + case TRUNCATE_PARTITION: + b.append("TRUNCATE PARTITION ").append(PlainSelect.getStringList(partitions)); + break; + case COALESCE_PARTITION: + b.append("COALESCE PARTITION ").append(coalescePartitionNumber); + break; + case REORGANIZE_PARTITION: + b.append("REORGANIZE PARTITION ") + .append(PlainSelect.getStringList(partitions)) + .append(" INTO (") + .append(partitionDefinitions.stream() + .map(PartitionDefinition::toString) + .collect(Collectors.joining(", "))) + .append(")"); + break; + case EXCHANGE_PARTITION: + b.append("EXCHANGE PARTITION "); + b.append(partitions.get(0)).append(" WITH TABLE ") + .append(exchangePartitionTableName); + if (exchangePartitionWithValidation) { + b.append(" WITH VALIDATION "); + } else if (exchangePartitionWithoutValidation) { + b.append(" WITHOUT VALIDATION "); } - if (colDataTypeList.size() > 1) { - b.append(")"); + break; + case ANALYZE_PARTITION: + b.append("ANALYZE PARTITION ").append(PlainSelect.getStringList(partitions)); + break; + case CHECK_PARTITION: + b.append("CHECK PARTITION ").append(PlainSelect.getStringList(partitions)); + break; + case OPTIMIZE_PARTITION: + b.append("OPTIMIZE PARTITION ").append(PlainSelect.getStringList(partitions)); + break; + case REBUILD_PARTITION: + b.append("REBUILD PARTITION ").append(PlainSelect.getStringList(partitions)); + break; + case REPAIR_PARTITION: + b.append("REPAIR PARTITION ").append(PlainSelect.getStringList(partitions)); + break; + case REMOVE_PARTITIONING: + b.append("REMOVE PARTITIONING"); + break; + case PARTITION_BY: + b.append("PARTITION BY ").append(partitionType).append(" "); + if (partitionExpression != null) { + b.append("(").append(partitionExpression).append(") "); + } else if (partitionColumns != null && !partitionColumns.isEmpty()) { + b.append("COLUMNS(").append(String.join(", ", partitionColumns)).append(") "); } - } else if (getColumnDropNotNullList() != null) { - b.append("COLUMN "); - b.append(PlainSelect.getStringList(columnDropNotNullList)); - } else if (columnDropDefaultList != null && !columnDropDefaultList.isEmpty()) { + b.append("(").append(partitionDefinitions.stream() + .map(PartitionDefinition::toString) + .collect(Collectors.joining(", "))) + .append(")"); + break; + } + } + + /** + * Handles the general case for ADD, MODIFY, CHANGE, DROP (column), COMMENT, row-level security, + * and all field-based dispatch (columns, constraints, FK, UK, PK, index). + */ + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", + "PMD.ExcessiveMethodLength"}) + protected void toStringGeneral(StringBuilder b) { + if (operation == AlterOperation.COMMENT_WITH_EQUAL_SIGN) { + b.append("COMMENT =").append(" "); + } else if (operation == AlterOperation.ENABLE_ROW_LEVEL_SECURITY) { + b.append("ENABLE ROW LEVEL SECURITY").append(" "); + } else if (operation == AlterOperation.DISABLE_ROW_LEVEL_SECURITY) { + b.append("DISABLE ROW LEVEL SECURITY").append(" "); + } else if (operation == AlterOperation.FORCE_ROW_LEVEL_SECURITY) { + b.append("FORCE ROW LEVEL SECURITY").append(" "); + } else if (operation == AlterOperation.NO_FORCE_ROW_LEVEL_SECURITY) { + b.append("NO FORCE ROW LEVEL SECURITY").append(" "); + } else { + b.append(operation).append(" "); + } + if (commentText != null) { + if (columnName != null) { + b.append(columnName).append(" COMMENT "); + } + b.append(commentText); + } else if (columnName != null) { + if (hasColumn) { b.append("COLUMN "); - b.append(PlainSelect.getStringList(columnDropDefaultList)); - } else if (constraintName != null) { - b.append("CONSTRAINT "); - if (usingIfExists) { - b.append("IF EXISTS "); + } + if (usingIfExists) { + b.append("IF EXISTS "); + } + if (operation == AlterOperation.RENAME) { + b.append(columnOldName).append(" TO "); + } + b.append(columnName); + } else if (getColDataTypeList() != null) { + if (operation == AlterOperation.CHANGE) { + if (optionalSpecifier != null) { + b.append(optionalSpecifier).append(" "); } - b.append(constraintName); - } else if (pkColumns != null) { - b.append("PRIMARY KEY (").append(PlainSelect.getStringList(pkColumns)).append(')'); - } else if (ukColumns != null) { - b.append("UNIQUE"); - if (ukName != null) { + b.append(columnOldName).append(" "); + } else if (colDataTypeList.size() > 1) { + b.append("("); + } else { + if (hasColumn) { + b.append("COLUMN "); + } else if (hasColumns) { + b.append("COLUMNS "); + } + if (useIfNotExists + && operation == AlterOperation.ADD) { + b.append("IF NOT EXISTS "); + } + } + if (useBrackets && colDataTypeList.size() == 1) { + b.append(" ( "); + } + b.append(PlainSelect.getStringList(colDataTypeList)); + if (useBrackets && colDataTypeList.size() == 1) { + b.append(" ) "); + } + if (colDataTypeList.size() > 1) { + b.append(")"); + } + } else if (getColumnDropNotNullList() != null) { + b.append("COLUMN "); + b.append(PlainSelect.getStringList(columnDropNotNullList)); + } else if (columnDropDefaultList != null && !columnDropDefaultList.isEmpty()) { + b.append("COLUMN "); + b.append(PlainSelect.getStringList(columnDropDefaultList)); + } else if (constraintName != null) { + b.append("CONSTRAINT "); + if (usingIfExists) { + b.append("IF EXISTS "); + } + b.append(constraintName); + } else if (pkColumns != null) { + b.append("PRIMARY KEY (").append(PlainSelect.getStringList(pkColumns)).append(')'); + } else if (ukColumns != null) { + b.append("UNIQUE"); + if (ukName != null) { + if (isUkTypeSpecified()) { if (getUk()) { b.append(" KEY "); } else { b.append(" INDEX "); } - b.append(ukName); + } else { + b.append(" "); } - b.append(" (").append(PlainSelect.getStringList(ukColumns)).append(")"); - } else if (fkColumns != null) { - b.append("FOREIGN KEY (") - .append(PlainSelect.getStringList(fkColumns)) - .append(") REFERENCES ") - .append( - fkSourceSchema != null && fkSourceSchema.trim().length() > 0 - ? fkSourceSchema + "." - : "") - .append(fkSourceTable) - .append(" (") - .append(PlainSelect.getStringList(fkSourceColumns)) - .append(")"); - referentialActions.forEach(b::append); - } else if (index != null) { - b.append(index); - } - - - if (getConstraints() != null && !getConstraints().isEmpty()) { - b.append(' ').append(PlainSelect.getStringList(constraints, false, false)); - } - if (getUseEqual()) { - b.append('='); + b.append(ukName); } + b.append(" (").append(PlainSelect.getStringList(ukColumns)).append(")"); + } else if (fkColumns != null + && !(index instanceof net.sf.jsqlparser.statement.create.table.ForeignKeyIndex)) { + // @deprecated path - kept for backward compatibility when ForeignKeyIndex is not set + b.append("FOREIGN KEY (") + .append(PlainSelect.getStringList(fkColumns)) + .append(") REFERENCES ") + .append( + fkSourceSchema != null && fkSourceSchema.trim().length() > 0 + ? fkSourceSchema + "." + : "") + .append(fkSourceTable) + .append(" (") + .append(PlainSelect.getStringList(fkSourceColumns)) + .append(")"); + referentialActions.forEach(b::append); + } else if (index != null) { + b.append(index); } - if (parameters != null && !parameters.isEmpty()) { - b.append(' ').append(PlainSelect.getStringList(parameters, false, false)); + if (getConstraints() != null && !getConstraints().isEmpty()) { + b.append(' ').append(PlainSelect.getStringList(constraints, false, false)); } - - if (index != null && index.getCommentText() != null) { - // `USING` is a parameters - b.append(" COMMENT ").append(index.getCommentText()); + if (getUseEqual()) { + b.append('='); } - - return b.toString(); } public AlterExpression withOperation(AlterOperation operation) { @@ -646,21 +1249,25 @@ public AlterExpression withOnDeleteCascade(boolean onDeleteCascade) { return this; } + @Deprecated public AlterExpression withFkColumns(List fkColumns) { this.setFkColumns(fkColumns); return this; } + @Deprecated public AlterExpression withFkSourceSchema(String fkSourceSchema) { this.setFkSourceTable(fkSourceSchema); return this; } + @Deprecated public AlterExpression withFkSourceTable(String fkSourceTable) { this.setFkSourceTable(fkSourceTable); return this; } + @Deprecated public AlterExpression withFkSourceColumns(List fkSourceColumns) { this.setFkSourceColumns(fkSourceColumns); return this; @@ -715,18 +1322,21 @@ public AlterExpression addUkColumns(Collection ukColumns) { return this.withUkColumns(collection); } + @Deprecated public AlterExpression addFkColumns(String... fkColumns) { List collection = Optional.ofNullable(getFkColumns()).orElseGet(ArrayList::new); Collections.addAll(collection, fkColumns); return this.withFkColumns(collection); } + @Deprecated public AlterExpression addFkColumns(Collection fkColumns) { List collection = Optional.ofNullable(getFkColumns()).orElseGet(ArrayList::new); collection.addAll(fkColumns); return this.withFkColumns(collection); } + @Deprecated public AlterExpression addFkSourceColumns(String... fkSourceColumns) { List collection = Optional.ofNullable(getFkSourceColumns()).orElseGet(ArrayList::new); @@ -734,6 +1344,7 @@ public AlterExpression addFkSourceColumns(String... fkSourceColumns) { return this.withFkSourceColumns(collection); } + @Deprecated public AlterExpression addFkSourceColumns(Collection fkSourceColumns) { List collection = Optional.ofNullable(getFkSourceColumns()).orElseGet(ArrayList::new); @@ -755,6 +1366,30 @@ public AlterExpression addConstraints(Collection cons return this.withConstraints(collection); } + public List getPartitions() { + return partitions; + } + + public void setPartitions(List partitions) { + this.partitions = partitions; + } + + public List getPartitionDefinitions() { + return partitionDefinitions; + } + + public void setPartitionDefinitions(List partitionDefinition) { + this.partitionDefinitions = partitionDefinition; + } + + public void setHasEqualForCharacterSet(boolean hasEqualForCharacterSet) { + this.hasEqualForCharacterSet = hasEqualForCharacterSet; + } + + public void setHasEqualForCollate(boolean hasEqualForCollate) { + this.hasEqualForCollate = hasEqualForCollate; + } + public static final class ColumnDataType extends ColumnDefinition { private final boolean withType; @@ -848,4 +1483,54 @@ public String toString() { return columnName + " DROP DEFAULT"; } } + + public static final class ColumnSetDefault implements Serializable { + private final String columnName; + private final String defaultValue; + + public ColumnSetDefault(String columnName, String defaultValue) { + this.columnName = columnName; + this.defaultValue = defaultValue; + } + + public String getColumnName() { + return columnName; + } + + public String getDefaultValue() { + return defaultValue; + } + + @Override + public String toString() { + return columnName + " SET DEFAULT " + defaultValue; + } + } + + public static final class ColumnSetVisibility implements Serializable { + private final String columnName; + private final boolean visible; + + public ColumnSetVisibility(String columnName, boolean visible) { + this.columnName = columnName; + this.visible = visible; + } + + public String getColumnName() { + return columnName; + } + + public boolean isVisible() { + return visible; + } + + @Override + public String toString() { + return columnName + " SET " + (visible ? " VISIBLE" : " INVISIBLE"); + } + } + + public enum ConvertType { + CONVERT_TO, DEFAULT_CHARACTER_SET, CHARACTER_SET + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionCharset.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionCharset.java new file mode 100644 index 000000000..b78d5892e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionCharset.java @@ -0,0 +1,22 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.alter; + +/** + * Internal subclass for character set and collation operations within ALTER TABLE. Handles CONVERT + * TO CHARACTER SET, DEFAULT CHARACTER SET, CHARACTER SET, and COLLATE. + */ +public class AlterExpressionCharset extends AlterExpression { + + @Override + protected void appendBody(StringBuilder b) { + toStringConvert(b); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionDrop.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionDrop.java new file mode 100644 index 000000000..37e3b8587 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionDrop.java @@ -0,0 +1,67 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.alter; + +import net.sf.jsqlparser.statement.select.PlainSelect; + +/** + * Internal subclass for DROP operations within ALTER TABLE. Handles DROP column, DROP CONSTRAINT, + * DROP INDEX/KEY, DROP PRIMARY KEY, DROP UNIQUE, DROP FOREIGN KEY, and DROP PARTITION. + */ +public class AlterExpressionDrop extends AlterExpression { + + @Override + protected void appendBody(StringBuilder b) { + switch (getOperation()) { + case DROP_PRIMARY_KEY: + b.append("DROP PRIMARY KEY "); + break; + case DROP_UNIQUE: + b.append("DROP UNIQUE (") + .append(PlainSelect.getStringList(getPkColumns())).append(')'); + break; + case DROP_FOREIGN_KEY: + b.append("DROP FOREIGN KEY (") + .append(PlainSelect.getStringList(getPkColumns())).append(')'); + break; + case DROP_PARTITION: + b.append("DROP PARTITION ") + .append(PlainSelect.getStringList(getPartitions())); + break; + default: + toStringDropDefault(b); + break; + } + } + + private void toStringDropDefault(StringBuilder b) { + b.append("DROP "); + if (getColumnName() == null && getPkColumns() != null && !getPkColumns().isEmpty()) { + // Oracle Multi Column Drop + b.append("(").append(PlainSelect.getStringList(getPkColumns())).append(')'); + } else if (getConstraintName() != null) { + b.append("CONSTRAINT "); + if (isUsingIfExists()) { + b.append("IF EXISTS "); + } + b.append(getConstraintName()); + } else if (getColumnName() != null) { + if (hasColumn()) { + b.append("COLUMN "); + } + if (isUsingIfExists()) { + b.append("IF EXISTS "); + } + b.append(getColumnName()); + } else if (getIndex() != null) { + b.append(getIndex()); + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionPartition.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionPartition.java new file mode 100644 index 000000000..dd9e37b6f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionPartition.java @@ -0,0 +1,23 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.alter; + +/** + * Internal subclass for partition maintenance operations within ALTER TABLE. Handles TRUNCATE, + * COALESCE, REORGANIZE, EXCHANGE, ANALYZE, CHECK, OPTIMIZE, REBUILD, REPAIR PARTITION, PARTITION + * BY, and REMOVE PARTITIONING. + */ +public class AlterExpressionPartition extends AlterExpression { + + @Override + protected void appendBody(StringBuilder b) { + toStringPartition(b); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionRename.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionRename.java new file mode 100644 index 000000000..703e20047 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionRename.java @@ -0,0 +1,38 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.alter; + +/** + * Internal subclass for RENAME operations within ALTER TABLE. Handles RENAME COLUMN, RENAME TO + * (table), RENAME INDEX/KEY/CONSTRAINT. + */ +public class AlterExpressionRename extends AlterExpression { + + @Override + protected void appendBody(StringBuilder b) { + switch (getOperation()) { + case RENAME: + b.append("RENAME "); + if (hasColumn()) { + b.append("COLUMN "); + } + b.append(getColumnOldName()).append(" TO ").append(getColumnName()); + break; + case RENAME_TABLE: + b.append("RENAME TO ").append(getNewTableName()); + break; + case RENAME_INDEX: + case RENAME_KEY: + case RENAME_CONSTRAINT: + toStringRename(b); + break; + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionTableOption.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionTableOption.java new file mode 100644 index 000000000..06a1af136 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpressionTableOption.java @@ -0,0 +1,35 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.alter; + +/** + * Internal subclass for table-level option operations within ALTER TABLE. Handles ENGINE, + * ALGORITHM, LOCK, KEY_BLOCK_SIZE, COMMENT, ENCRYPTION, AUTO_INCREMENT (SET_TABLE_OPTION), + * DISCARD/IMPORT TABLESPACE, DISABLE/ENABLE KEYS. + */ +public class AlterExpressionTableOption extends AlterExpression { + + @Override + protected void appendBody(StringBuilder b) { + switch (getOperation()) { + case COMMENT: + b.append("COMMENT "); + b.append(getCommentText()); + break; + case COMMENT_WITH_EQUAL_SIGN: + b.append("COMMENT = "); + b.append(getCommentText()); + break; + default: + toStringSimpleKeyword(b); + break; + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterOperation.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterOperation.java index 3d0ead731..48fe639ea 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterOperation.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterOperation.java @@ -10,7 +10,7 @@ package net.sf.jsqlparser.statement.alter; public enum AlterOperation { - ADD, ALTER, DROP, DROP_PRIMARY_KEY, DROP_UNIQUE, DROP_FOREIGN_KEY, MODIFY, CHANGE, ALGORITHM, RENAME, RENAME_TABLE, RENAME_INDEX, RENAME_KEY, RENAME_CONSTRAINT, COMMENT, COMMENT_WITH_EQUAL_SIGN, UNSPECIFIC, TRUNCATE_PARTITION; + ADD, ALTER, DROP, DROP_PRIMARY_KEY, DROP_UNIQUE, DROP_FOREIGN_KEY, MODIFY, CHANGE, CONVERT, COLLATE, ALGORITHM, RENAME, RENAME_TABLE, RENAME_INDEX, RENAME_KEY, RENAME_CONSTRAINT, COMMENT, COMMENT_WITH_EQUAL_SIGN, UNSPECIFIC, ADD_PARTITION, DROP_PARTITION, DISCARD_PARTITION, IMPORT_PARTITION, TRUNCATE_PARTITION, COALESCE_PARTITION, REORGANIZE_PARTITION, EXCHANGE_PARTITION, ANALYZE_PARTITION, CHECK_PARTITION, OPTIMIZE_PARTITION, REBUILD_PARTITION, REPAIR_PARTITION, REMOVE_PARTITIONING, PARTITION_BY, SET_TABLE_OPTION, ENGINE, FORCE, KEY_BLOCK_SIZE, LOCK, DISCARD_TABLESPACE, IMPORT_TABLESPACE, DISABLE_KEYS, ENABLE_KEYS, ENABLE_ROW_LEVEL_SECURITY, DISABLE_ROW_LEVEL_SECURITY, FORCE_ROW_LEVEL_SECURITY, NO_FORCE_ROW_LEVEL_SECURITY; public static AlterOperation from(String operation) { return Enum.valueOf(AlterOperation.class, operation.toUpperCase()); diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterSession.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterSession.java index 64c25ad94..e7e8308d9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterSession.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterSession.java @@ -11,15 +11,16 @@ package net.sf.jsqlparser.statement.alter; import java.util.List; + import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; /** - * * @author are - * @see ALTER SESSION + * @see ALTER + * SESSION */ -public class AlterSession implements Statement { +public class AlterSession implements Statement { private AlterSessionOperation operation; private List parameters; @@ -28,6 +29,12 @@ public AlterSession(AlterSessionOperation operation, List parameters) { this.parameters = parameters; } + private static void appendParameters(StringBuilder builder, List parameters) { + for (String s : parameters) { + builder.append(" ").append(s); + } + } + public AlterSessionOperation getOperation() { return operation; } @@ -43,15 +50,9 @@ public List getParameters() { public void setParameters(List parameters) { this.parameters = parameters; } - - private static void appendParamaters(StringBuilder builder, List parameters) { - for (String s: parameters) { - builder.append(" ").append(s); - } - } @Override - @SuppressWarnings({"PMD.ExcessiveMethodLength", "PMD.CyclomaticComplexity"}) + @SuppressWarnings({"PMD.ExcessiveMethodLength", "PMD.CyclomaticComplexity"}) public String toString() { StringBuilder builder = new StringBuilder(); builder.append("ALTER SESSION "); @@ -67,7 +68,7 @@ public String toString() { break; case CLOSE_DATABASE_LINK: builder.append("CLOSE DATABASE LINK "); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; case ENABLE_COMMIT_IN_PROCEDURE: builder.append("ENABLE COMMIT IN PROCEDURE"); @@ -81,72 +82,72 @@ public String toString() { case DISABLE_GUARD: builder.append("DISABLE GUARD"); break; - + case ENABLE_PARALLEL_DML: builder.append("ENABLE PARALLEL DML"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; - + case DISABLE_PARALLEL_DML: builder.append("DISABLE PARALLEL DML"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; - + case FORCE_PARALLEL_DML: builder.append("FORCE PARALLEL DML"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; - + case ENABLE_PARALLEL_DDL: builder.append("ENABLE PARALLEL DDL"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; - + case DISABLE_PARALLEL_DDL: builder.append("DISABLE PARALLEL DDL"); break; - + case FORCE_PARALLEL_DDL: builder.append("FORCE PARALLEL DDL"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; - + case ENABLE_PARALLEL_QUERY: builder.append("ENABLE PARALLEL QUERY"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; - + case DISABLE_PARALLEL_QUERY: builder.append("DISABLE PARALLEL QUERY"); break; - + case FORCE_PARALLEL_QUERY: builder.append("FORCE PARALLEL QUERY"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; - + case ENABLE_RESUMABLE: builder.append("ENABLE RESUMABLE"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; - + case DISABLE_RESUMABLE: builder.append("DISABLE RESUMABLE"); break; - + case SET: builder.append("SET"); - appendParamaters(builder, parameters); + appendParameters(builder, parameters); break; default: // not going to happen - + } return builder.toString(); } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterSessionOperation.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterSessionOperation.java index 1ab603d59..1b8e4ec2a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterSessionOperation.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterSessionOperation.java @@ -11,7 +11,6 @@ package net.sf.jsqlparser.statement.alter; /** - * * @author are */ public enum AlterSessionOperation { diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterSystemOperation.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterSystemOperation.java index 8cd08ba6b..e3a4dc553 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterSystemOperation.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterSystemOperation.java @@ -11,7 +11,6 @@ package net.sf.jsqlparser.statement.alter; /** - * * @author Andreas Reichel * @see ALTER * SESSION @@ -44,11 +43,6 @@ public enum AlterSystemOperation { this.label = label; } - @Override - public String toString() { - return label; - } - public static AlterSystemOperation from(String operation) { // We can't use Enum.valueOf() since there White Space involved for (AlterSystemOperation alterSystemOperation : values()) { @@ -58,4 +52,9 @@ public static AlterSystemOperation from(String operation) { } return null; } + + @Override + public String toString() { + return label; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterSystemStatement.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterSystemStatement.java index 15fef66f1..40ff46b06 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterSystemStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterSystemStatement.java @@ -11,13 +11,14 @@ import java.util.List; import java.util.Objects; + import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; /** - * * @author Andreas Reichel - * @see ALTER SESSION + * @see ALTER + * SESSION */ public class AlterSystemStatement implements Statement { @@ -25,8 +26,16 @@ public class AlterSystemStatement implements Statement { private final List parameters; public AlterSystemStatement(AlterSystemOperation operation, List parameters) { - this.operation = Objects.requireNonNull(operation, "The ALTER SYSTEM Operation must not be Null"); - this.parameters = Objects.requireNonNull(parameters, "The PARAMETERS List must not be null although it can be empty."); + this.operation = + Objects.requireNonNull(operation, "The ALTER SYSTEM Operation must not be Null"); + this.parameters = Objects.requireNonNull(parameters, + "The PARAMETERS List must not be null although it can be empty."); + } + + private static void appendParameters(StringBuilder builder, List parameters) { + for (String s : parameters) { + builder.append(" ").append(s); + } } public AlterSystemOperation getOperation() { @@ -36,24 +45,18 @@ public AlterSystemOperation getOperation() { public List getParameters() { return parameters; } - + @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); - } - - private static void appendParameters(StringBuilder builder, List parameters) { - for (String s: parameters) { - builder.append(" ").append(s); - } + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } - + public StringBuilder appendTo(StringBuilder builder) { builder.append("ALTER SYSTEM ").append(operation); appendParameters(builder, parameters); return builder; } - + @Override public String toString() { return appendTo(new StringBuilder()).toString(); diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/RenameTableStatement.java b/src/main/java/net/sf/jsqlparser/statement/alter/RenameTableStatement.java index c53806f28..94eb39be0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/RenameTableStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/RenameTableStatement.java @@ -15,48 +15,53 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Set; + import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; /** - * * @author are - * @see Rename + * @see Rename */ public class RenameTableStatement implements Statement { private final LinkedHashMap tableNames = new LinkedHashMap<>(); - + private boolean usingTableKeyword = false; private boolean usingIfExistsKeyword = false; - + private String waitDirective = ""; public RenameTableStatement(Table oldName, Table newName) { tableNames.put( - Objects.requireNonNull(oldName, "The OLD NAME of the Rename Statement must not be null.") - , Objects.requireNonNull(newName, "The NEW NAME of the Rename Statement must not be null.") - ); + Objects.requireNonNull(oldName, + "The OLD NAME of the Rename Statement must not be null."), + Objects.requireNonNull(newName, + "The NEW NAME of the Rename Statement must not be null.")); } - - public RenameTableStatement(Table oldName, Table newName, boolean usingTableKeyword, boolean usingIfExistsKeyword, String waitDirective) { + + public RenameTableStatement(Table oldName, Table newName, boolean usingTableKeyword, + boolean usingIfExistsKeyword, String waitDirective) { tableNames.put( - Objects.requireNonNull(oldName, "The OLD NAME of the Rename Statement must not be null.") - , Objects.requireNonNull(newName, "The NEW NAME of the Rename Statement must not be null.") - ); - + Objects.requireNonNull(oldName, + "The OLD NAME of the Rename Statement must not be null."), + Objects.requireNonNull(newName, + "The NEW NAME of the Rename Statement must not be null.")); + this.usingTableKeyword = usingTableKeyword; this.usingIfExistsKeyword = usingIfExistsKeyword; this.waitDirective = waitDirective; } - + public void addTableNames(Table oldName, Table newName) { tableNames.put( - Objects.requireNonNull(oldName, "The OLD NAME of the Rename Statement must not be null.") - , Objects.requireNonNull(newName, "The NEW NAME of the Rename Statement must not be null.") - ); + Objects.requireNonNull(oldName, + "The OLD NAME of the Rename Statement must not be null."), + Objects.requireNonNull(newName, + "The NEW NAME of the Rename Statement must not be null.")); } - + public boolean isUsingTableKeyword() { return usingTableKeyword; @@ -65,7 +70,7 @@ public boolean isUsingTableKeyword() { public void setUsingTableKeyword(boolean usingTableKeyword) { this.usingTableKeyword = usingTableKeyword; } - + public RenameTableStatement withUsingTableKeyword(boolean usingTableKeyword) { this.usingTableKeyword = usingTableKeyword; return this; @@ -78,7 +83,7 @@ public boolean isUsingIfExistsKeyword() { public void setUsingIfExistsKeyword(boolean usingIfExistsKeyword) { this.usingIfExistsKeyword = usingIfExistsKeyword; } - + public RenameTableStatement withUsingIfExistsKeyword(boolean usingIfExistsKeyword) { this.usingIfExistsKeyword = usingIfExistsKeyword; return this; @@ -91,7 +96,7 @@ public String getWaitDirective() { public void setWaitDirective(String waitDirective) { this.waitDirective = waitDirective; } - + public RenameTableStatement withWaitDirective(String waitDirective) { this.waitDirective = waitDirective; return this; @@ -108,32 +113,34 @@ public boolean isTableNamesEmpty() { public Set> getTableNames() { return tableNames.entrySet(); } - + @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); - } - + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + public StringBuilder appendTo(StringBuilder builder) { - int i=0; + int i = 0; for (Entry e : tableNames.entrySet()) { - if (i==0) { + if (i == 0) { builder - .append("RENAME") - .append(usingTableKeyword ? " TABLE " : " ") - .append(usingIfExistsKeyword ? " IF EXISTS " : " ") - .append(e.getKey()) - .append(waitDirective!=null && waitDirective.length()>0 ? " " + waitDirective : "") - .append(" TO ") - .append(e.getValue()); + .append("RENAME") + .append(usingTableKeyword ? " TABLE " : " ") + .append(usingIfExistsKeyword ? " IF EXISTS " : " ") + .append(e.getKey()) + .append(waitDirective != null && waitDirective.length() > 0 + ? " " + waitDirective + : "") + .append(" TO ") + .append(e.getValue()); } else { builder - .append(", ") - .append(e.getKey()) - .append(" TO ") - .append(e.getValue()); + .append(", ") + .append(e.getKey()) + .append(" TO ") + .append(e.getValue()); } - + i++; } return builder; diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/sequence/AlterSequence.java b/src/main/java/net/sf/jsqlparser/statement/alter/sequence/AlterSequence.java index cd994717b..a9869f8ed 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/sequence/AlterSequence.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/sequence/AlterSequence.java @@ -20,17 +20,17 @@ public class AlterSequence implements Statement { public Sequence sequence; - public void setSequence(Sequence sequence) { - this.sequence = sequence; - } - public Sequence getSequence() { return sequence; } + public void setSequence(Sequence sequence) { + this.sequence = sequence; + } + @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java b/src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java index 35373ae09..ab25cf3b4 100644 --- a/src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java +++ b/src/main/java/net/sf/jsqlparser/statement/analyze/Analyze.java @@ -18,8 +18,8 @@ public class Analyze implements Statement { private Table table; @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Table getTable() { diff --git a/src/main/java/net/sf/jsqlparser/statement/comment/Comment.java b/src/main/java/net/sf/jsqlparser/statement/comment/Comment.java index 23942a889..d213aac6b 100755 --- a/src/main/java/net/sf/jsqlparser/statement/comment/Comment.java +++ b/src/main/java/net/sf/jsqlparser/statement/comment/Comment.java @@ -23,8 +23,8 @@ public class Comment implements Statement { private StringValue comment; @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Table getTable() { diff --git a/src/main/java/net/sf/jsqlparser/statement/create/function/CreateFunction.java b/src/main/java/net/sf/jsqlparser/statement/create/function/CreateFunction.java index b5e1c68a1..ac20c0e3a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/function/CreateFunction.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/function/CreateFunction.java @@ -26,7 +26,7 @@ public CreateFunction() { public CreateFunction(List functionDeclarationParts) { this(false, functionDeclarationParts); } - + public CreateFunction(boolean orReplace, List functionDeclarationParts) { super(orReplace, "FUNCTION", functionDeclarationParts); } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java b/src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java index 3fc4fcbf1..0da992dd6 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java @@ -22,6 +22,7 @@ public class CreateIndex implements Statement { private Index index; private List tailParameters; private boolean indexTypeBeforeOn = false; + private boolean usingIfNotExists = false; public boolean isIndexTypeBeforeOn() { return indexTypeBeforeOn; @@ -40,11 +41,9 @@ public CreateIndex setUsingIfNotExists(boolean usingIfNotExists) { return this; } - private boolean usingIfNotExists = false; - @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Index getIndex() { @@ -106,9 +105,7 @@ public String toString() { buffer.append( index.getColumns().stream() - .map(cp -> cp.columnName + (cp.getParams() != null - ? " " + String.join(" ", cp.getParams()) - : "")) + .map(Index.ColumnParams::toString) .collect(joining(", "))); buffer.append(")"); diff --git a/src/main/java/net/sf/jsqlparser/statement/create/policy/CreatePolicy.java b/src/main/java/net/sf/jsqlparser/statement/create/policy/CreatePolicy.java new file mode 100644 index 000000000..7c11636aa --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/create/policy/CreatePolicy.java @@ -0,0 +1,131 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.create.policy; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +import java.util.ArrayList; +import java.util.List; + +/** + * PostgreSQL CREATE POLICY statement for Row Level Security (RLS). + * + * Syntax: CREATE POLICY name ON table_name [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ] [ TO + * { role_name | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ] [ USING ( using_expression ) ] [ + * WITH CHECK ( check_expression ) ] + */ +public class CreatePolicy implements Statement { + + private String policyName; + private Table table; + private String command; // ALL, SELECT, INSERT, UPDATE, DELETE + private List roles = new ArrayList<>(); + private Expression usingExpression; + private Expression withCheckExpression; + + public String getPolicyName() { + return policyName; + } + + public CreatePolicy setPolicyName(String policyName) { + this.policyName = policyName; + return this; + } + + public Table getTable() { + return table; + } + + public CreatePolicy setTable(Table table) { + this.table = table; + return this; + } + + public String getCommand() { + return command; + } + + public CreatePolicy setCommand(String command) { + this.command = command; + return this; + } + + public List getRoles() { + return roles; + } + + public CreatePolicy setRoles(List roles) { + this.roles = roles; + return this; + } + + public CreatePolicy addRole(String role) { + this.roles.add(role); + return this; + } + + public Expression getUsingExpression() { + return usingExpression; + } + + public CreatePolicy setUsingExpression(Expression usingExpression) { + this.usingExpression = usingExpression; + return this; + } + + public Expression getWithCheckExpression() { + return withCheckExpression; + } + + public CreatePolicy setWithCheckExpression(Expression withCheckExpression) { + this.withCheckExpression = withCheckExpression; + return this; + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("CREATE POLICY "); + builder.append(policyName); + builder.append(" ON "); + builder.append(table.toString()); + + if (command != null) { + builder.append(" FOR ").append(command); + } + + if (roles != null && !roles.isEmpty()) { + builder.append(" TO "); + for (int i = 0; i < roles.size(); i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(roles.get(i)); + } + } + + if (usingExpression != null) { + builder.append(" USING (").append(usingExpression.toString()).append(")"); + } + + if (withCheckExpression != null) { + builder.append(" WITH CHECK (").append(withCheckExpression.toString()).append(")"); + } + + return builder.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/procedure/CreateProcedure.java b/src/main/java/net/sf/jsqlparser/statement/create/procedure/CreateProcedure.java index 047f46718..77b385148 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/procedure/CreateProcedure.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/procedure/CreateProcedure.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.List; + import net.sf.jsqlparser.statement.CreateFunctionalStatement; /** @@ -41,7 +42,8 @@ public CreateProcedure addFunctionDeclarationParts(String... functionDeclaration } @Override - public CreateProcedure addFunctionDeclarationParts(Collection functionDeclarationParts) { + public CreateProcedure addFunctionDeclarationParts( + Collection functionDeclarationParts) { return (CreateProcedure) super.addFunctionDeclarationParts(functionDeclarationParts); } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java b/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java index 7832f291e..e972c9c30 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java @@ -14,19 +14,22 @@ import java.util.Collections; import java.util.List; import java.util.Optional; + import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; public class CreateSchema implements Statement { private String authorization; + private String catalogName = null; private String schemaName; private List schemaPath; private List statements = new ArrayList<>(); + private boolean hasIfNotExists = false; @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } /** @@ -34,7 +37,6 @@ public void accept(StatementVisitor statementVisitor) { * * @param statement The statement to be added * @return true if the operation was successful - * */ public boolean addStatement(Statement statement) { return statements.add(statement); @@ -44,75 +46,95 @@ public boolean addStatement(Statement statement) { * The owner of the schema. * * @return Owner name - * */ public String getAuthorization() { return authorization; } /** - * The name of the schema + * The owner of the schems. * - * @return Schema name + * @param authorization Owner name */ - public String getSchemaName() { - return schemaName; + public void setAuthorization(String authorization) { + this.authorization = authorization; } - /** - * The path of the schema - * - * @return Schema path - * - */ - public List getSchemaPath() { - return schemaPath; + public String getCatalogName() { + return catalogName; } - /** - * The statements executed as part of the schema creation - * - * @return the statements - * - */ - public List getStatements() { - return statements; + public CreateSchema setCatalogName(String catalogName) { + this.catalogName = catalogName; + return this; } /** - * The owner of the schems. - * - * @param authorization Owner name + * The name of the schema * + * @return Schema name */ - public void setAuthorization(String authorization) { - this.authorization = authorization; + public String getSchemaName() { + return schemaName; } /** * Set the name of the schema * * @param schemaName Schema name - * */ public void setSchemaName(String schemaName) { this.schemaName = schemaName; } + /** + * The path of the schema + * + * @return Schema path + */ + public List getSchemaPath() { + return schemaPath; + } + /** * Set the path of the schema * * @param schemaPath Schema path - * */ public void setSchemaPath(List schemaPath) { this.schemaPath = schemaPath; } + /** + * The statements executed as part of the schema creation + * + * @return the statements + */ + public List getStatements() { + return statements; + } + + public boolean hasIfNotExists() { + return hasIfNotExists; + } + + public CreateSchema setIfNotExists(boolean hasIfNotExists) { + this.hasIfNotExists = hasIfNotExists; + return this; + } + public String toString() { String sql = "CREATE SCHEMA"; + if (hasIfNotExists) { + sql += " IF NOT EXISTS"; + } if (schemaName != null) { - sql += " " + schemaName; + sql += " "; + + if (catalogName!=null) { + sql += catalogName + "."; + } + sql += schemaName; } if (authorization != null) { sql += " AUTHORIZATION " + authorization; diff --git a/src/main/java/net/sf/jsqlparser/statement/create/sequence/CreateSequence.java b/src/main/java/net/sf/jsqlparser/statement/create/sequence/CreateSequence.java index ba21a04b1..0d1c2b7f7 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/sequence/CreateSequence.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/sequence/CreateSequence.java @@ -1,47 +1,47 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2020 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.statement.create.sequence; - -import net.sf.jsqlparser.schema.Sequence; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.StatementVisitor; - -/** - * A {@code CREATE SEQUENCE} statement - */ -public class CreateSequence implements Statement { - - public Sequence sequence; - - public void setSequence(Sequence sequence) { - this.sequence = sequence; - } - - public Sequence getSequence() { - return sequence; - } - - @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); - } - - @Override - public String toString() { - String sql; - sql = "CREATE SEQUENCE " + sequence; - return sql; - } - - public CreateSequence withSequence(Sequence sequence) { - this.setSequence(sequence); - return this; - } -} +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.create.sequence; + +import net.sf.jsqlparser.schema.Sequence; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +/** + * A {@code CREATE SEQUENCE} statement + */ +public class CreateSequence implements Statement { + + public Sequence sequence; + + public Sequence getSequence() { + return sequence; + } + + public void setSequence(Sequence sequence) { + this.sequence = sequence; + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public String toString() { + String sql; + sql = "CREATE SEQUENCE " + sequence; + return sql; + } + + public CreateSequence withSequence(Sequence sequence) { + this.setSequence(sequence); + return this; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/synonym/CreateSynonym.java b/src/main/java/net/sf/jsqlparser/statement/create/synonym/CreateSynonym.java index 3528bc60c..ac7eb2640 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/synonym/CreateSynonym.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/synonym/CreateSynonym.java @@ -18,19 +18,19 @@ public class CreateSynonym implements Statement { + public Synonym synonym; private boolean orReplace; private boolean publicSynonym; - public Synonym synonym; private List forList = new ArrayList<>(); - public void setSynonym(Synonym synonym) { - this.synonym = synonym; - } - public Synonym getSynonym() { return synonym; } + public void setSynonym(Synonym synonym) { + this.synonym = synonym; + } + public boolean isOrReplace() { return orReplace; } @@ -47,14 +47,14 @@ public void setPublicSynonym(boolean publicSynonym) { this.publicSynonym = publicSynonym; } - public void setForList(List forList) { - this.forList = forList; - } - public List getForList() { return forList; } + public void setForList(List forList) { + this.forList = forList; + } + public String getFor() { StringBuilder b = new StringBuilder(); for (String name : forList) { @@ -67,8 +67,8 @@ public String getFor() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/CheckConstraint.java b/src/main/java/net/sf/jsqlparser/statement/create/table/CheckConstraint.java index 21a3e5384..254fb3d01 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/CheckConstraint.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/CheckConstraint.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.List; + import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.schema.Table; @@ -38,7 +39,12 @@ public void setExpression(Expression expression) { @Override public String toString() { - return "CONSTRAINT " + getName() + " CHECK (" + expression + ")"; + StringBuilder b = new StringBuilder(); + if (getName() != null) { + b.append("CONSTRAINT ").append(getName()).append(" "); + } + b.append("CHECK (").append(expression).append(")"); + return b.toString(); } public CheckConstraint withTable(Table table) { @@ -100,4 +106,8 @@ public CheckConstraint withIndexSpec(List idxSpec) { return (CheckConstraint) super.withIndexSpec(idxSpec); } + @Override + public CheckConstraint withIndexKeyword(String indexKeyword) { + return (CheckConstraint) super.withIndexKeyword(indexKeyword); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/ColDataType.java b/src/main/java/net/sf/jsqlparser/statement/create/table/ColDataType.java index 4e63dd829..b7b7a9ae9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/ColDataType.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/ColDataType.java @@ -52,14 +52,14 @@ public List getArgumentsStringList() { return argumentsStringList; } - public String getDataType() { - return dataType; - } - public void setArgumentsStringList(List list) { argumentsStringList = list; } + public String getDataType() { + return dataType; + } + public void setDataType(String string) { dataType = string; } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java index 90a0e0e40..a7f47104c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java @@ -9,6 +9,7 @@ */ package net.sf.jsqlparser.statement.create.table; +import net.sf.jsqlparser.statement.imprt.ImportColumn; import net.sf.jsqlparser.statement.select.PlainSelect; import java.io.Serializable; @@ -21,7 +22,7 @@ /** * Globally used definition class for columns. */ -public class ColumnDefinition implements Serializable { +public class ColumnDefinition implements ImportColumn, Serializable { private String columnName; private ColDataType colDataType; diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/CreateTable.java b/src/main/java/net/sf/jsqlparser/statement/create/table/CreateTable.java index d3793589e..d2be0e026 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/CreateTable.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/CreateTable.java @@ -42,8 +42,8 @@ public class CreateTable implements Statement { private SpannerInterleaveIn interleaveIn = null; @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Table getTable() { @@ -78,11 +78,12 @@ public List getColumns() { } public void setColumns(List columns) { - this.columns =columns; + this.columns = columns; } /** - * @return a list of options (as simple strings) of this table definition, as ("TYPE", "=", "MYISAM") + * @return a list of options (as simple strings) of this table definition, as ("TYPE", "=", + * "MYISAM") */ public List getTableOptionsStrings() { return tableOptionsStrings; @@ -102,8 +103,8 @@ public void setCreateOptionsStrings(List createOptionsStrings) { /** * @return a list of {@link Index}es (for example "PRIMARY KEY") of this table.
- * Indexes created with column definitions (as in mycol INT PRIMARY KEY) are not inserted into - * this list. + * Indexes created with column definitions (as in mycol INT PRIMARY KEY) are not + * inserted into this list. */ public List getIndexes() { return indexes; @@ -166,46 +167,84 @@ public void setRowMovement(RowMovement rowMovement) { @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public String toString() { - String sql; + StringBuilder b = new StringBuilder(); + appendCreateClause(b); + appendColumnDefinitions(b); + appendTableOptions(b); + appendTableProperties(b); + return b.toString(); + } + + private void appendCreateClause(StringBuilder b) { String createOps = PlainSelect.getStringList(createOptionsStrings, false, false); - sql = "CREATE " + (unlogged ? "UNLOGGED " : "") - + (!"".equals(createOps) ? createOps + " " : "") - + (orReplace ? "OR REPLACE " : "") - + "TABLE " + (ifNotExists ? "IF NOT EXISTS " : "") + table; + b.append("CREATE "); + if (unlogged) { + b.append("UNLOGGED "); + } + if (!"".equals(createOps)) { + b.append(createOps).append(" "); + } + if (orReplace) { + b.append("OR REPLACE "); + } + b.append("TABLE "); + if (ifNotExists) { + b.append("IF NOT EXISTS "); + } + b.append(table); + } + private void appendColumnDefinitions(StringBuilder b) { if (columns != null && !columns.isEmpty()) { - sql += " "; - sql += PlainSelect.getStringList(columns, true, true); + b.append(" "); + b.append(PlainSelect.getStringList(columns, true, true)); } if (columnDefinitions != null && !columnDefinitions.isEmpty()) { - sql += " ("; - - sql += PlainSelect.getStringList(columnDefinitions, true, false); + b.append(" ("); + b.append(PlainSelect.getStringList(columnDefinitions, true, false)); if (indexes != null && !indexes.isEmpty()) { - sql += ", "; - sql += PlainSelect.getStringList(indexes); + b.append(", "); + b.append(PlainSelect.getStringList(indexes)); } - sql += ")"; + b.append(")"); } + } + + private void appendTableOptions(StringBuilder b) { String options = PlainSelect.getStringList(tableOptionsStrings, false, false); if (options != null && options.length() > 0) { - sql += " " + options; + b.append(" ").append(options); } + } + private void appendTableProperties(StringBuilder b) { if (rowMovement != null) { - sql += " " + rowMovement.getMode().toString() + " ROW MOVEMENT"; + b.append(" ").append(rowMovement.getMode()).append(" ROW MOVEMENT"); } if (select != null) { - sql += " AS " + (selectParenthesis ? "(" : "") + select.toString() + (selectParenthesis ? ")" : ""); + b.append(" AS "); + if (selectParenthesis) { + b.append("("); + } + b.append(select); + if (selectParenthesis) { + b.append(")"); + } } if (likeTable != null) { - sql += " LIKE " + (selectParenthesis ? "(" : "") + likeTable.toString() + (selectParenthesis ? ")" : ""); + b.append(" LIKE "); + if (selectParenthesis) { + b.append("("); + } + b.append(likeTable); + if (selectParenthesis) { + b.append(")"); + } } if (interleaveIn != null) { - sql += ", " + interleaveIn; + b.append(", ").append(interleaveIn); } - return sql; } public CreateTable withTable(Table table) { @@ -259,25 +298,30 @@ public CreateTable withIndexes(List indexes) { } public CreateTable addCreateOptionsStrings(String... createOptionsStrings) { - List collection = Optional.ofNullable(getCreateOptionsStrings()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getCreateOptionsStrings()).orElseGet(ArrayList::new); Collections.addAll(collection, createOptionsStrings); return this.withCreateOptionsStrings(collection); } public CreateTable addCreateOptionsStrings(Collection createOptionsStrings) { - List collection = Optional.ofNullable(getCreateOptionsStrings()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getCreateOptionsStrings()).orElseGet(ArrayList::new); collection.addAll(createOptionsStrings); return this.withCreateOptionsStrings(collection); } public CreateTable addColumnDefinitions(ColumnDefinition... columnDefinitions) { - List collection = Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); + List collection = + Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); Collections.addAll(collection, columnDefinitions); return this.withColumnDefinitions(collection); } - public CreateTable addColumnDefinitions(Collection columnDefinitions) { - List collection = Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); + public CreateTable addColumnDefinitions( + Collection columnDefinitions) { + List collection = + Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); collection.addAll(columnDefinitions); return this.withColumnDefinitions(collection); } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/ExcludeConstraint.java b/src/main/java/net/sf/jsqlparser/statement/create/table/ExcludeConstraint.java index cbae5035a..4cdc37bc4 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/ExcludeConstraint.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/ExcludeConstraint.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.List; + import net.sf.jsqlparser.expression.Expression; public class ExcludeConstraint extends Index { @@ -74,7 +75,8 @@ public ExcludeConstraint addColumns(ColumnParams... functionDeclarationParts) { } @Override - public ExcludeConstraint addColumns(Collection functionDeclarationParts) { + public ExcludeConstraint addColumns( + Collection functionDeclarationParts) { return (ExcludeConstraint) super.addColumns(functionDeclarationParts); } @@ -88,4 +90,8 @@ public ExcludeConstraint withName(String name) { return (ExcludeConstraint) super.withName(name); } + @Override + public ExcludeConstraint withIndexKeyword(String indexKeyword) { + return (ExcludeConstraint) super.withIndexKeyword(indexKeyword); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/ForeignKeyIndex.java b/src/main/java/net/sf/jsqlparser/statement/create/table/ForeignKeyIndex.java index eb9f20c4b..c877a1ad9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/ForeignKeyIndex.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/ForeignKeyIndex.java @@ -204,4 +204,8 @@ public ForeignKeyIndex withIndexSpec(List idxSpec) { return (ForeignKeyIndex) super.withIndexSpec(idxSpec); } + @Override + public ForeignKeyIndex withIndexKeyword(String indexKeyword) { + return (ForeignKeyIndex) super.withIndexKeyword(indexKeyword); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java b/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java index 720fa1abe..114b30d14 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java @@ -17,23 +17,33 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.statement.select.PlainSelect; public class Index implements Serializable { + private final List name = new ArrayList<>(); private String type; private String using; private List columns; - private final List name = new ArrayList<>(); private List idxSpec; private String commentText; + private String indexKeyword; public List getColumnsNames() { return columns.stream() - .map(col -> col.columnName) + .map(ColumnParams::getColumnName) .collect(toList()); } + public void setColumnsNames(List list) { + if (list == null) { + this.columns = Collections.emptyList(); + } else { + this.columns = list.stream().map(ColumnParams::new).collect(toList()); + } + } + @Deprecated public List getColumnWithParams() { return getColumns(); @@ -73,6 +83,18 @@ public String getName() { return name.isEmpty() ? null : String.join(".", name); } + public void setName(String name) { + this.name.clear(); + if (name != null) { + this.name.add(name); + } + } + + public void setName(List name) { + this.name.clear(); + this.name.addAll(name); + } + public List getNameParts() { return Collections.unmodifiableList(name); } @@ -81,19 +103,8 @@ public String getType() { return type; } - /** - * In postgresql, the index type (Btree, GIST, etc.) is indicated with a USING clause. Please - * note that: Oracle - the type might be BITMAP, indicating a bitmap kind of index MySQL - the - * type might be FULLTEXT or SPATIAL - * - * @param using - */ - public void setUsing(String using) { - this.using = using; - } - - public void setColumnsNames(List list) { - columns = list.stream().map(ColumnParams::new).collect(toList()); + public void setType(String string) { + type = string; } public Index withColumnsNames(List list) { @@ -101,24 +112,21 @@ public Index withColumnsNames(List list) { return this; } - public void setName(String name) { - this.name.clear(); - this.name.add(name); - } - - public void setName(List name) { - this.name.clear(); - this.name.addAll(name); - } - - public void setType(String string) { - type = string; - } - public String getUsing() { return using; } + /** + * In postgresql, the index type (Btree, GIST, etc.) is indicated with a USING clause. Please + * note that: Oracle - the type might be BITMAP, indicating a bitmap kind of index MySQL - the + * type might be FULLTEXT or SPATIAL + * + * @param using + */ + public void setUsing(String using) { + this.using = using; + } + public List getIndexSpec() { return idxSpec; } @@ -132,18 +140,35 @@ public Index withIndexSpec(List idxSpec) { return this; } + public void setIndexKeyword(String indexKeyword) { + this.indexKeyword = indexKeyword; + } + + public String getIndexKeyword() { + return indexKeyword; + } + + public Index withIndexKeyword(String indexKeyword) { + this.setIndexKeyword(indexKeyword); + return this; + } + @Override public String toString() { String idxSpecText = PlainSelect.getStringList(idxSpec, false, false); - String head = (type != null ? type : "") + (!name.isEmpty() ? " " + getName() : ""); - String tail = PlainSelect.getStringList(columns, true, true) - + (!"".equals(idxSpecText) ? " " + idxSpecText : ""); + String keyword = (indexKeyword != null) ? " " + indexKeyword : ""; + String head = + (type != null ? type : "") + + keyword + + (!name.isEmpty() ? " " + getName() : "") + + (using != null ? " USING " + using : ""); - if ("".equals(tail)) { - return head; - } + String tail = (columns != null && !columns.isEmpty() + ? PlainSelect.getStringList(columns, true, true) + : "") + + (!idxSpecText.isEmpty() ? " " + idxSpecText : ""); - return head + " " + tail; + return tail.isEmpty() ? head : head + " " + tail; } public Index withType(String type) { @@ -166,39 +191,63 @@ public Index withName(String name) { return this; } + public String getCommentText() { + return commentText; + } + + public void setCommentText(String commentText) { + this.commentText = commentText; + } + public static class ColumnParams implements Serializable { public final String columnName; public final List params; + private final Expression expression; public ColumnParams(String columnName) { this.columnName = columnName; this.params = null; + this.expression = null; } public ColumnParams(String columnName, List params) { this.columnName = columnName; this.params = params; + this.expression = null; + } + + public ColumnParams(Expression expression) { + this.columnName = null; + this.params = null; + this.expression = expression; + } + + public ColumnParams(Expression expression, List params) { + this.columnName = null; + this.params = params; + this.expression = expression; } public String getColumnName() { - return columnName; + return expression != null ? expression.toString() : columnName; } public List getParams() { return params; } - @Override - public String toString() { - return columnName + (params != null ? " " + String.join(" ", params) : ""); + public Expression getExpression() { + return expression; } - } - public String getCommentText() { - return commentText; - } + public boolean isExpression() { + return expression != null; + } - public void setCommentText(String commentText) { - this.commentText = commentText; + @Override + public String toString() { + String head = expression != null ? "(" + expression + ")" : columnName; + return head + (params != null ? " " + String.join(" ", params) : ""); + } } } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/NamedConstraint.java b/src/main/java/net/sf/jsqlparser/statement/create/table/NamedConstraint.java index f9a7f391d..ee2cce33b 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/NamedConstraint.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/NamedConstraint.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.List; + import net.sf.jsqlparser.statement.select.PlainSelect; public class NamedConstraint extends Index { @@ -69,4 +70,8 @@ public NamedConstraint withIndexSpec(List idxSpec) { return (NamedConstraint) super.withIndexSpec(idxSpec); } + @Override + public NamedConstraint withIndexKeyword(String indexKeyword) { + return (NamedConstraint) super.withIndexKeyword(indexKeyword); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/PartitionDefinition.java b/src/main/java/net/sf/jsqlparser/statement/create/table/PartitionDefinition.java new file mode 100644 index 000000000..24d15dfd0 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/PartitionDefinition.java @@ -0,0 +1,74 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.create.table; + +import java.io.Serializable; +import java.util.List; +import net.sf.jsqlparser.statement.select.PlainSelect; + +public class PartitionDefinition implements Serializable { + private String partitionName; + private String partitionOperation; + private List values; + private String storageEngine; + + public PartitionDefinition(String partitionName, String partitionOperation, + List values, String storageEngine) { + this.partitionName = partitionName; + this.partitionOperation = partitionOperation; + this.values = values; + this.storageEngine = storageEngine; + } + + public String getPartitionName() { + return partitionName; + } + + public void setPartitionName(String partitionName) { + this.partitionName = partitionName; + } + + public String getPartitionOperation() { + return partitionOperation; + } + + public void setPartitionOperation(String partitionOperation) { + this.partitionOperation = partitionOperation; + } + + public List getValues() { + return values; + } + + public void setValues(List values) { + this.values = values; + } + + public String getStorageEngine() { + return storageEngine; + } + + public void setStorageEngine(String storageEngine) { + this.storageEngine = storageEngine; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + b.append("PARTITION ").append(partitionName) + .append(" ").append(partitionOperation) + .append(" (").append(PlainSelect.getStringList(values)) + .append(")"); + if (storageEngine != null) { + b.append(" ENGINE = ").append(storageEngine); + } + return b.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/RowMovement.java b/src/main/java/net/sf/jsqlparser/statement/create/table/RowMovement.java index a9934dcdf..cf6bbe248 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/RowMovement.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/RowMovement.java @@ -12,7 +12,8 @@ import java.io.Serializable; /** - * Holds data for the {@code row_movement} clause: https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_7002.htm#i2204697 + * Holds data for the {@code row_movement} clause: + * https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_7002.htm#i2204697 */ public class RowMovement implements Serializable { diff --git a/src/main/java/net/sf/jsqlparser/statement/create/view/AlterView.java b/src/main/java/net/sf/jsqlparser/statement/create/view/AlterView.java index 8d43aab3e..079f70bd3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/view/AlterView.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/view/AlterView.java @@ -28,11 +28,6 @@ public class AlterView implements Statement { private boolean useReplace = false; private List columnNames = null; - @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); - } - public Table getView() { return view; } @@ -117,4 +112,9 @@ public AlterView addColumnNames(Collection columnNames) { public E getSelectBody(Class type) { return type.cast(getSelect()); } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java b/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java index 034902cca..0d7679743 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.create.view; import java.util.List; + import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; @@ -34,8 +35,8 @@ public class CreateView implements Statement { private List viewCommentOptions = null; @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Table getView() { diff --git a/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java b/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java index 3e5c171a3..4e0f45ffe 100644 --- a/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java +++ b/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java @@ -11,11 +11,13 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.OracleHint; +import net.sf.jsqlparser.expression.PreferringClause; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.OutputClause; import net.sf.jsqlparser.statement.ReturningClause; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.select.FromItem; import net.sf.jsqlparser.statement.select.Join; import net.sf.jsqlparser.statement.select.Limit; import net.sf.jsqlparser.statement.select.OrderByElement; @@ -28,18 +30,20 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static java.util.stream.Collectors.joining; public class Delete implements Statement { - private List withItemsList; + private List> withItemsList; private Table table; private OracleHint oracleHint = null; private List tables; - private List
usingList; + private List usingFromItemList; private List joins; private Expression where; + private PreferringClause preferringClause; private Limit limit; private List orderByElements; private boolean hasFrom = true; @@ -67,28 +71,28 @@ public Delete setReturningClause(ReturningClause returningClause) { return this; } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } - public Delete withWithItemsList(List withItemsList) { + public Delete withWithItemsList(List> withItemsList) { this.setWithItemsList(withItemsList); return this; } - public Delete addWithItemsList(WithItem... withItemsList) { - List collection = + public Delete addWithItemsList(WithItem... withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); Collections.addAll(collection, withItemsList); return this.withWithItemsList(collection); } - public Delete addWithItemsList(Collection withItemsList) { - List collection = + public Delete addWithItemsList(Collection> withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); collection.addAll(withItemsList); return this.withWithItemsList(collection); @@ -103,26 +107,34 @@ public void setOrderByElements(List orderByElements) { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Table getTable() { return table; } - public Expression getWhere() { - return where; - } - public void setTable(Table name) { table = name; } + public Expression getWhere() { + return where; + } + public void setWhere(Expression expression) { where = expression; } + public PreferringClause getPreferringClause() { + return preferringClause; + } + + public void setPreferringClause(PreferringClause preferringClause) { + this.preferringClause = preferringClause; + } + public OracleHint getOracleHint() { return oracleHint; } @@ -147,12 +159,29 @@ public void setTables(List
tables) { this.tables = tables; } + /** + * This is compatible with the old logic. When calling this method, you need to ensure that the + * specific table is used after using. + * + * @return Table collection used in using. + */ + @Deprecated public List
getUsingList() { - return usingList; + if (usingFromItemList == null || usingFromItemList.isEmpty()) { + return new ArrayList<>(); + } + return usingFromItemList.stream().map(ele -> (Table) ele).collect(Collectors.toList()); } + /** + * This is compatible with the old logic. When calling this method, you need to ensure that the + * specific table is used after using. + * + * @param usingList Table collection used in using. + */ + @Deprecated public void setUsingList(List
usingList) { - this.usingList = usingList; + this.usingFromItemList = new ArrayList<>(usingList); } public List getJoins() { @@ -177,8 +206,8 @@ public String toString() { StringBuilder b = new StringBuilder(); if (withItemsList != null && !withItemsList.isEmpty()) { b.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); b.append(withItem); if (iter.hasNext()) { b.append(","); @@ -218,10 +247,10 @@ public String toString() { } b.append(" ").append(table); - if (usingList != null && usingList.size() > 0) { + if (usingFromItemList != null && !usingFromItemList.isEmpty()) { b.append(" USING "); - b.append(usingList.stream() - .map(Table::toString) + b.append(usingFromItemList.stream() + .map(Object::toString) .collect(joining(", "))); } @@ -239,6 +268,10 @@ public String toString() { b.append(" WHERE ").append(where); } + if (preferringClause != null) { + b.append(" ").append(preferringClause); + } + if (orderByElements != null) { b.append(PlainSelect.orderByToString(orderByElements)); } @@ -259,11 +292,30 @@ public Delete withTables(List
tables) { return this; } + /** + * The old method has been replaced by withUsingFromItemList. + * + * @param usingList + * @return + * @see Delete#withUsingFromItemList + */ + @Deprecated public Delete withUsingList(List
usingList) { this.setUsingList(usingList); return this; } + /** + * New using syntax method.Supports the complete using syntax of pg, such as subqueries, etc. + * + * @param usingFromItemList + * @return + */ + public Delete withUsingFromItemList(List usingFromItemList) { + this.setUsingFromItemList(usingFromItemList); + return this; + } + public Delete withJoins(List joins) { this.setJoins(joins); return this; @@ -289,6 +341,11 @@ public Delete withWhere(Expression where) { return this; } + public Delete withPreferringClause(PreferringClause preferringClause) { + this.setPreferringClause(preferringClause); + return this; + } + public Delete withHasFrom(boolean hasFrom) { this.setHasFrom(hasFrom); return this; @@ -309,30 +366,30 @@ public Delete withModifierQuick(boolean modifierQuick) { return this; } - public void setModifierPriority(DeleteModifierPriority modifierPriority) { - this.modifierPriority = modifierPriority; - } - public DeleteModifierPriority getModifierPriority() { return modifierPriority; } - public void setModifierIgnore(boolean modifierIgnore) { - this.modifierIgnore = modifierIgnore; - } - - public void setModifierQuick(boolean modifierQuick) { - this.modifierQuick = modifierQuick; + public void setModifierPriority(DeleteModifierPriority modifierPriority) { + this.modifierPriority = modifierPriority; } public boolean isModifierIgnore() { return modifierIgnore; } + public void setModifierIgnore(boolean modifierIgnore) { + this.modifierIgnore = modifierIgnore; + } + public boolean isModifierQuick() { return modifierQuick; } + public void setModifierQuick(boolean modifierQuick) { + this.modifierQuick = modifierQuick; + } + public Delete addTables(Table... tables) { List
collection = Optional.ofNullable(getTables()).orElseGet(ArrayList::new); Collections.addAll(collection, tables); @@ -345,18 +402,60 @@ public Delete addTables(Collection tables) { return this.withTables(collection); } + /** + * The old method has been replaced by addUsingFromItemList. + * + * @param usingList + * @return + * @see Delete#addUsingFromItemList + */ + @Deprecated public Delete addUsingList(Table... usingList) { List
collection = Optional.ofNullable(getUsingList()).orElseGet(ArrayList::new); Collections.addAll(collection, usingList); return this.withUsingList(collection); } + /** + * New using syntax method.Supports the complete using syntax of pg, such as subqueries, etc. + * + * @param usingFromItemList + * @return + */ + public Delete addUsingFromItemList(FromItem... usingFromItemList) { + List collection = + Optional.ofNullable(getUsingFromItemList()).orElseGet(ArrayList::new); + Collections.addAll(collection, usingFromItemList); + return this.withUsingFromItemList(collection); + } + + /** + * The old method has been replaced by addUsingFromItemList. + * + * @param usingList + * @return + * @see Delete#addUsingFromItemList + */ + @Deprecated public Delete addUsingList(Collection usingList) { List
collection = Optional.ofNullable(getUsingList()).orElseGet(ArrayList::new); collection.addAll(usingList); return this.withUsingList(collection); } + /** + * New using syntax method. Supports the complete using syntax of pg, such as subqueries, etc. + * + * @param usingFromItemList + * @return + */ + public Delete addUsingFromItemList(Collection usingFromItemList) { + List collection = + Optional.ofNullable(getUsingFromItemList()).orElseGet(ArrayList::new); + collection.addAll(usingFromItemList); + return this.withUsingFromItemList(collection); + } + public Delete addJoins(Join... joins) { List collection = Optional.ofNullable(getJoins()).orElseGet(ArrayList::new); Collections.addAll(collection, joins); @@ -386,4 +485,23 @@ public Delete addOrderByElements(Collection orderByEle public E getWhere(Class type) { return type.cast(getWhere()); } + + /** + * Return the content after using. Supports the complete using syntax of pg, such as subqueries, + * etc. + * + * @return + */ + public List getUsingFromItemList() { + return usingFromItemList; + } + + /** + * Supports the complete using syntax of pg, such as subqueries, etc. + * + * @param usingFromItemList The content after using. + */ + public void setUsingFromItemList(List usingFromItemList) { + this.usingFromItemList = usingFromItemList; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/delete/ParenthesedDelete.java b/src/main/java/net/sf/jsqlparser/statement/delete/ParenthesedDelete.java new file mode 100644 index 000000000..ffdf57d4b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/delete/ParenthesedDelete.java @@ -0,0 +1,62 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.delete; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class ParenthesedDelete extends Delete implements ParenthesedStatement { + + Alias alias; + Delete delete; + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + public ParenthesedDelete withAlias(Alias alias) { + this.setAlias(alias); + return this; + } + + public Delete getDelete() { + return delete; + } + + public void setDelete(Delete delete) { + this.delete = delete; + } + + public ParenthesedDelete withDelete(Delete delete) { + setDelete(delete); + return this; + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("(").append(delete).append(")"); + if (alias != null) { + builder.append(alias); + } + return builder.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/drop/Drop.java b/src/main/java/net/sf/jsqlparser/statement/drop/Drop.java index 402574d26..a7ac36253 100644 --- a/src/main/java/net/sf/jsqlparser/statement/drop/Drop.java +++ b/src/main/java/net/sf/jsqlparser/statement/drop/Drop.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; + import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; @@ -32,31 +33,38 @@ public class Drop implements Statement { private boolean isUsingTemporary; + public static String formatFuncParams(List params) { + if (params == null) { + return ""; + } + return params.isEmpty() ? "()" : PlainSelect.getStringList(params, true, true); + } + @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Table getName() { return name; } - public List getParameters() { - return parameters; - } - - public String getType() { - return type; - } - public void setName(Table string) { name = string; } + public List getParameters() { + return parameters; + } + public void setParameters(List list) { parameters = list; } + public String getType() { + return type; + } + public void setType(String string) { type = string; } @@ -74,7 +82,7 @@ public boolean isUsingTemporary() { } public void setUsingTemporary(boolean useTemporary) { - this.isUsingTemporary=useTemporary; + this.isUsingTemporary = useTemporary; } public Drop withUsingTemporary(boolean useTemporary) { @@ -117,13 +125,6 @@ public String toString() { return sql; } - public static String formatFuncParams(List params) { - if (params == null) { - return ""; - } - return params.isEmpty() ? "()" : PlainSelect.getStringList(params, true, true); - } - public List getParamsByType(String type) { return typeToParameters.get(type); } diff --git a/src/main/java/net/sf/jsqlparser/statement/execute/Execute.java b/src/main/java/net/sf/jsqlparser/statement/execute/Execute.java index 366a982e6..e0d597700 100644 --- a/src/main/java/net/sf/jsqlparser/statement/execute/Execute.java +++ b/src/main/java/net/sf/jsqlparser/statement/execute/Execute.java @@ -63,8 +63,8 @@ public boolean isParenthesis() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/statement/export/DBMSDestination.java b/src/main/java/net/sf/jsqlparser/statement/export/DBMSDestination.java new file mode 100644 index 000000000..38774023a --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/DBMSDestination.java @@ -0,0 +1,118 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.ConnectionDefinition; +import net.sf.jsqlparser.statement.ErrorClause; +import net.sf.jsqlparser.statement.SourceDestinationType; +import net.sf.jsqlparser.statement.select.PlainSelect; + +import java.io.Serializable; +import java.util.List; + +public class DBMSDestination implements ExportIntoItem, Serializable { + private SourceDestinationType destinationType; + private ConnectionDefinition connectionDefinition; + private Table table; + private ExpressionList columns; + private List dbmsTableDestinationOptions; + private StringValue statement; + private ErrorClause errorClause; + + public SourceDestinationType getDestinationType() { + return destinationType; + } + + public void setDestinationType(SourceDestinationType destinationType) { + this.destinationType = destinationType; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public List getDBMSTableDestinationOptions() { + return dbmsTableDestinationOptions; + } + + public void setDBMSTableDestinationOptions( + List dbmsTableDestinationOptions) { + this.dbmsTableDestinationOptions = dbmsTableDestinationOptions; + } + + public StringValue getStatement() { + return statement; + } + + public void setStatement(StringValue statement) { + this.statement = statement; + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(destinationType); + + sql.append(" "); + sql.append(connectionDefinition); + + if (table != null) { + sql.append(" TABLE ").append(table); + PlainSelect.appendStringListTo(sql, columns, true, true); + if (dbmsTableDestinationOptions != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, dbmsTableDestinationOptions, false, false); + } + } else if (statement != null) { + sql.append(" STATEMENT ").append(statement); + } + + if (errorClause != null) { + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/export/DBMSTableDestinationOption.java b/src/main/java/net/sf/jsqlparser/statement/export/DBMSTableDestinationOption.java new file mode 100644 index 000000000..904acea95 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/DBMSTableDestinationOption.java @@ -0,0 +1,67 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class DBMSTableDestinationOption implements Serializable { + private String key; + private Expression value; + + private DBMSTableDestinationOption(String key, Expression value) { + this.key = key; + this.value = value; + } + + public DBMSTableDestinationOption(String key) { + this(key, (Expression) null); + } + + public DBMSTableDestinationOption(String key, StringValue value) { + this(key, (Expression) value); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Expression getValue() { + return value; + } + + public void setValue(StringValue value) { + this.value = value; + } + + public void setValue(LongValue value) { + this.value = value; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(key); + if (value != null) { + sql.append(" "); + sql.append(value); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/export/Export.java b/src/main/java/net/sf/jsqlparser/statement/export/Export.java new file mode 100644 index 000000000..dd6628a20 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/Export.java @@ -0,0 +1,81 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.select.*; + +public class Export implements Statement { + private Table table; + private ExpressionList columns; + private Select select; + private ExportIntoItem exportIntoItem; + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public Select getSelect() { + return select; + } + + public void setSelect(Select select) { + this.select = select; + } + + public ExportIntoItem getExportIntoItem() { + return exportIntoItem; + } + + public void setExportIntoItem(ExportIntoItem exportIntoItem) { + this.exportIntoItem = exportIntoItem; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + sql.append("EXPORT "); + if (table != null || select != null) { + if (table != null) { + sql.append(table); + PlainSelect.appendStringListTo(sql, columns, true, true); + } else { + sql.append(select); + } + sql.append(" "); + } + + sql.append("INTO "); + sql.append(exportIntoItem); + + return sql.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/export/ExportIntoItem.java b/src/main/java/net/sf/jsqlparser/statement/export/ExportIntoItem.java new file mode 100644 index 000000000..4558b67e9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/ExportIntoItem.java @@ -0,0 +1,18 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.statement.ErrorClause; + +public interface ExportIntoItem { + ErrorClause getErrorClause(); + + void setErrorClause(ErrorClause errorClause); +} diff --git a/src/main/java/net/sf/jsqlparser/statement/export/FileDestination.java b/src/main/java/net/sf/jsqlparser/statement/export/FileDestination.java new file mode 100644 index 000000000..6ff364075 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/export/FileDestination.java @@ -0,0 +1,50 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.statement.*; + +import java.io.Serializable; + +public class FileDestination extends FileSourceDestination implements ExportIntoItem, Serializable { + private ErrorClause errorClause; + + public SourceDestinationType getDestinationType() { + return getType(); + } + + public void setDestinationType(SourceDestinationType destinationType) { + setType(destinationType); + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(super.toString()); + + if (errorClause != null) { + sql.append(" "); + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/grant/Grant.java b/src/main/java/net/sf/jsqlparser/statement/grant/Grant.java index d553adff6..191e66c0c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/grant/Grant.java +++ b/src/main/java/net/sf/jsqlparser/statement/grant/Grant.java @@ -14,7 +14,9 @@ import java.util.Collections; import java.util.List; import java.util.Optional; + import static java.util.stream.Collectors.joining; + import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; @@ -22,12 +24,12 @@ public class Grant implements Statement { private String role; private List privileges; - private List objectName = new ArrayList<>(); + private final List objectName = new ArrayList<>(); private List users; @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public String getRole() { @@ -47,25 +49,26 @@ public void setPrivileges(List privileges) { } public String getObjectName() { - return objectName.size()==0?null:objectName.stream() - .map(part -> part==null?"":part) - .collect(joining(".")); - } - - public List getObjectNameParts() { - return objectName; + return objectName.isEmpty() ? null + : objectName.stream() + .map(part -> part == null ? "" : part) + .collect(joining(".")); } public void setObjectName(String objectName) { this.objectName.clear(); this.objectName.add(objectName); } - + public void setObjectName(List objectName) { this.objectName.clear(); this.objectName.addAll(objectName); } + public List getObjectNameParts() { + return objectName; + } + public List getUsers() { return users; } @@ -115,7 +118,7 @@ public Grant withObjectName(String objectName) { this.setObjectName(objectName); return this; } - + public Grant withObjectName(List objectName) { this.setObjectName(objectName); return this; diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/DBMSSource.java b/src/main/java/net/sf/jsqlparser/statement/imprt/DBMSSource.java new file mode 100644 index 000000000..0845af338 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/DBMSSource.java @@ -0,0 +1,106 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.ConnectionDefinition; +import net.sf.jsqlparser.statement.ErrorClause; +import net.sf.jsqlparser.statement.SourceDestinationType; +import net.sf.jsqlparser.statement.select.PlainSelect; + +import java.io.Serializable; +import java.util.List; + +public class DBMSSource implements ImportFromItem, Serializable { + private SourceDestinationType sourceType; + private ConnectionDefinition connectionDefinition; + private Table table; + private ExpressionList columns; + private List statements; + private ErrorClause errorClause; + + public SourceDestinationType getSourceType() { + return sourceType; + } + + public void setSourceType(SourceDestinationType sourceType) { + this.sourceType = sourceType; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public List getStatements() { + return statements; + } + + public void setStatements(List statements) { + this.statements = statements; + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(sourceType); + + sql.append(" "); + sql.append(connectionDefinition); + + if (table != null) { + sql.append(" TABLE ").append(table); + PlainSelect.appendStringListTo(sql, columns, true, true); + } else if (statements != null) { + for (StringValue statement : statements) { + sql.append(" STATEMENT ").append(statement); + } + } + + if (errorClause != null) { + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/FileSource.java b/src/main/java/net/sf/jsqlparser/statement/imprt/FileSource.java new file mode 100644 index 000000000..0be5bbab6 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/FileSource.java @@ -0,0 +1,50 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.statement.*; + +import java.io.Serializable; + +public class FileSource extends FileSourceDestination implements ImportFromItem, Serializable { + private ErrorClause errorClause; + + public SourceDestinationType getSourceType() { + return getType(); + } + + public void setSourceType(SourceDestinationType sourceType) { + setType(sourceType); + } + + @Override + public ErrorClause getErrorClause() { + return errorClause; + } + + @Override + public void setErrorClause(ErrorClause errorClause) { + this.errorClause = errorClause; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(super.toString()); + + if (errorClause != null) { + sql.append(" "); + sql.append(errorClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/Import.java b/src/main/java/net/sf/jsqlparser/statement/imprt/Import.java new file mode 100644 index 000000000..e71799a3d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/Import.java @@ -0,0 +1,128 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.select.*; + +import java.util.List; + +public class Import extends ASTNodeAccessImpl implements FromItem, Statement { + private Table table; + private ExpressionList columns; + private List importColumns; + private ImportFromItem fromItem; + private Alias alias; + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public List getImportColumns() { + return importColumns; + } + + public void setImportColumns(List importColumns) { + this.importColumns = importColumns; + } + + public ImportFromItem getFromItem() { + return fromItem; + } + + public void setFromItem(ImportFromItem fromItem) { + this.fromItem = fromItem; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + sql.append("IMPORT "); + if (table != null || importColumns != null) { + sql.append("INTO "); + if (table != null) { + sql.append(table); + PlainSelect.appendStringListTo(sql, columns, true, true); + } else { + PlainSelect.appendStringListTo(sql, importColumns, true, true); + } + sql.append(" "); + } + + sql.append("FROM "); + sql.append(fromItem); + + return sql.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + @Override + public Pivot getPivot() { + return null; + } + + @Override + public void setPivot(Pivot pivot) {} + + @Override + public UnPivot getUnPivot() { + return null; + } + + @Override + public void setUnPivot(UnPivot unpivot) {} + + @Override + public SampleClause getSampleClause() { + return null; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + return null; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/ImportColumn.java b/src/main/java/net/sf/jsqlparser/statement/imprt/ImportColumn.java new file mode 100644 index 000000000..7d3f719dd --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/ImportColumn.java @@ -0,0 +1,13 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +public interface ImportColumn { +} diff --git a/src/main/java/net/sf/jsqlparser/statement/imprt/ImportFromItem.java b/src/main/java/net/sf/jsqlparser/statement/imprt/ImportFromItem.java new file mode 100644 index 000000000..86e736cca --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/imprt/ImportFromItem.java @@ -0,0 +1,18 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.statement.ErrorClause; + +public interface ImportFromItem { + ErrorClause getErrorClause(); + + void setErrorClause(ErrorClause errorClause); +} diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java b/src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java index 69d6532f0..8e82829b4 100644 --- a/src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java +++ b/src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java @@ -10,7 +10,7 @@ package net.sf.jsqlparser.statement.insert; public enum ConflictActionType { - DO_NOTHING, DO_UPDATE; + NOTHING, DO_NOTHING, DO_UPDATE; public static ConflictActionType from(String type) { return Enum.valueOf(ConflictActionType.class, type.toUpperCase()); diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java b/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java index bb5595a35..4920aec62 100644 --- a/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java +++ b/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java @@ -9,9 +9,16 @@ */ package net.sf.jsqlparser.statement.insert; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.OracleHint; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Partition; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.OutputClause; import net.sf.jsqlparser.statement.ReturningClause; @@ -24,30 +31,37 @@ import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.statement.update.UpdateSet; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; - @SuppressWarnings({"PMD.CyclomaticComplexity"}) public class Insert implements Statement { private Table table; private OracleHint oracleHint = null; private ExpressionList columns; + private List partitions; private Select select; + private boolean onlyDefaultValues = false; + private boolean overriding = false; private List duplicateUpdateSets = null; private InsertModifierPriority modifierPriority = null; private boolean modifierIgnore = false; + private boolean overwrite = false; + private boolean tableKeyword = false; private ReturningClause returningClause; private List setUpdateSets = null; - private List withItemsList; + private List> withItemsList; private OutputClause outputClause; private InsertConflictTarget conflictTarget; private InsertConflictAction conflictAction; + private InsertDuplicateAction duplicateAction; + private Alias rowAlias; + private boolean oracleMultiInsert = false; + private boolean oracleMultiInsertFirst = false; + private List oracleMultiInsertBranches; public List getDuplicateUpdateSets() { + if (duplicateAction != null) { + return duplicateAction.getUpdateSets(); + } return duplicateUpdateSets; } @@ -56,7 +70,13 @@ public List getSetUpdateSets() { } public Insert withDuplicateUpdateSets(List duplicateUpdateSets) { - this.duplicateUpdateSets = duplicateUpdateSets; + if (duplicateAction != null) { + duplicateAction.setConflictActionType(ConflictActionType.DO_UPDATE); + duplicateAction.setUpdateSets(duplicateUpdateSets); + } else { + duplicateAction = new InsertDuplicateAction(ConflictActionType.DO_UPDATE); + duplicateAction.setUpdateSets(duplicateUpdateSets); + } return this; } @@ -74,11 +94,17 @@ public void setOutputClause(OutputClause outputClause) { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Table getTable() { + if (table == null && oracleMultiInsertBranches != null + && !oracleMultiInsertBranches.isEmpty() + && oracleMultiInsertBranches.get(0).getClauses() != null + && !oracleMultiInsertBranches.get(0).getClauses().isEmpty()) { + return oracleMultiInsertBranches.get(0).getClauses().get(0).getTable(); + } return table; } @@ -102,6 +128,14 @@ public void setColumns(ExpressionList list) { columns = list; } + public List getPartitions() { + return partitions; + } + + public void setPartitions(List list) { + partitions = list; + } + @Deprecated public boolean isUseValues() { return select != null && select instanceof Values; @@ -143,7 +177,8 @@ public boolean isUseSelectBrackets() { @Deprecated public boolean isUseDuplicate() { - return duplicateUpdateSets != null && !duplicateUpdateSets.isEmpty(); + return duplicateAction != null && duplicateAction.getUpdateSets() != null + && !duplicateAction.getUpdateSets().isEmpty(); } public InsertModifierPriority getModifierPriority() { @@ -162,20 +197,61 @@ public void setModifierIgnore(boolean modifierIgnore) { this.modifierIgnore = modifierIgnore; } + public boolean isOverwrite() { + return overwrite; + } + + public void setOverwrite(boolean overwrite) { + this.overwrite = overwrite; + } + + public boolean isTableKeyword() { + return tableKeyword; + } + + public void setTableKeyword(boolean tableKeyword) { + this.tableKeyword = tableKeyword; + } @Deprecated public boolean isUseSet() { return setUpdateSets != null && !setUpdateSets.isEmpty(); } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } + public boolean isOverriding() { + return overriding; + } + + public void setOverriding(boolean overriding) { + this.overriding = overriding; + } + + public Insert withOverriding(boolean overriding) { + this.setOverriding(overriding); + return this; + } + + public boolean isOnlyDefaultValues() { + return onlyDefaultValues; + } + + public void setOnlyDefaultValues(boolean onlyDefaultValues) { + this.onlyDefaultValues = onlyDefaultValues; + } + + public Insert withOnlyDefaultValues(boolean onlyDefaultValues) { + this.setOnlyDefaultValues(onlyDefaultValues); + return this; + } + public InsertConflictTarget getConflictTarget() { return conflictTarget; } @@ -202,14 +278,50 @@ public Insert withConflictAction(InsertConflictAction conflictAction) { return this; } + public boolean isOracleMultiInsert() { + return oracleMultiInsert; + } + + public void setOracleMultiInsert(boolean oracleMultiInsert) { + this.oracleMultiInsert = oracleMultiInsert; + } + + public boolean isOracleMultiInsertFirst() { + return oracleMultiInsertFirst; + } + + public void setOracleMultiInsertFirst(boolean oracleMultiInsertFirst) { + this.oracleMultiInsertFirst = oracleMultiInsertFirst; + } + + public List getOracleMultiInsertBranches() { + return oracleMultiInsertBranches; + } + + public void setOracleMultiInsertBranches( + List oracleMultiInsertBranches) { + this.oracleMultiInsertBranches = oracleMultiInsertBranches; + } + @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public String toString() { StringBuilder sql = new StringBuilder(); + appendWithItems(sql); + appendInsertPrefix(sql); + if (appendOracleMultiInsert(sql)) { + return sql.toString(); + } + appendInsertTargetAndValues(sql); + appendInsertActions(sql); + return sql.toString(); + } + + private void appendWithItems(StringBuilder sql) { if (withItemsList != null && !withItemsList.isEmpty()) { sql.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); sql.append(withItem); if (iter.hasNext()) { sql.append(","); @@ -217,6 +329,9 @@ public String toString() { sql.append(" "); } } + } + + private void appendInsertPrefix(StringBuilder sql) { sql.append("INSERT "); if (oracleHint != null) { sql.append(oracleHint).append(" "); @@ -227,9 +342,40 @@ public String toString() { if (modifierIgnore) { sql.append("IGNORE "); } - sql.append("INTO "); + } + + private boolean appendOracleMultiInsert(StringBuilder sql) { + if (!oracleMultiInsert) { + return false; + } + + sql.append(oracleMultiInsertFirst ? "FIRST" : "ALL"); + if (oracleMultiInsertBranches != null && !oracleMultiInsertBranches.isEmpty()) { + for (OracleMultiInsertBranch branch : oracleMultiInsertBranches) { + appendOracleMultiInsertBranch(sql, branch); + } + } + if (select != null) { + sql.append(" ").append(select); + } + return true; + } + + private void appendInsertTargetAndValues(StringBuilder sql) { + if (overwrite) { + sql.append("OVERWRITE "); + } else { + sql.append("INTO "); + } + if (tableKeyword) { + sql.append("TABLE "); + } sql.append(table).append(" "); + if (onlyDefaultValues) { + sql.append("DEFAULT VALUES"); + } + if (columns != null) { sql.append("("); for (int i = 0; i < columns.size(); i++) { @@ -242,6 +388,16 @@ public String toString() { sql.append(") "); } + if (overriding) { + sql.append("OVERRIDING SYSTEM VALUE "); + } + + if (partitions != null) { + sql.append(" PARTITION ("); + Partition.appendPartitionsTo(sql, partitions); + sql.append(") "); + } + if (outputClause != null) { sql.append(outputClause); } @@ -249,15 +405,20 @@ public String toString() { if (select != null) { sql.append(select); } + } + private void appendInsertActions(StringBuilder sql) { if (setUpdateSets != null && !setUpdateSets.isEmpty()) { sql.append("SET "); - sql = UpdateSet.appendUpdateSetsTo(sql, setUpdateSets); + UpdateSet.appendUpdateSetsTo(sql, setUpdateSets); + if (rowAlias != null) { + sql.append(" ").append(rowAlias); + } } - if (duplicateUpdateSets != null && !duplicateUpdateSets.isEmpty()) { + if (duplicateAction != null) { sql.append(" ON DUPLICATE KEY UPDATE "); - sql = UpdateSet.appendUpdateSetsTo(sql, duplicateUpdateSets); + duplicateAction.appendTo(sql); } if (conflictAction != null) { @@ -272,11 +433,9 @@ public String toString() { if (returningClause != null) { returningClause.appendTo(sql); } - - return sql.toString(); } - public Insert withWithItemsList(List withList) { + public Insert withWithItemsList(List> withList) { this.withItemsList = withList; return this; } @@ -316,4 +475,53 @@ public Insert addColumns(Collection columns) { collection.addAll(columns); return this.withColumns(collection); } + + public InsertDuplicateAction getDuplicateAction() { + return duplicateAction; + } + + public void setDuplicateAction(InsertDuplicateAction duplicateAction) { + this.duplicateAction = duplicateAction; + } + + public Alias getRowAlias() { + return rowAlias; + } + + public void setRowAlias(Alias rowAlias) { + this.rowAlias = rowAlias; + } + + public Insert withOracleMultiInsert(boolean oracleMultiInsert) { + this.setOracleMultiInsert(oracleMultiInsert); + return this; + } + + public Insert withOracleMultiInsertFirst(boolean oracleMultiInsertFirst) { + this.setOracleMultiInsertFirst(oracleMultiInsertFirst); + return this; + } + + public Insert withOracleMultiInsertBranches( + List oracleMultiInsertBranches) { + this.setOracleMultiInsertBranches(oracleMultiInsertBranches); + return this; + } + + private void appendOracleMultiInsertBranch(StringBuilder sql, + OracleMultiInsertBranch branch) { + if (branch == null || branch.getClauses() == null || branch.getClauses().isEmpty()) { + return; + } + + if (branch.getWhenExpression() != null) { + sql.append(" WHEN ").append(branch.getWhenExpression()).append(" THEN"); + } else if (branch.isElseClause()) { + sql.append(" ELSE"); + } + + for (OracleMultiInsertClause clause : branch.getClauses()) { + sql.append(" ").append(clause); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/InsertConflictAction.java b/src/main/java/net/sf/jsqlparser/statement/insert/InsertConflictAction.java index 8bbba83b7..76781bbcc 100644 --- a/src/main/java/net/sf/jsqlparser/statement/insert/InsertConflictAction.java +++ b/src/main/java/net/sf/jsqlparser/statement/insert/InsertConflictAction.java @@ -21,7 +21,7 @@ /** * https://www.postgresql.org/docs/current/sql-insert.html - * + * *
  * conflict_action is one of:
  *
@@ -36,10 +36,8 @@
 
 public class InsertConflictAction implements Serializable {
     ConflictActionType conflictActionType;
-
-    private List updateSets;
-
     Expression whereExpression;
+    private List updateSets;
 
     public InsertConflictAction(ConflictActionType conflictActionType) {
         this.conflictActionType = Objects.requireNonNull(conflictActionType,
diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/InsertConflictTarget.java b/src/main/java/net/sf/jsqlparser/statement/insert/InsertConflictTarget.java
index 070996483..59c2d624c 100644
--- a/src/main/java/net/sf/jsqlparser/statement/insert/InsertConflictTarget.java
+++ b/src/main/java/net/sf/jsqlparser/statement/insert/InsertConflictTarget.java
@@ -16,14 +16,14 @@
 
 /**
  * https://www.postgresql.org/docs/current/sql-insert.html
- * 
+ *
  * 
  * conflict_target can be one of:
  *
  *     ( { index_column_name | ( index_expression ) } [ COLLATE collation ] [ opclass ] [, ...] ) [ WHERE index_predicate ]
  *     ON CONSTRAINT constraint_name
  * 
- * + *

* Currently, COLLATE is not supported yet. */ public class InsertConflictTarget implements Serializable { diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/InsertDuplicateAction.java b/src/main/java/net/sf/jsqlparser/statement/insert/InsertDuplicateAction.java new file mode 100644 index 000000000..4a106a6f7 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/insert/InsertDuplicateAction.java @@ -0,0 +1,120 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.insert; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.update.UpdateSet; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * on duplicate key is one of: + * + * ON DUPLICATE KEY UPDATE NOTHING ON DUPLICATE KEY UPDATE { column_name = { expression | DEFAULT } + * | ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) | ( column_name [, ...] + * ) = ( sub-SELECT ) } [, ...] [ WHERE condition ] + * + * @author zhangconan + */ +public class InsertDuplicateAction implements Serializable { + + ConflictActionType conflictActionType; + Expression whereExpression; + private List updateSets; + + public InsertDuplicateAction(ConflictActionType conflictActionType) { + this.conflictActionType = Objects.requireNonNull(conflictActionType, + "The Conflict Action Type is mandatory and must not be Null."); + } + + public List getUpdateSets() { + return updateSets; + } + + public void setUpdateSets(List updateSets) { + this.updateSets = updateSets; + } + + public InsertDuplicateAction withUpdateSets(List updateSets) { + this.setUpdateSets(updateSets); + return this; + } + + public ConflictActionType getConflictActionType() { + return conflictActionType; + } + + public void setConflictActionType(ConflictActionType conflictActionType) { + this.conflictActionType = Objects.requireNonNull(conflictActionType, + "The Conflict Action Type is mandatory and must not be Null."); + } + + public InsertDuplicateAction withConflictActionType(ConflictActionType conflictActionType) { + setConflictActionType(conflictActionType); + return this; + } + + public InsertDuplicateAction addUpdateSet(Column column, Expression expression) { + return this.addUpdateSet(new UpdateSet()); + } + + public InsertDuplicateAction addUpdateSet(UpdateSet updateSet) { + if (updateSets == null) { + updateSets = new ArrayList<>(); + } + this.updateSets.add(updateSet); + return this; + } + + public InsertDuplicateAction withUpdateSets(Collection updateSets) { + this.setUpdateSets(new ArrayList<>(updateSets)); + return this; + } + + public Expression getWhereExpression() { + return whereExpression; + } + + public void setWhereExpression(Expression whereExpression) { + this.whereExpression = whereExpression; + } + + public InsertDuplicateAction withWhereExpression(Expression whereExpression) { + setWhereExpression(whereExpression); + return this; + } + + @SuppressWarnings("PMD.SwitchStmtsShouldHaveDefault") + public StringBuilder appendTo(StringBuilder builder) { + switch (conflictActionType) { + case NOTHING: + builder.append(" NOTHING "); + break; + default: + UpdateSet.appendUpdateSetsTo(builder, updateSets); + + if (whereExpression != null) { + builder.append(" WHERE ").append(whereExpression); + } + break; + } + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/OracleMultiInsertBranch.java b/src/main/java/net/sf/jsqlparser/statement/insert/OracleMultiInsertBranch.java new file mode 100644 index 000000000..64cdb1696 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/insert/OracleMultiInsertBranch.java @@ -0,0 +1,74 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.insert; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import net.sf.jsqlparser.expression.Expression; + +public class OracleMultiInsertBranch implements Serializable { + + private Expression whenExpression; + private boolean elseClause; + private List clauses = new ArrayList<>(); + + public Expression getWhenExpression() { + return whenExpression; + } + + public void setWhenExpression(Expression whenExpression) { + this.whenExpression = whenExpression; + if (whenExpression != null) { + this.elseClause = false; + } + } + + public boolean isElseClause() { + return elseClause; + } + + public void setElseClause(boolean elseClause) { + this.elseClause = elseClause; + if (elseClause) { + this.whenExpression = null; + } + } + + public List getClauses() { + return clauses; + } + + public void setClauses(List clauses) { + this.clauses = clauses == null ? new ArrayList<>() : clauses; + } + + public void addClause(OracleMultiInsertClause clause) { + if (clause == null) { + return; + } + clauses.add(clause); + } + + public OracleMultiInsertBranch withWhenExpression(Expression whenExpression) { + this.setWhenExpression(whenExpression); + return this; + } + + public OracleMultiInsertBranch withElseClause(boolean elseClause) { + this.setElseClause(elseClause); + return this; + } + + public OracleMultiInsertBranch withClauses(List clauses) { + this.setClauses(clauses); + return this; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/OracleMultiInsertClause.java b/src/main/java/net/sf/jsqlparser/statement/insert/OracleMultiInsertClause.java new file mode 100644 index 000000000..1a7bdc6d3 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/insert/OracleMultiInsertClause.java @@ -0,0 +1,87 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.insert; + +import java.io.Serializable; +import java.util.Iterator; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.select.Select; + +public class OracleMultiInsertClause implements Serializable { + + private Table table; + private ExpressionList columns; + private Select select; + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public ExpressionList getColumns() { + return columns; + } + + public void setColumns(ExpressionList columns) { + this.columns = columns; + } + + public Select getSelect() { + return select; + } + + public void setSelect(Select select) { + this.select = select; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder("INTO "); + sql.append(table); + + if (columns != null && !columns.isEmpty()) { + sql.append(" ("); + for (Iterator iter = columns.iterator(); iter.hasNext();) { + Column column = iter.next(); + sql.append(column.getColumnName()); + if (iter.hasNext()) { + sql.append(", "); + } + } + sql.append(")"); + } + + if (select != null) { + sql.append(" ").append(select); + } + + return sql.toString(); + } + + public OracleMultiInsertClause withTable(Table table) { + this.setTable(table); + return this; + } + + public OracleMultiInsertClause withColumns(ExpressionList columns) { + this.setColumns(columns); + return this; + } + + public OracleMultiInsertClause withSelect(Select select) { + this.setSelect(select); + return this; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/insert/ParenthesedInsert.java b/src/main/java/net/sf/jsqlparser/statement/insert/ParenthesedInsert.java new file mode 100644 index 000000000..b9c83526c --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/insert/ParenthesedInsert.java @@ -0,0 +1,61 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.insert; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class ParenthesedInsert extends Insert implements ParenthesedStatement { + Alias alias; + Insert insert; + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + public ParenthesedInsert withAlias(Alias alias) { + this.setAlias(alias); + return this; + } + + public Insert getInsert() { + return insert; + } + + public void setInsert(Insert insert) { + this.insert = insert; + } + + public ParenthesedInsert withInsert(Insert insert) { + setInsert(insert); + return this; + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("(").append(insert).append(")"); + if (alias != null) { + builder.append(alias); + } + return builder.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java b/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java new file mode 100644 index 000000000..be372218e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/lock/LockMode.java @@ -0,0 +1,33 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.lock; + +/** + * Describes the LockMode of a LOCK TABLE-Statement. + */ +public enum LockMode { + // These two modes are more common + Share("SHARE"), Exclusive("EXCLUSIVE"), + + // These are Oracle specific, as far as I know + RowShare("ROW SHARE"), RowExclusive("ROW EXCLUSIVE"), ShareUpdate( + "SHARE UPDATE"), ShareRowExclusive("SHARE ROW EXCLUSIVE"); + + private final String value; + + LockMode(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + +} diff --git a/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java b/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java new file mode 100644 index 000000000..2ec25e220 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/lock/LockStatement.java @@ -0,0 +1,123 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.lock; + +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +/** + * Statement to Lock a specific table.
+ * Example:
+ * LOCK TABLE t IN EXCLUSIVE MODE
+ *
+ */ +public class LockStatement implements Statement { + + private Table table; + private LockMode lockMode; + private boolean noWait; + private Long waitSeconds; + + /** + * Creates a new LockStatement + * + * @param table The table to lock + * @param lockMode The lock mode + */ + public LockStatement(Table table, LockMode lockMode) { + this.table = table; + this.lockMode = lockMode; + } + + public LockStatement(Table table, LockMode lockMode, boolean noWait, Long waitSeconds) { + this(table, lockMode); + this.table = table; + this.lockMode = lockMode; + this.noWait = noWait; + this.waitSeconds = waitSeconds; + } + + private void checkValidState() { + if (noWait && waitSeconds != null) { + throw new IllegalStateException( + "A LOCK statement cannot have NOWAIT and WAIT at the same time"); + } + } + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public LockMode getLockMode() { + return lockMode; + } + + public void setLockMode(LockMode lockMode) { + this.lockMode = lockMode; + } + + /** + * @return True if the statement has a NOWAIT clause + */ + public boolean isNoWait() { + return noWait; + } + + /** + * Sets the NOWAIT-Flag. + * + * @param noWait True if the statement should have the NOWAIT clause + */ + public void setNoWait(boolean noWait) { + this.noWait = noWait; + checkValidState(); + } + + /** + * Sets the WAIT-Timeout. If this value is set, the Statement is rendered with WAIT + * <timeoutSeconds>
+ * If the value is set to NULL, the WAIT-clause is skipped + * + * @param waitSeconds The number of seconds for the WAIT timeout or NULL to skip the WAIT clause + */ + public void setWaitSeconds(Long waitSeconds) { + this.waitSeconds = waitSeconds; + checkValidState(); + } + + /** + * @return The number of seconds in the WAIT clause, or NULL if the statement has no WAIT clause + */ + public Long getWaitSeconds() { + return waitSeconds; + } + + @Override + public String toString() { + return "LOCK TABLE " + + table.getFullyQualifiedName() + + " IN " + + lockMode.getValue() + + " MODE" + + (noWait ? " NOWAIT" : "") + + (waitSeconds != null ? " WAIT " + waitSeconds : ""); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + +} diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/Merge.java b/src/main/java/net/sf/jsqlparser/statement/merge/Merge.java index ed2c9ee50..7a3baf7a4 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/Merge.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/Merge.java @@ -30,7 +30,7 @@ public class Merge implements Statement { - private List withItemsList; + private List> withItemsList; private Table table; private OracleHint oracleHint = null; private FromItem fromItem; @@ -75,28 +75,28 @@ private void deriveStandardClausesFromOperations() { .orElse(false); } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } - public Merge withWithItemsList(List withItemsList) { + public Merge withWithItemsList(List> withItemsList) { this.setWithItemsList(withItemsList); return this; } - public Merge addWithItemsList(WithItem... withItemsList) { - List collection = + public Merge addWithItemsList(WithItem... withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); Collections.addAll(collection, withItemsList); return this.withWithItemsList(collection); } - public Merge addWithItemsList(Collection withItemsList) { - List collection = + public Merge addWithItemsList(Collection> withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); collection.addAll(withItemsList); return this.withWithItemsList(collection); @@ -192,8 +192,8 @@ public void setMergeUpdate(MergeUpdate mergeUpdate) { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public boolean isInsertFirst() { @@ -220,8 +220,8 @@ public String toString() { StringBuilder b = new StringBuilder(); if (withItemsList != null && !withItemsList.isEmpty()) { b.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); b.append(withItem); if (iter.hasNext()) { b.append(","); diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeDelete.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeDelete.java index fee068a99..bfacef1c1 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeDelete.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeDelete.java @@ -30,8 +30,8 @@ public MergeDelete withAndPredicate(Expression andPredicate) { } @Override - public void accept(MergeOperationVisitor mergeOperationVisitor) { - mergeOperationVisitor.visit(this); + public T accept(MergeOperationVisitor mergeOperationVisitor, S context) { + return mergeOperationVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java index 95b69bbf3..7e33db8b0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java @@ -58,8 +58,8 @@ public void setWhereCondition(Expression whereCondition) { } @Override - public void accept(MergeOperationVisitor mergeOperationVisitor) { - mergeOperationVisitor.visit(this); + public T accept(MergeOperationVisitor mergeOperationVisitor, S context) { + return mergeOperationVisitor.visit(this, context); } @Override @@ -67,15 +67,15 @@ public String toString() { StringBuilder b = new StringBuilder(); b.append(" WHEN NOT MATCHED"); if (andPredicate != null) { - b.append(" AND ").append(andPredicate.toString()); + b.append(" AND ").append(andPredicate); } b.append(" THEN INSERT "); if (columns != null) { - b.append(columns.toString()); + b.append(columns); } b.append(" VALUES ").append(values.toString()); if (whereCondition != null) { - b.append(" WHERE ").append(whereCondition.toString()); + b.append(" WHERE ").append(whereCondition); } return b.toString(); } diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperation.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperation.java index 6a4a9ceff..71447d23d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperation.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperation.java @@ -13,5 +13,5 @@ * Marker interface to cover {@link MergeDelete}, {@link MergeUpdate} and {@link MergeInsert} */ public interface MergeOperation { - void accept(MergeOperationVisitor mergeOperationVisitor); + T accept(MergeOperationVisitor mergeOperationVisitor, S context); } diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java index 5a0f217d6..d2439fbd8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java @@ -9,11 +9,20 @@ */ package net.sf.jsqlparser.statement.merge; -public interface MergeOperationVisitor { +import java.util.Collection; - void visit(MergeDelete mergeDelete); +public interface MergeOperationVisitor { - void visit(MergeUpdate mergeUpdate); + T visit(MergeDelete mergeDelete, S context); - void visit(MergeInsert mergeInsert); + T visit(MergeUpdate mergeUpdate, S context); + + T visit(MergeInsert mergeInsert, S context); + + default T visit(Collection mergeOperations, S context) { + if (mergeOperations != null) { + mergeOperations.forEach(operation -> operation.accept(this, context)); + } + return null; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitorAdapter.java index 80883192c..61ff7a45a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitorAdapter.java @@ -9,20 +9,47 @@ */ package net.sf.jsqlparser.statement.merge; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.statement.select.SelectVisitorAdapter; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class MergeOperationVisitorAdapter implements MergeOperationVisitor { - @Override - public void visit(MergeDelete mergeDelete) { +public class MergeOperationVisitorAdapter implements MergeOperationVisitor { + private ExpressionVisitor expressionVisitor; + public MergeOperationVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(); } - @Override - public void visit(MergeUpdate mergeUpdate) { + public MergeOperationVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + } + public MergeOperationVisitorAdapter(SelectVisitorAdapter selectVisitorAdapter) { + this.expressionVisitor = selectVisitorAdapter.getExpressionVisitor(); } @Override - public void visit(MergeInsert mergeInsert) { + public T visit(MergeDelete mergeDelete, S context) { + expressionVisitor.visitExpression(mergeDelete.getAndPredicate(), context); + return null; + } + @Override + public T visit(MergeUpdate mergeUpdate, S context) { + expressionVisitor.visitExpression(mergeUpdate.getAndPredicate(), context); + expressionVisitor.visitUpdateSets(mergeUpdate.getUpdateSets(), context); + expressionVisitor.visitExpression(mergeUpdate.getWhereCondition(), context); + expressionVisitor.visitExpression(mergeUpdate.getDeleteWhereCondition(), context); + return null; + } + + @Override + public T visit(MergeInsert mergeInsert, S context) { + expressionVisitor.visitExpression(mergeInsert.getAndPredicate(), context); + expressionVisitor.visitExpressions(mergeInsert.getColumns(), context); + expressionVisitor.visitExpressions(mergeInsert.getValues(), context); + expressionVisitor.visitExpression(mergeInsert.getWhereCondition(), context); + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/merge/MergeUpdate.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeUpdate.java index c744ac4f2..2cae3e176 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeUpdate.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeUpdate.java @@ -62,8 +62,8 @@ public void setDeleteWhereCondition(Expression deleteWhereCondition) { } @Override - public void accept(MergeOperationVisitor mergeOperationVisitor) { - mergeOperationVisitor.visit(this); + public T accept(MergeOperationVisitor mergeOperationVisitor, S context) { + return mergeOperationVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/AggregatePipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/AggregatePipeOperator.java new file mode 100644 index 000000000..552ac662d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/AggregatePipeOperator.java @@ -0,0 +1,112 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.util.ArrayList; + +public class AggregatePipeOperator extends PipeOperator { + private final ArrayList> selectItems = new ArrayList<>(); + private final ArrayList selectItemsOrderSuffices = new ArrayList<>(); + + private final ArrayList> groupItems = new ArrayList<>(); + private final ArrayList groupItemsOrderSuffices = new ArrayList<>(); + private boolean usingShortHandOrdering = false; + + public AggregatePipeOperator(SelectItem selectItem, String orderSuffix) { + selectItems.add(selectItem); + selectItemsOrderSuffices.add(orderSuffix); + } + + public ArrayList> getSelectItems() { + return selectItems; + } + + public ArrayList> getGroupItems() { + return groupItems; + } + + public ArrayList getSelectItemsOrderSuffices() { + return selectItemsOrderSuffices; + } + + public ArrayList getGroupItemsOrderSuffices() { + return groupItemsOrderSuffices; + } + + public AggregatePipeOperator add(SelectItem selectItem, String orderSuffix) { + selectItems.add(selectItem); + return this; + } + + public AggregatePipeOperator with(SelectItem selectItem, String orderSuffix) { + return this.add(selectItem, orderSuffix); + } + + public AggregatePipeOperator addGroupItem(SelectItem selectItem, String orderSuffix) { + groupItems.add(selectItem); + groupItemsOrderSuffices.add(orderSuffix); + return this; + } + + public AggregatePipeOperator withGroupItem(SelectItem selectItem, String orderSuffix) { + return this.addGroupItem(selectItem, orderSuffix); + } + + public boolean isUsingShortHandOrdering() { + return usingShortHandOrdering; + } + + public AggregatePipeOperator setShorthandOrdering(boolean usingShortHandOrdering) { + this.usingShortHandOrdering = usingShortHandOrdering; + return this; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("AGGREGATE"); + int i = 0; + for (SelectItem selectItem : selectItems) { + builder.append(i > 0 ? ", " : " ").append(selectItem); + if (i < selectItemsOrderSuffices.size() && selectItemsOrderSuffices.get(i) != null + && !selectItemsOrderSuffices.get(i).isEmpty()) { + builder.append(" ").append(selectItemsOrderSuffices.get(i)); + } + i++; + } + builder.append("\n"); + + if (!groupItems.isEmpty()) { + builder.append("\t").append("GROUP"); + if (isUsingShortHandOrdering()) { + builder.append(" AND ORDER"); + } + builder.append(" BY"); + i = 0; + for (SelectItem selectItem : groupItems) { + builder.append(i > 0 ? ", " : " ").append(selectItem); + if (i < groupItemsOrderSuffices.size() && groupItemsOrderSuffices.get(i) != null + && !groupItemsOrderSuffices.get(i).isEmpty()) { + builder.append(" ").append(groupItemsOrderSuffices.get(i)); + } + i++; + } + builder.append("\n"); + } + + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java new file mode 100644 index 000000000..0f1bf8bc1 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java @@ -0,0 +1,41 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Alias; + +public class AsPipeOperator extends PipeOperator { + private Alias alias; + + public AsPipeOperator(Alias alias) { + this.alias = alias; + } + + public Alias getAlias() { + return alias; + } + + public AsPipeOperator setAlias(Alias alias) { + this.alias = alias; + return this; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append(alias); + builder.append("\n"); + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/CallPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/CallPipeOperator.java new file mode 100644 index 000000000..08f444e87 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/CallPipeOperator.java @@ -0,0 +1,56 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.select.TableFunction; + +public class CallPipeOperator extends PipeOperator { + private TableFunction tableFunction; + private Alias alias; + + public CallPipeOperator(TableFunction tableFunction, Alias alias) { + this.tableFunction = tableFunction; + this.alias = alias; + } + + public TableFunction getTableFunction() { + return tableFunction; + } + + public CallPipeOperator setTableFunction(TableFunction tableFunction) { + this.tableFunction = tableFunction; + return this; + } + + public Alias getAlias() { + return alias; + } + + public CallPipeOperator setAlias(Alias alias) { + this.alias = alias; + return this; + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> CALL ").append(tableFunction); + if (alias != null) { + builder.append(" ").append(alias); + } + + return builder; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java new file mode 100644 index 000000000..0742e4f05 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java @@ -0,0 +1,215 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +public class DropPipeOperator extends PipeOperator { + private ExpressionList columns; + + public DropPipeOperator(ExpressionList columns) { + this.columns = columns; + } + + public ExpressionList getColumns() { + return columns; + } + + public DropPipeOperator setColumns(ExpressionList columns) { + this.columns = columns; + return this; + } + + public boolean containsAll(Collection c) { + return columns.containsAll(c); + } + + public Column get(int index) { + return columns.get(index); + } + + public ExpressionList addExpression(Column expression) { + return columns.addExpression(expression); + } + + public ExpressionList addExpressions(Column... expressions) { + return columns.addExpressions(expressions); + } + + public ExpressionList addExpressions(Collection expressions) { + return columns.addExpressions(expressions); + } + + public ExpressionList withExpressions(Column... expressions) { + return columns.withExpressions(expressions); + } + + public ExpressionList withExpressions(Collection expressions) { + return columns.withExpressions(expressions); + } + + public K accept(ExpressionVisitor expressionVisitor, S context) { + return columns.accept(expressionVisitor, context); + } + + public void trimToSize() { + columns.trimToSize(); + } + + public boolean addAll(int index, Collection c) { + return columns.addAll(index, c); + } + + public boolean retainAll(Collection c) { + return columns.retainAll(c); + } + + public Stream parallelStream() { + return columns.parallelStream(); + } + + public boolean addAll(Collection c) { + return columns.addAll(c); + } + + public int indexOf(Column o) { + return columns.indexOf(o); + } + + public void accept(ExpressionVisitor expressionVisitor) { + columns.accept(expressionVisitor); + } + + public void forEach(Consumer action) { + columns.forEach(action); + } + + public int lastIndexOf(Column o) { + return columns.lastIndexOf(o); + } + + public Stream stream() { + return columns.stream(); + } + + public Spliterator spliterator() { + return columns.spliterator(); + } + + public Column set(int index, Column element) { + return columns.set(index, element); + } + + public void sort(Comparator c) { + columns.sort(c); + } + + public void ensureCapacity(int minCapacity) { + columns.ensureCapacity(minCapacity); + } + + public boolean remove(Column o) { + return columns.remove(o); + } + + public Object[] toArray() { + return columns.toArray(); + } + + public Iterator iterator() { + return columns.iterator(); + } + + public T[] toArray(IntFunction generator) { + return columns.toArray(generator); + } + + public boolean add(Column column) { + return columns.add(column); + } + + public ListIterator listIterator(int index) { + return columns.listIterator(index); + } + + public void replaceAll(UnaryOperator operator) { + columns.replaceAll(operator); + } + + public List subList(int fromIndex, int toIndex) { + return columns.subList(fromIndex, toIndex); + } + + public boolean removeAll(Collection c) { + return columns.removeAll(c); + } + + public boolean isEmpty() { + return columns.isEmpty(); + } + + public void clear() { + columns.clear(); + } + + public boolean contains(Column o) { + return columns.contains(o); + } + + public Column remove(int index) { + return columns.remove(index); + } + + public boolean removeIf(Predicate filter) { + return columns.removeIf(filter); + } + + public T[] toArray(T[] a) { + return columns.toArray(a); + } + + public void add(int index, Column element) { + columns.add(index, element); + } + + public int size() { + return columns.size(); + } + + public ListIterator listIterator() { + return columns.listIterator(); + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("DROP "); + columns.appendTo(builder).append("\n"); + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java new file mode 100644 index 000000000..dea25685c --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java @@ -0,0 +1,18 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.SelectItem; + +public class ExtendPipeOperator extends SelectPipeOperator { + public ExtendPipeOperator(SelectItem selectItem) { + super("EXTEND", selectItem, null); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java b/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java new file mode 100644 index 000000000..6937afce0 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java @@ -0,0 +1,319 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.statement.select.FromItem; +import net.sf.jsqlparser.statement.select.FromItemVisitor; +import net.sf.jsqlparser.statement.select.Join; +import net.sf.jsqlparser.statement.select.LateralView; +import net.sf.jsqlparser.statement.select.Pivot; +import net.sf.jsqlparser.statement.select.SampleClause; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectVisitor; +import net.sf.jsqlparser.statement.select.UnPivot; +import net.sf.jsqlparser.statement.select.WithItem; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +public class FromQuery extends Select { + private boolean usingFromKeyword = true; + private FromItem fromItem; + private List lateralViews = null; + private List joins = null; + private final ArrayList pipeOperators = new ArrayList<>(); + + public FromQuery(FromItem fromItem) { + this.fromItem = fromItem; + } + + public FromQuery(FromItem fromItem, boolean usingFromKeyword) { + this.fromItem = fromItem; + this.usingFromKeyword = usingFromKeyword; + } + + public FromItem getFromItem() { + return fromItem; + } + + public FromQuery setFromItem(FromItem fromItem) { + this.fromItem = fromItem; + return this; + } + + public FromQuery with(FromItem fromItem) { + return this.setFromItem(fromItem); + } + + public boolean isUsingFromKeyword() { + return usingFromKeyword; + } + + + public List getLateralViews() { + return lateralViews; + } + + public FromQuery setLateralViews(List lateralViews) { + this.lateralViews = lateralViews; + return this; + } + + public FromQuery addLateralViews(Collection lateralViews) { + if (this.lateralViews == null) { + this.lateralViews = new ArrayList<>(lateralViews); + } else { + this.lateralViews.addAll(lateralViews); + } + return this; + } + + public FromQuery addLateralViews(LateralView... lateralViews) { + return this.addLateralViews(Arrays.asList(lateralViews)); + } + + public List getJoins() { + return joins; + } + + public FromQuery setJoins(List joins) { + this.joins = joins; + return this; + } + + public FromQuery addJoins(Collection joins) { + if (this.joins == null) { + this.joins = new ArrayList<>(joins); + } else { + this.joins.addAll(joins); + } + return this; + } + + public FromQuery addJoins(Join... joins) { + return addJoins(Arrays.asList(joins)); + } + + public FromQuery setUsingFromKeyword(boolean usingFromKeyword) { + this.usingFromKeyword = usingFromKeyword; + return this; + } + + public FromQuery with(boolean usingFromKeyword) { + return this.setUsingFromKeyword(usingFromKeyword); + } + + public ArrayList getPipeOperators() { + return pipeOperators; + } + + public FromQuery add(PipeOperator operator) { + pipeOperators.add(operator); + return this; + } + + public void add(int index, PipeOperator element) { + pipeOperators.add(index, element); + } + + public PipeOperator remove(int index) { + return pipeOperators.remove(index); + } + + public boolean remove(Object o) { + return pipeOperators.remove(o); + } + + public void clear() { + pipeOperators.clear(); + } + + public boolean addAll(Collection c) { + return pipeOperators.addAll(c); + } + + public boolean addAll(int index, Collection c) { + return pipeOperators.addAll(index, c); + } + + public boolean removeAll(Collection c) { + return pipeOperators.removeAll(c); + } + + public boolean retainAll(Collection c) { + return pipeOperators.retainAll(c); + } + + public List subList(int fromIndex, int toIndex) { + return pipeOperators.subList(fromIndex, toIndex); + } + + public void forEach(Consumer action) { + pipeOperators.forEach(action); + } + + public Spliterator spliterator() { + return pipeOperators.spliterator(); + } + + public boolean removeIf(Predicate filter) { + return pipeOperators.removeIf(filter); + } + + public void replaceAll(UnaryOperator operator) { + pipeOperators.replaceAll(operator); + } + + public FromQuery with(PipeOperator operator) { + return this.add(operator); + } + + public PipeOperator get(int index) { + return pipeOperators.get(index); + } + + public PipeOperator set(int index, PipeOperator element) { + return pipeOperators.set(index, element); + } + + public int size() { + return pipeOperators.size(); + } + + public boolean isEmpty() { + return pipeOperators.isEmpty(); + } + + public boolean contains(Object o) { + return pipeOperators.contains(o); + } + + public int indexOf(Object o) { + return pipeOperators.indexOf(o); + } + + public int lastIndexOf(Object o) { + return pipeOperators.lastIndexOf(o); + } + + public Object[] toArray() { + return pipeOperators.toArray(); + } + + public T[] toArray(T[] a) { + return pipeOperators.toArray(a); + } + + @Override + public Alias getAlias() { + return null; + } + + @Override + public void setAlias(Alias alias) { + + } + + @Override + public Pivot getPivot() { + return null; + } + + @Override + public void setPivot(Pivot pivot) { + + } + + @Override + public UnPivot getUnPivot() { + return null; + } + + @Override + public void setUnPivot(UnPivot unpivot) { + + } + + @Override + public SampleClause getSampleClause() { + return null; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + return null; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + @Override + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); + } + + public T accept(FromQueryVisitor fromQueryVisitor, S context) { + return fromQueryVisitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + if (withItemsList != null && !withItemsList.isEmpty()) { + builder.append("WITH "); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); + builder.append(withItem); + if (iter.hasNext()) { + builder.append(","); + } + builder.append(" "); + } + } + + if (usingFromKeyword) { + builder.append("FROM "); + } + builder.append(fromItem).append("\n"); + if (lateralViews != null) { + for (LateralView lateralView : lateralViews) { + builder.append(" ").append(lateralView); + } + } + if (joins != null) { + for (Join join : joins) { + if (join.isSimple()) { + builder.append(", ").append(join); + } else { + builder.append(" ").append(join); + } + } + } + for (PipeOperator operator : pipeOperators) { + operator.appendTo(builder); + } + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/FromQueryVisitor.java b/src/main/java/net/sf/jsqlparser/statement/piped/FromQueryVisitor.java new file mode 100644 index 000000000..caa76cb61 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/FromQueryVisitor.java @@ -0,0 +1,14 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +public interface FromQueryVisitor { + T visit(FromQuery fromQuery, S context); +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java new file mode 100644 index 000000000..ebf4be1e5 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java @@ -0,0 +1,43 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.Join; + +public class JoinPipeOperator extends PipeOperator { + private Join join; + + public JoinPipeOperator(Join join) { + this.join = join; + } + + public Join getJoin() { + return join; + } + + public JoinPipeOperator setJoin(Join join) { + this.join = join; + return this; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append(join); + builder.append("\n"); + return builder; + } + + +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java new file mode 100644 index 000000000..144736463 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java @@ -0,0 +1,58 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Expression; + +public class LimitPipeOperator extends PipeOperator { + private Expression limitExpression; + private Expression offsetExpression; + + public LimitPipeOperator(Expression limitExpression, Expression offsetExpression) { + this.limitExpression = limitExpression; + this.offsetExpression = offsetExpression; + } + + public LimitPipeOperator(Expression limitExpression) { + this(limitExpression, null); + } + + public Expression getLimitExpression() { + return limitExpression; + } + + public LimitPipeOperator setLimitExpression(Expression limitExpression) { + this.limitExpression = limitExpression; + return this; + } + + public Expression getOffsetExpression() { + return offsetExpression; + } + + public LimitPipeOperator setOffsetExpression(Expression offsetExpression) { + this.offsetExpression = offsetExpression; + return this; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("LIMIT ").append(limitExpression); + if (offsetExpression != null) { + builder.append(" OFFSET ").append(offsetExpression); + } + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/OrderByPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/OrderByPipeOperator.java new file mode 100644 index 000000000..35eba46ea --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/OrderByPipeOperator.java @@ -0,0 +1,47 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.OrderByElement; + +import java.util.List; + +public class OrderByPipeOperator extends PipeOperator { + private List orderByElements; + + public OrderByPipeOperator(List orderByElements) { + this.orderByElements = orderByElements; + } + + public List getOrderByElements() { + return orderByElements; + } + + public OrderByPipeOperator setOrderByElements(List orderByElements) { + this.orderByElements = orderByElements; + return this; + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ") + .append("ORDER BY "); + for (OrderByElement orderByElement : orderByElements) { + builder.append(orderByElement); + } + builder.append("\n"); + return builder; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperator.java new file mode 100644 index 000000000..8c43be516 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperator.java @@ -0,0 +1,16 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public abstract class PipeOperator extends ASTNodeAccessImpl { + public abstract T accept(PipeOperatorVisitor visitor, S context); +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java new file mode 100644 index 000000000..f3f211e41 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java @@ -0,0 +1,47 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +public interface PipeOperatorVisitor { + T visit(AggregatePipeOperator aggregate, S context); + + T visit(AsPipeOperator as, S context); + + T visit(CallPipeOperator call, S context); + + T visit(DropPipeOperator drop, S context); + + T visit(ExtendPipeOperator extend, S context); + + T visit(JoinPipeOperator join, S context); + + T visit(LimitPipeOperator limit, S context); + + T visit(OrderByPipeOperator orderBy, S context); + + T visit(PivotPipeOperator pivot, S context); + + T visit(RenamePipeOperator rename, S context); + + T visit(SelectPipeOperator select, S context); + + T visit(SetPipeOperator set, S context); + + T visit(TableSamplePipeOperator tableSample, S context); + + T visit(SetOperationPipeOperator union, S context); + + T visit(UnPivotPipeOperator unPivot, S context); + + T visit(WherePipeOperator where, S context); + + T visit(WindowPipeOperator window, S context); +} + diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/PivotPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/PivotPipeOperator.java new file mode 100644 index 000000000..94cbfdedf --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/PivotPipeOperator.java @@ -0,0 +1,92 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Function; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.util.List; + +public class PivotPipeOperator extends PipeOperator { + private Function aggregateExpression; + private Column inputColumn; + private List> pivotColumns; + private Alias alias = null; + + public PivotPipeOperator(Function aggregateExpression, Column inputColumn, + List> pivotColumns, Alias alias) { + this.aggregateExpression = aggregateExpression; + this.inputColumn = inputColumn; + this.pivotColumns = pivotColumns; + this.alias = alias; + } + + public Function getAggregateExpression() { + return aggregateExpression; + } + + public PivotPipeOperator setAggregateExpression(Function aggregateExpression) { + this.aggregateExpression = aggregateExpression; + return this; + } + + public Column getInputColumn() { + return inputColumn; + } + + public PivotPipeOperator setInputColumn(Column inputColumn) { + this.inputColumn = inputColumn; + return this; + } + + public List> getPivotColumns() { + return pivotColumns; + } + + public PivotPipeOperator setPivotColumns(List> pivotColumns) { + this.pivotColumns = pivotColumns; + return this; + } + + public Alias getAlias() { + return alias; + } + + public PivotPipeOperator setAlias(Alias alias) { + this.alias = alias; + return this; + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder + .append("|> ") + .append("PIVOT( ") + .append(aggregateExpression) + .append(" FOR ") + .append(inputColumn) + .append(" IN (") + .append(Select.getStringList(pivotColumns)) + .append("))"); + if (alias != null) { + builder.append(" ").append(alias); + } + builder.append("\n"); + return builder; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/RenamePipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/RenamePipeOperator.java new file mode 100644 index 000000000..6ddc8aa61 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/RenamePipeOperator.java @@ -0,0 +1,18 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.SelectItem; + +public class RenamePipeOperator extends SelectPipeOperator { + public RenamePipeOperator(SelectItem selectItem) { + super("RENAME", selectItem, null); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java new file mode 100644 index 000000000..82a188a58 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java @@ -0,0 +1,68 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.util.ArrayList; + +public class SelectPipeOperator extends PipeOperator { + private final String operatorName; + private final String modifier; + + private final ArrayList> selectItems = new ArrayList<>(); + + public SelectPipeOperator(String operatorName, SelectItem selectItem, String modifier) { + this.operatorName = operatorName; + this.modifier = modifier; + selectItems.add(selectItem); + } + + public String getOperatorName() { + return operatorName; + } + + public String getModifier() { + return modifier; + } + + public ArrayList> getSelectItems() { + return selectItems; + } + + public SelectPipeOperator add(SelectItem selectItem) { + selectItems.add(selectItem); + return this; + } + + public SelectPipeOperator with(SelectItem selectItem) { + return this.add(selectItem); + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append(operatorName); + if (modifier != null && !modifier.isEmpty()) { + builder.append(" ").append(modifier); + } + + int i = 0; + for (SelectItem selectItem : selectItems) { + builder.append(i++ > 0 ? ", " : " ").append(selectItem); + } + builder.append("\n"); + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperator.java new file mode 100644 index 000000000..d236ff5ed --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperator.java @@ -0,0 +1,86 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.ParenthesedSelect; +import net.sf.jsqlparser.statement.select.SetOperationList; + +import java.util.ArrayList; + +public class SetOperationPipeOperator extends PipeOperator { + private ArrayList selects; + private SetOperationList.SetOperationType setOperationType; + private String modifier; + + public SetOperationPipeOperator(ParenthesedSelect select, + SetOperationList.SetOperationType setOperationType, String modifier) { + this.selects = new ArrayList<>(); + this.selects.add(select); + + this.setOperationType = setOperationType; + this.modifier = modifier; + } + + public SetOperationPipeOperator add(ParenthesedSelect select) { + this.selects.add(select); + return this; + } + + public ArrayList getSelects() { + return selects; + } + + public SetOperationPipeOperator setSelects(ArrayList selects) { + this.selects = selects; + return this; + } + + public SetOperationList.SetOperationType getSetOperationType() { + return setOperationType; + } + + public SetOperationPipeOperator setSetOperationType( + SetOperationList.SetOperationType setOperationType) { + this.setOperationType = setOperationType; + return this; + } + + public String getModifier() { + return modifier; + } + + public SetOperationPipeOperator setModifier(String modifier) { + this.modifier = modifier; + return this; + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append(setOperationType); + if (modifier != null) { + builder.append(" ").append(modifier); + } + + int i = 0; + for (ParenthesedSelect select : selects) { + if (i++ > 0) { + builder.append(", "); + } + builder.append(select); + } + builder.append("\n"); + return builder; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java new file mode 100644 index 000000000..806cf211b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java @@ -0,0 +1,181 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.update.UpdateSet; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +public class SetPipeOperator extends PipeOperator { + private List updateSets; + + public SetPipeOperator(List updateSets) { + this.updateSets = updateSets; + } + + public List getUpdateSets() { + return updateSets; + } + + public SetPipeOperator setUpdateSets(List updateSets) { + this.updateSets = updateSets; + return this; + } + + public int size() { + return updateSets.size(); + } + + public void forEach(Consumer action) { + updateSets.forEach(action); + } + + public boolean remove(Object o) { + return updateSets.remove(o); + } + + public Spliterator spliterator() { + return updateSets.spliterator(); + } + + public boolean addAll(Collection c) { + return updateSets.addAll(c); + } + + public Stream parallelStream() { + return updateSets.parallelStream(); + } + + public UpdateSet get(int index) { + return updateSets.get(index); + } + + public boolean containsAll(Collection c) { + return updateSets.containsAll(c); + } + + public List subList(int fromIndex, int toIndex) { + return updateSets.subList(fromIndex, toIndex); + } + + public ListIterator listIterator() { + return updateSets.listIterator(); + } + + public void sort(Comparator c) { + updateSets.sort(c); + } + + public T[] toArray(T[] a) { + return updateSets.toArray(a); + } + + public ListIterator listIterator(int index) { + return updateSets.listIterator(index); + } + + public Stream stream() { + return updateSets.stream(); + } + + public int lastIndexOf(Object o) { + return updateSets.lastIndexOf(o); + } + + public boolean add(UpdateSet updateSet) { + return updateSets.add(updateSet); + } + + public void clear() { + updateSets.clear(); + } + + public Iterator iterator() { + return updateSets.iterator(); + } + + public boolean retainAll(Collection c) { + return updateSets.retainAll(c); + } + + public int indexOf(Object o) { + return updateSets.indexOf(o); + } + + public T[] toArray(IntFunction generator) { + return updateSets.toArray(generator); + } + + public boolean contains(Object o) { + return updateSets.contains(o); + } + + public Object[] toArray() { + return updateSets.toArray(); + } + + public void replaceAll(UnaryOperator operator) { + updateSets.replaceAll(operator); + } + + public UpdateSet remove(int index) { + return updateSets.remove(index); + } + + public boolean addAll(int index, Collection c) { + return updateSets.addAll(index, c); + } + + public boolean removeIf(Predicate filter) { + return updateSets.removeIf(filter); + } + + public void add(int index, UpdateSet element) { + updateSets.add(index, element); + } + + public boolean removeAll(Collection c) { + return updateSets.removeAll(c); + } + + public UpdateSet set(int index, UpdateSet element) { + return updateSets.set(index, element); + } + + public boolean isEmpty() { + return updateSets.isEmpty(); + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("SET"); + int i = 0; + for (UpdateSet updateSet : updateSets) { + builder.append(i++ > 0 ? ", " : " ").append(updateSet); + } + builder.append("\n"); + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperator.java new file mode 100644 index 000000000..bc9fcc735 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperator.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +public class TableSamplePipeOperator extends PipeOperator { + double percent; + + public TableSamplePipeOperator(double percent) { + this.percent = percent; + } + + public TableSamplePipeOperator(String percentStr) { + this.percent = Double.parseDouble(percentStr); + } + + public double getPercent() { + return percent; + } + + public TableSamplePipeOperator setPercent(double percent) { + this.percent = percent; + return this; + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("TABLESAMPLE SYSTEM (").append(percent).append(" PERCENT)"); + return builder; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperator.java new file mode 100644 index 000000000..b2c598917 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperator.java @@ -0,0 +1,91 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.util.List; + +public class UnPivotPipeOperator extends PipeOperator { + private Column valuesColumn; + private Column nameColumn; + private List> pivotColumns; + private Alias alias = null; + + public UnPivotPipeOperator(Column valuesColumn, Column nameColumn, + List> pivotColumns, Alias alias) { + this.valuesColumn = valuesColumn; + this.nameColumn = nameColumn; + this.pivotColumns = pivotColumns; + this.alias = alias; + } + + public Column getValuesColumn() { + return valuesColumn; + } + + public UnPivotPipeOperator setValuesColumn(Column valuesColumn) { + this.valuesColumn = valuesColumn; + return this; + } + + public Column getNameColumn() { + return nameColumn; + } + + public UnPivotPipeOperator setNameColumn(Column nameColumn) { + this.nameColumn = nameColumn; + return this; + } + + public List> getPivotColumns() { + return pivotColumns; + } + + public UnPivotPipeOperator setPivotColumns(List> pivotColumns) { + this.pivotColumns = pivotColumns; + return this; + } + + public Alias getAlias() { + return alias; + } + + public UnPivotPipeOperator setAlias(Alias alias) { + this.alias = alias; + return this; + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder + .append("|> ") + .append("UNPIVOT( ") + .append(valuesColumn) + .append(" FOR ") + .append(nameColumn) + .append(" IN (") + .append(Select.getStringList(pivotColumns)) + .append("))"); + if (alias != null) { + builder.append(" ").append(alias); + } + builder.append("\n"); + return builder; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/WherePipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/WherePipeOperator.java new file mode 100644 index 000000000..15bcd8dbe --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/WherePipeOperator.java @@ -0,0 +1,43 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Expression; + +public class WherePipeOperator extends PipeOperator { + private Expression expression; + + public WherePipeOperator(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + public WherePipeOperator setExpression(Expression expression) { + this.expression = expression; + return this; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ") + .append("WHERE ") + .append(expression) + .append("\n"); + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java new file mode 100644 index 000000000..31902570d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java @@ -0,0 +1,18 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.SelectItem; + +public class WindowPipeOperator extends SelectPipeOperator { + public WindowPipeOperator(SelectItem selectItem) { + super("WINDOW", selectItem, null); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/refresh/RefreshMaterializedViewStatement.java b/src/main/java/net/sf/jsqlparser/statement/refresh/RefreshMaterializedViewStatement.java index 86b530ed3..6519cfe5c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/refresh/RefreshMaterializedViewStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/refresh/RefreshMaterializedViewStatement.java @@ -91,8 +91,8 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public RefreshMaterializedViewStatement withTableName(Table view) { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/AbstractFromitem.java b/src/main/java/net/sf/jsqlparser/statement/select/AbstractFromitem.java new file mode 100644 index 000000000..7bc94b678 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/AbstractFromitem.java @@ -0,0 +1,62 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public abstract class AbstractFromitem extends ASTNodeAccessImpl implements FromItem { + private Alias alias; + private Pivot pivot; + private UnPivot unPivot; + private SampleClause sampleClause = null; + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + @Override + public Pivot getPivot() { + return pivot; + } + + @Override + public void setPivot(Pivot pivot) { + this.pivot = pivot; + } + + @Override + public UnPivot getUnPivot() { + return unPivot; + } + + @Override + public void setUnPivot(UnPivot unpivot) { + this.unPivot = unpivot; + } + + @Override + public SampleClause getSampleClause() { + return sampleClause; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + this.sampleClause = sampleClause; + return this; + } + +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/AllColumns.java b/src/main/java/net/sf/jsqlparser/statement/select/AllColumns.java index 433dffdc6..08b8532e3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/AllColumns.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/AllColumns.java @@ -21,11 +21,20 @@ public class AllColumns extends ASTNodeAccessImpl implements Expression { protected ExpressionList exceptColumns; protected List> replaceExpressions; + private String exceptKeyword; public AllColumns(ExpressionList exceptColumns, List> replaceExpressions) { this.exceptColumns = exceptColumns; this.replaceExpressions = replaceExpressions; + this.exceptKeyword = exceptColumns != null ? "Except" : null; + } + + public AllColumns(ExpressionList exceptColumns, + List> replaceExpressions, String exceptKeyword) { + this.exceptColumns = exceptColumns; + this.replaceExpressions = replaceExpressions; + this.exceptKeyword = exceptKeyword; } public AllColumns() { @@ -36,6 +45,11 @@ public ExpressionList getExceptColumns() { return exceptColumns; } + public AllColumns setExceptColumns(ExpressionList exceptColumns) { + this.exceptColumns = exceptColumns; + return this; + } + public ExpressionList addExceptColumn(Column column) { if (exceptColumns == null) { exceptColumns = new ExpressionList<>(); @@ -44,15 +58,15 @@ public ExpressionList addExceptColumn(Column column) { return exceptColumns; } - public AllColumns setExceptColumns(ExpressionList exceptColumns) { - this.exceptColumns = exceptColumns; - return this; - } - public List> getReplaceExpressions() { return replaceExpressions; } + public AllColumns setReplaceExpressions(List> replaceExpressions) { + this.replaceExpressions = replaceExpressions; + return this; + } + public List> addReplaceExpression(SelectItem selectItem) { if (replaceExpressions == null) { replaceExpressions = new ArrayList<>(); @@ -61,25 +75,25 @@ public List> addReplaceExpression(SelectItem selectItem) { return replaceExpressions; } - public AllColumns setReplaceExpressions(List> replaceExpressions) { - this.replaceExpressions = replaceExpressions; + public String getExceptKeyword() { + return exceptKeyword; + } + + public AllColumns setExceptKeyword(String exceptKeyword) { + this.exceptKeyword = exceptKeyword; return this; } public StringBuilder appendTo(StringBuilder builder) { builder.append("*"); - if (exceptColumns != null && exceptColumns.size() > 0) { - builder.append(" Except( "); + if (exceptColumns != null && !exceptColumns.isEmpty()) { + builder.append(" ").append(exceptKeyword).append("( "); exceptColumns.appendTo(builder); builder.append(" )"); } - if (replaceExpressions != null && replaceExpressions.size() > 0) { - builder.append(" Replace("); - int i = 0; - for (SelectItem selectItem : replaceExpressions) { - builder.append(i++ > 0 ? ", " : " "); - selectItem.appendTo(builder); - } + if (replaceExpressions != null && !replaceExpressions.isEmpty()) { + builder.append(" REPLACE( "); + builder.append(Select.getStringList(replaceExpressions)); builder.append(" )"); } return builder; @@ -91,7 +105,7 @@ public String toString() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/AllTableColumns.java b/src/main/java/net/sf/jsqlparser/statement/select/AllTableColumns.java index cda2e8136..0030da89b 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/AllTableColumns.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/AllTableColumns.java @@ -9,29 +9,37 @@ */ package net.sf.jsqlparser.statement.select; +import java.util.List; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; - -import java.util.List; +import net.sf.jsqlparser.statement.ReturningReferenceType; public class AllTableColumns extends AllColumns { private Table table; + private ReturningReferenceType returningReferenceType = null; + private String returningQualifier = null; public AllTableColumns(Table table, ExpressionList exceptColumns, - List> replaceExpressions) { - super(exceptColumns, replaceExpressions); + List> replaceExpressions, String exceptKeyword) { + super(exceptColumns, replaceExpressions, exceptKeyword); this.table = table; } + public AllTableColumns(Table table, ExpressionList exceptColumns, + List> replaceExpressions) { + this(table, exceptColumns, replaceExpressions, "EXCEPT"); + } + public AllTableColumns(Table table) { this(table, null, null); } public AllTableColumns(Table table, AllColumns allColumns) { - this(table, allColumns.exceptColumns, allColumns.replaceExpressions); + this(table, allColumns.exceptColumns, allColumns.replaceExpressions, + allColumns.getExceptKeyword()); } public Table getTable() { @@ -49,11 +57,43 @@ public AllTableColumns withTable(Table table) { @Override public StringBuilder appendTo(StringBuilder builder) { - return super.appendTo(table.appendTo(builder).append(".")); + if (returningQualifier != null) { + return super.appendTo(builder.append(returningQualifier).append(".")); + } + if (table != null) { + return super.appendTo(table.appendTo(builder).append(".")); + } + return super.appendTo(builder); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public ReturningReferenceType getReturningReferenceType() { + return returningReferenceType; + } + + public AllTableColumns setReturningReferenceType( + ReturningReferenceType returningReferenceType) { + this.returningReferenceType = returningReferenceType; + return this; + } + + public String getReturningQualifier() { + return returningQualifier; + } + + public AllTableColumns setReturningQualifier(String returningQualifier) { + this.returningQualifier = returningQualifier; + return this; + } + + public AllTableColumns withReturningReference(ReturningReferenceType returningReferenceType, + String returningQualifier) { + this.returningReferenceType = returningReferenceType; + this.returningQualifier = returningQualifier; + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Distinct.java b/src/main/java/net/sf/jsqlparser/statement/select/Distinct.java index 37f64ad81..c0312384a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Distinct.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Distinct.java @@ -20,6 +20,7 @@ public class Distinct implements Serializable { private List> onSelectItems; private boolean useUnique = false; + private boolean useDistinctRow = false; public Distinct() {} @@ -43,9 +44,18 @@ public void setUseUnique(boolean useUnique) { this.useUnique = useUnique; } + public boolean isUseDistinctRow() { + return useDistinctRow; + } + + public void setUseDistinctRow(boolean useDistinctRow) { + this.useDistinctRow = useDistinctRow; + } + @Override public String toString() { - String sql = useUnique ? "UNIQUE" : "DISTINCT"; + String distinctIdentifier = useDistinctRow ? "DISTINCTROW" : "DISTINCT"; + String sql = useUnique ? "UNIQUE" : distinctIdentifier; if (onSelectItems != null && !onSelectItems.isEmpty()) { sql += " ON (" + PlainSelect.getStringList(onSelectItems) + ")"; diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java b/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java index f6b11a70a..c38dd140b 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java @@ -14,6 +14,26 @@ public class ExceptOp extends SetOperation { public ExceptOp() { + this(""); + } + + public ExceptOp(String modifier) { super(SetOperationType.EXCEPT); + this.modifier = modifier; + } + + public ExceptOp withDistinct(boolean distinct) { + this.setDistinct(distinct); + return this; + } + + public ExceptOp withAll(boolean all) { + this.setAll(all); + return this; + } + + public ExceptOp withModifier(String modifier) { + this.modifier = modifier; + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Fetch.java b/src/main/java/net/sf/jsqlparser/statement/select/Fetch.java index f4590d7df..4e8fd9db6 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Fetch.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Fetch.java @@ -19,9 +19,9 @@ import java.util.List; public class Fetch implements Serializable { + private final List fetchParameters = new ArrayList<>(); private Expression expression = null; private boolean isFetchParamFirst = false; - private final List fetchParameters = new ArrayList<>(); @Deprecated public long getRowCount() { @@ -51,6 +51,11 @@ public JdbcParameter getFetchJdbcParameter() { return expression instanceof JdbcParameter ? (JdbcParameter) expression : null; } + @Deprecated + public void setFetchJdbcParameter(JdbcParameter jdbc) { + this.setExpression(jdbc); + } + public Fetch addFetchParameter(String parameter) { fetchParameters.add(parameter); return this; @@ -69,15 +74,6 @@ public String getFetchParam() { return parameterStr.trim(); } - public boolean isFetchParamFirst() { - return isFetchParamFirst; - } - - @Deprecated - public void setFetchJdbcParameter(JdbcParameter jdbc) { - this.setExpression(jdbc); - } - @Deprecated public void setFetchParam(String s) { fetchParameters.clear(); @@ -86,6 +82,10 @@ public void setFetchParam(String s) { } } + public boolean isFetchParamFirst() { + return isFetchParamFirst; + } + public void setFetchParamFirst(boolean b) { this.isFetchParamFirst = b; } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/First.java b/src/main/java/net/sf/jsqlparser/statement/select/First.java index b6d872941..3744e30a3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/First.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/First.java @@ -15,14 +15,6 @@ public class First implements Serializable { - public enum Keyword { - FIRST, LIMIT; - - public static Keyword from(String keyword) { - return Enum.valueOf(Keyword.class, keyword.toUpperCase()); - } - } - private Keyword keyword; private Long rowCount; private JdbcParameter jdbcParameter; @@ -94,4 +86,12 @@ public First withVariable(String variable) { this.setVariable(variable); return this; } + + public enum Keyword { + FIRST, LIMIT; + + public static Keyword from(String keyword) { + return Enum.valueOf(Keyword.class, keyword.toUpperCase()); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ForClause.java b/src/main/java/net/sf/jsqlparser/statement/select/ForClause.java index 28af1c276..4604425a3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ForClause.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ForClause.java @@ -12,14 +12,6 @@ import net.sf.jsqlparser.parser.ASTNodeAccessImpl; public class ForClause extends ASTNodeAccessImpl { - public enum ForOption { - BROWSE, XML, JSON; - - public static ForOption from(String option) { - return Enum.valueOf(ForOption.class, option.toUpperCase()); - } - } - private ForOption forOption; public ForOption getForOption() { @@ -35,4 +27,12 @@ public ForClause setForOption(String forOption) { public String toString() { return appendTo(new StringBuilder()).toString(); } + + public enum ForOption { + BROWSE, XML, JSON; + + public static ForOption from(String option) { + return Enum.valueOf(ForOption.class, option.toUpperCase()); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java b/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java index a58233ed1..3ca0b61d0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java @@ -20,15 +20,18 @@ public enum ForMode { NO_KEY_UPDATE("NO KEY UPDATE"), - KEY_SHARE("KEY SHARE"); + KEY_SHARE("KEY SHARE"), - private final String value; + // https://www.ibm.com/docs/en/db2-for-zos/13.0.0?topic=statement-read-only-clause + READ_ONLY("READ ONLY"), FETCH_ONLY("FETCH ONLY"); - public String getValue() { - return value; - } + private final String value; ForMode(String s) { this.value = s; } + + public String getValue() { + return value; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ForUpdateClause.java b/src/main/java/net/sf/jsqlparser/statement/select/ForUpdateClause.java new file mode 100644 index 000000000..499324551 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/ForUpdateClause.java @@ -0,0 +1,135 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import java.util.List; +import net.sf.jsqlparser.schema.Table; + +/** + * Represents a FOR UPDATE / FOR SHARE locking clause in a SELECT statement. + * + *

+ * Supports all common SQL dialects: + *

    + *
  • {@code FOR UPDATE} – standard row locking
  • + *
  • {@code FOR UPDATE OF t1, t2} – table-specific locking (Oracle, PostgreSQL)
  • + *
  • {@code FOR UPDATE NOWAIT} – fail immediately if rows are locked (Oracle, PostgreSQL)
  • + *
  • {@code FOR UPDATE WAIT n} – wait up to n seconds (Oracle)
  • + *
  • {@code FOR UPDATE SKIP LOCKED} – skip locked rows (Oracle, PostgreSQL)
  • + *
  • {@code FOR SHARE} – shared row lock (PostgreSQL)
  • + *
  • {@code FOR KEY SHARE} – key-level shared lock (PostgreSQL)
  • + *
  • {@code FOR NO KEY UPDATE} – non-key exclusive lock (PostgreSQL)
  • + *
+ *

+ */ +public class ForUpdateClause { + + private ForMode mode; + private List
tables; + private Wait wait; + private boolean noWait; + private boolean skipLocked; + + public ForMode getMode() { + return mode; + } + + public ForUpdateClause setMode(ForMode mode) { + this.mode = mode; + return this; + } + + public List
getTables() { + return tables; + } + + public ForUpdateClause setTables(List
tables) { + this.tables = tables; + return this; + } + + /** + * Returns the first table from the OF clause, or {@code null} if none was specified. + * + * @return the first table, or {@code null} + */ + public Table getFirstTable() { + return (tables != null && !tables.isEmpty()) ? tables.get(0) : null; + } + + public Wait getWait() { + return wait; + } + + public ForUpdateClause setWait(Wait wait) { + this.wait = wait; + return this; + } + + public boolean isNoWait() { + return noWait; + } + + public ForUpdateClause setNoWait(boolean noWait) { + this.noWait = noWait; + return this; + } + + public boolean isSkipLocked() { + return skipLocked; + } + + public ForUpdateClause setSkipLocked(boolean skipLocked) { + this.skipLocked = skipLocked; + return this; + } + + /** Returns {@code true} when the mode is {@link ForMode#UPDATE}. */ + public boolean isForUpdate() { + return mode == ForMode.UPDATE; + } + + /** Returns {@code true} when the mode is {@link ForMode#SHARE}. */ + public boolean isForShare() { + return mode == ForMode.SHARE; + } + + /** Returns {@code true} when at least one table was listed in the OF clause. */ + public boolean hasTableList() { + return tables != null && !tables.isEmpty(); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append(" FOR ").append(mode.getValue()); + if (tables != null && !tables.isEmpty()) { + builder.append(" OF "); + for (int i = 0; i < tables.size(); i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(tables.get(i)); + } + } + if (wait != null) { + builder.append(wait); + } + if (noWait) { + builder.append(" NOWAIT"); + } else if (skipLocked) { + builder.append(" SKIP LOCKED"); + } + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItem.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItem.java index 2c63b0b63..b452d69a9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItem.java @@ -14,34 +14,68 @@ public interface FromItem extends ASTNodeAccess { - void accept(FromItemVisitor fromItemVisitor); + T accept(FromItemVisitor fromItemVisitor, S context); + + default void accept(FromItemVisitor fromItemVisitor) { + this.accept(fromItemVisitor, null); + } Alias getAlias(); + void setAlias(Alias alias); + default FromItem withAlias(Alias alias) { setAlias(alias); return this; } - void setAlias(Alias alias); - Pivot getPivot(); + void setPivot(Pivot pivot); + default FromItem withPivot(Pivot pivot) { setPivot(pivot); return this; } - void setPivot(Pivot pivot); - UnPivot getUnPivot(); + void setUnPivot(UnPivot unpivot); + default FromItem withUnPivot(UnPivot unpivot) { setUnPivot(unpivot); return this; } - void setUnPivot(UnPivot unpivot); + SampleClause getSampleClause(); + + FromItem setSampleClause(SampleClause sampleClause); + + default StringBuilder appendTo(StringBuilder builder, Alias alias) { + return appendTo(builder, alias, null, null, null); + } + + default StringBuilder appendTo(StringBuilder builder, Alias alias, SampleClause sampleClause, + Pivot pivot, + UnPivot unPivot) { + if (alias != null) { + builder.append(alias); + } + + if (sampleClause != null) { + builder.append(sampleClause); + } + + if (pivot != null) { + builder.append(" ").append(pivot); + } + + if (unPivot != null) { + builder.append(" ").append(unPivot); + } + + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java index 6d6b85ba4..6b1048031 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java @@ -10,18 +10,99 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.Import; +import net.sf.jsqlparser.statement.piped.FromQuery; -public interface FromItemVisitor { +import java.util.Collection; +import java.util.List; - void visit(Table tableName); +public interface FromItemVisitor { - void visit(ParenthesedSelect selectBody); + default T visitFromItem(FromItem fromItem, S context) { + if (fromItem != null) { + fromItem.accept(this, context); + } + return null; + } - void visit(LateralSubSelect lateralSubSelect); + default T visitTables(List
tables, S context) { + if (tables != null) { + for (Table table : tables) { + table.accept(this, context); + } + } + return null; + } - void visit(TableFunction tableFunction); + default T visitJoins(Collection joins, S context) { + if (joins != null) { + for (Join join : joins) { + join.getFromItem().accept(this, context); + } + } + return null; + } - void visit(ParenthesedFromItem aThis); + T visit(Table tableName, S context); + + default void visit(Table tableName) { + this.visit(tableName, null); + } + + T visit(ParenthesedSelect selectBody, S context); + + default void visit(ParenthesedSelect selectBody) { + this.visit(selectBody, null); + } + + T visit(LateralSubSelect lateralSubSelect, S context); + + default void visit(LateralSubSelect lateralSubSelect) { + this.visit(lateralSubSelect, null); + } + + T visit(TableFunction tableFunction, S context); + + default void visit(TableFunction tableFunction) { + this.visit(tableFunction, null); + } + + T visit(ParenthesedFromItem parenthesedFromItem, S context); + + default void visit(ParenthesedFromItem parenthesedFromItem) { + this.visit(parenthesedFromItem, null); + } + + T visit(Values values, S context); + + default void visit(Values values) { + this.visit(values, null); + } + + T visit(PlainSelect plainSelect, S context); + + default void visit(PlainSelect plainSelect) { + this.visit(plainSelect, null); + } + + T visit(SetOperationList setOperationList, S context); + + default void visit(SetOperationList setOperationList) { + this.visit(setOperationList, null); + } + + T visit(TableStatement tableStatement, S context); + + default void visit(TableStatement tableStatement) { + this.visit(tableStatement, null); + } + + T visit(Import imprt, S context); + + default void visit(Import imprt) { + this.visit(imprt, null); + } + + T visit(FromQuery fromQuery, S context); - void visit(Values values); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java index fcc7ca089..23bd480b8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java @@ -9,38 +9,144 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.Import; +import net.sf.jsqlparser.statement.piped.FromQuery; + +import java.util.ArrayList; +import java.util.Collection; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class FromItemVisitorAdapter implements FromItemVisitor { +public class FromItemVisitorAdapter implements FromItemVisitor { + private SelectVisitor selectVisitor; + private ExpressionVisitor expressionVisitor; + + public FromItemVisitorAdapter(SelectVisitor selectVisitor, + ExpressionVisitor expressionVisitor) { + this.selectVisitor = selectVisitor; + this.expressionVisitor = expressionVisitor; + } + + public FromItemVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.selectVisitor = new SelectVisitorAdapter<>(expressionVisitor); + this.expressionVisitor = expressionVisitor; + } + + public FromItemVisitorAdapter() { + this.selectVisitor = new SelectVisitorAdapter<>(); + this.expressionVisitor = new ExpressionVisitorAdapter<>(this.selectVisitor); + } + + + public SelectVisitor getSelectVisitor() { + return selectVisitor; + } + + public FromItemVisitorAdapter setSelectVisitor(SelectVisitor selectVisitor) { + this.selectVisitor = selectVisitor; + return this; + } + + public FromItemVisitorAdapter setSelectVisitor(SelectVisitorAdapter selectVisitor) { + this.selectVisitor = selectVisitor; + this.expressionVisitor = selectVisitor.getExpressionVisitor(); + return this; + } + + public ExpressionVisitor getExpressionVisitor() { + return expressionVisitor; + } + + public FromItemVisitorAdapter setExpressionVisitor(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + return this; + } @Override - public void visit(Table table) { + public T visitJoins(Collection joins, S context) { + if (joins != null) { + for (Join join : joins) { + join.getFromItem().accept(this, context); + if (join.getUsingColumns() != null) { + for (Column column : join.getUsingColumns()) { + column.accept(expressionVisitor, context); + } + } + if (join.getOnExpressions() != null) { + for (Expression expression : join.getOnExpressions()) { + expression.accept(expressionVisitor, context); + } + } + } + } + return null; + } + @Override + public T visit(Table table, S context) { + return null; } @Override - public void visit(ParenthesedSelect selectBody) { + public T visit(ParenthesedSelect select, S context) { + return select.getPlainSelect().accept(selectVisitor, context); + } + @Override + public T visit(LateralSubSelect lateralSubSelect, S context) { + return lateralSubSelect.getPlainSelect().accept(selectVisitor, context); } @Override - public void visit(LateralSubSelect lateralSubSelect) { + public T visit(TableFunction tableFunction, S context) { + + return null; + } + @Override + public T visit(ParenthesedFromItem fromItem, S context) { + return fromItem.getFromItem().accept(this, context); } @Override - public void visit(TableFunction valuesList) { + public T visit(Values values, S context) { + for (Expression expression : values.getExpressions()) { + expression.accept(expressionVisitor, context); + } + return null; + } + @Override + public T visit(PlainSelect plainSelect, S context) { + return plainSelect.accept(selectVisitor, context); } @Override - public void visit(ParenthesedFromItem aThis) { + public T visit(SetOperationList setOperationList, S context) { + ArrayList results = new ArrayList<>(); + for (Select select : setOperationList.getSelects()) { + results.add(select.accept(selectVisitor, context)); + } + return results.isEmpty() ? null : results.get(0); + } + @Override + public T visit(TableStatement tableStatement, S context) { + return null; } @Override - public void visit(Values values) { + public T visit(Import imprt, S context) { + + return null; + } + public T visit(FromQuery fromQuery, S context) { + return fromQuery.accept(selectVisitor, context); } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FunctionAllColumns.java b/src/main/java/net/sf/jsqlparser/statement/select/FunctionAllColumns.java new file mode 100644 index 000000000..7a4fa5ce2 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/FunctionAllColumns.java @@ -0,0 +1,49 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.Function; + + +public class FunctionAllColumns extends AllColumns { + private Function function; + + public FunctionAllColumns(Function function) { + super(null, null, null); + this.function = function; + } + + public Function getFunction() { + return function; + } + + public FunctionAllColumns setFunction(Function function) { + this.function = function; + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("("); + builder.append(function); + builder.append(").*"); + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java index d052ad465..63b6b479d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java @@ -16,13 +16,14 @@ import java.util.Collections; import java.util.List; import java.util.Optional; + import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; public class GroupByElement implements Serializable { - private ExpressionList groupByExpressions = new ExpressionList(); - private List groupingSets = new ArrayList<>(); + private ExpressionList groupByExpressions = new ExpressionList<>(); + private List> groupingSets = new ArrayList<>(); // postgres rollup is an ExpressionList private boolean mysqlWithRollup = false; @@ -30,40 +31,40 @@ public boolean isUsingBrackets() { return groupByExpressions.isUsingBrackets(); } - public void accept(GroupByVisitor groupByVisitor) { - groupByVisitor.visit(this); + public T accept(GroupByVisitor groupByVisitor, S context) { + return groupByVisitor.visit(this, context); } - public ExpressionList getGroupByExpressionList() { + public ExpressionList getGroupByExpressionList() { return groupByExpressions; } - public void setGroupByExpressions(ExpressionList groupByExpressions) { - this.groupByExpressions = groupByExpressions; - } - @Deprecated - public ExpressionList getGroupByExpressions() { + public ExpressionList getGroupByExpressions() { return groupByExpressions; } + public void setGroupByExpressions(ExpressionList groupByExpressions) { + this.groupByExpressions = groupByExpressions; + } + @Deprecated public void addGroupByExpression(Expression groupByExpression) { if (groupByExpressions.getExpressions() == null) { - groupByExpressions.setExpressions(new ArrayList()); + groupByExpressions.setExpressions(new ArrayList<>()); } - groupByExpressions.getExpressions().add(groupByExpression); + groupByExpressions.add(groupByExpression); } - public List getGroupingSets() { + public List> getGroupingSets() { return groupingSets; } - public void setGroupingSets(List groupingSets) { + public void setGroupingSets(List> groupingSets) { this.groupingSets = groupingSets; } - public void addGroupingSet(ExpressionList list) { + public void addGroupingSet(ExpressionList list) { this.groupingSets.add(list); } @@ -74,16 +75,16 @@ public String toString() { b.append("GROUP BY "); if (groupByExpressions != null) { - b.append(groupByExpressions.toString()); + b.append(groupByExpressions); } int i = 0; - if (groupingSets.size() > 0) { + if (!groupingSets.isEmpty()) { if (b.charAt(b.length() - 1) != ' ') { b.append(' '); } b.append("GROUPING SETS ("); - for (ExpressionList expressionList : groupingSets) { + for (ExpressionList expressionList : groupingSets) { b.append(i++ > 0 ? ", " : "").append(Select.getStringList( expressionList, true, expressionList instanceof ParenthesedExpressionList)); @@ -98,12 +99,12 @@ public String toString() { return b.toString(); } - public GroupByElement withGroupByExpressions(ExpressionList groupByExpressions) { + public GroupByElement withGroupByExpressions(ExpressionList groupByExpressions) { this.setGroupByExpressions(groupByExpressions); return this; } - public GroupByElement withGroupingSets(List groupingSets) { + public GroupByElement withGroupingSets(List> groupingSets) { this.setGroupingSets(groupingSets); return this; } @@ -126,7 +127,8 @@ public GroupByElement addGroupingSets(Object... groupingSets) { return this.withGroupingSets(collection); } - public GroupByElement addGroupingSets(Collection groupingSets) { + public GroupByElement addGroupingSets( + Collection>> groupingSets) { List collection = Optional.ofNullable(getGroupingSets()).orElseGet(ArrayList::new); collection.addAll(groupingSets); return this.withGroupingSets(collection); diff --git a/src/main/java/net/sf/jsqlparser/statement/select/GroupByVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/GroupByVisitor.java index 21bfc5784..24ade130d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/GroupByVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/GroupByVisitor.java @@ -9,7 +9,11 @@ */ package net.sf.jsqlparser.statement.select; -public interface GroupByVisitor { +public interface GroupByVisitor { - void visit(GroupByElement groupBy); + T visit(GroupByElement groupBy, S context); + + default void visit(GroupByElement groupBy) { + this.visit(groupBy, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java b/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java index f2248ca1b..dd027d5ff 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java @@ -14,6 +14,26 @@ public class IntersectOp extends SetOperation { public IntersectOp() { + this(""); + } + + public IntersectOp(String modifier) { super(SetOperationType.INTERSECT); + this.modifier = modifier; + } + + public IntersectOp withDistinct(boolean distinct) { + this.setDistinct(distinct); + return this; + } + + public IntersectOp withAll(boolean all) { + this.setAll(all); + return this; + } + + public IntersectOp withModifier(String modifier) { + this.modifier = modifier; + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/IntoTableVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/IntoTableVisitor.java index 64a85ca9c..40be04581 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/IntoTableVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/IntoTableVisitor.java @@ -11,7 +11,11 @@ import net.sf.jsqlparser.schema.Table; -public interface IntoTableVisitor { +public interface IntoTableVisitor { - void visit(Table tableName); + T visit(Table tableName, S context); + + default void visit(Table tableName) { + this.visit(tableName, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/IntoTableVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/IntoTableVisitorAdapter.java index 77e56e6e9..44393beb3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/IntoTableVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/IntoTableVisitorAdapter.java @@ -12,10 +12,10 @@ import net.sf.jsqlparser.schema.Table; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class IntoTableVisitorAdapter implements IntoTableVisitor { +public class IntoTableVisitorAdapter implements IntoTableVisitor { @Override - public void visit(Table tableName) { - + public T visit(Table tableName, S context) { + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Join.java b/src/main/java/net/sf/jsqlparser/statement/select/Join.java index d057a5381..191465e27 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Join.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Join.java @@ -23,6 +23,8 @@ @SuppressWarnings({"PMD.CyclomaticComplexity"}) public class Join extends ASTNodeAccessImpl { + private final LinkedList onExpressions = new LinkedList<>(); + private final LinkedList usingColumns = new LinkedList<>(); private boolean outer = false; private boolean right = false; private boolean left = false; @@ -33,11 +35,12 @@ public class Join extends ASTNodeAccessImpl { private boolean simple = false; private boolean cross = false; private boolean semi = false; + private boolean any = false; + private boolean all = false; private boolean straight = false; private boolean apply = false; + private boolean fetch = false; private FromItem fromItem; - private final LinkedList onExpressions = new LinkedList<>(); - private final LinkedList usingColumns = new LinkedList<>(); private KSQLJoinWindow joinWindow; private JoinHint joinHint = null; @@ -46,20 +49,19 @@ public boolean isSimple() { return simple; } + public void setSimple(boolean b) { + simple = b; + } + public Join withSimple(boolean b) { this.setSimple(b); return this; } - public void setSimple(boolean b) { - simple = b; - } - /** * A JOIN means INNER when the INNER keyword is set or when no other qualifier has been set. * * @return Tells, if a JOIN means a qualified INNER JOIN. - * */ public boolean isInnerJoin() { return inner @@ -75,20 +77,13 @@ public boolean isInnerJoin() { } /** - * * @return Tells, if the INNER keyword has been set. */ public boolean isInner() { return inner; } - public Join withInner(boolean b) { - this.setInner(b); - return this; - } - /** - * * Sets the INNER keyword and switches off any contradicting qualifiers automatically. */ public void setInner(boolean b) { @@ -102,19 +97,24 @@ public void setInner(boolean b) { inner = b; } + public Join withInner(boolean b) { + this.setInner(b); + return this; + } + public boolean isStraight() { return straight; } + public void setStraight(boolean b) { + straight = b; + } + public Join withStraight(boolean b) { this.setStraight(b); return this; } - public void setStraight(boolean b) { - straight = b; - } - /** * Whether is a "OUTER" join * @@ -124,13 +124,7 @@ public boolean isOuter() { return outer; } - public Join withOuter(boolean b) { - this.setOuter(b); - return this; - } - /** - * * Sets the OUTER keyword and switches off any contradicting qualifiers automatically. */ public void setOuter(boolean b) { @@ -140,17 +134,40 @@ public void setOuter(boolean b) { outer = b; } + public Join withOuter(boolean b) { + this.setOuter(b); + return this; + } + public boolean isApply() { return apply; } + public void setApply(boolean apply) { + this.apply = apply; + } + public Join withApply(boolean apply) { this.setApply(apply); return this; } - public void setApply(boolean apply) { - this.apply = apply; + /** + * Whether is a "FETCH" join (JPQL/HQL) + * + * @return true if is a "FETCH" join + */ + public boolean isFetch() { + return fetch; + } + + public void setFetch(boolean b) { + fetch = b; + } + + public Join withFetch(boolean b) { + this.setFetch(b); + return this; } /** @@ -162,31 +179,67 @@ public boolean isSemi() { return semi; } + public void setSemi(boolean b) { + semi = b; + } + public Join withSemi(boolean b) { this.setSemi(b); return this; } - public void setSemi(boolean b) { - semi = b; + /** + * Whether is an "ANY" join + * + * @return true if is an "ANY" join + */ + public boolean isAny() { + return any; + } + + public void setAny(boolean b) { + if (b) { + all = false; + } + any = b; + } + + public Join withAny(boolean b) { + this.setAny(b); + return this; } /** - * Whether is a "LEFT" join + * Whether is an "ALL" join * - * @return true if is a "LEFT" join + * @return true if is an "ALL" join */ - public boolean isLeft() { - return left; + public boolean isAll() { + return all; } - public Join withLeft(boolean b) { - this.setLeft(b); + public void setAll(boolean b) { + if (b) { + any = false; + } + all = b; + } + + public Join withAll(boolean b) { + this.setAll(b); return this; } /** + * Whether is a "LEFT" join * + * @return true if is a "LEFT" join + */ + public boolean isLeft() { + return left; + } + + /** * Sets the LEFT keyword and switches off any contradicting qualifiers automatically. */ public void setLeft(boolean b) { @@ -197,6 +250,11 @@ public void setLeft(boolean b) { left = b; } + public Join withLeft(boolean b) { + this.setLeft(b); + return this; + } + /** * Whether is a "RIGHT" join * @@ -206,13 +264,7 @@ public boolean isRight() { return right; } - public Join withRight(boolean b) { - this.setRight(b); - return this; - } - /** - * * Sets the RIGHT keyword and switches off any contradicting qualifiers automatically. */ public void setRight(boolean b) { @@ -223,6 +275,11 @@ public void setRight(boolean b) { right = b; } + public Join withRight(boolean b) { + this.setRight(b); + return this; + } + /** * Whether is a "NATURAL" join * @@ -232,23 +289,23 @@ public boolean isNatural() { return natural; } + public void setNatural(boolean b) { + natural = b; + } + public boolean isGlobal() { return global; } + public void setGlobal(boolean b) { + global = b; + } + public Join withNatural(boolean b) { this.setNatural(b); return this; } - public void setNatural(boolean b) { - natural = b; - } - - public void setGlobal(boolean b) { - global = b; - } - /** * Whether is a "FULL" join * @@ -258,46 +315,47 @@ public boolean isFull() { return full; } + public void setFull(boolean b) { + full = b; + } + public Join withFull(boolean b) { this.setFull(b); return this; } - public void setFull(boolean b) { - full = b; - } - public boolean isCross() { return cross; } + public void setCross(boolean cross) { + this.cross = cross; + } + public Join withCross(boolean cross) { this.setCross(cross); return this; } - public void setCross(boolean cross) { - this.cross = cross; - } - /** * Returns the right item of the join - * */ + @Deprecated public FromItem getRightItem() { return fromItem; } + @Deprecated + public void setRightItem(FromItem item) { + fromItem = item; + } + @Deprecated public Join withRightItem(FromItem item) { this.setFromItem(item); return this; } - public void setRightItem(FromItem item) { - fromItem = item; - } - public FromItem getFromItem() { return fromItem; } @@ -315,19 +373,25 @@ public Expression getOnExpression() { return onExpressions.get(0); } + @Deprecated + public void setOnExpression(Expression expression) { + onExpressions.add(0, expression); + } + public Collection getOnExpressions() { return onExpressions; } - @Deprecated - public Join withOnExpression(Expression expression) { - this.setOnExpression(expression); + public Join setOnExpressions(Collection expressions) { + onExpressions.clear(); + onExpressions.addAll(expressions); return this; } @Deprecated - public void setOnExpression(Expression expression) { - onExpressions.add(0, expression); + public Join withOnExpression(Expression expression) { + this.setOnExpression(expression); + return this; } public Join addOnExpression(Expression expression) { @@ -335,12 +399,6 @@ public Join addOnExpression(Expression expression) { return this; } - public Join setOnExpressions(Collection expressions) { - onExpressions.clear(); - onExpressions.addAll(expressions); - return this; - } - /** * Returns the "USING" list of {@link net.sf.jsqlparser.schema.Column}s (if any) */ @@ -348,38 +406,38 @@ public List getUsingColumns() { return usingColumns; } - public Join withUsingColumns(List list) { - this.setUsingColumns(list); - return this; - } - public void setUsingColumns(List list) { usingColumns.clear(); usingColumns.addAll(list); } + public Join withUsingColumns(List list) { + this.setUsingColumns(list); + return this; + } + public boolean isWindowJoin() { return joinWindow != null; } /** * Return the "WITHIN" join window (if any) - * + * * @return */ public KSQLJoinWindow getJoinWindow() { return joinWindow; } + public void setJoinWindow(KSQLJoinWindow joinWindow) { + this.joinWindow = joinWindow; + } + public Join withJoinWindow(KSQLJoinWindow joinWindow) { this.setJoinWindow(joinWindow); return this; } - public void setJoinWindow(KSQLJoinWindow joinWindow) { - this.joinWindow = joinWindow; - } - public JoinHint getJoinHint() { return joinHint; } @@ -407,6 +465,12 @@ public String toString() { builder.append("NATURAL "); } + if (isAny()) { + builder.append("ANY "); + } else if (isAll()) { + builder.append("ALL "); + } + if (isRight()) { builder.append("RIGHT "); } else if (isFull()) { @@ -434,6 +498,9 @@ public String toString() { builder.append(joinHint).append(" "); } builder.append("JOIN "); + if (fetch) { + builder.append("FETCH "); + } } builder.append(fromItem).append((joinWindow != null) ? " WITHIN " + joinWindow : ""); @@ -442,7 +509,7 @@ public String toString() { for (Expression onExpression : onExpressions) { builder.append(" ON ").append(onExpression); } - if (usingColumns.size() > 0) { + if (!usingColumns.isEmpty()) { builder.append(PlainSelect.getFormattedList(usingColumns, "USING", true, true)); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/KSQLJoinWindow.java b/src/main/java/net/sf/jsqlparser/statement/select/KSQLJoinWindow.java index a1598aac8..4bcc6a0a1 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/KSQLJoinWindow.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/KSQLJoinWindow.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + import static net.sf.jsqlparser.statement.select.KSQLWindow.TimeUnit; public class KSQLJoinWindow extends ASTNodeAccessImpl { @@ -22,6 +23,10 @@ public class KSQLJoinWindow extends ASTNodeAccessImpl { private long afterDuration; private TimeUnit afterTimeUnit; + public final static TimeUnit from(String timeUnitStr) { + return Enum.valueOf(TimeUnit.class, timeUnitStr.toUpperCase()); + } + public boolean isBeforeAfterWindow() { return beforeAfter; } @@ -116,8 +121,4 @@ public KSQLJoinWindow withAfterTimeUnit(TimeUnit afterTimeUnit) { this.setAfterTimeUnit(afterTimeUnit); return this; } - - public final static TimeUnit from(String timeUnitStr) { - return Enum.valueOf(TimeUnit.class, timeUnitStr.toUpperCase()); - } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/KSQLWindow.java b/src/main/java/net/sf/jsqlparser/statement/select/KSQLWindow.java index 79d0b5492..12b98d0f8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/KSQLWindow.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/KSQLWindow.java @@ -13,32 +13,6 @@ public class KSQLWindow extends ASTNodeAccessImpl { - public enum TimeUnit { - DAY, HOUR, MINUTE, SECOND, MILLISECOND, DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS; - - public static TimeUnit from(String unit) { - return Enum.valueOf(TimeUnit.class, unit.toUpperCase()); - } - } - - public enum WindowType { - HOPPING("HOPPING"), SESSION("SESSION"), TUMBLING("TUMBLING"); - - private String windowType; - - WindowType(String windowType) { - this.windowType = windowType; - } - - public String getWindowType() { - return windowType; - } - - public static WindowType from(String type) { - return Enum.valueOf(WindowType.class, type.toUpperCase()); - } - } - private boolean hopping; private boolean tumbling; private boolean session; @@ -47,6 +21,8 @@ public static WindowType from(String type) { private long advanceDuration; private TimeUnit advanceTimeUnit; + public KSQLWindow() {} + public boolean isHoppingWindow() { return hopping; } @@ -103,8 +79,6 @@ public void setAdvanceTimeUnit(TimeUnit advanceTimeUnit) { this.advanceTimeUnit = advanceTimeUnit; } - public KSQLWindow() {} - @Override public String toString() { if (isHoppingWindow()) { @@ -137,4 +111,30 @@ public KSQLWindow withAdvanceTimeUnit(TimeUnit advanceTimeUnit) { return this; } + public enum TimeUnit { + DAY, HOUR, MINUTE, SECOND, MILLISECOND, DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS; + + public static TimeUnit from(String unit) { + return Enum.valueOf(TimeUnit.class, unit.toUpperCase()); + } + } + + public enum WindowType { + HOPPING("HOPPING"), SESSION("SESSION"), TUMBLING("TUMBLING"); + + private String windowType; + + WindowType(String windowType) { + this.windowType = windowType; + } + + public static WindowType from(String type) { + return Enum.valueOf(WindowType.class, type.toUpperCase()); + } + + public String getWindowType() { + return windowType; + } + } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/LateralSubSelect.java b/src/main/java/net/sf/jsqlparser/statement/select/LateralSubSelect.java index bc9556251..736a6c8c0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/LateralSubSelect.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/LateralSubSelect.java @@ -13,7 +13,7 @@ /** * lateral sub select - * + * * @author tobens */ public class LateralSubSelect extends ParenthesedSelect { @@ -68,12 +68,13 @@ public String toString() { return prefix + super.toString(); } - public void accept(SelectVisitor selectVisitor) { - selectVisitor.visit(this); + @Override + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); } @Override - public void accept(FromItemVisitor fromItemVisitor) { - fromItemVisitor.visit(this); + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Limit.java b/src/main/java/net/sf/jsqlparser/statement/select/Limit.java index 0c39bde05..ec5923a3f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Limit.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Limit.java @@ -25,7 +25,7 @@ public class Limit extends ASTNodeAccessImpl { /** * A query with the LIMIT n BY expressions clause selects the first n rows for each distinct * value of expressions. The key for LIMIT BY can contain any number of expressions. - * + * * @see ClickHouse * LIMIT BY Clause @@ -36,14 +36,14 @@ public Expression getOffset() { return offset; } - public Expression getRowCount() { - return rowCount; - } - public void setOffset(Expression l) { offset = l; } + public Expression getRowCount() { + return rowCount; + } + public void setRowCount(Expression l) { rowCount = l; } @@ -89,7 +89,7 @@ public String toString() { } if (byExpressions != null) { - retVal += " BY " + byExpressions.toString(); + retVal += " BY " + byExpressions; } return retVal; diff --git a/src/main/java/net/sf/jsqlparser/statement/select/MinusOp.java b/src/main/java/net/sf/jsqlparser/statement/select/MinusOp.java index ab779978a..bcd3ff4c6 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/MinusOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/MinusOp.java @@ -12,8 +12,27 @@ import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; public class MinusOp extends SetOperation { - public MinusOp() { + this(""); + } + + public MinusOp(String modifier) { super(SetOperationType.MINUS); + this.modifier = modifier; + } + + public MinusOp withDistinct(boolean distinct) { + this.setDistinct(distinct); + return this; + } + + public MinusOp withAll(boolean all) { + this.setAll(all); + return this; + } + + public MinusOp withModifier(String modifier) { + this.modifier = modifier; + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/MySqlSelectIntoClause.java b/src/main/java/net/sf/jsqlparser/statement/select/MySqlSelectIntoClause.java new file mode 100644 index 000000000..5c5f93bab --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/MySqlSelectIntoClause.java @@ -0,0 +1,205 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import java.io.Serializable; +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class MySqlSelectIntoClause extends ASTNodeAccessImpl implements Serializable { + + public enum Position { + BEFORE_FROM, TRAILING + } + + public enum Type { + OUTFILE, DUMPFILE + } + + public enum FieldsKeyword { + FIELDS, COLUMNS + } + + private Position position = Position.TRAILING; + private Type type; + private StringValue fileName; + private String characterSet; + private FieldsKeyword fieldsKeyword; + private StringValue fieldsTerminatedBy; + private boolean fieldsOptionallyEnclosed; + private StringValue fieldsEnclosedBy; + private StringValue fieldsEscapedBy; + private StringValue linesStartingBy; + private StringValue linesTerminatedBy; + + public Position getPosition() { + return position; + } + + public void setPosition(Position position) { + this.position = position; + } + + public MySqlSelectIntoClause withPosition(Position position) { + this.setPosition(position); + return this; + } + + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } + + public StringValue getFileName() { + return fileName; + } + + public void setFileName(StringValue fileName) { + this.fileName = fileName; + } + + public String getCharacterSet() { + return characterSet; + } + + public void setCharacterSet(String characterSet) { + this.characterSet = characterSet; + } + + public FieldsKeyword getFieldsKeyword() { + return fieldsKeyword; + } + + public void setFieldsKeyword(FieldsKeyword fieldsKeyword) { + this.fieldsKeyword = fieldsKeyword; + } + + public StringValue getFieldsTerminatedBy() { + return fieldsTerminatedBy; + } + + public void setFieldsTerminatedBy(StringValue fieldsTerminatedBy) { + this.fieldsTerminatedBy = fieldsTerminatedBy; + } + + public boolean isFieldsOptionallyEnclosed() { + return fieldsOptionallyEnclosed; + } + + public void setFieldsOptionallyEnclosed(boolean fieldsOptionallyEnclosed) { + this.fieldsOptionallyEnclosed = fieldsOptionallyEnclosed; + } + + public StringValue getFieldsEnclosedBy() { + return fieldsEnclosedBy; + } + + public void setFieldsEnclosedBy(StringValue fieldsEnclosedBy) { + this.fieldsEnclosedBy = fieldsEnclosedBy; + } + + public StringValue getFieldsEscapedBy() { + return fieldsEscapedBy; + } + + public void setFieldsEscapedBy(StringValue fieldsEscapedBy) { + this.fieldsEscapedBy = fieldsEscapedBy; + } + + public StringValue getLinesStartingBy() { + return linesStartingBy; + } + + public void setLinesStartingBy(StringValue linesStartingBy) { + this.linesStartingBy = linesStartingBy; + } + + public StringValue getLinesTerminatedBy() { + return linesTerminatedBy; + } + + public void setLinesTerminatedBy(StringValue linesTerminatedBy) { + this.linesTerminatedBy = linesTerminatedBy; + } + + public boolean hasFieldsClause() { + return fieldsKeyword != null || fieldsTerminatedBy != null || fieldsEnclosedBy != null + || fieldsEscapedBy != null; + } + + public boolean hasLinesClause() { + return linesStartingBy != null || linesTerminatedBy != null; + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("INTO ").append(type); + appendFileName(builder); + appendCharacterSet(builder); + appendFieldsClause(builder); + appendLinesClause(builder); + return builder; + } + + private void appendFileName(StringBuilder builder) { + if (fileName != null) { + builder.append(" ").append(fileName); + } + } + + private void appendCharacterSet(StringBuilder builder) { + if (characterSet != null) { + builder.append(" CHARACTER SET ").append(characterSet); + } + } + + private void appendFieldsClause(StringBuilder builder) { + if (!hasFieldsClause()) { + return; + } + + builder.append(" ").append(fieldsKeyword != null ? fieldsKeyword : FieldsKeyword.FIELDS); + + if (fieldsTerminatedBy != null) { + builder.append(" TERMINATED BY ").append(fieldsTerminatedBy); + } + if (fieldsEnclosedBy != null) { + builder.append(" "); + if (fieldsOptionallyEnclosed) { + builder.append("OPTIONALLY "); + } + builder.append("ENCLOSED BY ").append(fieldsEnclosedBy); + } + if (fieldsEscapedBy != null) { + builder.append(" ESCAPED BY ").append(fieldsEscapedBy); + } + } + + private void appendLinesClause(StringBuilder builder) { + if (!hasLinesClause()) { + return; + } + + builder.append(" LINES"); + if (linesStartingBy != null) { + builder.append(" STARTING BY ").append(linesStartingBy); + } + if (linesTerminatedBy != null) { + builder.append(" TERMINATED BY ").append(linesTerminatedBy); + } + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/MySqlSqlCacheFlags.java b/src/main/java/net/sf/jsqlparser/statement/select/MySqlSqlCacheFlags.java index de7ba026e..1656e302a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/MySqlSqlCacheFlags.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/MySqlSqlCacheFlags.java @@ -10,7 +10,6 @@ package net.sf.jsqlparser.statement.select; /** - * * @author tw */ public enum MySqlSqlCacheFlags { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Offset.java b/src/main/java/net/sf/jsqlparser/statement/select/Offset.java index c9b1337e7..eeb354a3f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Offset.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Offset.java @@ -21,14 +21,14 @@ public Expression getOffset() { return offsetExpression; } - public String getOffsetParam() { - return offsetParam; - } - public void setOffset(Expression offsetExpression) { this.offsetExpression = offsetExpression; } + public String getOffsetParam() { + return offsetParam; + } + public void setOffsetParam(String s) { offsetParam = s; } @@ -36,7 +36,7 @@ public void setOffsetParam(String s) { @Override public String toString() { - return " OFFSET " + offsetExpression + (offsetParam != null ? " " + offsetParam : ""); + return " OFFSET " + offsetExpression + (offsetParam != null ? " " + offsetParam : ""); } public Offset withOffset(Expression offsetExpression) { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/OrderByElement.java b/src/main/java/net/sf/jsqlparser/statement/select/OrderByElement.java index 36597fde4..8ac4de9fd 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/OrderByElement.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/OrderByElement.java @@ -10,18 +10,11 @@ package net.sf.jsqlparser.statement.select; import java.io.Serializable; + import net.sf.jsqlparser.expression.Expression; public class OrderByElement implements Serializable { - public enum NullOrdering { - NULLS_FIRST, NULLS_LAST; - - public static NullOrdering from(String ordering) { - return Enum.valueOf(NullOrdering.class, ordering.toUpperCase()); - } - } - private Expression expression; // postgres rollup is an ExpressionList private boolean mysqlWithRollup = false; @@ -33,6 +26,10 @@ public boolean isAsc() { return asc; } + public void setAsc(boolean asc) { + this.asc = asc; + } + public NullOrdering getNullOrdering() { return nullOrdering; } @@ -41,20 +38,16 @@ public void setNullOrdering(NullOrdering nullOrdering) { this.nullOrdering = nullOrdering; } - public void setAsc(boolean asc) { - this.asc = asc; + public boolean isAscDescPresent() { + return ascDescPresent; } public void setAscDescPresent(boolean ascDescPresent) { this.ascDescPresent = ascDescPresent; } - public boolean isAscDescPresent() { - return ascDescPresent; - } - - public void accept(OrderByVisitor orderByVisitor) { - orderByVisitor.visit(this); + public T accept(OrderByVisitor orderByVisitor, S context) { + return orderByVisitor.visit(this, context); } public Expression getExpression() { @@ -119,4 +112,12 @@ public OrderByElement setMysqlWithRollup(boolean mysqlWithRollup) { return this; } + public enum NullOrdering { + NULLS_FIRST, NULLS_LAST; + + public static NullOrdering from(String ordering) { + return Enum.valueOf(NullOrdering.class, ordering.toUpperCase()); + } + } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/OrderByVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/OrderByVisitor.java index e54b8fc0a..8b43f7c26 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/OrderByVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/OrderByVisitor.java @@ -9,7 +9,11 @@ */ package net.sf.jsqlparser.statement.select; -public interface OrderByVisitor { +public interface OrderByVisitor { - void visit(OrderByElement orderBy); + T visit(OrderByElement orderBy, S context); + + default void visit(OrderByElement orderBy) { + this.visit(orderBy, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/OrderByVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/OrderByVisitorAdapter.java index a22396334..2ab0a50e3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/OrderByVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/OrderByVisitorAdapter.java @@ -10,10 +10,10 @@ package net.sf.jsqlparser.statement.select; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class OrderByVisitorAdapter implements OrderByVisitor { +public class OrderByVisitorAdapter implements OrderByVisitor { @Override - public void visit(OrderByElement orderBy) { - + public T visit(OrderByElement orderBy, S context) { + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedFromItem.java b/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedFromItem.java index f35f1f407..1d32fde7c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedFromItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedFromItem.java @@ -23,6 +23,7 @@ public class ParenthesedFromItem extends ASTNodeAccessImpl implements FromItem { private Alias alias; private Pivot pivot; private UnPivot unPivot; + private SampleClause sampleClause; public ParenthesedFromItem() {} @@ -42,6 +43,10 @@ public List getJoins() { return joins; } + public void setJoins(List list) { + joins = list; + } + public Join getJoin(int index) { return joins.get(index); } @@ -57,13 +62,9 @@ public FromItem withJoins(List joins) { return this; } - public void setJoins(List list) { - joins = list; - } - @Override - public void accept(FromItemVisitor fromItemVisitor) { - fromItemVisitor.visit(this); + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); } public StringBuilder appendTo(StringBuilder builder) { @@ -130,6 +131,22 @@ public void setUnPivot(UnPivot unpivot) { this.unPivot = unpivot; } + @Override + public SampleClause getSampleClause() { + return sampleClause; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + this.sampleClause = sampleClause; + return this; + } + + public ParenthesedFromItem withSampleClause(SampleClause sampleClause) { + this.sampleClause = sampleClause; + return this; + } + public ParenthesedFromItem withFromItem(FromItem fromItem) { this.setFromItem(fromItem); return this; diff --git a/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedSelect.java b/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedSelect.java index 0553e2c2f..59e2bac3d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedSelect.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ParenthesedSelect.java @@ -12,24 +12,18 @@ import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; import java.util.Collection; import java.util.List; -public class ParenthesedSelect extends Select implements FromItem { +public class ParenthesedSelect extends Select implements FromItem, ParenthesedStatement { Alias alias; Pivot pivot; UnPivot unPivot; Select select; - - private static Alias getAliasFromItem(FromItem fromItem) { - if (fromItem instanceof Table && fromItem.getAlias() == null) { - Table t = (Table) fromItem; - return new Alias(t.getName(), true); - } else { - return new Alias(fromItem.getAlias().getName(), true); - } - } + SampleClause sampleClause = null; public ParenthesedSelect() {} @@ -78,6 +72,19 @@ public ParenthesedSelect(Collection selectExpressions, FromItem from this.alias = getAliasFromItem(fromItem); } + private static Alias getAliasFromItem(FromItem fromItem) { + if (fromItem instanceof Table && fromItem.getAlias() == null) { + Table t = (Table) fromItem; + return new Alias(t.getName(), true); + } else if (fromItem instanceof TableFunction && fromItem.getAlias() == null) { + TableFunction t = (TableFunction) fromItem; + return new Alias(t.getName(), true); + } else { + return fromItem.getAlias() != null ? new Alias(fromItem.getAlias().getName(), true) + : null; + } + } + @Override public Alias getAlias() { return alias; @@ -111,10 +118,30 @@ public void setUnPivot(UnPivot unPivot) { this.unPivot = unPivot; } + @Override + public SampleClause getSampleClause() { + return sampleClause; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + this.sampleClause = sampleClause; + return this; + } + + public ParenthesedSelect withSampleClause(SampleClause sampleClause) { + this.sampleClause = sampleClause; + return this; + } + public Select getSelect() { return select; } + public void setSelect(Select select) { + this.select = select; + } + public Values getValues() { return (Values) select; } @@ -127,10 +154,6 @@ public SetOperationList getSetOperationList() { return (SetOperationList) select; } - public void setSelect(Select select) { - this.select = select; - } - public ParenthesedSelect withSelect(Select selectBody) { setSelect(selectBody); return this; @@ -142,27 +165,23 @@ public ParenthesedSelect withOrderByElements(List orderByElement } @Override - public void accept(SelectVisitor selectVisitor) { - selectVisitor.visit(this); + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); } @Override - public void accept(FromItemVisitor fromItemVisitor) { - fromItemVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public StringBuilder appendSelectBodyTo(StringBuilder builder) { builder.append("(").append(select).append(")"); - if (alias != null) { - builder.append(alias); - } - - if (pivot != null) { - builder.append(" ").append(pivot); - } - if (unPivot != null) { - builder.append(" ").append(unPivot); - } + appendTo(builder, alias, sampleClause, pivot, unPivot); return builder; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Pivot.java b/src/main/java/net/sf/jsqlparser/statement/select/Pivot.java index fd6f43035..be3a9595f 100755 --- a/src/main/java/net/sf/jsqlparser/statement/select/Pivot.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Pivot.java @@ -27,11 +27,11 @@ public class Pivot implements Serializable { private List> functionItems; private ExpressionList forColumns; private List> singleInItems; - private List> multiInItems; + private List>> multiInItems; private Alias alias; - public void accept(PivotVisitor pivotVisitor) { - pivotVisitor.visit(this); + public T accept(PivotVisitor pivotVisitor, S context) { + return pivotVisitor.visit(this, context); } public List> getSingleInItems() { @@ -42,11 +42,11 @@ public void setSingleInItems(List> singleInItems) { this.singleInItems = singleInItems; } - public List> getMultiInItems() { + public List>> getMultiInItems() { return multiInItems; } - public void setMultiInItems(List> multiInItems) { + public void setMultiInItems(List>> multiInItems) { this.multiInItems = multiInItems; } @@ -99,12 +99,18 @@ public Pivot withForColumns(ExpressionList forColumns) { return this; } + public Pivot addForColumn(Column... forColumns) { + ExpressionList forColumnsList = new ExpressionList<>(forColumns); + this.setForColumns(forColumnsList); + return this; + } + public Pivot withSingleInItems(List> singleInItems) { this.setSingleInItems(singleInItems); return this; } - public Pivot withMultiInItems(List> multiInItems) { + public Pivot withMultiInItems(List>> multiInItems) { this.setMultiInItems(multiInItems); return this; } @@ -153,15 +159,15 @@ public Pivot addSingleInItems(Collection> singleInItems) return this.withSingleInItems(collection); } - public Pivot addMultiInItems(SelectItem... multiInItems) { - List> collection = + public Pivot addMultiInItems(SelectItem>... multiInItems) { + List>> collection = Optional.ofNullable(getMultiInItems()).orElseGet(ArrayList::new); Collections.addAll(collection, multiInItems); return this.withMultiInItems(collection); } - public Pivot addMultiInItems(Collection> multiInItems) { - List> collection = + public Pivot addMultiInItems(Collection>> multiInItems) { + List>> collection = Optional.ofNullable(getMultiInItems()).orElseGet(ArrayList::new); collection.addAll(multiInItems); return this.withMultiInItems(collection); diff --git a/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitor.java index e348aa9d8..27069423e 100755 --- a/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitor.java @@ -9,12 +9,23 @@ */ package net.sf.jsqlparser.statement.select; -public interface PivotVisitor { +public interface PivotVisitor { - void visit(Pivot pivot); + T visit(Pivot pivot, S context); - void visit(PivotXml pivot); + default void visit(Pivot pivot) { + this.visit(pivot, null); + } - void visit(UnPivot unpivot); + T visit(PivotXml pivotXml, S context); + default void visit(PivotXml pivotXml) { + this.visit(pivotXml, null); + } + + T visit(UnPivot unpivot, S context); + + default void visit(UnPivot unpivot) { + this.visit(unpivot, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java index b988e2e6a..2a9f2c6af 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java @@ -9,21 +9,36 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class PivotVisitorAdapter implements PivotVisitor { +public class PivotVisitorAdapter implements PivotVisitor { + private final ExpressionVisitor expressionVisitor; + + public PivotVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter(); + } + + public PivotVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + } @Override - public void visit(Pivot pivot) { + public T visit(Pivot pivot, S context) { + return null; } @Override - public void visit(PivotXml pivot) { + public T visit(PivotXml pivot, S context) { + return null; } @Override - public void visit(UnPivot unpivot) { + public T visit(UnPivot unpivot, S context) { + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/PivotXml.java b/src/main/java/net/sf/jsqlparser/statement/select/PivotXml.java index 0c6929c40..b016d79dd 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/PivotXml.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/PivotXml.java @@ -23,8 +23,8 @@ public class PivotXml extends Pivot { private boolean inAny = false; @Override - public void accept(PivotVisitor pivotVisitor) { - pivotVisitor.visit(this); + public T accept(PivotVisitor pivotVisitor, S context) { + return pivotVisitor.visit(this, context); } public Select getInSelect() { @@ -91,7 +91,7 @@ public PivotXml withSingleInItems(List> singleInItems) { } @Override - public PivotXml withMultiInItems(List> multiInItems) { + public PivotXml withMultiInItems(List>> multiInItems) { return (PivotXml) super.withMultiInItems(multiInItems); } @@ -126,12 +126,13 @@ public PivotXml addSingleInItems(SelectItem... singleInItems) { } @Override - public PivotXml addMultiInItems(SelectItem... multiInItems) { + public PivotXml addMultiInItems(SelectItem>... multiInItems) { return (PivotXml) super.addMultiInItems(multiInItems); } @Override - public PivotXml addMultiInItems(Collection> multiInItems) { + public PivotXml addMultiInItems( + Collection>> multiInItems) { return (PivotXml) super.addMultiInItems(multiInItems); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java b/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java index 2dd8019f1..1d76255e0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java @@ -9,12 +9,7 @@ */ package net.sf.jsqlparser.statement.select; -import net.sf.jsqlparser.expression.Alias; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.OracleHierarchicalExpression; -import net.sf.jsqlparser.expression.OracleHint; -import net.sf.jsqlparser.expression.WindowDefinition; -import net.sf.jsqlparser.schema.Table; +import static java.util.stream.Collectors.joining; import java.util.ArrayList; import java.util.Arrays; @@ -23,18 +18,27 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; - -import static java.util.stream.Collectors.joining; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.OracleHierarchicalExpression; +import net.sf.jsqlparser.expression.OracleHint; +import net.sf.jsqlparser.expression.PreferringClause; +import net.sf.jsqlparser.expression.WindowDefinition; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.update.UpdateSet; @SuppressWarnings({"PMD.CyclomaticComplexity"}) public class PlainSelect extends Select { private Distinct distinct = null; + private BigQuerySelectQualifier bigQuerySelectQualifier = null; private List> selectItems; private List
intoTables; + private MySqlSelectIntoClause mySqlSelectIntoClause; private FromItem fromItem; private List lateralViews; private List joins; + private Expression preWhere; private Expression where; private GroupByElement groupBy; private Expression having; @@ -45,27 +49,24 @@ public class PlainSelect extends Select { private First first; private Top top; private OracleHierarchicalExpression oracleHierarchical = null; + private PreferringClause preferringClause = null; private OracleHint oracleHint = null; private boolean mySqlSqlCalcFoundRows = false; private MySqlSqlCacheFlags mySqlCacheFlag = null; private String forXmlPath; private KSQLWindow ksqlWindow = null; private boolean emitChanges = false; - private List windowDefinitions; - /** * @see Clickhouse * FINAL */ private boolean isUsingFinal = false; - private boolean isUsingOnly = false; - private boolean useWithNoLog = false; - private Table intoTempTable = null; + private List settings = null; public PlainSelect() {} @@ -130,14 +131,34 @@ public FromItem getFromItem() { return fromItem; } + public void setFromItem(FromItem item) { + fromItem = item; + } + public List
getIntoTables() { return intoTables; } + public void setIntoTables(List
intoTables) { + this.intoTables = intoTables; + } + + public MySqlSelectIntoClause getMySqlSelectIntoClause() { + return mySqlSelectIntoClause; + } + + public void setMySqlSelectIntoClause(MySqlSelectIntoClause mySqlSelectIntoClause) { + this.mySqlSelectIntoClause = mySqlSelectIntoClause; + } + public List> getSelectItems() { return selectItems; } + public void setSelectItems(List> list) { + selectItems = list; + } + public SelectItem getSelectItem(int index) { return selectItems.get(index); } @@ -146,17 +167,21 @@ public Expression getWhere() { return where; } - public PlainSelect withFromItem(FromItem item) { - this.setFromItem(item); - return this; + public void setWhere(Expression where) { + this.where = where; } - public void setFromItem(FromItem item) { - fromItem = item; + public Expression getPreWhere() { + return preWhere; } - public void setIntoTables(List
intoTables) { - this.intoTables = intoTables; + public void setPreWhere(Expression preWhere) { + this.preWhere = preWhere; + } + + public PlainSelect withFromItem(FromItem item) { + this.setFromItem(item); + return this; } public PlainSelect withSelectItems(List> list) { @@ -168,10 +193,6 @@ public PlainSelect withSelectItems(SelectItem... selectItems) { return this.withSelectItems(Arrays.asList(selectItems)); } - public void setSelectItems(List> list) { - selectItems = list; - } - public PlainSelect addSelectItems(SelectItem... items) { selectItems = Optional.ofNullable(selectItems).orElseGet(ArrayList::new); selectItems.addAll(Arrays.asList(items)); @@ -200,16 +221,12 @@ public PlainSelect addSelectItem(Expression expression) { return addSelectItem(expression, null); } - public void setWhere(Expression where) { - this.where = where; - } - public List getLateralViews() { return lateralViews; } public void setLateralViews(Collection lateralViews) { - if (this.lateralViews == null && lateralViews != null) { + if (this.lateralViews == null) { this.lateralViews = new ArrayList<>(); } else { this.lateralViews.clear(); @@ -245,6 +262,10 @@ public List getJoins() { return joins; } + public void setJoins(List list) { + joins = list; + } + public Join getJoin(int index) { return joins.get(index); } @@ -260,10 +281,6 @@ public PlainSelect withJoins(List joins) { return this; } - public void setJoins(List list) { - joins = list; - } - public boolean isUsingFinal() { return isUsingFinal; } @@ -316,9 +333,37 @@ public PlainSelect withIntoTempTable(Table intoTempTable) { return this; } + public List getSettings() { + return settings; + } + + public void setSettings(List settings) { + this.settings = settings; + } + + public PlainSelect withSettings(List settings) { + this.setSettings(settings); + return this; + } + + @Override + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + @Override + public SampleClause getSampleClause() { + return null; + } + @Override - public void accept(SelectVisitor selectVisitor) { - selectVisitor.visit(this); + public FromItem setSampleClause(SampleClause sampleClause) { + return null; } public OptimizeFor getOptimizeFor() { @@ -369,6 +414,15 @@ public void setDistinct(Distinct distinct) { this.distinct = distinct; } + public BigQuerySelectQualifier getBigQuerySelectQualifier() { + return bigQuerySelectQualifier; + } + + public PlainSelect setBigQuerySelectQualifier(BigQuerySelectQualifier bigQuerySelectQualifier) { + this.bigQuerySelectQualifier = bigQuerySelectQualifier; + return this; + } + public Expression getHaving() { return having; } @@ -414,6 +468,14 @@ public void setOracleHierarchical(OracleHierarchicalExpression oracleHierarchica this.oracleHierarchical = oracleHierarchical; } + public PreferringClause getPreferringClause() { + return preferringClause; + } + + public void setPreferringClause(PreferringClause preferringClause) { + this.preferringClause = preferringClause; + } + public OracleHint getOracleHint() { return oracleHint; } @@ -438,14 +500,14 @@ public void setKsqlWindow(KSQLWindow ksqlWindow) { this.ksqlWindow = ksqlWindow; } - public void setEmitChanges(boolean emitChanges) { - this.emitChanges = emitChanges; - } - public boolean isEmitChanges() { return emitChanges; } + public void setEmitChanges(boolean emitChanges) { + this.emitChanges = emitChanges; + } + public List getWindowDefinitions() { return windowDefinitions; } @@ -478,6 +540,18 @@ public StringBuilder appendSelectBodyTo(StringBuilder builder) { if (distinct != null) { builder.append(distinct).append(" "); } + + if (bigQuerySelectQualifier != null) { + switch (bigQuerySelectQualifier) { + case AS_STRUCT: + builder.append("AS STRUCT "); + break; + case AS_VALUE: + builder.append("AS VALUE "); + break; + } + } + if (top != null) { builder.append(top).append(" "); } @@ -499,6 +573,12 @@ public StringBuilder appendSelectBodyTo(StringBuilder builder) { } } + if (mySqlSelectIntoClause != null + && mySqlSelectIntoClause + .getPosition() == MySqlSelectIntoClause.Position.BEFORE_FROM) { + builder.append(" ").append(mySqlSelectIntoClause); + } + if (fromItem != null) { builder.append(" FROM "); if (isUsingOnly) { @@ -527,12 +607,18 @@ public StringBuilder appendSelectBodyTo(StringBuilder builder) { if (ksqlWindow != null) { builder.append(" WINDOW ").append(ksqlWindow); } + if (preWhere != null) { + builder.append(" PREWHERE ").append(preWhere); + } if (where != null) { builder.append(" WHERE ").append(where); } if (oracleHierarchical != null) { builder.append(oracleHierarchical); } + if (preferringClause != null) { + builder.append(" ").append(preferringClause); + } if (groupBy != null) { builder.append(" ").append(groupBy); } @@ -552,6 +638,9 @@ public StringBuilder appendSelectBodyTo(StringBuilder builder) { } } else { // without from + if (preWhere != null) { + builder.append(" PREWHERE ").append(preWhere); + } if (where != null) { builder.append(" WHERE ").append(where); } @@ -572,6 +661,16 @@ public String toString() { StringBuilder builder = new StringBuilder(); super.appendTo(builder); + if (mySqlSelectIntoClause != null + && mySqlSelectIntoClause.getPosition() == MySqlSelectIntoClause.Position.TRAILING) { + builder.append(" ").append(mySqlSelectIntoClause); + } + + if (settings != null && !settings.isEmpty()) { + builder.append(" SETTINGS "); + UpdateSet.appendUpdateSetsTo(builder, settings); + } + if (optimizeFor != null) { builder.append(optimizeFor); } @@ -593,22 +692,22 @@ public PlainSelect withMySqlSqlNoCache(MySqlSqlCacheFlags mySqlCacheFlag) { return this; } - public void setMySqlSqlCalcFoundRows(boolean mySqlCalcFoundRows) { - this.mySqlSqlCalcFoundRows = mySqlCalcFoundRows; - } - - public void setMySqlSqlCacheFlag(MySqlSqlCacheFlags sqlCacheFlag) { - this.mySqlCacheFlag = sqlCacheFlag; - } - public boolean getMySqlSqlCalcFoundRows() { return this.mySqlSqlCalcFoundRows; } + public void setMySqlSqlCalcFoundRows(boolean mySqlCalcFoundRows) { + this.mySqlSqlCalcFoundRows = mySqlCalcFoundRows; + } + public MySqlSqlCacheFlags getMySqlSqlCacheFlag() { return this.mySqlCacheFlag; } + public void setMySqlSqlCacheFlag(MySqlSqlCacheFlags sqlCacheFlag) { + this.mySqlCacheFlag = sqlCacheFlag; + } + public PlainSelect withDistinct(Distinct distinct) { this.setDistinct(distinct); return this; @@ -619,11 +718,21 @@ public PlainSelect withIntoTables(List
intoTables) { return this; } + public PlainSelect withMySqlSelectIntoClause(MySqlSelectIntoClause mySqlSelectIntoClause) { + this.setMySqlSelectIntoClause(mySqlSelectIntoClause); + return this; + } + public PlainSelect withWhere(Expression where) { this.setWhere(where); return this; } + public PlainSelect withPreWhere(Expression preWhere) { + this.setPreWhere(preWhere); + return this; + } + public PlainSelect withOptimizeFor(OptimizeFor optimizeFor) { this.setOptimizeFor(optimizeFor); return this; @@ -654,6 +763,11 @@ public PlainSelect withOracleHierarchical(OracleHierarchicalExpression oracleHie return this; } + public PlainSelect withPreferringClause(PreferringClause preferringClause) { + this.setPreferringClause(preferringClause); + return this; + } + public PlainSelect withOracleHint(OracleHint oracleHint) { this.setOracleHint(oracleHint); return this; @@ -709,6 +823,18 @@ public PlainSelect addJoins(Collection joins) { return this.withJoins(collection); } + public PlainSelect addSettings(UpdateSet... settings) { + List collection = Optional.ofNullable(getSettings()).orElseGet(ArrayList::new); + Collections.addAll(collection, settings); + return this.withSettings(collection); + } + + public PlainSelect addSettings(Collection settings) { + List collection = Optional.ofNullable(getSettings()).orElseGet(ArrayList::new); + collection.addAll(settings); + return this.withSettings(collection); + } + public E getFromItem(Class type) { return type.cast(getFromItem()); } @@ -717,7 +843,15 @@ public E getWhere(Class type) { return type.cast(getWhere()); } + public E getPreWhere(Class type) { + return type.cast(getPreWhere()); + } + public E getHaving(Class type) { return type.cast(getHaving()); } + + public enum BigQuerySelectQualifier { + AS_STRUCT, AS_VALUE + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SampleClause.java b/src/main/java/net/sf/jsqlparser/statement/select/SampleClause.java index ea15a5921..eba561686 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SampleClause.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SampleClause.java @@ -10,45 +10,45 @@ package net.sf.jsqlparser.statement.select; public class SampleClause { - public enum SampleKeyword { - SAMPLE, TABLESAMPLE; - - public static SampleKeyword from(String sampleKeyword) { - return Enum.valueOf(SampleKeyword.class, sampleKeyword.toUpperCase()); - } - } - - public enum SampleMethod { - BERNOULLI, SYSTEM, BLOCK; - - public static SampleMethod from(String sampleMethod) { - return Enum.valueOf(SampleMethod.class, sampleMethod.toUpperCase()); - } - } - private SampleKeyword keyword; private SampleMethod method; private Number percentageArgument; + private String percentageUnit; + private boolean argumentInBrackets = true; + // ClickHouse specific + private Number offsetArgument; private Number repeatArgument; - // Oracle Specific private Number seedArgument; public SampleClause(String keyword, String method, Number percentageArgument, + String percentageUnit, Number repeatArgument, Number seedArgument) { + this(keyword, method, percentageArgument, percentageUnit, repeatArgument, seedArgument, + true, + null); + } + + public SampleClause(String keyword, String method, Number percentageArgument, + String percentageUnit, + Number repeatArgument, Number seedArgument, boolean argumentInBrackets, + Number offsetArgument) { this.keyword = SampleKeyword.from(keyword); this.method = method == null || method.length() == 0 ? null : SampleMethod.from(method); this.percentageArgument = percentageArgument; + this.percentageUnit = percentageUnit; + this.argumentInBrackets = argumentInBrackets; + this.offsetArgument = offsetArgument; this.repeatArgument = repeatArgument; this.seedArgument = seedArgument; } public SampleClause() { - this(SampleKeyword.TABLESAMPLE.toString(), null, null, null, null); + this(SampleKeyword.TABLESAMPLE.toString(), null, null, null, null, null); } public SampleClause(String keyword) { - this(keyword, null, null, null, null); + this(keyword, null, null, null, null, null); } public SampleKeyword getKeyword() { @@ -73,6 +73,33 @@ public Number getRepeatArgument() { return repeatArgument; } + public String getPercentageUnit() { + return percentageUnit; + } + + public SampleClause setPercentageUnit(String percentageUnit) { + this.percentageUnit = percentageUnit; + return this; + } + + public boolean isArgumentInBrackets() { + return argumentInBrackets; + } + + public SampleClause setArgumentInBrackets(boolean argumentInBrackets) { + this.argumentInBrackets = argumentInBrackets; + return this; + } + + public Number getOffsetArgument() { + return offsetArgument; + } + + public SampleClause setOffsetArgument(Number offsetArgument) { + this.offsetArgument = offsetArgument; + return this; + } + public SampleClause setRepeatArgument(Number repeatArgument) { this.repeatArgument = repeatArgument; return this; @@ -109,7 +136,19 @@ public StringBuilder appendTo(StringBuilder builder) { } if (percentageArgument != null) { - builder.append(" (").append(percentageArgument).append(")"); + if (argumentInBrackets) { + builder.append(" (").append(percentageArgument) + .append(percentageUnit != null ? " " + percentageUnit : "").append(")"); + } else { + builder.append(" ").append(percentageArgument); + if (percentageUnit != null) { + builder.append(" ").append(percentageUnit); + } + } + } + + if (offsetArgument != null) { + builder.append(" OFFSET ").append(offsetArgument); } if (repeatArgument != null) { @@ -126,4 +165,33 @@ public StringBuilder appendTo(StringBuilder builder) { public String toString() { return appendTo(new StringBuilder()).toString(); } + + public enum SampleKeyword { + SAMPLE("SAMPLE"), TABLESAMPLE("TABLESAMPLE"), USING_SAMPLE("USING SAMPLE"); + + String keyword; + + SampleKeyword(String keyword) { + this.keyword = keyword; + } + + public static SampleKeyword from(String sampleKeyword) { + return Enum.valueOf(SampleKeyword.class, + sampleKeyword.toUpperCase().replaceAll(" ", "_")); + } + + @Override + public String toString() { + return keyword; + } + } + + public enum SampleMethod { + BERNOULLI, SYSTEM, BLOCK; + + public static SampleMethod from(String sampleMethod) { + return Enum.valueOf(SampleMethod.class, + sampleMethod.toUpperCase().replaceAll(" ", "_")); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Select.java b/src/main/java/net/sf/jsqlparser/statement/select/Select.java index 435fd6553..737608020 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Select.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Select.java @@ -9,23 +9,23 @@ */ package net.sf.jsqlparser.statement.select; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.ExpressionVisitor; -import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.StatementVisitor; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Optional; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; -public abstract class Select extends ASTNodeAccessImpl implements Statement, Expression { - protected Table forUpdateTable = null; - List withItemsList; +public abstract class Select extends ASTNodeAccessImpl implements Statement, Expression, FromItem { + protected List
forUpdateTables = null; + protected List> withItemsList; Limit limitBy; Limit limit; Offset offset; @@ -40,6 +40,10 @@ public abstract class Select extends ASTNodeAccessImpl implements Statement, Exp private boolean skipLocked; private Wait wait; private boolean noWait = false; + private boolean forUpdateBeforeOrderBy = false; + Alias alias; + Pivot pivot; + UnPivot unPivot; public static String orderByToString(List orderByElements) { return orderByToString(false, orderByElements); @@ -75,9 +79,9 @@ public static String getFormattedList(List list, String expression, boolean u *

* The same as getStringList(list, true, false) * - * @see #getStringList(List, boolean, boolean) * @param list list of objects with toString methods * @return comma separated list of the elements in the list + * @see #getStringList(List, boolean, boolean) */ public static String getStringList(List list) { return getStringList(list, true, false); @@ -126,27 +130,27 @@ public static StringBuilder appendStringListTo(StringBuilder builder, List li return builder; } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } - public Select withWithItemsList(List withItemsList) { + public Select withWithItemsList(List> withItemsList) { this.setWithItemsList(withItemsList); return this; } - public Select addWithItemsList(Collection withItemsList) { - List collection = + public Select addWithItemsList(Collection> withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); collection.addAll(withItemsList); return this.withWithItemsList(collection); } - public Select addWithItemsList(WithItem... withItemsList) { + public Select addWithItemsList(WithItem... withItemsList) { return addWithItemsList(Arrays.asList(withItemsList)); } @@ -158,14 +162,14 @@ public void setOracleSiblings(boolean oracleSiblings) { this.oracleSiblings = oracleSiblings; } - public void setNoWait(boolean noWait) { - this.noWait = noWait; - } - public boolean isNoWait() { return this.noWait; } + public void setNoWait(boolean noWait) { + this.noWait = noWait; + } + public Select withOracleSiblings(boolean oracleSiblings) { this.setOracleSiblings(oracleSiblings); return this; @@ -288,21 +292,92 @@ public void setForMode(ForMode forMode) { this.forMode = forMode; } + /** + * Returns the first table from the {@code FOR UPDATE OF} clause, or {@code null} if no table + * was specified. Use {@link #getForUpdateTables()} to retrieve all tables. + * + * @return the first table, or {@code null} + */ public Table getForUpdateTable() { - return this.forUpdateTable; + return (forUpdateTables != null && !forUpdateTables.isEmpty()) ? forUpdateTables.get(0) + : null; } + /** + * Sets a single table for the {@code FOR UPDATE OF} clause. + * + * @param forUpdateTable the table, or {@code null} to clear + */ public void setForUpdateTable(Table forUpdateTable) { - this.forUpdateTable = forUpdateTable; + if (forUpdateTable == null) { + this.forUpdateTables = null; + } else { + this.forUpdateTables = new ArrayList<>(); + this.forUpdateTables.add(forUpdateTable); + } } /** - * Sets the {@link Wait} for this SELECT + * Returns the list of tables named in the {@code FOR UPDATE OF t1, t2, ...} clause, or + * {@code null} if no OF clause was present. * - * @param wait the {@link Wait} for this SELECT + * @return list of tables, or {@code null} */ - public void setWait(final Wait wait) { - this.wait = wait; + public List

getForUpdateTables() { + return forUpdateTables; + } + + /** + * Sets the list of tables for the {@code FOR UPDATE OF t1, t2, ...} clause. + * + * @param forUpdateTables list of tables + */ + public void setForUpdateTables(List
forUpdateTables) { + this.forUpdateTables = forUpdateTables; + } + + public Select withForUpdateTables(List
forUpdateTables) { + this.setForUpdateTables(forUpdateTables); + return this; + } + + /** + * Builds and returns a {@link ForUpdateClause} representing the current FOR UPDATE / FOR SHARE + * state of this SELECT, or {@code null} if no FOR clause is present. + * + * @return a {@link ForUpdateClause} view, or {@code null} + */ + public ForUpdateClause getForUpdate() { + if (forMode == null) { + return null; + } + ForUpdateClause clause = new ForUpdateClause(); + clause.setMode(forMode); + clause.setTables(forUpdateTables); + clause.setWait(wait); + clause.setNoWait(noWait); + clause.setSkipLocked(skipLocked); + return clause; + } + + /** + * Returns {@code true} when the {@code FOR UPDATE} clause appears before the {@code ORDER BY} + * clause in the original SQL (non-standard ordering supported by some databases). + * + * @return {@code true} if FOR UPDATE precedes ORDER BY + */ + public boolean isForUpdateBeforeOrderBy() { + return forUpdateBeforeOrderBy; + } + + /** + * Indicates whether the {@code FOR UPDATE} clause precedes the {@code ORDER BY} clause in the + * SQL output. + * + * @param forUpdateBeforeOrderBy {@code true} to emit FOR UPDATE before ORDER BY + */ + public void setForUpdateBeforeOrderBy(boolean forUpdateBeforeOrderBy) { + this.forUpdateBeforeOrderBy = forUpdateBeforeOrderBy; } /** @@ -314,6 +389,15 @@ public Wait getWait() { return wait; } + /** + * Sets the {@link Wait} for this SELECT + * + * @param wait the {@link Wait} for this SELECT + */ + public void setWait(final Wait wait) { + this.wait = wait; + } + public boolean isSkipLocked() { return skipLocked; } @@ -322,13 +406,48 @@ public void setSkipLocked(boolean skipLocked) { this.skipLocked = skipLocked; } - public abstract StringBuilder appendSelectBodyTo(StringBuilder builder); + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + public Select withAlias(Alias alias) { + this.setAlias(alias); + return this; + } + + @Override + public Pivot getPivot() { + return pivot; + } + + @Override + public void setPivot(Pivot pivot) { + this.pivot = pivot; + } + + public UnPivot getUnPivot() { + return unPivot; + } + + public void setUnPivot(UnPivot unPivot) { + this.unPivot = unPivot; + } + + public StringBuilder appendSelectBodyTo(StringBuilder builder) { + return builder; + }; @SuppressWarnings({"PMD.CyclomaticComplexity"}) public StringBuilder appendTo(StringBuilder builder) { if (withItemsList != null && !withItemsList.isEmpty()) { builder.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { WithItem withItem = iter.next(); builder.append(withItem); if (iter.hasNext()) { @@ -340,12 +459,16 @@ public StringBuilder appendTo(StringBuilder builder) { appendSelectBodyTo(builder); + appendTo(builder, alias, null, pivot, unPivot); + + if (!forUpdateBeforeOrderBy) { + builder.append(orderByToString(oracleSiblings, orderByElements)); + } + if (forClause != null) { forClause.appendTo(builder); } - builder.append(orderByToString(oracleSiblings, orderByElements)); - if (limitBy != null) { builder.append(limitBy); } @@ -365,8 +488,14 @@ public StringBuilder appendTo(StringBuilder builder) { builder.append(" FOR "); builder.append(forMode.getValue()); - if (getForUpdateTable() != null) { - builder.append(" OF ").append(forUpdateTable); + if (forUpdateTables != null && !forUpdateTables.isEmpty()) { + builder.append(" OF "); + for (int i = 0; i < forUpdateTables.size(); i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(forUpdateTables.get(i)); + } } if (wait != null) { @@ -381,6 +510,10 @@ public StringBuilder appendTo(StringBuilder builder) { } } + if (forUpdateBeforeOrderBy) { + builder.append(orderByToString(oracleSiblings, orderByElements)); + } + return builder; } @@ -389,15 +522,15 @@ public String toString() { return appendTo(new StringBuilder()).toString(); } - public abstract void accept(SelectVisitor selectVisitor); + public abstract T accept(SelectVisitor selectVisitor, S context); - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Deprecated diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectItem.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectItem.java index 3b7600ead..1861be402 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectItem.java @@ -67,6 +67,14 @@ public Alias getAlias() { return alias; } + public String getAliasName() { + return alias != null ? alias.getName() : null; + } + + public String getUnquotedAliasName() { + return alias != null ? alias.getUnquotedName() : null; + } + public void setAlias(Alias alias) { this.alias = alias; } @@ -79,8 +87,8 @@ public void setExpression(T expression) { this.expression = expression; } - public void accept(SelectItemVisitor selectItemVisitor) { - selectItemVisitor.visit(this); + public K accept(SelectItemVisitor selectItemVisitor, S context) { + return selectItemVisitor.visit(this, context); } @Override @@ -93,7 +101,7 @@ public SelectItem withExpression(T expression) { return this; } - public SelectItem withAlias(Alias alias) { + public SelectItem withAlias(Alias alias) { this.setAlias(alias); return this; } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitor.java index 2f12539e2..9e23873d3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitor.java @@ -9,6 +9,12 @@ */ package net.sf.jsqlparser.statement.select; -public interface SelectItemVisitor { - void visit(SelectItem selectItem); +import net.sf.jsqlparser.expression.Expression; + +public interface SelectItemVisitor { + T visit(SelectItem selectItem, S context); + + default void visit(SelectItem selectItem) { + this.visit(selectItem, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java index eeb2d1b61..a72ff0b70 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java @@ -9,10 +9,24 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class SelectItemVisitorAdapter implements SelectItemVisitor { - @Override - public void visit(SelectItem item) { +public class SelectItemVisitorAdapter implements SelectItemVisitor { + private final ExpressionVisitor expressionVisitor; + + public SelectItemVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(); + } + public SelectItemVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + } + + @Override + public T visit(SelectItem item, S context) { + return item.getExpression().accept(expressionVisitor, context); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java index 04a6b9d9e..db5ce3175 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java @@ -9,19 +9,66 @@ */ package net.sf.jsqlparser.statement.select; -public interface SelectVisitor { +import net.sf.jsqlparser.statement.OutputClause; +import net.sf.jsqlparser.statement.piped.FromQuery; - void visit(ParenthesedSelect parenthesedSelect); +import java.util.List; - void visit(PlainSelect plainSelect); +public interface SelectVisitor { + default T visitWithItems(List> withItemsList, S context) { + if (withItemsList != null) { + for (WithItem withItem : withItemsList) { + withItem.accept(this, context); + } + } + return null; + } - void visit(SetOperationList setOpList); + default T visitOutputClause(OutputClause outputClause, S context) { + return null; + } - void visit(WithItem withItem); + T visit(ParenthesedSelect parenthesedSelect, S context); - void visit(Values aThis); + default void visit(ParenthesedSelect parenthesedSelect) { + this.visit(parenthesedSelect, null); + } - void visit(LateralSubSelect lateralSubSelect); + T visit(PlainSelect plainSelect, S context); - void visit(TableStatement tableStatement); + default void visit(PlainSelect plainSelect) { + this.visit(plainSelect, null); + } + + T visit(FromQuery fromQuery, S context); + + T visit(SetOperationList setOpList, S context); + + default void visit(SetOperationList setOpList) { + this.visit(setOpList, null); + } + + T visit(WithItem withItem, S context); + + default void visit(WithItem withItem) { + this.visit(withItem, null); + } + + T visit(Values values, S context); + + default void visit(Values values) { + this.visit(values, null); + } + + T visit(LateralSubSelect lateralSubSelect, S context); + + default void visit(LateralSubSelect lateralSubSelect) { + this.visit(lateralSubSelect, null); + } + + T visit(TableStatement tableStatement, S context); + + default void visit(TableStatement tableStatement) { + this.visit(tableStatement, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java index a349a9005..9b0eb33a6 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java @@ -9,41 +9,238 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; +import net.sf.jsqlparser.statement.OutputClause; +import net.sf.jsqlparser.statement.piped.FromQuery; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public class SelectVisitorAdapter implements SelectVisitor { +public class SelectVisitorAdapter implements SelectVisitor { + private final ExpressionVisitor expressionVisitor; + private final PivotVisitor pivotVisitor; + private final SelectItemVisitor selectItemVisitor; + private final FromItemVisitor fromItemVisitor; - @Override - public void visit(ParenthesedSelect parenthesedSelect) { - parenthesedSelect.getSelect().accept(this); + public SelectVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(this); + this.pivotVisitor = new PivotVisitorAdapter<>(this.expressionVisitor); + this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); + this.fromItemVisitor = new FromItemVisitorAdapter<>(this, this.expressionVisitor); + } + + public SelectVisitorAdapter(ExpressionVisitor expressionVisitor, + PivotVisitor pivotVisitor, SelectItemVisitor selectItemVisitor, + FromItemVisitor fromItemVisitor) { + this.expressionVisitor = expressionVisitor; + this.pivotVisitor = pivotVisitor; + this.selectItemVisitor = selectItemVisitor; + this.fromItemVisitor = fromItemVisitor; + } + + public SelectVisitorAdapter(ExpressionVisitor expressionVisitor, + FromItemVisitor fromItemVisitor) { + this.expressionVisitor = expressionVisitor; + this.pivotVisitor = new PivotVisitorAdapter<>(); + this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); + this.fromItemVisitor = fromItemVisitor; + } + + public SelectVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + this.pivotVisitor = new PivotVisitorAdapter<>(); + this.selectItemVisitor = new SelectItemVisitorAdapter<>(this.expressionVisitor); + this.fromItemVisitor = new FromItemVisitorAdapter<>(); } @Override - public void visit(PlainSelect plainSelect) { + public T visitOutputClause(OutputClause outputClause, S context) { + if (outputClause != null) { + if (outputClause.getSelectItemList() != null) { + for (SelectItem selectItem : outputClause.getSelectItemList()) { + selectItem.accept(selectItemVisitor, context); + } + } + if (outputClause.getTableVariable() != null) { + outputClause.getTableVariable().accept(expressionVisitor, context); + } + if (outputClause.getOutputTable() != null) { + outputClause.getOutputTable().accept(fromItemVisitor, context); + } + // @todo: check why this is a list of strings + // if (outputClause.getColumnList()!=null) { + // for (Column column:outputClause.getColumnList()) + // } + } + return null; + } + + public ExpressionVisitor getExpressionVisitor() { + return expressionVisitor; + } + public PivotVisitor getPivotVisitor() { + return pivotVisitor; + } + + public SelectItemVisitor getSelectItemVisitor() { + return selectItemVisitor; + } + + public FromItemVisitor getFromItemVisitor() { + return fromItemVisitor; } @Override - public void visit(SetOperationList setOpList) { + public T visit(ParenthesedSelect select, S context) { + visitWithItems(select.withItemsList, context); + + select.getSelect().accept(this, context); + expressionVisitor.visitOrderBy(select.getOrderByElements(), context); + + Pivot pivot = select.getPivot(); + if (pivot != null) { + pivot.accept(pivotVisitor, context); + } + UnPivot unpivot = select.getUnPivot(); + if (unpivot != null) { + unpivot.accept(pivotVisitor, context); + } + + expressionVisitor.visitLimit(select.getLimit(), context); + + if (select.getOffset() != null) { + expressionVisitor.visitExpression(select.getOffset().getOffset(), null); + } + if (select.getFetch() != null) { + expressionVisitor.visitExpression(select.getFetch().getExpression(), null); + } + + return null; } @Override - public void visit(WithItem withItem) { + @SuppressWarnings({"PMD.ExcessiveMethodLength"}) + public T visit(PlainSelect plainSelect, S context) { + visitWithItems(plainSelect.withItemsList, context); + + if (plainSelect.getDistinct() != null) { + for (SelectItem selectItem : plainSelect.getDistinct().getOnSelectItems()) { + selectItem.accept(selectItemVisitor, context); + } + } + if (plainSelect.getTop() != null) { + plainSelect.getTop().getExpression().accept(expressionVisitor, context); + } + + for (SelectItem selectItem : plainSelect.getSelectItems()) { + selectItem.accept(selectItemVisitor, context); + } + + if (plainSelect.getMySqlSelectIntoClause() != null) { + MySqlSelectIntoClause mySqlSelectIntoClause = plainSelect.getMySqlSelectIntoClause(); + expressionVisitor.visitExpression(mySqlSelectIntoClause.getFileName(), context); + expressionVisitor.visitExpression(mySqlSelectIntoClause.getFieldsTerminatedBy(), + context); + expressionVisitor.visitExpression(mySqlSelectIntoClause.getFieldsEnclosedBy(), context); + expressionVisitor.visitExpression(mySqlSelectIntoClause.getFieldsEscapedBy(), context); + expressionVisitor.visitExpression(mySqlSelectIntoClause.getLinesStartingBy(), context); + expressionVisitor.visitExpression(mySqlSelectIntoClause.getLinesTerminatedBy(), + context); + } + + fromItemVisitor.visitTables(plainSelect.getIntoTables(), context); + fromItemVisitor.visitFromItem(plainSelect.getFromItem(), context); + + // if (plainSelect.getLateralViews() != null) { + // //@todo: implement this + // } + + fromItemVisitor.visitJoins(plainSelect.getJoins(), context); + + // if (plainSelect.getKsqlWindow() != null) { + // //@todo: implement + // } + + expressionVisitor.visitExpression(plainSelect.getPreWhere(), context); + expressionVisitor.visitExpression(plainSelect.getWhere(), context); + + // if (plainSelect.getOracleHierarchical() != null) { + // //@todo: implement + // } + // + + expressionVisitor.visitPreferringClause(plainSelect.getPreferringClause(), context); + expressionVisitor.visit(plainSelect.getGroupBy(), context); + expressionVisitor.visitExpression(plainSelect.getHaving(), context); + expressionVisitor.visitExpression(plainSelect.getQualify(), context); + + // if (plainSelect.getWindowDefinitions() != null) { + // //@todo: implement + // } + + Pivot pivot = plainSelect.getPivot(); + if (pivot != null) { + pivot.accept(pivotVisitor, context); + } + UnPivot unpivot = plainSelect.getUnPivot(); + if (unpivot != null) { + unpivot.accept(pivotVisitor, context); + } + + expressionVisitor.visitOrderBy(plainSelect.getOrderByElements(), context); + + // if (plainSelect.getLimitBy() != null) { + // //@todo: implement + // } + // if (plainSelect.getLimit() != null) { + // //@todo: implement + // } + if (plainSelect.getOffset() != null) { + expressionVisitor.visitExpression(plainSelect.getOffset().getOffset(), context); + } + if (plainSelect.getFetch() != null) { + expressionVisitor.visitExpression(plainSelect.getFetch().getExpression(), context); + } + // if (plainSelect.getForMode() != null) { + // //@todo: implement + // } + + fromItemVisitor.visitFromItem(plainSelect.getIntoTempTable(), context); + return null; } @Override - public void visit(Values aThis) { + public T visit(FromQuery fromQuery, S context) { + return null; + } + @Override + public T visit(SetOperationList setOpList, S context) { + for (Select select : setOpList.getSelects()) { + select.accept(this, context); + } + return null; } @Override - public void visit(LateralSubSelect lateralSubSelect) { + public T visit(WithItem withItem, S context) { + return withItem.getSelect().accept(this, context); + } + @Override + public T visit(Values aThis, S context) { + return null; } @Override - public void visit(TableStatement tableStatement) { + public T visit(LateralSubSelect lateralSubSelect, S context) { + return lateralSubSelect.getSelect().accept(this, context); + } + @Override + public T visit(TableStatement tableStatement, S context) { + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java b/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java index 0600e5957..4438d7537 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SetOperation.java @@ -13,8 +13,29 @@ import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; public abstract class SetOperation extends ASTNodeAccessImpl { + String modifier; - private SetOperationType type; + public String getModifier() { + return modifier != null ? modifier : ""; + } + + public boolean isAll() { + return modifier != null && modifier.contains("ALL"); + } + + public void setAll(boolean all) { + this.modifier = "ALL"; + } + + public boolean isDistinct() { + return modifier != null && modifier.contains("DISTINCT"); + } + + public void setDistinct(boolean distinct) { + this.modifier = "DISTINCT"; + } + + private final SetOperationType type; public SetOperation(SetOperationType type) { this.type = type; @@ -22,6 +43,6 @@ public SetOperation(SetOperationType type) { @Override public String toString() { - return type.name(); + return modifier == null || modifier.isEmpty() ? type.name() : type.name() + " " + modifier; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SetOperationList.java b/src/main/java/net/sf/jsqlparser/statement/select/SetOperationList.java index 48a609240..465eca2d5 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SetOperationList.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SetOperationList.java @@ -9,6 +9,7 @@ */ package net.sf.jsqlparser.statement.select; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -22,40 +23,55 @@ public class SetOperationList extends Select { private List orderByElements; @Override - public void accept(SelectVisitor selectVisitor) { - selectVisitor.visit(this); + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + @Override + public SampleClause getSampleClause() { + return null; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + return null; } public List getOrderByElements() { return orderByElements; } - public List getSelects() { + return selects; } public void setSelects(List select, List ops) { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/TableFunction.java b/src/main/java/net/sf/jsqlparser/statement/select/TableFunction.java index 44309b1a9..2f4b8614f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/TableFunction.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/TableFunction.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Function; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) @@ -19,6 +20,7 @@ public class TableFunction extends Function implements FromItem { private Pivot pivot = null; private UnPivot unPivot = null; private Function function; + private String withClause = null; public TableFunction(Function function) { this.function = function; @@ -29,21 +31,40 @@ public TableFunction(String prefix, Function function) { this.function = function; } - public Function getFunction() { - return function; + public TableFunction(Function function, String withClause) { + this.function = function; + this.withClause = withClause; } - @Deprecated - public Function getExpression() { - return getFunction(); + public TableFunction(String prefix, Function function, String withClause) { + this.prefix = prefix; + this.function = function; + this.withClause = withClause; + } + + public TableFunction(String prefix, String name, Expression... parameters) { + this.prefix = prefix; + this.function = new Function(name, parameters); } + public TableFunction(String name, Expression... parameters) { + this(null, name, parameters); + } + + public Function getFunction() { + return function; + } public TableFunction setFunction(Function function) { this.function = function; return this; } + @Deprecated + public Function getExpression() { + return getFunction(); + } + public String getPrefix() { return prefix; } @@ -53,9 +74,22 @@ public TableFunction setPrefix(String prefix) { return this; } + public String getWithClause() { + return withClause; + } + + public void setWithClause(String withClause) { + this.withClause = withClause; + } + + public TableFunction withWithClause(String withClause) { + this.withClause = withClause; + return this; + } + @Override - public void accept(FromItemVisitor fromItemVisitor) { - fromItemVisitor.visit(this); + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); } @Override @@ -103,12 +137,26 @@ public TableFunction withUnPivot(UnPivot unpivot) { return (TableFunction) FromItem.super.withUnPivot(unpivot); } + @Override + public SampleClause getSampleClause() { + return null; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + return null; + } + public StringBuilder appendTo(StringBuilder builder) { if (prefix != null) { builder.append(prefix).append(" "); } builder.append(function.toString()); + if (withClause != null) { + builder.append(" WITH ").append(withClause); + } + if (alias != null) { builder.append(alias); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/TableStatement.java b/src/main/java/net/sf/jsqlparser/statement/select/TableStatement.java index b665b16a6..d5c7dc152 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/TableStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/TableStatement.java @@ -12,10 +12,9 @@ import net.sf.jsqlparser.schema.Table; /** + * @author jxnu-liguobin * @see `TABLE table_name [ORDER * BY column_name] [LIMIT number [OFFSET number]]` Union not currently supported - * - * @author jxnu-liguobin */ public class TableStatement extends Select { @@ -53,7 +52,22 @@ public StringBuilder appendTo(StringBuilder builder) { } @Override - public void accept(SelectVisitor selectVisitor) { - selectVisitor.visit(this); + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + @Override + public SampleClause getSampleClause() { + return null; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Top.java b/src/main/java/net/sf/jsqlparser/statement/select/Top.java index 7dc31b0cc..dd4541124 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Top.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Top.java @@ -45,14 +45,14 @@ public void setPercentage(boolean percentage) { this.isPercentage = percentage; } - public void setWithTies(boolean withTies) { - this.isWithTies = withTies; - } - public boolean isWithTies() { return isWithTies; } + public void setWithTies(boolean withTies) { + this.isWithTies = withTies; + } + @Override public String toString() { String result = "TOP "; diff --git a/src/main/java/net/sf/jsqlparser/statement/select/UnPivot.java b/src/main/java/net/sf/jsqlparser/statement/select/UnPivot.java index 8d39f831e..c5549280c 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/UnPivot.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/UnPivot.java @@ -25,8 +25,8 @@ public class UnPivot implements Serializable { private List> unpivotInClause; private Alias alias; - public void accept(PivotVisitor pivotVisitor) { - pivotVisitor.visit(this); + public T accept(PivotVisitor pivotVisitor, S context) { + return pivotVisitor.visit(this, context); } public boolean getIncludeNulls() { diff --git a/src/main/java/net/sf/jsqlparser/statement/select/UnionOp.java b/src/main/java/net/sf/jsqlparser/statement/select/UnionOp.java index 68271bcd6..00941e14a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/UnionOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/UnionOp.java @@ -12,39 +12,13 @@ import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; public class UnionOp extends SetOperation { - - private boolean distinct; - private boolean all; - public UnionOp() { - super(SetOperationType.UNION); - } - - public boolean isAll() { - return all; - } - - public void setAll(boolean all) { - this.all = all; + this(""); } - public boolean isDistinct() { - return distinct; - } - - public void setDistinct(boolean distinct) { - this.distinct = distinct; - } - - @Override - public String toString() { - String allDistinct = ""; - if (isAll()) { - allDistinct = " ALL"; - } else if (isDistinct()) { - allDistinct = " DISTINCT"; - } - return super.toString() + allDistinct; + public UnionOp(String modifier) { + super(SetOperationType.UNION); + this.modifier = modifier; } public UnionOp withDistinct(boolean distinct) { @@ -56,4 +30,9 @@ public UnionOp withAll(boolean all) { this.setAll(all); return this; } + + public UnionOp withModifier(String modifier) { + this.modifier = modifier; + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Values.java b/src/main/java/net/sf/jsqlparser/statement/select/Values.java index dfce8506d..6cc0e3851 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Values.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Values.java @@ -20,16 +20,22 @@ public class Values extends Select implements FromItem { private ExpressionList expressions; + private Alias alias; public Values() { - // empty constructor + this(null, null); } public Values(ExpressionList expressions) { this.expressions = expressions; } - public ExpressionList getExpressions() { + public Values(ExpressionList expressions, Alias alias) { + this.expressions = expressions; + this.alias = alias; + } + + public ExpressionList getExpressions() { return expressions; } @@ -42,12 +48,18 @@ public void setExpressions(ExpressionList expressions) { public StringBuilder appendSelectBodyTo(StringBuilder builder) { builder.append("VALUES "); builder.append(expressions.toString()); + appendTo(builder, alias); return builder; } @Override - public void accept(SelectVisitor selectVisitor) { - selectVisitor.visit(this); + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); } public Values withExpressions(ExpressionList expressions) { @@ -67,19 +79,14 @@ public Values addExpressions(Collection expressions) { return this; } - @Override - public void accept(FromItemVisitor fromItemVisitor) { - fromItemVisitor.visit(this); - } - @Override public Alias getAlias() { - return null; + return alias; } @Override public void setAlias(Alias alias) { - + this.alias = alias; } @Override @@ -101,4 +108,14 @@ public UnPivot getUnPivot() { public void setUnPivot(UnPivot unpivot) { } + + @Override + public SampleClause getSampleClause() { + return null; + } + + @Override + public FromItem setSampleClause(SampleClause sampleClause) { + return null; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Wait.java b/src/main/java/net/sf/jsqlparser/statement/select/Wait.java index 0d94e22a0..e66fc73b5 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Wait.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Wait.java @@ -25,7 +25,7 @@ public void setTimeout(long timeout) { /** * Returns a String containing the WAIT clause and its timeout, where TIMEOUT is specified by - * {@link #getTimeout()}. The returned string will null be: + * {@link #getTimeout()}. The returned string will null be: * " WAIT <TIMEOUT>" * */ diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java new file mode 100644 index 000000000..c24d8a37f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionDeclaration.java @@ -0,0 +1,115 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +import java.io.Serializable; +import java.util.List; + +public class WithFunctionDeclaration implements Serializable { + private String functionName; + private List parameters; + private String returnType; + private Expression returnExpression; + + public WithFunctionDeclaration() {} + + public WithFunctionDeclaration(String functionName, List parameters, + String returnType, Expression returnExpression) { + this.functionName = functionName; + this.parameters = parameters; + this.returnType = returnType; + this.returnExpression = returnExpression; + } + + public String getFunctionName() { + return functionName; + } + + public void setFunctionName(String functionName) { + this.functionName = functionName; + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public String getReturnType() { + return returnType; + } + + public void setReturnType(String returnType) { + this.returnType = returnType; + } + + public Expression getReturnExpression() { + return returnExpression; + } + + public void setReturnExpression(Expression returnExpression) { + this.returnExpression = returnExpression; + } + + public WithFunctionDeclaration withFunctionName(String functionName) { + this.setFunctionName(functionName); + return this; + } + + public WithFunctionDeclaration withParameters(List parameters) { + this.setParameters(parameters); + return this; + } + + public WithFunctionDeclaration withReturnType(String returnType) { + this.setReturnType(returnType); + return this; + } + + public WithFunctionDeclaration withReturnExpression(Expression returnExpression) { + this.setReturnExpression(returnExpression); + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + builder + .append("FUNCTION ") + .append(functionName) + .append("("); + for (int i = 0; parameters != null && i < parameters.size(); i++) { + if (i > 0) { + builder.append(", "); + } + parameters.get(i).appendTo(builder); + } + return builder + .append(") RETURNS ") + .append(returnType) + .append(" RETURN ") + .append(returnExpression); + } + + public T accept(ExpressionVisitor expressionVisitor, S context) { + if (returnExpression != null) { + return returnExpression.accept(expressionVisitor, context); + } + return null; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionParameter.java b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionParameter.java new file mode 100644 index 000000000..aeef044f5 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithFunctionParameter.java @@ -0,0 +1,59 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import java.io.Serializable; + +public class WithFunctionParameter implements Serializable { + private String name; + private String type; // e.g., INT + + public WithFunctionParameter() {} + + public WithFunctionParameter(String name, String type) { + this.name = name; + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public WithFunctionParameter withName(String name) { + this.name = name; + return this; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public WithFunctionParameter withType(String type) { + this.type = type; + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + return builder.append(name).append(" ").append(type); + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithIsolation.java b/src/main/java/net/sf/jsqlparser/statement/select/WithIsolation.java index 7aef6ef4e..e6ac80754 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/WithIsolation.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithIsolation.java @@ -19,6 +19,7 @@ public class WithIsolation implements Serializable { public String getIsolation() { return this.isolation; } + public void setIsolation(String s) { this.isolation = s; } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java index de673f491..01605c8a9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java @@ -9,17 +9,71 @@ */ package net.sf.jsqlparser.statement.select; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; + +public class WithItem implements Serializable { + private K statement; + private Alias alias; + private List> withItemList; + private WithFunctionDeclaration withFunctionDeclaration; + private WithSearchClause searchClause; + private boolean recursive = false; + private boolean usingNot = false; + private boolean materialized = false; -public class WithItem extends ParenthesedSelect { + public WithItem(K statement, Alias alias) { + this.statement = statement; + this.alias = alias; + } - private List> withItemList; + public WithItem() { + this(null, (Alias) null); + } - private boolean recursive = false; + public K getParenthesedStatement() { + return statement; + } + + public void setParenthesedStatement(K statement) { + this.statement = statement; + } + + public WithItem withParenthesedStatement(K statement) { + this.setParenthesedStatement(statement); + return this; + } + + public Alias getAlias() { + return alias; + } + + public String getAliasName() { + return alias != null ? alias.getName() : null; + } + + public String getUnquotedAliasName() { + return alias != null ? alias.getUnquotedName() : null; + } + + public void setAlias(Alias alias) { + this.alias = alias; + } + + public WithItem withAlias(Alias alias) { + this.setAlias(alias); + return this; + } public boolean isRecursive() { return recursive; @@ -29,6 +83,31 @@ public void setRecursive(boolean recursive) { this.recursive = recursive; } + public boolean isMaterialized() { + return materialized; + } + + public void setMaterialized(boolean materialized) { + this.materialized = materialized; + } + + public K getStatement() { + return statement; + } + + public WithItem setStatement(K statement) { + this.statement = statement; + return this; + } + + public boolean isUsingNot() { + return usingNot; + } + + public WithItem setUsingNot(boolean usingNot) { + this.usingNot = usingNot; + return this; + } /** * The {@link SelectItem}s in this WITH (for example the A,B,C in "WITH mywith (A,B,C) AS ...") @@ -43,48 +122,127 @@ public void setWithItemList(List> withItemList) { this.withItemList = withItemList; } - @Override - @SuppressWarnings({"PMD.CyclomaticComplexity"}) - public StringBuilder appendSelectBodyTo(StringBuilder builder) { - builder.append(recursive ? "RECURSIVE " : ""); - builder.append(alias.getName()); - builder.append( - (withItemList != null) ? " " + PlainSelect.getStringList(withItemList, true, true) - : ""); - builder.append(" AS "); + public WithFunctionDeclaration getWithFunctionDeclaration() { + return withFunctionDeclaration; + } + + public void setWithFunctionDeclaration(WithFunctionDeclaration withFunctionDeclaration) { + this.withFunctionDeclaration = withFunctionDeclaration; + } + + public WithItem withWithFunctionDeclaration( + WithFunctionDeclaration withFunctionDeclaration) { + this.setWithFunctionDeclaration(withFunctionDeclaration); + return this; + } + + public WithSearchClause getSearchClause() { + return searchClause; + } - select.appendTo(builder); + public void setSearchClause(WithSearchClause searchClause) { + this.searchClause = searchClause; + } - return builder; + public WithItem withSearchClause(WithSearchClause searchClause) { + this.setSearchClause(searchClause); + return this; } @Override - public void accept(SelectVisitor visitor) { - visitor.visit(this); + public String toString() { + StringBuilder builder = new StringBuilder(); + if (withFunctionDeclaration != null) { + builder.append(withFunctionDeclaration); + } else { + builder.append(recursive ? "RECURSIVE " : ""); + if (alias != null) { + builder.append(alias.getName()); + } + if (withItemList != null) { + builder.append("("); + int size = withItemList.size(); + for (int i = 0; i < size; i++) { + builder.append(withItemList.get(i)).append(i < size - 1 ? "," : ""); + } + builder.append(")"); + } + builder.append(" AS "); + if (materialized) { + builder.append(usingNot + ? "NOT MATERIALIZED " + : "MATERIALIZED "); + } + builder.append(statement); + if (searchClause != null) { + builder.append(" ").append(searchClause); + } + } + return builder.toString(); + } + + @Deprecated + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); } + public T accept(StatementVisitor statementVisitor, S context) { + if (statement != null) { + return statement.accept(statementVisitor, context); + } + return null; + } - public WithItem withWithItemList(List> withItemList) { + public WithItem withWithItemList(List> withItemList) { this.setWithItemList(withItemList); return this; } - public WithItem withRecursive(boolean recursive) { + public WithItem withRecursive(boolean recursive, boolean materialized) { + this.setRecursive(recursive); + this.setMaterialized(materialized); + return this; + } + + public WithItem withRecursive(boolean recursive, boolean usingNot, boolean materialized) { this.setRecursive(recursive); + this.setUsingNot(usingNot); + this.setMaterialized(materialized); return this; } - public WithItem addWithItemList(SelectItem... withItemList) { + public WithItem addWithItemList(SelectItem... withItemList) { List> collection = Optional.ofNullable(getWithItemList()).orElseGet(ArrayList::new); Collections.addAll(collection, withItemList); return this.withWithItemList(collection); } - public WithItem addWithItemList(Collection> withItemList) { + public WithItem addWithItemList(Collection> withItemList) { List> collection = Optional.ofNullable(getWithItemList()).orElseGet(ArrayList::new); collection.addAll(withItemList); return this.withWithItemList(collection); } + + public ParenthesedSelect getSelect() { + return (ParenthesedSelect) statement; + } + + public ParenthesedInsert getInsert() { + return (ParenthesedInsert) statement; + } + + public ParenthesedUpdate getUpdate() { + return (ParenthesedUpdate) statement; + } + + public ParenthesedDelete getDelete() { + return (ParenthesedDelete) statement; + } + + public void setSelect(ParenthesedSelect select) { + this.statement = (K) select; + } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/WithSearchClause.java b/src/main/java/net/sf/jsqlparser/statement/select/WithSearchClause.java new file mode 100644 index 000000000..84de6e223 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithSearchClause.java @@ -0,0 +1,100 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import java.io.Serializable; +import java.util.Collection; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; + +public class WithSearchClause implements Serializable { + public enum SearchOrder { + BREADTH, DEPTH + } + + private SearchOrder searchOrder; + private ExpressionList searchColumns; + private String sequenceColumnName; + + public WithSearchClause() {} + + public WithSearchClause(SearchOrder searchOrder, ExpressionList searchColumns, + String sequenceColumnName) { + this.searchOrder = searchOrder; + this.searchColumns = searchColumns; + this.sequenceColumnName = sequenceColumnName; + } + + public SearchOrder getSearchOrder() { + return searchOrder; + } + + public void setSearchOrder(SearchOrder searchOrder) { + this.searchOrder = searchOrder; + } + + public WithSearchClause withSearchOrder(SearchOrder searchOrder) { + this.setSearchOrder(searchOrder); + return this; + } + + public ExpressionList getSearchColumns() { + return searchColumns; + } + + public void setSearchColumns(ExpressionList searchColumns) { + this.searchColumns = searchColumns; + } + + public WithSearchClause withSearchColumns(ExpressionList searchColumns) { + this.setSearchColumns(searchColumns); + return this; + } + + public WithSearchClause addSearchColumns(Column... searchColumns) { + ExpressionList collection = + getSearchColumns() != null ? getSearchColumns() : new ExpressionList<>(); + collection.addExpressions(searchColumns); + return this.withSearchColumns(collection); + } + + public WithSearchClause addSearchColumns(Collection searchColumns) { + ExpressionList collection = + getSearchColumns() != null ? getSearchColumns() : new ExpressionList<>(); + collection.addAll(searchColumns); + return this.withSearchColumns(collection); + } + + public String getSequenceColumnName() { + return sequenceColumnName; + } + + public void setSequenceColumnName(String sequenceColumnName) { + this.sequenceColumnName = sequenceColumnName; + } + + public WithSearchClause withSequenceColumnName(String sequenceColumnName) { + this.setSequenceColumnName(sequenceColumnName); + return this; + } + + @Override + public String toString() { + return new StringBuilder() + .append("SEARCH ") + .append(searchOrder) + .append(" FIRST BY ") + .append(Select.getStringList(searchColumns)) + .append(" SET ") + .append(sequenceColumnName) + .toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/show/ShowIndexStatement.java b/src/main/java/net/sf/jsqlparser/statement/show/ShowIndexStatement.java index 39a35d07c..d6b4bf72d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/show/ShowIndexStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/show/ShowIndexStatement.java @@ -1,21 +1,20 @@ - /*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2019 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ package net.sf.jsqlparser.statement.show; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; /** -* -* @author Jayant Kumar Yadav -*/ + * @author Jayant Kumar Yadav + */ public class ShowIndexStatement implements Statement { @@ -43,12 +42,12 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public ShowIndexStatement withTableName(String tableName) { this.setTableName(tableName); return this; } -} \ No newline at end of file +} diff --git a/src/main/java/net/sf/jsqlparser/statement/show/ShowTablesStatement.java b/src/main/java/net/sf/jsqlparser/statement/show/ShowTablesStatement.java index 16106b823..5aaa8c8eb 100644 --- a/src/main/java/net/sf/jsqlparser/statement/show/ShowTablesStatement.java +++ b/src/main/java/net/sf/jsqlparser/statement/show/ShowTablesStatement.java @@ -17,7 +17,7 @@ /** * A {@code SHOW TABLES} statement - * + * * @see MySQL show tables */ public class ShowTablesStatement implements Statement { @@ -98,8 +98,8 @@ public String toString() { } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public enum SelectionMode { diff --git a/src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java b/src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java index 9848c7799..58442d38e 100644 --- a/src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java +++ b/src/main/java/net/sf/jsqlparser/statement/truncate/Truncate.java @@ -9,31 +9,42 @@ */ package net.sf.jsqlparser.statement.truncate; +import static java.util.stream.Collectors.joining; + +import java.util.List; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; public class Truncate implements Statement { - private Table table; - boolean cascade; // to support TRUNCATE TABLE ... CASCADE - - boolean tableToken; // to support TRUNCATE without TABLE + boolean cascade; // to support TRUNCATE TABLE ... CASCADE + boolean tableToken; // to support TRUNCATE without TABLE boolean only; // to support TRUNCATE with ONLY + private Table table; + private List
tables; @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public Table getTable() { return table; } + public List
getTables() { + return tables; + } + public void setTable(Table table) { this.table = table; } + public void setTables(List
tables) { + this.tables = tables; + } + public boolean getCascade() { return cascade; } @@ -53,10 +64,15 @@ public String toString() { sb.append(" ONLY"); } sb.append(" "); - sb.append(table); - + if (tables != null && !tables.isEmpty()) { + sb.append(tables.stream() + .map(Table::toString) + .collect(joining(", "))); + } else { + sb.append(table); + } if (cascade) { - sb.append( " CASCADE"); + sb.append(" CASCADE"); } return sb.toString(); } @@ -77,7 +93,7 @@ public void setOnly(boolean only) { this.only = only; } - public Truncate withTableToken(boolean hasTableToken){ + public Truncate withTableToken(boolean hasTableToken) { this.setTableToken(hasTableToken); return this; } @@ -87,10 +103,16 @@ public Truncate withTable(Table table) { return this; } + public Truncate withTables(List
tables) { + this.setTables(tables); + return this; + } + public Truncate withCascade(boolean cascade) { this.setCascade(cascade); return this; } + public Truncate withOnly(boolean only) { this.setOnly(only); return this; diff --git a/src/main/java/net/sf/jsqlparser/statement/update/ParenthesedUpdate.java b/src/main/java/net/sf/jsqlparser/statement/update/ParenthesedUpdate.java new file mode 100644 index 000000000..8dc95c2eb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/update/ParenthesedUpdate.java @@ -0,0 +1,62 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.update; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.ParenthesedStatement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class ParenthesedUpdate extends Update implements ParenthesedStatement { + + Alias alias; + Update update; + + @Override + public Alias getAlias() { + return alias; + } + + @Override + public void setAlias(Alias alias) { + this.alias = alias; + } + + public ParenthesedUpdate withAlias(Alias alias) { + this.setAlias(alias); + return this; + } + + public Update getUpdate() { + return update; + } + + public void setUpdate(Update update) { + this.update = update; + } + + public ParenthesedUpdate withUpdate(Update update) { + setUpdate(update); + return this; + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("(").append(update).append(")"); + if (alias != null) { + builder.append(alias); + } + return builder.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/update/Update.java b/src/main/java/net/sf/jsqlparser/statement/update/Update.java index 0a6224d76..b09854fe6 100644 --- a/src/main/java/net/sf/jsqlparser/statement/update/Update.java +++ b/src/main/java/net/sf/jsqlparser/statement/update/Update.java @@ -11,6 +11,7 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.OracleHint; +import net.sf.jsqlparser.expression.PreferringClause; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.OutputClause; @@ -36,9 +37,10 @@ @SuppressWarnings({"PMD.CyclomaticComplexity"}) public class Update implements Statement { - private List withItemsList; + private List> withItemsList; private Table table; private Expression where; + private PreferringClause preferringClause; private List updateSets; private FromItem fromItem; private List joins; @@ -64,46 +66,46 @@ public List getUpdateSets() { return updateSets; } - public UpdateSet getUpdateSet(int index) { - return updateSets.get(index); - } - public void setUpdateSets(List updateSets) { this.updateSets = updateSets; } + public UpdateSet getUpdateSet(int index) { + return updateSets.get(index); + } + public Update withUpdateSets(List updateSets) { this.setUpdateSets(updateSets); return this; } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } - public List getWithItemsList() { + public List> getWithItemsList() { return withItemsList; } - public void setWithItemsList(List withItemsList) { + public void setWithItemsList(List> withItemsList) { this.withItemsList = withItemsList; } - public Update withWithItemsList(List withItemsList) { + public Update withWithItemsList(List> withItemsList) { this.setWithItemsList(withItemsList); return this; } - public Update addWithItemsList(WithItem... withItemsList) { - List collection = + public Update addWithItemsList(WithItem... withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); Collections.addAll(collection, withItemsList); return this.withWithItemsList(collection); } - public Update addWithItemsList(Collection withItemsList) { - List collection = + public Update addWithItemsList(Collection> withItemsList) { + List> collection = Optional.ofNullable(getWithItemsList()).orElseGet(ArrayList::new); collection.addAll(withItemsList); return this.withWithItemsList(collection); @@ -113,18 +115,26 @@ public Table getTable() { return table; } - public Expression getWhere() { - return where; - } - public void setTable(Table table) { this.table = table; } + public Expression getWhere() { + return where; + } + public void setWhere(Expression expression) { where = expression; } + public PreferringClause getPreferringClause() { + return preferringClause; + } + + public void setPreferringClause(PreferringClause preferringClause) { + this.preferringClause = preferringClause; + } + public OracleHint getOracleHint() { return oracleHint; } @@ -150,11 +160,6 @@ public List getColumns() { return updateSets.get(0).columns; } - @Deprecated - public List getExpressions() { - return updateSets.get(0).values; - } - @Deprecated public void setColumns(List list) { if (updateSets.isEmpty()) { @@ -164,6 +169,11 @@ public void setColumns(List list) { updateSets.get(0).columns.addAll(list); } + @Deprecated + public List getExpressions() { + return updateSets.get(0).values; + } + @Deprecated public void setExpressions(List list) { updateSets.get(0).values.clear(); @@ -233,22 +243,22 @@ public void setUseSelect(boolean useSelect) { // todo } - public void setOrderByElements(List orderByElements) { - this.orderByElements = orderByElements; - } - - public void setLimit(Limit limit) { - this.limit = limit; - } - public List getOrderByElements() { return orderByElements; } + public void setOrderByElements(List orderByElements) { + this.orderByElements = orderByElements; + } + public Limit getLimit() { return limit; } + public void setLimit(Limit limit) { + this.limit = limit; + } + public ReturningClause getReturningClause() { return returningClause; } @@ -282,8 +292,8 @@ public String toString() { if (withItemsList != null && !withItemsList.isEmpty()) { b.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + WithItem withItem = iter.next(); b.append(withItem); if (iter.hasNext()) { b.append(","); @@ -336,6 +346,9 @@ public String toString() { b.append(" WHERE "); b.append(where); } + if (preferringClause != null) { + b.append(" ").append(preferringClause); + } if (orderByElements != null) { b.append(PlainSelect.orderByToString(orderByElements)); } @@ -400,6 +413,11 @@ public Update withWhere(Expression where) { return this; } + public Update withPreferringClause(PreferringClause preferringClause) { + this.setPreferringClause(preferringClause); + return this; + } + public Update withColumns(List columns) { this.setColumns(columns); return this; diff --git a/src/main/java/net/sf/jsqlparser/statement/update/UpdateSet.java b/src/main/java/net/sf/jsqlparser/statement/update/UpdateSet.java index 84299c0fb..abfd21192 100644 --- a/src/main/java/net/sf/jsqlparser/statement/update/UpdateSet.java +++ b/src/main/java/net/sf/jsqlparser/statement/update/UpdateSet.java @@ -36,30 +36,40 @@ public UpdateSet(Column column, Expression value) { this.values.add(value); } - public ExpressionList getColumns() { - return columns; + public final static StringBuilder appendUpdateSetsTo(StringBuilder builder, + Collection updateSets) { + int j = 0; + for (UpdateSet updateSet : updateSets) { + updateSet.appendTo(builder, j); + j++; + } + return builder; } - public Column getColumn(int index) { - return columns.get(index); + public ExpressionList getColumns() { + return columns; } public void setColumns(ExpressionList columns) { this.columns = Objects.requireNonNull(columns); } - public ExpressionList getValues() { - return values; + public Column getColumn(int index) { + return columns.get(index); } - public Expression getValue(int index) { - return values.get(index); + public ExpressionList getValues() { + return values; } public void setValues(ExpressionList values) { this.values = Objects.requireNonNull(values); } + public Expression getValue(int index) { + return values.get(index); + } + public void add(Column column, Expression value) { this.add(column); this.add(value); @@ -95,16 +105,6 @@ public void add(ExpressionList expressionList) { values.addAll(expressionList); } - public final static StringBuilder appendUpdateSetsTo(StringBuilder builder, - Collection updateSets) { - int j = 0; - for (UpdateSet updateSet : updateSets) { - updateSet.appendTo(builder, j); - j++; - } - return builder; - } - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPath"}) StringBuilder appendTo(StringBuilder builder, int j) { if (j > 0) { @@ -118,4 +118,8 @@ StringBuilder appendTo(StringBuilder builder, int j) { return builder; } + @Override + public String toString() { + return appendTo(new StringBuilder(), 0).toString(); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java b/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java index 4e63782d2..c13397569 100644 --- a/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java +++ b/src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java @@ -14,6 +14,8 @@ import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.insert.ConflictActionType; +import net.sf.jsqlparser.statement.insert.InsertDuplicateAction; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SetOperationList; @@ -35,6 +37,7 @@ public class Upsert implements Statement { private List duplicateUpdateSets; private UpsertType upsertType = UpsertType.UPSERT; private boolean isUsingInto; + private InsertDuplicateAction duplicateAction; public List getUpdateSets() { return updateSets; @@ -46,17 +49,26 @@ public Upsert setUpdateSets(List updateSets) { } public List getDuplicateUpdateSets() { + if (duplicateAction != null) { + return duplicateAction.getUpdateSets(); + } return duplicateUpdateSets; } public Upsert setDuplicateUpdateSets(List duplicateUpdateSets) { - this.duplicateUpdateSets = duplicateUpdateSets; + if (duplicateAction != null) { + duplicateAction.setConflictActionType(ConflictActionType.DO_UPDATE); + duplicateAction.setUpdateSets(duplicateUpdateSets); + } else { + duplicateAction = new InsertDuplicateAction(ConflictActionType.DO_UPDATE); + duplicateAction.setUpdateSets(duplicateUpdateSets); + } return this; } @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } public UpsertType getUpsertType() { @@ -181,9 +193,9 @@ public String toString() { } } - if (duplicateUpdateSets != null) { + if (duplicateAction != null) { sb.append(" ON DUPLICATE KEY UPDATE "); - UpdateSet.appendUpdateSetsTo(sb, duplicateUpdateSets); + duplicateAction.appendTo(sb); } return sb.toString(); @@ -219,4 +231,12 @@ public Upsert addColumns(Collection columns) { collection.addAll(columns); return this.withColumns(collection); } + + public InsertDuplicateAction getDuplicateAction() { + return duplicateAction; + } + + public void setDuplicateAction(InsertDuplicateAction duplicateAction) { + this.duplicateAction = duplicateAction; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java b/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java index 58ca4326f..baf251ecc 100644 --- a/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java +++ b/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java @@ -11,7 +11,9 @@ import java.util.LinkedList; import java.util.List; + import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.PlainSelect; @@ -31,42 +33,50 @@ * * @author tw */ -public class AddAliasesVisitor implements SelectVisitor, SelectItemVisitor { +public class AddAliasesVisitor implements SelectVisitor, SelectItemVisitor { private static final String NOT_SUPPORTED_YET = "Not supported yet."; - private List aliases = new LinkedList(); + private final List aliases = new LinkedList(); private boolean firstRun = true; private int counter = 0; private String prefix = "A"; @Override - public void visit(ParenthesedSelect parenthesedSelect) { - parenthesedSelect.getSelect().accept(this); + public T visit(ParenthesedSelect parenthesedSelect, S context) { + parenthesedSelect.getSelect().accept(this, context); + return null; } @Override - public void visit(PlainSelect plainSelect) { + public T visit(PlainSelect plainSelect, S context) { firstRun = true; counter = 0; aliases.clear(); - for (SelectItem item : plainSelect.getSelectItems()) { - item.accept(this); + for (SelectItem item : plainSelect.getSelectItems()) { + item.accept(this, context); } firstRun = false; - for (SelectItem item : plainSelect.getSelectItems()) { - item.accept(this); + for (SelectItem item : plainSelect.getSelectItems()) { + item.accept(this, context); } + return null; + } + + @Override + public T visit(FromQuery fromQuery, S context) { + throw new UnsupportedOperationException(NOT_SUPPORTED_YET); } @Override - public void visit(SetOperationList setOpList) { - for (Select select : setOpList.getSelects()) { - select.accept(this); + public T visit(SetOperationList setOperationList, S context) { + for (Select select : setOperationList.getSelects()) { + select.accept(this, context); } + return null; } @Override - public void visit(SelectItem selectExpressionItem) { + public T visit(SelectItem selectExpressionItem, S context) { if (firstRun) { if (selectExpressionItem.getAlias() != null) { aliases.add(selectExpressionItem.getAlias().getName().toUpperCase()); @@ -83,6 +93,7 @@ public void visit(SelectItem selectExpressionItem) { } } } + return null; } protected String getNextAlias() { @@ -95,26 +106,23 @@ public void setPrefix(String prefix) { } @Override - public void visit(WithItem withItem) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); // To change body of generated - // methods, choose Tools | - // Templates. + public T visit(WithItem withItem, S context) { + throw new UnsupportedOperationException(NOT_SUPPORTED_YET); } @Override - public void visit(Values aThis) { - throw new UnsupportedOperationException("Not supported yet."); // To change body of - // generated methods, choose - // Tools | Templates. + public T visit(Values values, S context) { + throw new UnsupportedOperationException(NOT_SUPPORTED_YET); } @Override - public void visit(LateralSubSelect lateralSubSelect) { - lateralSubSelect.getSelect().accept(this); + public T visit(LateralSubSelect lateralSubSelect, S context) { + lateralSubSelect.getSelect().accept(this, context); + return null; } @Override - public void visit(TableStatement tableStatement) { - throw new UnsupportedOperationException("Not supported yet."); + public T visit(TableStatement tableStatement, S context) { + throw new UnsupportedOperationException(NOT_SUPPORTED_YET); } } diff --git a/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java b/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java index 46b746f0a..ca642b7a1 100644 --- a/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java +++ b/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java @@ -11,8 +11,11 @@ import java.util.LinkedList; import java.util.List; + import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.PlainSelect; @@ -33,10 +36,12 @@ * @author tw */ @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) -public abstract class ConnectExpressionsVisitor implements SelectVisitor, SelectItemVisitor { +public abstract class ConnectExpressionsVisitor + implements SelectVisitor, SelectItemVisitor { + private final List> itemsExpr = + new LinkedList<>(); private String alias = "expr"; - private final List itemsExpr = new LinkedList(); public ConnectExpressionsVisitor() {} @@ -47,19 +52,21 @@ public ConnectExpressionsVisitor(String alias) { protected abstract BinaryExpression createBinaryExpression(); @Override - public void visit(ParenthesedSelect parenthesedSelect) { - parenthesedSelect.getSelect().accept(this); + public T visit(ParenthesedSelect parenthesedSelect, S context) { + parenthesedSelect.getSelect().accept(this, context); + return null; } @Override - public void visit(LateralSubSelect lateralSubSelect) { - lateralSubSelect.getSelect().accept(this); + public T visit(LateralSubSelect lateralSubSelect, S context) { + lateralSubSelect.getSelect().accept(this, context); + return null; } @Override - public void visit(PlainSelect plainSelect) { - for (SelectItem item : plainSelect.getSelectItems()) { - item.accept(this); + public T visit(PlainSelect plainSelect, S context) { + for (SelectItem item : plainSelect.getSelectItems()) { + item.accept(this, context); } if (itemsExpr.size() > 1) { @@ -73,7 +80,7 @@ public void visit(PlainSelect plainSelect) { } binExpr.setRightExpression(itemsExpr.get(itemsExpr.size() - 1).getExpression()); - SelectItem sei = new SelectItem(); + SelectItem sei = new SelectItem<>(); sei.setExpression(binExpr); plainSelect.getSelectItems().clear(); @@ -81,30 +88,40 @@ public void visit(PlainSelect plainSelect) { } plainSelect.getSelectItems().get(0).setAlias(new Alias(alias)); + return null; + } + + @Override + public T visit(FromQuery fromQuery, S context) { + throw new UnsupportedOperationException("Not supported yet."); } @Override - public void visit(SetOperationList setOpList) { + public T visit(SetOperationList setOpList, S context) { for (Select select : setOpList.getSelects()) { - select.accept(this); + select.accept(this, context); } + return null; } @Override - public void visit(WithItem withItem) {} + public T visit(WithItem withItem, S context) { + return null; + } @Override - public void visit(SelectItem selectItem) { + public T visit(SelectItem selectItem, S context) { itemsExpr.add(selectItem); + return null; } @Override - public void visit(Values aThis) { + public T visit(Values aThis, S context) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public void visit(TableStatement tableStatement) { + public T visit(TableStatement tableStatement, S context) { throw new UnsupportedOperationException("Not supported yet."); } } diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 270281096..09ca9faba 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -9,60 +9,13 @@ */ package net.sf.jsqlparser.util; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.expression.AllValue; -import net.sf.jsqlparser.expression.AnalyticExpression; -import net.sf.jsqlparser.expression.AnyComparisonExpression; -import net.sf.jsqlparser.expression.ArrayConstructor; -import net.sf.jsqlparser.expression.ArrayExpression; -import net.sf.jsqlparser.expression.BinaryExpression; -import net.sf.jsqlparser.expression.CaseExpression; -import net.sf.jsqlparser.expression.CastExpression; -import net.sf.jsqlparser.expression.CollateExpression; -import net.sf.jsqlparser.expression.ConnectByRootOperator; -import net.sf.jsqlparser.expression.DateTimeLiteralExpression; -import net.sf.jsqlparser.expression.DateValue; -import net.sf.jsqlparser.expression.DoubleValue; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.expression.ExpressionVisitor; -import net.sf.jsqlparser.expression.ExtractExpression; -import net.sf.jsqlparser.expression.Function; -import net.sf.jsqlparser.expression.HexValue; -import net.sf.jsqlparser.expression.IntervalExpression; -import net.sf.jsqlparser.expression.JdbcNamedParameter; -import net.sf.jsqlparser.expression.JdbcParameter; -import net.sf.jsqlparser.expression.JsonAggregateFunction; -import net.sf.jsqlparser.expression.JsonExpression; -import net.sf.jsqlparser.expression.JsonFunction; -import net.sf.jsqlparser.expression.JsonFunctionExpression; -import net.sf.jsqlparser.expression.KeepExpression; -import net.sf.jsqlparser.expression.LambdaExpression; -import net.sf.jsqlparser.expression.LongValue; -import net.sf.jsqlparser.expression.MySQLGroupConcat; -import net.sf.jsqlparser.expression.NextValExpression; -import net.sf.jsqlparser.expression.NotExpression; -import net.sf.jsqlparser.expression.NullValue; -import net.sf.jsqlparser.expression.NumericBind; -import net.sf.jsqlparser.expression.OracleHierarchicalExpression; -import net.sf.jsqlparser.expression.OracleHint; -import net.sf.jsqlparser.expression.OracleNamedFunctionParameter; -import net.sf.jsqlparser.expression.OverlapsCondition; -import net.sf.jsqlparser.expression.RangeExpression; -import net.sf.jsqlparser.expression.RowConstructor; -import net.sf.jsqlparser.expression.RowGetExpression; -import net.sf.jsqlparser.expression.SignedExpression; -import net.sf.jsqlparser.expression.StringValue; -import net.sf.jsqlparser.expression.StructType; -import net.sf.jsqlparser.expression.TimeKeyExpression; -import net.sf.jsqlparser.expression.TimeValue; -import net.sf.jsqlparser.expression.TimestampValue; -import net.sf.jsqlparser.expression.TimezoneExpression; -import net.sf.jsqlparser.expression.TranscodingFunction; -import net.sf.jsqlparser.expression.TrimFunction; -import net.sf.jsqlparser.expression.UserVariable; -import net.sf.jsqlparser.expression.VariableAssignment; -import net.sf.jsqlparser.expression.WhenClause; -import net.sf.jsqlparser.expression.XMLSerializeExpr; +import net.sf.jsqlparser.expression.*; import net.sf.jsqlparser.expression.operators.arithmetic.Addition; import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd; import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift; @@ -81,6 +34,7 @@ import net.sf.jsqlparser.expression.operators.relational.Between; import net.sf.jsqlparser.expression.operators.relational.ContainedBy; import net.sf.jsqlparser.expression.operators.relational.Contains; +import net.sf.jsqlparser.expression.operators.relational.CosineSimilarity; import net.sf.jsqlparser.expression.operators.relational.DoubleAnd; import net.sf.jsqlparser.expression.operators.relational.EqualsTo; import net.sf.jsqlparser.expression.operators.relational.ExcludesExpression; @@ -95,6 +49,7 @@ import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression; import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression; import net.sf.jsqlparser.expression.operators.relational.IsNullExpression; +import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression; import net.sf.jsqlparser.expression.operators.relational.JsonOperator; import net.sf.jsqlparser.expression.operators.relational.LikeExpression; import net.sf.jsqlparser.expression.operators.relational.Matches; @@ -102,6 +57,8 @@ import net.sf.jsqlparser.expression.operators.relational.MinorThan; import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals; import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo; +import net.sf.jsqlparser.expression.operators.relational.Plus; +import net.sf.jsqlparser.expression.operators.relational.PriorTo; import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator; import net.sf.jsqlparser.expression.operators.relational.SimilarToExpression; import net.sf.jsqlparser.expression.operators.relational.TSQLLeftJoin; @@ -121,6 +78,7 @@ import net.sf.jsqlparser.statement.ResetStatement; import net.sf.jsqlparser.statement.RollbackStatement; import net.sf.jsqlparser.statement.SavepointStatement; +import net.sf.jsqlparser.statement.SessionStatement; import net.sf.jsqlparser.statement.SetStatement; import net.sf.jsqlparser.statement.ShowColumnsStatement; import net.sf.jsqlparser.statement.ShowStatement; @@ -137,6 +95,7 @@ import net.sf.jsqlparser.statement.analyze.Analyze; import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; @@ -144,15 +103,25 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.OracleMultiInsertBranch; +import net.sf.jsqlparser.statement.insert.OracleMultiInsertClause; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; import net.sf.jsqlparser.statement.merge.Merge; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; +import net.sf.jsqlparser.statement.select.FromItem; import net.sf.jsqlparser.statement.select.FromItemVisitor; +import net.sf.jsqlparser.statement.select.FunctionAllColumns; import net.sf.jsqlparser.statement.select.Join; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.OrderByElement; @@ -171,15 +140,11 @@ import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; +import net.sf.jsqlparser.statement.update.UpdateSet; import net.sf.jsqlparser.statement.upsert.Upsert; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** * Find all used tables within an select statement. @@ -188,15 +153,35 @@ * Override extractTableName method to modify the extracted table names (e.g. without schema). */ @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.UncommentedEmptyMethodBody"}) -public class TablesNamesFinder implements SelectVisitor, FromItemVisitor, ExpressionVisitor, - SelectItemVisitor, StatementVisitor { +public class TablesNamesFinder + implements SelectVisitor, FromItemVisitor, ExpressionVisitor, + SelectItemVisitor, StatementVisitor { - private static final String NOT_SUPPORTED_YET = "Not supported yet."; private Set tables; private boolean allowColumnProcessing = false; private List otherItemNames; + public static Set findTables(String sqlStr) throws JSQLParserException { + TablesNamesFinder tablesNamesFinder = new TablesNamesFinder<>(); + return tablesNamesFinder.getTables(CCJSqlParserUtil.parse(sqlStr)); + } + + public static Set findTablesOrOtherSources(String sqlStr) throws JSQLParserException { + TablesNamesFinder tablesNamesFinder = new TablesNamesFinder<>(); + return tablesNamesFinder.getTablesOrOtherSources(CCJSqlParserUtil.parse(sqlStr)); + } + + public static Set findTablesInExpression(String exprStr) throws JSQLParserException { + TablesNamesFinder tablesNamesFinder = new TablesNamesFinder<>(); + return tablesNamesFinder.getTables(CCJSqlParserUtil.parseExpression(exprStr)); + } + + private static void throwUnsupported(T type) { + throw new UnsupportedOperationException(String.format( + "Finding tables from %s is not supported", type.getClass().getSimpleName())); + } + @Deprecated public List getTableList(Statement statement) { return new ArrayList(getTables(statement)); @@ -204,18 +189,18 @@ public List getTableList(Statement statement) { public Set getTables(Statement statement) { init(false); - statement.accept(this); + statement.accept(this, null); // @todo: assess this carefully, maybe we want to remove more specifically // only Aliases on WithItems, Parenthesed Selects and Lateral Selects - tables.removeAll(otherItemNames); + otherItemNames.forEach(tables::remove); return tables; } public Set getTablesOrOtherSources(Statement statement) { init(false); - statement.accept(this); + statement.accept(this, null); HashSet tablesOrOtherSources = new HashSet<>(tables); tablesOrOtherSources.addAll(otherItemNames); @@ -223,46 +208,45 @@ public Set getTablesOrOtherSources(Statement statement) { return tablesOrOtherSources; } - public static Set findTables(String sqlStr) throws JSQLParserException { - TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); - return tablesNamesFinder.getTables(CCJSqlParserUtil.parse(sqlStr)); - } - - public static Set findTablesOrOtherSources(String sqlStr) throws JSQLParserException { - TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); - return tablesNamesFinder.getTablesOrOtherSources(CCJSqlParserUtil.parse(sqlStr)); - } - @Override - public void visit(Select select) { - List withItemsList = select.getWithItemsList(); + public Void visit(Select select, S context) { + List> withItemsList = select.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { - withItem.accept((SelectVisitor) this); + for (WithItem withItem : withItemsList) { + withItem.accept((SelectVisitor) this, context); } } - select.accept((SelectVisitor) this); + select.accept((SelectVisitor) this, context); + return null; + } + + @Override + public void visit(Select select) { + StatementVisitor.super.visit(select); } @Override - public void visit(TranscodingFunction transcodingFunction) { - transcodingFunction.getExpression().accept(this); + public Void visit(TranscodingFunction transcodingFunction, S context) { + transcodingFunction.getExpression().accept(this, context); + return null; } @Override - public void visit(TrimFunction trimFunction) { + public Void visit(TrimFunction trimFunction, S context) { if (trimFunction.getExpression() != null) { - trimFunction.getExpression().accept(this); + trimFunction.getExpression().accept(this, context); } if (trimFunction.getFromExpression() != null) { - trimFunction.getFromExpression().accept(this); + trimFunction.getFromExpression().accept(this, context); } + return null; } @Override - public void visit(RangeExpression rangeExpression) { - rangeExpression.getStartExpression().accept(this); - rangeExpression.getEndExpression().accept(this); + public Void visit(RangeExpression rangeExpression, S context) { + rangeExpression.getStartExpression().accept(this, context); + rangeExpression.getEndExpression().accept(this, context); + return null; } /** @@ -275,65 +259,85 @@ public List getTableList(Expression expr) { public Set getTables(Expression expr) { init(true); - expr.accept(this); + expr.accept(this, null); return tables; } - public static Set findTablesInExpression(String exprStr) throws JSQLParserException { - TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); - return tablesNamesFinder.getTables(CCJSqlParserUtil.parseExpression(exprStr)); + @Override + public Void visit(WithItem withItem, S context) { + if (withItem.getAlias() != null) { + otherItemNames.add(withItem.getAlias().getName()); + } + if (withItem.getSelect() != null) { + withItem.getSelect().accept((SelectVisitor) this, context); + } + return null; } @Override - public void visit(WithItem withItem) { - otherItemNames.add(withItem.getAlias().getName()); - withItem.getSelect().accept((SelectVisitor) this); + public void visit(WithItem withItem) { + SelectVisitor.super.visit(withItem); } @Override - public void visit(ParenthesedSelect select) { + public Void visit(ParenthesedSelect select, S context) { if (select.getAlias() != null) { otherItemNames.add(select.getAlias().getName()); } - List withItemsList = select.getWithItemsList(); + List> withItemsList = select.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { - withItem.accept((SelectVisitor) this); + for (WithItem withItem : withItemsList) { + withItem.accept((SelectVisitor) this, context); } } - select.getSelect().accept((SelectVisitor) this); + select.getSelect().accept((SelectVisitor) this, context); + return null; } @Override - public void visit(PlainSelect plainSelect) { - List withItemsList = plainSelect.getWithItemsList(); + public void visit(ParenthesedSelect parenthesedSelect) { + SelectVisitor.super.visit(parenthesedSelect); + } + + @Override + public Void visit(PlainSelect plainSelect, S context) { + List> withItemsList = plainSelect.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { - withItem.accept((SelectVisitor) this); + for (WithItem withItem : withItemsList) { + withItem.accept((SelectVisitor) this, context); } } if (plainSelect.getSelectItems() != null) { for (SelectItem item : plainSelect.getSelectItems()) { - item.accept(this); + item.accept(this, context); } } if (plainSelect.getFromItem() != null) { - plainSelect.getFromItem().accept(this); + plainSelect.getFromItem().accept(this, context); } - visitJoins(plainSelect.getJoins()); + visitJoins(plainSelect.getJoins(), context); + if (plainSelect.getPreWhere() != null) { + plainSelect.getPreWhere().accept(this, context); + } if (plainSelect.getWhere() != null) { - plainSelect.getWhere().accept(this); + plainSelect.getWhere().accept(this, context); } if (plainSelect.getHaving() != null) { - plainSelect.getHaving().accept(this); + plainSelect.getHaving().accept(this, context); } if (plainSelect.getOracleHierarchical() != null) { - plainSelect.getOracleHierarchical().accept(this); + plainSelect.getOracleHierarchical().accept(this, context); } + return null; + } + + @Override + public void visit(PlainSelect plainSelect) { + SelectVisitor.super.visit(plainSelect); } /** @@ -347,246 +351,311 @@ protected String extractTableName(Table table) { } @Override - public void visit(Table tableName) { - String tableWholeName = extractTableName(tableName); + public Void visit(Table table, S context) { + String tableWholeName = extractTableName(table); if (!otherItemNames.contains(tableWholeName)) { tables.add(tableWholeName); } + return null; } @Override - public void visit(Addition addition) { + public void visit(Table tableName) { + this.visit(tableName, null); + } + + @Override + public Void visit(Addition addition, S context) { visitBinaryExpression(addition); + return null; } @Override - public void visit(AndExpression andExpression) { + public Void visit(AndExpression andExpression, S context) { visitBinaryExpression(andExpression); + return null; } @Override - public void visit(Between between) { - between.getLeftExpression().accept(this); - between.getBetweenExpressionStart().accept(this); - between.getBetweenExpressionEnd().accept(this); + public Void visit(Between between, S context) { + between.getLeftExpression().accept(this, context); + between.getBetweenExpressionStart().accept(this, context); + between.getBetweenExpressionEnd().accept(this, context); + return null; } @Override - public void visit(OverlapsCondition overlapsCondition) { - overlapsCondition.getLeft().accept(this); - overlapsCondition.getRight().accept(this); + public Void visit(OverlapsCondition overlapsCondition, S context) { + overlapsCondition.getLeft().accept(this, context); + overlapsCondition.getRight().accept(this, context); + return null; } @Override - public void visit(Column tableColumn) { + public Void visit(Column tableColumn, S context) { if (allowColumnProcessing && tableColumn.getTable() != null && tableColumn.getTable().getName() != null) { - visit(tableColumn.getTable()); + visit(tableColumn.getTable(), context); } + return null; } @Override - public void visit(Division division) { + public Void visit(Division division, S context) { visitBinaryExpression(division); + return null; } @Override - public void visit(IntegerDivision division) { + public Void visit(IntegerDivision division, S context) { visitBinaryExpression(division); + return null; } @Override - public void visit(DoubleValue doubleValue) { + public Void visit(DoubleValue doubleValue, S context) { + return null; } @Override - public void visit(EqualsTo equalsTo) { + public Void visit(EqualsTo equalsTo, S context) { visitBinaryExpression(equalsTo); + return null; } @Override - public void visit(Function function) { - ExpressionList exprList = function.getParameters(); + public Void visit(Function function, S context) { + ExpressionList exprList = function.getParameters(); + if (exprList != null) { + visit(exprList, context); + } + exprList = function.getChainedParameters(); if (exprList != null) { - visit(exprList); + visit(exprList, context); } + return null; } @Override - public void visit(GreaterThan greaterThan) { + public Void visit(GreaterThan greaterThan, S context) { visitBinaryExpression(greaterThan); + return null; } @Override - public void visit(GreaterThanEquals greaterThanEquals) { + public Void visit(GreaterThanEquals greaterThanEquals, S context) { visitBinaryExpression(greaterThanEquals); + return null; } @Override - public void visit(InExpression inExpression) { - inExpression.getLeftExpression().accept(this); - inExpression.getRightExpression().accept(this); + public Void visit(InExpression inExpression, S context) { + inExpression.getLeftExpression().accept(this, context); + inExpression.getRightExpression().accept(this, context); + return null; } @Override - public void visit(IncludesExpression includesExpression) { - includesExpression.getLeftExpression().accept(this); - includesExpression.getRightExpression().accept(this); + public Void visit(IncludesExpression includesExpression, S context) { + includesExpression.getLeftExpression().accept(this, context); + includesExpression.getRightExpression().accept(this, context); + return null; } @Override - public void visit(ExcludesExpression excludesExpression) { - excludesExpression.getLeftExpression().accept(this); - excludesExpression.getRightExpression().accept(this); + public Void visit(ExcludesExpression excludesExpression, S context) { + excludesExpression.getLeftExpression().accept(this, context); + excludesExpression.getRightExpression().accept(this, context); + return null; } @Override - public void visit(FullTextSearch fullTextSearch) { + public Void visit(FullTextSearch fullTextSearch, S context) { + return null; } @Override - public void visit(SignedExpression signedExpression) { - signedExpression.getExpression().accept(this); + public Void visit(SignedExpression signedExpression, S context) { + signedExpression.getExpression().accept(this, context); + return null; } @Override - public void visit(IsNullExpression isNullExpression) { + public Void visit(IsNullExpression isNullExpression, S context) { + isNullExpression.getLeftExpression().accept(this, context); + return null; + } + @Override + public Void visit(IsBooleanExpression isBooleanExpression, S context) { + isBooleanExpression.getLeftExpression().accept(this, context); + return null; } @Override - public void visit(IsBooleanExpression isBooleanExpression) { + public Void visit(IsUnknownExpression isUnknownExpression, S context) { + return null; } @Override - public void visit(JdbcParameter jdbcParameter) { + public Void visit(JdbcParameter jdbcParameter, S context) { + return null; } @Override - public void visit(LikeExpression likeExpression) { + public Void visit(LikeExpression likeExpression, S context) { visitBinaryExpression(likeExpression); + return null; } @Override - public void visit(ExistsExpression existsExpression) { - existsExpression.getRightExpression().accept(this); + public Void visit(ExistsExpression existsExpression, S context) { + existsExpression.getRightExpression().accept(this, context); + return null; } @Override - public void visit(MemberOfExpression memberOfExpression) { - memberOfExpression.getLeftExpression().accept(this); - memberOfExpression.getRightExpression().accept(this); + public Void visit(MemberOfExpression memberOfExpression, S context) { + memberOfExpression.getLeftExpression().accept(this, context); + memberOfExpression.getRightExpression().accept(this, context); + return null; } @Override - public void visit(LongValue longValue) { + public Void visit(LongValue longValue, S context) { + return null; } @Override - public void visit(MinorThan minorThan) { + public Void visit(MinorThan minorThan, S context) { visitBinaryExpression(minorThan); + return null; } @Override - public void visit(MinorThanEquals minorThanEquals) { + public Void visit(MinorThanEquals minorThanEquals, S context) { visitBinaryExpression(minorThanEquals); + return null; } @Override - public void visit(Multiplication multiplication) { + public Void visit(Multiplication multiplication, S context) { visitBinaryExpression(multiplication); + return null; } @Override - public void visit(NotEqualsTo notEqualsTo) { + public Void visit(NotEqualsTo notEqualsTo, S context) { visitBinaryExpression(notEqualsTo); + return null; } @Override - public void visit(DoubleAnd doubleAnd) { + public Void visit(DoubleAnd doubleAnd, S context) { visitBinaryExpression(doubleAnd); + return null; } @Override - public void visit(Contains contains) { + public Void visit(Contains contains, S context) { visitBinaryExpression(contains); + return null; } @Override - public void visit(ContainedBy containedBy) { + public Void visit(ContainedBy containedBy, S context) { visitBinaryExpression(containedBy); + return null; } @Override - public void visit(NullValue nullValue) { + public Void visit(NullValue nullValue, S context) { + return null; } @Override - public void visit(OrExpression orExpression) { + public Void visit(OrExpression orExpression, S context) { visitBinaryExpression(orExpression); + return null; } @Override - public void visit(XorExpression xorExpression) { + public Void visit(XorExpression xorExpression, S context) { visitBinaryExpression(xorExpression); + return null; } @Override - public void visit(StringValue stringValue) { + public Void visit(StringValue stringValue, S context) { + return null; } @Override - public void visit(Subtraction subtraction) { + public Void visit(BooleanValue booleanValue, S context) { + + return null; + } + + @Override + public Void visit(Subtraction subtraction, S context) { visitBinaryExpression(subtraction); + return null; } @Override - public void visit(NotExpression notExpr) { - notExpr.getExpression().accept(this); + public Void visit(NotExpression notExpr, S context) { + notExpr.getExpression().accept(this, context); + return null; } @Override - public void visit(BitwiseRightShift expr) { + public Void visit(BitwiseRightShift expr, S context) { visitBinaryExpression(expr); + return null; } @Override - public void visit(BitwiseLeftShift expr) { + public Void visit(BitwiseLeftShift expr, S context) { visitBinaryExpression(expr); + return null; } public void visitBinaryExpression(BinaryExpression binaryExpression) { - binaryExpression.getLeftExpression().accept(this); - binaryExpression.getRightExpression().accept(this); + binaryExpression.getLeftExpression().accept(this, null); + binaryExpression.getRightExpression().accept(this, null); } @Override - public void visit(ExpressionList expressionList) { + public Void visit(ExpressionList expressionList, S context) { for (Expression expression : expressionList) { - expression.accept(this); + expression.accept(this, context); } + return null; } @Override - public void visit(DateValue dateValue) { + public Void visit(DateValue dateValue, S context) { + return null; } @Override - public void visit(TimestampValue timestampValue) { + public Void visit(TimestampValue timestampValue, S context) { + return null; } @Override - public void visit(TimeValue timeValue) { + public Void visit(TimeValue timeValue, S context) { + return null; } /* @@ -596,18 +665,19 @@ public void visit(TimeValue timeValue) { * CaseExpression) */ @Override - public void visit(CaseExpression caseExpression) { + public Void visit(CaseExpression caseExpression, S context) { if (caseExpression.getSwitchExpression() != null) { - caseExpression.getSwitchExpression().accept(this); + caseExpression.getSwitchExpression().accept(this, context); } if (caseExpression.getWhenClauses() != null) { for (WhenClause when : caseExpression.getWhenClauses()) { - when.accept(this); + when.accept(this, context); } } if (caseExpression.getElseExpression() != null) { - caseExpression.getElseExpression().accept(this); + caseExpression.getElseExpression().accept(this, context); } + return null; } /* @@ -617,113 +687,160 @@ public void visit(CaseExpression caseExpression) { * net.sf.jsqlparser.expression.ExpressionVisitor#visit(net.sf.jsqlparser.expression.WhenClause) */ @Override - public void visit(WhenClause whenClause) { + public Void visit(WhenClause whenClause, S context) { if (whenClause.getWhenExpression() != null) { - whenClause.getWhenExpression().accept(this); + whenClause.getWhenExpression().accept(this, context); } if (whenClause.getThenExpression() != null) { - whenClause.getThenExpression().accept(this); + whenClause.getThenExpression().accept(this, context); } + return null; } @Override - public void visit(AnyComparisonExpression anyComparisonExpression) { - anyComparisonExpression.getSelect().accept((ExpressionVisitor) this); + public Void visit(AnyComparisonExpression anyComparisonExpression, S context) { + anyComparisonExpression.getSelect().accept((ExpressionVisitor) this, context); + return null; } @Override - public void visit(Concat concat) { + public Void visit(Concat concat, S context) { visitBinaryExpression(concat); + return null; } @Override - public void visit(Matches matches) { + public Void visit(Matches matches, S context) { visitBinaryExpression(matches); + return null; } @Override - public void visit(BitwiseAnd bitwiseAnd) { + public Void visit(BitwiseAnd bitwiseAnd, S context) { visitBinaryExpression(bitwiseAnd); + return null; } @Override - public void visit(BitwiseOr bitwiseOr) { + public Void visit(BitwiseOr bitwiseOr, S context) { visitBinaryExpression(bitwiseOr); + return null; } @Override - public void visit(BitwiseXor bitwiseXor) { + public Void visit(BitwiseXor bitwiseXor, S context) { visitBinaryExpression(bitwiseXor); + return null; } @Override - public void visit(CastExpression cast) { - cast.getLeftExpression().accept(this); + public Void visit(CastExpression cast, S context) { + cast.getLeftExpression().accept(this, context); + return null; } @Override - public void visit(Modulo modulo) { + public Void visit(Modulo modulo, S context) { visitBinaryExpression(modulo); + return null; } @Override - public void visit(AnalyticExpression analytic) { + public Void visit(AnalyticExpression analytic, S context) { if (analytic.getExpression() != null) { - analytic.getExpression().accept(this); + analytic.getExpression().accept(this, context); } if (analytic.getDefaultValue() != null) { - analytic.getDefaultValue().accept(this); + analytic.getDefaultValue().accept(this, context); } if (analytic.getOffset() != null) { - analytic.getOffset().accept(this); + analytic.getOffset().accept(this, context); } if (analytic.getKeep() != null) { - analytic.getKeep().accept(this); + analytic.getKeep().accept(this, context); } if (analytic.getFuncOrderBy() != null) { for (OrderByElement element : analytic.getOrderByElements()) { - element.getExpression().accept(this); + element.getExpression().accept(this, context); } } if (analytic.getWindowElement() != null) { - analytic.getWindowElement().getRange().getStart().getExpression().accept(this); - analytic.getWindowElement().getRange().getEnd().getExpression().accept(this); - analytic.getWindowElement().getOffset().getExpression().accept(this); + if (analytic.getWindowElement().getRange().getStart().getExpression() != null) { + analytic.getWindowElement().getRange().getStart().getExpression().accept(this, + context); + } + if (analytic.getWindowElement().getRange().getEnd().getExpression() != null) { + analytic.getWindowElement().getRange().getEnd().getExpression().accept(this, + context); + } + if (analytic.getWindowElement().getOffset() != null) { + analytic.getWindowElement().getOffset().getExpression().accept(this, context); + } } + return null; } @Override - public void visit(SetOperationList list) { - List withItemsList = list.getWithItemsList(); + public Void visit(SetOperationList list, S context) { + List> withItemsList = list.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - for (WithItem withItem : withItemsList) { - withItem.accept((SelectVisitor) this); + for (WithItem withItem : withItemsList) { + withItem.accept((SelectVisitor) this, context); } } for (Select selectBody : list.getSelects()) { - selectBody.accept((SelectVisitor) this); + selectBody.accept((SelectVisitor) this, context); } + return null; + } + + @Override + public void visit(SetOperationList setOpList) { + SelectVisitor.super.visit(setOpList); } @Override - public void visit(ExtractExpression eexpr) { + public Void visit(ExtractExpression eexpr, S context) { if (eexpr.getExpression() != null) { - eexpr.getExpression().accept(this); + eexpr.getExpression().accept(this, context); } + return null; } @Override - public void visit(LateralSubSelect lateralSubSelect) { + public Void visit(LateralSubSelect lateralSubSelect, S context) { if (lateralSubSelect.getAlias() != null) { otherItemNames.add(lateralSubSelect.getAlias().getName()); } - lateralSubSelect.getSelect().accept((SelectVisitor) this); + lateralSubSelect.getSelect().accept((SelectVisitor) this, context); + return null; + } + + @Override + public void visit(LateralSubSelect lateralSubSelect) { + SelectVisitor.super.visit(lateralSubSelect); + } + + @Override + public Void visit(TableStatement tableStatement, S context) { + tableStatement.getTable().accept(this, null); + return null; } @Override public void visit(TableStatement tableStatement) { - tableStatement.getTable().accept(this); + SelectVisitor.super.visit(tableStatement); + } + + @Override + public Void visit(FromQuery fromQuery, S context) { + return null; + } + + @Override + public Void visit(DateUnitExpression dateUnitExpression, S context) { + return null; } /** @@ -741,324 +858,539 @@ protected void init(boolean allowColumnProcessing) { } @Override - public void visit(IntervalExpression iexpr) { - if (iexpr.getExpression() != null) { - iexpr.getExpression().accept(this); + public Void visit(IntervalExpression intervalExpression, S context) { + if (intervalExpression.getExpression() != null) { + intervalExpression.getExpression().accept(this, context); } + return null; } @Override - public void visit(JdbcNamedParameter jdbcNamedParameter) { + public Void visit(JdbcNamedParameter jdbcNamedParameter, S context) { + return null; } @Override - public void visit(OracleHierarchicalExpression oexpr) { - if (oexpr.getStartExpression() != null) { - oexpr.getStartExpression().accept(this); + public Void visit(OracleHierarchicalExpression hierarchicalExpression, S context) { + if (hierarchicalExpression.getStartExpression() != null) { + hierarchicalExpression.getStartExpression().accept(this, context); } - if (oexpr.getConnectExpression() != null) { - oexpr.getConnectExpression().accept(this); + if (hierarchicalExpression.getConnectExpression() != null) { + hierarchicalExpression.getConnectExpression().accept(this, context); } + return null; } @Override - public void visit(RegExpMatchOperator rexpr) { - visitBinaryExpression(rexpr); + public Void visit(RegExpMatchOperator regExpMatchOperator, S context) { + visitBinaryExpression(regExpMatchOperator); + return null; } @Override - public void visit(JsonExpression jsonExpr) { + public Void visit(JsonExpression jsonExpr, S context) { if (jsonExpr.getExpression() != null) { - jsonExpr.getExpression().accept(this); + jsonExpr.getExpression().accept(this, context); } + return null; } @Override - public void visit(JsonOperator jsonExpr) { + public Void visit(JsonOperator jsonExpr, S context) { visitBinaryExpression(jsonExpr); + return null; + } + + @Override + public Void visit(AllColumns allColumns, S context) { + + return null; } @Override - public void visit(AllColumns allColumns) { + public Void visit(AllTableColumns allTableColumns, S context) { + return null; } @Override - public void visit(AllTableColumns allTableColumns) { + public Void visit(FunctionAllColumns functionAllColumns, S context) { + return null; } @Override - public void visit(AllValue allValue) { + public Void visit(AllValue allValue, S context) { + return null; } @Override - public void visit(IsDistinctExpression isDistinctExpression) { + public Void visit(IsDistinctExpression isDistinctExpression, S context) { visitBinaryExpression(isDistinctExpression); + return null; } @Override - public void visit(SelectItem item) { - item.getExpression().accept(this); + public Void visit(SelectItem item, S context) { + item.getExpression().accept(this, context); + return null; } @Override - public void visit(UserVariable var) { + public void visit(SelectItem selectItem) { + SelectItemVisitor.super.visit(selectItem); + } + + @Override + public Void visit(UserVariable userVariable, S context) { + return null; } @Override - public void visit(NumericBind bind) { + public Void visit(NumericBind numericBind, S context) { + return null; } @Override - public void visit(KeepExpression aexpr) { + public Void visit(KeepExpression keepExpression, S context) { + return null; } @Override - public void visit(MySQLGroupConcat groupConcat) { + public Void visit(MySQLGroupConcat groupConcat, S context) { + return null; } @Override - public void visit(Delete delete) { - visit(delete.getTable()); + public Void visit(Delete delete, S context) { + visit(delete.getTable(), context); - if (delete.getUsingList() != null) { - for (Table using : delete.getUsingList()) { - visit(using); + if (delete.getUsingFromItemList() != null) { + for (FromItem usingFromItem : delete.getUsingFromItemList()) { + usingFromItem.accept(this, context); } } - visitJoins(delete.getJoins()); + visitJoins(delete.getJoins(), context); if (delete.getWhere() != null) { - delete.getWhere().accept(this); + delete.getWhere().accept(this, context); } + return null; } @Override - public void visit(Update update) { - visit(update.getTable()); + public void visit(Delete delete) { + StatementVisitor.super.visit(delete); + } + + @Override + public Void visit(ParenthesedDelete delete, S context) { + return visit(delete.getDelete(), context); + } + + @Override + public Void visit(SessionStatement sessionStatement, S context) { + return null; + } + + @Override + public Void visit(Update update, S context) { if (update.getWithItemsList() != null) { - for (WithItem withItem : update.getWithItemsList()) { - withItem.accept((SelectVisitor) this); + for (WithItem withItem : update.getWithItemsList()) { + withItem.accept((SelectVisitor) this, context); } } + visit(update.getTable(), context); + if (update.getStartJoins() != null) { for (Join join : update.getStartJoins()) { - join.getRightItem().accept(this); + join.getRightItem().accept(this, context); } } - if (update.getExpressions() != null) { - for (Expression expression : update.getExpressions()) { - expression.accept(this); + + if (update.getUpdateSets() != null) { + for (UpdateSet updateSet : update.getUpdateSets()) { + updateSet.getColumns().accept(this, context); + updateSet.getValues().accept(this, context); } } if (update.getFromItem() != null) { - update.getFromItem().accept(this); + update.getFromItem().accept(this, context); } if (update.getJoins() != null) { for (Join join : update.getJoins()) { - join.getRightItem().accept(this); + join.getRightItem().accept(this, context); for (Expression expression : join.getOnExpressions()) { - expression.accept(this); + expression.accept(this, context); } } } if (update.getWhere() != null) { - update.getWhere().accept(this); + update.getWhere().accept(this, context); } + return null; } @Override - public void visit(Insert insert) { - visit(insert.getTable()); + public Void visit(ParenthesedUpdate update, S context) { + return visit(update.getUpdate(), context); + } + + @Override + public void visit(Update update) { + StatementVisitor.super.visit(update); + } + + @Override + public Void visit(Insert insert, S context) { + if (insert.isOracleMultiInsert() && insert.getOracleMultiInsertBranches() != null) { + for (OracleMultiInsertBranch branch : insert.getOracleMultiInsertBranches()) { + if (branch.getWhenExpression() != null) { + branch.getWhenExpression().accept(this, context); + } + if (branch.getClauses() == null) { + continue; + } + for (OracleMultiInsertClause clause : branch.getClauses()) { + visit(clause.getTable(), context); + if (clause.getSelect() != null) { + visit(clause.getSelect(), context); + } + } + } + } else if (insert.getTable() != null) { + visit(insert.getTable(), context); + } if (insert.getWithItemsList() != null) { - for (WithItem withItem : insert.getWithItemsList()) { - withItem.accept((SelectVisitor) this); + for (WithItem withItem : insert.getWithItemsList()) { + withItem.accept((SelectVisitor) this, context); } } if (insert.getSelect() != null) { - visit(insert.getSelect()); + visit(insert.getSelect(), context); } + return null; + } + + @Override + public Void visit(ParenthesedInsert insert, S context) { + return visit(insert.getInsert(), context); } + @Override + public void visit(Insert insert) { + StatementVisitor.super.visit(insert); + } + + @Override + public Void visit(Analyze analyze, S context) { + visit(analyze.getTable(), context); + return null; + } + + @Override public void visit(Analyze analyze) { - visit(analyze.getTable()); + StatementVisitor.super.visit(analyze); + } + + @Override + public Void visit(Drop drop, S context) { + visit(drop.getName(), context); + return null; } @Override public void visit(Drop drop) { - visit(drop.getName()); + StatementVisitor.super.visit(drop); + } + + @Override + public Void visit(Truncate truncate, S context) { + visit(truncate.getTable(), context); + return null; } @Override public void visit(Truncate truncate) { - visit(truncate.getTable()); + StatementVisitor.super.visit(truncate); + } + + @Override + public Void visit(CreateIndex createIndex, S context) { + throwUnsupported(createIndex); + return null; } @Override public void visit(CreateIndex createIndex) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + StatementVisitor.super.visit(createIndex); + } + + @Override + public Void visit(CreateSchema createSchema, S context) { + throwUnsupported(createSchema); + return null; } @Override - public void visit(CreateSchema aThis) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + public void visit(CreateSchema createSchema) { + StatementVisitor.super.visit(createSchema); } @Override - public void visit(CreateTable create) { - visit(create.getTable()); + public Void visit(CreateTable create, S context) { + visit(create.getTable(), null); if (create.getSelect() != null) { - create.getSelect().accept((SelectVisitor) this); + create.getSelect().accept((SelectVisitor) this, context); } + return null; + } + + @Override + public void visit(CreateTable createTable) { + StatementVisitor.super.visit(createTable); + } + + @Override + public Void visit(CreateView create, S context) { + visit(create.getView(), null); + if (create.getSelect() != null) { + create.getSelect().accept((SelectVisitor) this, context); + } + return null; } @Override public void visit(CreateView createView) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + StatementVisitor.super.visit(createView); + } + + @Override + public Void visit(Alter alter, S context) { + return alter.getTable().accept(this, context); } @Override public void visit(Alter alter) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + alter.getTable().accept(this, null); } @Override - public void visit(Statements stmts) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + public Void visit(Statements statements, S context) { + for (Statement statement : statements) { + statement.accept(this, context); + } + return null; + } + + @Override + public void visit(Statements statements) { + StatementVisitor.super.visit(statements); + } + + @Override + public Void visit(Execute execute, S context) { + throwUnsupported(execute); + return null; } @Override public void visit(Execute execute) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + StatementVisitor.super.visit(execute); + } + + @Override + public Void visit(SetStatement setStatement, S context) { + throwUnsupported(setStatement); + return null; } @Override public void visit(SetStatement set) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + StatementVisitor.super.visit(set); + } + + @Override + public Void visit(ResetStatement reset, S context) { + throwUnsupported(reset); + return null; } @Override public void visit(ResetStatement reset) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + StatementVisitor.super.visit(reset); + } + + @Override + public Void visit(ShowColumnsStatement showColumnsStatement, S context) { + throwUnsupported(showColumnsStatement); + return null; } @Override - public void visit(ShowColumnsStatement set) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + public void visit(ShowColumnsStatement showColumns) { + StatementVisitor.super.visit(showColumns); + } + + @Override + public Void visit(ShowIndexStatement showIndex, S context) { + throwUnsupported(showIndex); + return null; } @Override public void visit(ShowIndexStatement showIndex) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + StatementVisitor.super.visit(showIndex); } @Override - public void visit(RowConstructor rowConstructor) { + public Void visit(RowConstructor rowConstructor, S context) { for (Expression expr : rowConstructor) { - expr.accept(this); + expr.accept(this, context); } + return null; } @Override - public void visit(RowGetExpression rowGetExpression) { - rowGetExpression.getExpression().accept(this); + public Void visit(RowGetExpression rowGetExpression, S context) { + rowGetExpression.getExpression().accept(this, context); + return null; } @Override - public void visit(HexValue hexValue) { - - + public Void visit(HexValue hexValue, S context) { + return null; } @Override - public void visit(Merge merge) { - visit(merge.getTable()); + public Void visit(Merge merge, S context) { + visit(merge.getTable(), context); if (merge.getWithItemsList() != null) { - for (WithItem withItem : merge.getWithItemsList()) { - withItem.accept((SelectVisitor) this); + for (WithItem withItem : merge.getWithItemsList()) { + withItem.accept((SelectVisitor) this, context); } } if (merge.getFromItem() != null) { - merge.getFromItem().accept(this); + merge.getFromItem().accept(this, context); } + return null; } @Override - public void visit(OracleHint hint) { + public void visit(Merge merge) { + StatementVisitor.super.visit(merge); + } + + @Override + public Void visit(OracleHint hint, S context) { + return null; + } + @Override + public Void visit(TableFunction tableFunction, S context) { + visit(tableFunction.getFunction(), null); + return null; } @Override public void visit(TableFunction tableFunction) { - visit(tableFunction.getFunction()); + FromItemVisitor.super.visit(tableFunction); } @Override - public void visit(AlterView alterView) { - throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + public Void visit(AlterView alterView, S context) { + throwUnsupported(alterView); + return null; } @Override - public void visit(RefreshMaterializedViewStatement materializedView) { - visit(materializedView.getView()); + public void visit(AlterView alterView) { + StatementVisitor.super.visit(alterView); } @Override - public void visit(TimeKeyExpression timeKeyExpression) { + public Void visit(RefreshMaterializedViewStatement materializedView, S context) { + visit(materializedView.getView(), context); + return null; + } + @Override + public void visit(RefreshMaterializedViewStatement materializedView) { + StatementVisitor.super.visit(materializedView); } @Override - public void visit(DateTimeLiteralExpression literal) { + public Void visit(TimeKeyExpression timeKeyExpression, S context) { + return null; + } + @Override + public Void visit(DateTimeLiteralExpression literal, S context) { + return null; + } + @Override + public Void visit(Commit commit, S context) { + return null; } @Override public void visit(Commit commit) { - - + StatementVisitor.super.visit(commit); } @Override - public void visit(Upsert upsert) { - visit(upsert.getTable()); + public Void visit(Upsert upsert, S context) { + visit(upsert.getTable(), context); if (upsert.getExpressions() != null) { - upsert.getExpressions().accept(this); + upsert.getExpressions().accept(this, context); } if (upsert.getSelect() != null) { - visit(upsert.getSelect()); + visit(upsert.getSelect(), context); } + return null; } @Override - public void visit(UseStatement use) { + public void visit(Upsert upsert) { + StatementVisitor.super.visit(upsert); + } + @Override + public Void visit(UseStatement use, S context) { + return null; } @Override - public void visit(ParenthesedFromItem parenthesis) { - if (parenthesis.getAlias() != null) { - otherItemNames.add(parenthesis.getAlias().getName()); - } - parenthesis.getFromItem().accept(this); + public void visit(UseStatement use) { + StatementVisitor.super.visit(use); + } + + @Override + public Void visit(ParenthesedFromItem parenthesis, S context) { + parenthesis.getFromItem().accept(this, context); // support join keyword in fromItem - visitJoins(parenthesis.getJoins()); + visitJoins(parenthesis.getJoins(), context); + return null; + } + + @Override + public void visit(ParenthesedFromItem parenthesedFromItem) { + FromItemVisitor.super.visit(parenthesedFromItem); } /** @@ -1066,259 +1398,545 @@ public void visit(ParenthesedFromItem parenthesis) { * * @param joins join sql block */ - private void visitJoins(List joins) { + private void visitJoins(List joins, S context) { if (joins == null) { return; } for (Join join : joins) { - join.getFromItem().accept(this); - join.getRightItem().accept(this); + join.getFromItem().accept(this, context); for (Expression expression : join.getOnExpressions()) { - expression.accept(this); + expression.accept(this, context); } } } @Override - public void visit(Block block) { + public Void visit(Block block, S context) { if (block.getStatements() != null) { - visit(block.getStatements()); + visit(block.getStatements(), context); } + return null; } @Override - public void visit(Comment comment) { + public void visit(Block block) { + StatementVisitor.super.visit(block); + } + + @Override + public Void visit(Comment comment, S context) { if (comment.getTable() != null) { - visit(comment.getTable()); + visit(comment.getTable(), context); } if (comment.getColumn() != null) { Table table = comment.getColumn().getTable(); if (table != null) { - visit(table); + visit(table, context); } } + return null; + } + + @Override + public void visit(Comment comment) { + StatementVisitor.super.visit(comment); + } + + @Override + public Void visit(Values values, S context) { + values.getExpressions().accept(this, context); + return null; } @Override public void visit(Values values) { - values.getExpressions().accept(this); + SelectVisitor.super.visit(values); + } + + @Override + public Void visit(DescribeStatement describe, S context) { + describe.getTable().accept(this, context); + return null; } @Override public void visit(DescribeStatement describe) { - describe.getTable().accept(this); + StatementVisitor.super.visit(describe); } @Override - public void visit(ExplainStatement explain) { - if (explain.getStatement() != null) { - explain.getStatement().accept((StatementVisitor) this); + public Void visit(ExplainStatement explainStatement, S context) { + if (explainStatement.getStatement() != null) { + explainStatement.getStatement().accept((StatementVisitor) this, context); } + return null; } @Override - public void visit(NextValExpression nextVal) { + public void visit(ExplainStatement explainStatement) { + StatementVisitor.super.visit(explainStatement); + } + @Override + public Void visit(NextValExpression nextVal, S context) { + return null; } @Override - public void visit(CollateExpression col) { - col.getLeftExpression().accept(this); + public Void visit(CollateExpression collateExpression, S context) { + collateExpression.getLeftExpression().accept(this, context); + return null; } @Override - public void visit(ShowStatement aThis) { + public Void visit(ShowStatement showStatement, S context) { + return null; + } + @Override + public void visit(ShowStatement showStatement) { + StatementVisitor.super.visit(showStatement); } @Override - public void visit(SimilarToExpression expr) { + public Void visit(SimilarToExpression expr, S context) { visitBinaryExpression(expr); + return null; } @Override - public void visit(DeclareStatement aThis) { - + public Void visit(DeclareStatement declareStatement, S context) { + return null; } @Override - public void visit(Grant grant) { + public void visit(DeclareStatement declareStatement) { + StatementVisitor.super.visit(declareStatement); + } + @Override + public Void visit(Grant grant, S context) { + return null; + } + @Override + public void visit(Grant grant) { + StatementVisitor.super.visit(grant); } @Override - public void visit(ArrayExpression array) { - array.getObjExpression().accept(this); + public Void visit(ArrayExpression array, S context) { + array.getObjExpression().accept(this, context); if (array.getStartIndexExpression() != null) { - array.getIndexExpression().accept(this); + array.getIndexExpression().accept(this, context); } if (array.getStartIndexExpression() != null) { - array.getStartIndexExpression().accept(this); + array.getStartIndexExpression().accept(this, context); } if (array.getStopIndexExpression() != null) { - array.getStopIndexExpression().accept(this); + array.getStopIndexExpression().accept(this, context); } + return null; } @Override - public void visit(ArrayConstructor array) { + public Void visit(ArrayConstructor array, S context) { for (Expression expression : array.getExpressions()) { - expression.accept(this); + expression.accept(this, context); } + return null; + } + + @Override + public Void visit(CreateSequence createSequence, S context) { + throwUnsupported(createSequence); + return null; } @Override public void visit(CreateSequence createSequence) { - throw new UnsupportedOperationException( - "Finding tables from CreateSequence is not supported"); + StatementVisitor.super.visit(createSequence); + } + + @Override + public Void visit(AlterSequence alterSequence, S context) { + throwUnsupported(alterSequence); + return null; } @Override public void visit(AlterSequence alterSequence) { - throw new UnsupportedOperationException( - "Finding tables from AlterSequence is not supported"); + StatementVisitor.super.visit(alterSequence); + } + + @Override + public Void visit(CreateFunctionalStatement createFunctionalStatement, S context) { + throwUnsupported(createFunctionalStatement); + return null; } @Override public void visit(CreateFunctionalStatement createFunctionalStatement) { - throw new UnsupportedOperationException( - "Finding tables from CreateFunctionalStatement is not supported"); + StatementVisitor.super.visit(createFunctionalStatement); + } + + @Override + public Void visit(ShowTablesStatement showTables, S context) { + throwUnsupported(showTables); + return null; } @Override public void visit(ShowTablesStatement showTables) { - throw new UnsupportedOperationException( - "Finding tables from ShowTablesStatement is not supported"); + StatementVisitor.super.visit(showTables); } @Override - public void visit(TSQLLeftJoin tsqlLeftJoin) { + public Void visit(TSQLLeftJoin tsqlLeftJoin, S context) { visitBinaryExpression(tsqlLeftJoin); + return null; } @Override - public void visit(TSQLRightJoin tsqlRightJoin) { + public Void visit(TSQLRightJoin tsqlRightJoin, S context) { visitBinaryExpression(tsqlRightJoin); + return null; } @Override - public void visit(StructType structType) { + public Void visit(StructType structType, S context) { if (structType.getArguments() != null) { for (SelectItem selectItem : structType.getArguments()) { - selectItem.getExpression().accept(this); + selectItem.getExpression().accept(this, context); } } + return null; } @Override - public void visit(LambdaExpression lambdaExpression) { - lambdaExpression.getExpression().accept(this); + public Void visit(LambdaExpression lambdaExpression, S context) { + lambdaExpression.getExpression().accept(this, context); + return null; } @Override - public void visit(VariableAssignment var) { - var.getVariable().accept(this); - var.getExpression().accept(this); + public Void visit(HighExpression highExpression, S context) { + highExpression.getExpression().accept(this, context); + return null; } @Override - public void visit(XMLSerializeExpr aThis) { + public Void visit(LowExpression lowExpression, S context) { + lowExpression.getExpression().accept(this, context); + return null; + } + @Override + public Void visit(Plus plus, S context) { + visitBinaryExpression(plus); + return null; } @Override - public void visit(CreateSynonym createSynonym) { + public Void visit(PriorTo priorTo, S context) { + visitBinaryExpression(priorTo); + return null; + } + + @Override + public Void visit(Inverse inverse, S context) { + inverse.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(CosineSimilarity cosineSimilarity, S context) { + cosineSimilarity.getLeftExpression().accept(this, context); + cosineSimilarity.getRightExpression().accept(this, context); + return null; + } + + @Override + public Void visit(VariableAssignment variableAssignment, S context) { + variableAssignment.getVariable().accept(this, context); + variableAssignment.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(XMLSerializeExpr xmlSerializeExpr, S context) { + + return null; + } + + @Override + public Void visit(CreateSynonym createSynonym, S context) { throwUnsupported(createSynonym); + return null; } - private static void throwUnsupported(T type) { - throw new UnsupportedOperationException(String.format( - "Finding tables from %s is not supported", type.getClass().getSimpleName())); + @Override + public void visit(CreateSynonym createSynonym) { + StatementVisitor.super.visit(createSynonym); } @Override - public void visit(TimezoneExpression aThis) { - aThis.getLeftExpression().accept(this); + public Void visit(TimezoneExpression timezoneExpression, S context) { + timezoneExpression.getLeftExpression().accept(this, context); + return null; } @Override - public void visit(SavepointStatement savepointStatement) {} + public Void visit(SavepointStatement savepointStatement, S context) { + return null; + } + + @Override + public void visit(SavepointStatement savepointStatement) { + StatementVisitor.super.visit(savepointStatement); + } + + @Override + public Void visit(RollbackStatement rollbackStatement, S context) { + + return null; + } @Override public void visit(RollbackStatement rollbackStatement) { + StatementVisitor.super.visit(rollbackStatement); + } + @Override + public Void visit(AlterSession alterSession, S context) { + + return null; } @Override public void visit(AlterSession alterSession) { - + StatementVisitor.super.visit(alterSession); } @Override - public void visit(JsonAggregateFunction expression) { + public Void visit(JsonAggregateFunction expression, S context) { Expression expr = expression.getExpression(); if (expr != null) { - expr.accept(this); + expr.accept(this, context); } expr = expression.getFilterExpression(); if (expr != null) { - expr.accept(this); + expr.accept(this, context); } + return null; } @Override - public void visit(JsonFunction expression) { + public Void visit(JsonFunction expression, S context) { + for (JsonKeyValuePair keyValuePair : expression.getKeyValuePairs()) { + Object key = keyValuePair.getKey(); + Object value = keyValuePair.getValue(); + if (key instanceof Expression) { + ((Expression) key).accept(this, context); + } + if (value instanceof Expression) { + ((Expression) value).accept(this, context); + } + } + for (JsonFunctionExpression expr : expression.getExpressions()) { - expr.getExpression().accept(this); + expr.getExpression().accept(this, context); + } + + if (expression.getInputExpression() != null) { + expression.getInputExpression().getExpression().accept(this, context); + } + + if (expression.getJsonPathExpression() != null) { + expression.getJsonPathExpression().accept(this, context); + } + + for (Expression passingExpression : expression.getPassingExpressions()) { + passingExpression.accept(this, context); + } + + if (expression.getOnEmptyBehavior() != null + && expression.getOnEmptyBehavior().getExpression() != null) { + expression.getOnEmptyBehavior().getExpression().accept(this, context); + } + + if (expression.getOnErrorBehavior() != null + && expression.getOnErrorBehavior().getExpression() != null) { + expression.getOnErrorBehavior().getExpression().accept(this, context); } + return null; } @Override - public void visit(ConnectByRootOperator connectByRootOperator) { - connectByRootOperator.getColumn().accept(this); + public Void visit(JsonTableFunction expression, S context) { + for (Expression jsonExpression : expression.getAllExpressions()) { + if (jsonExpression != null) { + jsonExpression.accept(this, context); + } + } + return null; } - public void visit(IfElseStatement ifElseStatement) { - ifElseStatement.getIfStatement().accept(this); + @Override + public Void visit(ConnectByRootOperator connectByRootOperator, S context) { + connectByRootOperator.getColumn().accept(this, context); + return null; + } + + @Override + public Void visit(ConnectByPriorOperator connectByPriorOperator, S context) { + connectByPriorOperator.getColumn().accept(this, context); + return null; + } + + @Override + public Void visit(KeyExpression keyExpression, S context) { + keyExpression.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(IfElseStatement ifElseStatement, S context) { + ifElseStatement.getIfStatement().accept(this, context); if (ifElseStatement.getElseStatement() != null) { - ifElseStatement.getElseStatement().accept(this); + ifElseStatement.getElseStatement().accept(this, context); } + return null; } - public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) { - oracleNamedFunctionParameter.getExpression().accept(this); + @Override + public void visit(IfElseStatement ifElseStatement) { + StatementVisitor.super.visit(ifElseStatement); } @Override - public void visit(RenameTableStatement renameTableStatement) { + public Void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context) { + oracleNamedFunctionParameter.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(PostgresNamedFunctionParameter postgresNamedFunctionParameter, + S context) { + postgresNamedFunctionParameter.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(RenameTableStatement renameTableStatement, S context) { for (Map.Entry e : renameTableStatement.getTableNames()) { - e.getKey().accept(this); - e.getValue().accept(this); + e.getKey().accept(this, context); + e.getValue().accept(this, context); } + return null; } @Override - public void visit(PurgeStatement purgeStatement) { + public void visit(RenameTableStatement renameTableStatement) { + StatementVisitor.super.visit(renameTableStatement); + } + + @Override + public Void visit(PurgeStatement purgeStatement, S context) { if (purgeStatement.getPurgeObjectType() == PurgeObjectType.TABLE) { - ((Table) purgeStatement.getObject()).accept(this); + ((Table) purgeStatement.getObject()).accept(this, context); } + return null; + } + + @Override + public void visit(PurgeStatement purgeStatement) { + StatementVisitor.super.visit(purgeStatement); + } + + @Override + public Void visit(AlterSystemStatement alterSystemStatement, S context) { + // no tables involved in this statement + return null; } @Override public void visit(AlterSystemStatement alterSystemStatement) { + StatementVisitor.super.visit(alterSystemStatement); + } + + @Override + public Void visit(UnsupportedStatement unsupportedStatement, S context) { // no tables involved in this statement + return null; } @Override public void visit(UnsupportedStatement unsupportedStatement) { - // no tables involved in this statement + StatementVisitor.super.visit(unsupportedStatement); } @Override - public void visit(GeometryDistance geometryDistance) { + public Void visit(GeometryDistance geometryDistance, S context) { visitBinaryExpression(geometryDistance); + return null; } + @Override + public Void visit(Import imprt, S context) { + throwUnsupported(imprt); + return null; + } + + @Override + public void visit(Import imprt) { + StatementVisitor.super.visit(imprt); + } + + @Override + public Void visit(Export export, S context) { + throwUnsupported(export); + return null; + } + + @Override + public void visit(Export export) { + StatementVisitor.super.visit(export); + } + + @Override + public Void visit(LockStatement lock, S context) { + lock.getTable().accept(this); + return null; + } + + @Override + public void visit(LockStatement lock) { + StatementVisitor.super.visit(lock); + } + + @Override + public Void visit(CreatePolicy createPolicy, S context) { + if (createPolicy.getTable() != null) { + visit(createPolicy.getTable(), context); + } + + // Visit USING expression to find tables in subqueries + if (createPolicy.getUsingExpression() != null) { + createPolicy.getUsingExpression().accept(this, context); + } + + // Visit WITH CHECK expression to find tables in subqueries + if (createPolicy.getWithCheckExpression() != null) { + createPolicy.getWithCheckExpression().accept(this, context); + } + + return null; + } + + @Override + public void visit(CreatePolicy createPolicy) { + StatementVisitor.super.visit(createPolicy); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/cnfexpression/CNFConverter.java b/src/main/java/net/sf/jsqlparser/util/cnfexpression/CNFConverter.java index fbb4e8499..e1053acfd 100644 --- a/src/main/java/net/sf/jsqlparser/util/cnfexpression/CNFConverter.java +++ b/src/main/java/net/sf/jsqlparser/util/cnfexpression/CNFConverter.java @@ -14,189 +14,72 @@ import java.util.List; import java.util.Queue; import java.util.Stack; + import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.NotExpression; /** - * This class handles the conversion from a normal expression tree into - * the CNF form. - * - * Here is the definition of CNF form: - * https://en.wikipedia.org/wiki/Conjunctive_normal_form - * + * This class handles the conversion from a normal expression tree into the CNF form. + *

+ * Here is the definition of CNF form: https://en.wikipedia.org/wiki/Conjunctive_normal_form + *

* Basically it will follow these steps: - * - * To help understanding, I will generate an example: - * Here is the original tree: - * OR - * / \ - * OR NOT - * / \ | - * NOT H AND - * | / \ - * NOT G OR - * | / \ - * F H NOT - * | - * OR - * / \ - * AND L - * / \ - * ( ) ( ) - * | | - * J K - * - * 1. rebuild the tree by replacing the "and" and "or" operators - * (which are binary) into their counterparts node that could hold - * multiple elements. Also, leave out the parenthesis node between the - * conditional operators to make the tree uniform. - * - * After the transform, the result should be like this: - * OR(M) - * / \ - * OR(M) NOT - * / \ | - * NOT H AND(M) - * | / \ - * NOT G OR(M) - * | / \ - * F H NOT - * | - * OR(M) - * / \ - * AND(M) L - * / \ - * J K - * - * 2. push the not operators into the bottom of the expression. That - * means the not operator will be the root of the expression tree - * where no "and" or "or" exists. Be sure use the De Morgan's law + *

+ * To help understanding, I will generate an example: Here is the original tree: OR / \ OR NOT / \ | + * NOT H AND | / \ NOT G OR | / \ F H NOT | OR / \ AND L / \ ( ) ( ) | | J K + *

+ * 1. rebuild the tree by replacing the "and" and "or" operators (which are binary) into their + * counterparts node that could hold multiple elements. Also, leave out the parenthesis node between + * the conditional operators to make the tree uniform. + *

+ * After the transform, the result should be like this: OR(M) / \ OR(M) NOT / \ | NOT H AND(M) | / \ + * NOT G OR(M) | / \ F H NOT | OR(M) / \ AND(M) L / \ J K + *

+ * 2. push the not operators into the bottom of the expression. That means the not operator will be + * the root of the expression tree where no "and" or "or" exists. Be sure use the De Morgan's law * and double not law. - * - * How to use De Morgan law: - * For example, here is the original expression tree: - * NOT - * | - * AND(M) - * / \ - * G H - * - * After we use the De Morgan law, the result should be like this: - * OR(M) - * / \ - * NOT NOT - * | | - * G H - * - * After the transform, the result should be like this: - * OR(M) - * / \ - * OR(M) OR(M) - * / \ / \ - * F H NOT AND(M) - * | / \ - * G NOT OR(M) - * | / \ - * H AND(M) L - * / \ - * J K - * - * 3. gather all the adjacent "and" or "or" operator together. - * After doing that, the expression tree will be presented as: - * all the and expression will be in either odd or even levels, - * this will be the same for the or operator. - * - * After the transform, the expression tree should be like this: - * OR(M) - * / / \ \ - * F H NOT AND(M) - * | / \ - * G NOT OR(M) - * | / \ - * H AND(M) L - * / \ - * J K - * - * 4. push the and operator upwards until the root is an and - * operator and all the children are or operators with multiple - * components. At this time we get the result: an expression in CNF form. + *

+ * How to use De Morgan law: For example, here is the original expression tree: NOT | AND(M) / \ G H + *

+ * After we use the De Morgan law, the result should be like this: OR(M) / \ NOT NOT | | G H + *

+ * After the transform, the result should be like this: OR(M) / \ OR(M) OR(M) / \ / \ F H NOT AND(M) + * | / \ G NOT OR(M) | / \ H AND(M) L / \ J K + *

+ * 3. gather all the adjacent "and" or "or" operator together. After doing that, the expression tree + * will be presented as: all the and expression will be in either odd or even levels, this will be + * the same for the or operator. + *

+ * After the transform, the expression tree should be like this: OR(M) / / \ \ F H NOT AND(M) | / \ + * G NOT OR(M) | / \ H AND(M) L / \ J K + *

+ * 4. push the and operator upwards until the root is an and operator and all the children are or + * operators with multiple components. At this time we get the result: an expression in CNF form. * How do we push and up? Use distribution law! - * - * For example, here is the way to push the and up and merge them. - * OR - * / \ - * AND L - * / \ - * J K - * - * In the normal form, it could be: (J AND K) OR L. - * If we apply the distribution law, we will get the result like this: - * (J OR L) AND (K OR L), the tree form of this should be like: - * AND - * / \ - * OR OR - * / \ / \ - * J L K L - * - * So after we push the AND at the deepest level up and merge it with the - * existing add, we get this result. - * OR(M) - * / / \ \ - * F H NOT AND(M) - * | / | \ - * G NOT OR(M) OR(M) - * | / \ / \ - * H J L K L - * - * Now let us push the and up and we will get the result like this: - * AND(M) - * / | \ - * OR(M) OR(M) OR(M) - * / / \ \ / / | \ \ / / | \ \ - * F H NOT NOT F H NOT J L F H NOT K L - * | | | | - * G H G G - * - * 5. The last step, convert the Multiple Expression back to the binary - * form. Note the final tree shall be left-inclined. - * - * The final expression tree shall be like this: - * AND - * / \ - * AND ( ) - * / \ | - * ( ) ( ) part1 - * | | - * OR part2 - * / \ - * OR NOT - * / \ | - * OR NOT H - * / \ | - * F H G - * - * part1: OR - * / \ - * OR L - * / \ - * OR K - * / \ - * OR NOT - * / \ | - * F H G - * - * part2: OR - * / \ - * OR L - * / \ - * OR J - * / \ - * OR NOT - * / \ | - * F H G + *

+ * For example, here is the way to push the and up and merge them. OR / \ AND L / \ J K + *

+ * In the normal form, it could be: (J AND K) OR L. If we apply the distribution law, we will get + * the result like this: (J OR L) AND (K OR L), the tree form of this should be like: AND / \ OR OR + * / \ / \ J L K L + *

+ * So after we push the AND at the deepest level up and merge it with the existing add, we get this + * result. OR(M) / / \ \ F H NOT AND(M) | / | \ G NOT OR(M) OR(M) | / \ / \ H J L K L + *

+ * Now let us push the and up and we will get the result like this: AND(M) / | \ OR(M) OR(M) OR(M) / + * / \ \ / / | \ \ / / | \ \ F H NOT NOT F H NOT J L F H NOT K L | | | | G H G G + *

+ * 5. The last step, convert the Multiple Expression back to the binary form. Note the final tree + * shall be left-inclined. + *

+ * The final expression tree shall be like this: AND / \ AND ( ) / \ | ( ) ( ) part1 | | OR part2 / + * \ OR NOT / \ | OR NOT H / \ | F H G + *

+ * part1: OR / \ OR L / \ OR K / \ OR NOT / \ | F H G + *

+ * part2: OR / \ OR L / \ OR J / \ OR NOT / \ | F H G * * @author messfish - * */ public class CNFConverter { @@ -210,31 +93,19 @@ public class CNFConverter { private Expression child; // these two variable mainly serves as nodes that traverse through // the expression tree to change the structure of expression tree. - // notice temp1 will be settled as the root and temp2 will be + // notice temp1 will be settled as the root and temp2 will be // settled as the dummy root. private boolean isUsed = false; - private class Mule { - - private Expression parent; - private Expression child; - private int level; - - private Mule(Expression parent, Expression child, int level) { - this.parent = parent; - this.child = child; - this.level = level; - } - } - public static Expression convertToCNF(Expression expr) { CNFConverter cnf = new CNFConverter(); return cnf.convert(expr); } /** - * this method takes an expression tree and converts that into a CNF form. Notice the 5 steps shown above will turn - * into 5 different methods. For the sake of testing, I set them public. return the converted expression. + * this method takes an expression tree and converts that into a CNF form. Notice the 5 steps + * shown above will turn into 5 different methods. For the sake of testing, I set them public. + * return the converted expression. * * @param express the original expression tree. */ @@ -247,10 +118,11 @@ private Expression convert(Expression express) } reorder(express); pushNotDown(); - /* notice for the gather() function, we do not change the variable - * that points to the root by pointing to others. Also, we do not - * change those temp variables. So there is no need to set those - * variables back to their modified state. */ + /* + * notice for the gather() function, we do not change the variable that points to the root + * by pointing to others. Also, we do not change those temp variables. So there is no need + * to set those variables back to their modified state. + */ gather(); pushAndUp(); changeBack(); @@ -258,8 +130,8 @@ private Expression convert(Expression express) } /** - * this is the first step that rebuild the expression tree. Use the standard specified in the above class. Traverse - * the original tree recursively and rebuild the tree from that. + * this is the first step that rebuild the expression tree. Use the standard specified in the + * above class. Traverse the original tree recursively and rebuild the tree from that. * * @param express the original expression tree. */ @@ -271,15 +143,17 @@ private void reorder(Expression express) { } /** - * This method is used to deal with pushing not operators down. Since it needs an extra parameter, I will create a - * new method to handle this. + * This method is used to deal with pushing not operators down. Since it needs an extra + * parameter, I will create a new method to handle this. */ private void pushNotDown() { /* set the two temp parameters to their staring point. */ temp1 = root; temp2 = dummy; - /* I set it to zero since if the modification happens at the root, - * the parent will have the correct pointer to the children. */ + /* + * I set it to zero since if the modification happens at the root, the parent will have the + * correct pointer to the children. + */ pushNot(0); /* do not forget to set the operators back! */ root = ((MultiAndExpression) dummy).getChild(0); @@ -288,17 +162,20 @@ private void pushNotDown() { } /** - * This method is the helper function to push not operators down. traverse the tree thoroughly, when we meet the not - * operator. We only need to consider these three operators: MultiAndOperator, MultiOrOperator, NotOperator. Handle - * them in a seperate way. when we finish the traverse, the expression tree will have all the not operators pushed - * as downwards as they could. In the method, I use two global variables: temp1 and temp2 to traverse the expression + * This method is the helper function to push not operators down. traverse the tree thoroughly, + * when we meet the not operator. We only need to consider these three operators: + * MultiAndOperator, MultiOrOperator, NotOperator. Handle them in a seperate way. when we finish + * the traverse, the expression tree will have all the not operators pushed as downwards as they + * could. In the method, I use two global variables: temp1 and temp2 to traverse the expression * tree. Notice that temp2 will always be the parent of temp1. * * @param index the index of the children appeared in parents array. */ private void pushNot(int index) { - /* what really matters is the three logical operators: - * and, or, not. so we only deal with these three operators. */ + /* + * what really matters is the three logical operators: and, or, not. so we only deal with + * these three operators. + */ if (temp1 instanceof MultiAndExpression) { MultiAndExpression and = (MultiAndExpression) temp1; for (int i = 0; i < and.size(); i++) { @@ -319,8 +196,8 @@ private void pushNot(int index) { } /** - * This function mainly deals with pushing not operators down. check the child. If it is not a logic operator(and or - * or). stop at that point. Else use De Morgan law to push not downwards. + * This function mainly deals with pushing not operators down. check the child. If it is not a + * logic operator(and or or). stop at that point. Else use De Morgan law to push not downwards. * * @param index the index of the children appeared in parents array. */ @@ -331,29 +208,31 @@ private void handleNot(int index) { child = ((NotExpression) child).getExpression(); nums++; } - /* if the number of not operators are even. we could get - * rid of all the not operators. set the child to the parent. */ + /* + * if the number of not operators are even. we could get rid of all the not operators. set + * the child to the parent. + */ if (nums % 2 == 0) { ((MultipleExpression) temp2).setChild(index, child); temp1 = child; pushNot(-1); } else { - /* otherwise there will be one not left to push. - * if the child is not these two types of operators. - * that means we reach the leaves of the logical part. - * set a new not operator whose child is the current one - * and connect that operator with the parent and return. */ + /* + * otherwise there will be one not left to push. if the child is not these two types of + * operators. that means we reach the leaves of the logical part. set a new not operator + * whose child is the current one and connect that operator with the parent and return. + */ if (!(child instanceof MultiAndExpression) && !(child instanceof MultiOrExpression)) { -// if (child instanceof LikeExpression) { -// ((LikeExpression) child).setNot(); -// } else if (child instanceof BinaryExpression) { -// ((BinaryExpression) child).setNot(); -// } else { + // if (child instanceof LikeExpression) { + // ((LikeExpression) child).setNot(); + // } else if (child instanceof BinaryExpression) { + // ((BinaryExpression) child).setNot(); + // } else { child = new NotExpression(child); -// } + // } ((MultipleExpression) temp2).setChild(index, child); -// return; + // return; } else if (child instanceof MultiAndExpression) { MultiAndExpression and = (MultiAndExpression) child; List list = new ArrayList(); @@ -383,9 +262,10 @@ private void handleNot(int index) { } /** - * This method serves as dealing with the third step. It is used to put all the adjacent same multi operators - * together. BFS the tree and do it node by node. In the end we will get the tree where all the same multi operators - * store in the same odd level of the tree or in the same even level of the tree. + * This method serves as dealing with the third step. It is used to put all the adjacent same + * multi operators together. BFS the tree and do it node by node. In the end we will get the + * tree where all the same multi operators store in the same odd level of the tree or in the + * same even level of the tree. */ @SuppressWarnings({"PMD.CyclomaticComplexity"}) private void gather() { @@ -393,9 +273,11 @@ private void gather() { queue.offer(temp1); while (!queue.isEmpty()) { Expression express = queue.poll(); - /* at this level, we only deal with "multi and" and "multi or" - * operators, so we only consider these two operators. - * that means we do nothing if the operator is not those two. */ + /* + * at this level, we only deal with "multi and" and "multi or" operators, so we only + * consider these two operators. that means we do nothing if the operator is not those + * two. + */ if (express instanceof MultiAndExpression) { MultiAndExpression and = (MultiAndExpression) express; while (true) { @@ -407,14 +289,17 @@ private void gather() { break; } } - /* if the index is the size of the multi operator, - * that means this is already valid. jump out of the loop. */ + /* + * if the index is the size of the multi operator, that means this is already + * valid. jump out of the loop. + */ if (index == and.size()) { break; } else { - /* if not, remove the child out and push the child of that child - * in the operator, starting from the index where the child - * is removed. */ + /* + * if not, remove the child out and push the child of that child in the + * operator, starting from the index where the child is removed. + */ and.removeChild(index); MultipleExpression order = (MultipleExpression) get; for (int i = 0; i < order.size(); i++) { @@ -439,14 +324,17 @@ private void gather() { break; } } - /* if the index is the size of the multi operator, - * that means this is already valid. jump out of the loop. */ + /* + * if the index is the size of the multi operator, that means this is already + * valid. jump out of the loop. + */ if (index == or.size()) { break; } else { - /* if not, remove the child out and push the child of that child - * in the operator, starting from the index where the child - * is removed. */ + /* + * if not, remove the child out and push the child of that child in the + * operator, starting from the index where the child is removed. + */ or.removeChild(index); MultipleExpression order = (MultipleExpression) get; for (int i = 0; i < order.size(); i++) { @@ -464,10 +352,10 @@ private void gather() { } /** - * First, BFS the tree and gather all the or operators and their parents into a stack. Next, pop them out and push - * the and operators under the or operators upwards(if there are). Do this level by level, which means during each - * level we will call the gather() method to make the tree uniform. When we move out of the stack. The expression - * tree shall be in CNF form. + * First, BFS the tree and gather all the or operators and their parents into a stack. Next, pop + * them out and push the and operators under the or operators upwards(if there are). Do this + * level by level, which means during each level we will call the gather() method to make the + * tree uniform. When we move out of the stack. The expression tree shall be in CNF form. */ private void pushAndUp() { Queue queue = new LinkedList(); @@ -475,8 +363,10 @@ private void pushAndUp() { Mule root = new Mule(temp2, temp1, 0); queue.offer(root); int level = 1; - /* do the BFS and store valid mule into the stack. Notice the - * first parameter is parent and the second parameter is children. */ + /* + * do the BFS and store valid mule into the stack. Notice the first parameter is parent and + * the second parameter is children. + */ while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { @@ -507,17 +397,20 @@ private void pushAndUp() { this.root = ((MultiAndExpression) dummy).getChild(0); temp1 = this.root; temp2 = dummy; - /* at last, remember to gather again since there are no gather() - * method called if there are some movements on the root. */ + /* + * at last, remember to gather again since there are no gather() method called if there are + * some movements on the root. + */ gather(); } /** - * This helper function is used to deal with pushing and up: generally, pop the top element out of the stack, use - * BFS to traverse the tree and push and up. It will case the expression tree to have the and as the new root and - * multiple or as the children. Push them on the queue and repeat the same process until the newly generated or - * operator does not have any and operators in it(which means no elements will be added into the queue). when one - * level is finished, regroup the tree. Do this until the stack is empty, the result will be the expression in CNF + * This helper function is used to deal with pushing and up: generally, pop the top element out + * of the stack, use BFS to traverse the tree and push and up. It will case the expression tree + * to have the and as the new root and multiple or as the children. Push them on the queue and + * repeat the same process until the newly generated or operator does not have any and operators + * in it(which means no elements will be added into the queue). when one level is finished, + * regroup the tree. Do this until the stack is empty, the result will be the expression in CNF * form. * * @param stack the stack stores a list of combined data. @@ -536,16 +429,20 @@ private void pushAnd(Stack stack) { level = mule.level; } Queue queue = new LinkedList(); - /* this time we do not need to take down the level of the - * tree, so simply set a 0 to the last parameter. */ + /* + * this time we do not need to take down the level of the tree, so simply set a 0 to the + * last parameter. + */ Mule combined = new Mule(mule.parent, mule.child, 0); queue.offer(combined); while (!queue.isEmpty()) { Mule get = queue.poll(); Expression parent = get.parent; Expression child = get.child; - /* based on the code above, the stack only have the expression - * which they are multi operators. so safely convert them. */ + /* + * based on the code above, the stack only have the expression which they are multi + * operators. so safely convert them. + */ MultipleExpression children = (MultipleExpression) child; int index = 0; MultiAndExpression and = null; @@ -576,10 +473,11 @@ private void pushAnd(Stack stack) { } /** - * This is the final step of the CNF conversion: now we have the Expression tree that has one multiple and - * expression with a list of multiple or expression as the child. So we need to convert the multiple expression back - * to the binary counterparts. Note the converted tree is left inclined. Also I attach a parenthesis node before the - * or expression that is attached to the and expression to make the generated result resembles the CNF form. + * This is the final step of the CNF conversion: now we have the Expression tree that has one + * multiple and expression with a list of multiple or expression as the child. So we need to + * convert the multiple expression back to the binary counterparts. Note the converted tree is + * left inclined. Also I attach a parenthesis node before the or expression that is attached to + * the and expression to make the generated result resembles the CNF form. */ private void changeBack() { if (!(root instanceof MultiAndExpression)) { @@ -592,4 +490,17 @@ private void changeBack() { root = CloneHelper.changeBack(false, temp); } + private class Mule { + + private Expression parent; + private Expression child; + private int level; + + private Mule(Expression parent, Expression child, int level) { + this.parent = parent; + this.child = child; + this.level = level; + } + } + } diff --git a/src/main/java/net/sf/jsqlparser/util/cnfexpression/CloneHelper.java b/src/main/java/net/sf/jsqlparser/util/cnfexpression/CloneHelper.java index e9e97edf1..c0e5293e2 100644 --- a/src/main/java/net/sf/jsqlparser/util/cnfexpression/CloneHelper.java +++ b/src/main/java/net/sf/jsqlparser/util/cnfexpression/CloneHelper.java @@ -25,7 +25,6 @@ * condition part of the tree. * * @author messfish - * */ class CloneHelper { diff --git a/src/main/java/net/sf/jsqlparser/util/cnfexpression/MultiAndExpression.java b/src/main/java/net/sf/jsqlparser/util/cnfexpression/MultiAndExpression.java index a33c81009..03af12cdc 100644 --- a/src/main/java/net/sf/jsqlparser/util/cnfexpression/MultiAndExpression.java +++ b/src/main/java/net/sf/jsqlparser/util/cnfexpression/MultiAndExpression.java @@ -17,7 +17,6 @@ * This helper class is mainly used for handling the CNF conversion. * * @author messfish - * */ public final class MultiAndExpression extends MultipleExpression { diff --git a/src/main/java/net/sf/jsqlparser/util/cnfexpression/MultipleExpression.java b/src/main/java/net/sf/jsqlparser/util/cnfexpression/MultipleExpression.java index f37e823cd..b06b85399 100644 --- a/src/main/java/net/sf/jsqlparser/util/cnfexpression/MultipleExpression.java +++ b/src/main/java/net/sf/jsqlparser/util/cnfexpression/MultipleExpression.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.util.cnfexpression; import java.util.List; + import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.expression.NullValue; @@ -19,7 +20,6 @@ * This is a helper class that mainly used for handling the CNF conversion. * * @author messfish - * */ public abstract class MultipleExpression extends ASTNodeAccessImpl implements Expression { @@ -34,8 +34,8 @@ public int size() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(new NullValue()); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(new NullValue(), context); } public List getList() { diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AbstractDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AbstractDeParser.java index 4ef4d047c..6458f79c9 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AbstractDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AbstractDeParser.java @@ -20,14 +20,14 @@ * @param the type of statement this DeParser supports */ abstract class AbstractDeParser { - protected StringBuilder buffer; + protected StringBuilder builder; - protected AbstractDeParser(StringBuilder buffer) { - this.buffer = buffer; + protected AbstractDeParser(StringBuilder builder) { + this.builder = builder; } public static void deparseUpdateSets(List updateSets, StringBuilder buffer, - ExpressionVisitor visitor) { + ExpressionVisitor visitor) { ExpressionListDeParser expressionListDeParser = new ExpressionListDeParser<>(visitor, buffer); int j = 0; @@ -43,12 +43,12 @@ public static void deparseUpdateSets(List updateSets, StringBuilder b } } - public StringBuilder getBuffer() { - return buffer; + public StringBuilder getBuilder() { + return builder; } - public void setBuffer(StringBuilder buffer) { - this.buffer = buffer; + public void setBuilder(StringBuilder builder) { + this.builder = builder; } /** diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AlterDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AlterDeParser.java index 2cc04fcab..bfc00e7ef 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AlterDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AlterDeParser.java @@ -19,7 +19,7 @@ public AlterDeParser(StringBuilder buffer) { @Override public void deParse(Alter alter) { - buffer.append(alter.toString()); + builder.append(alter.toString()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AlterSequenceDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AlterSequenceDeParser.java index f01454762..b9c743bdc 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AlterSequenceDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AlterSequenceDeParser.java @@ -26,7 +26,7 @@ public AlterSequenceDeParser(StringBuilder buffer) { @Override public void deParse(AlterSequence statement) { - buffer.append("ALTER SEQUENCE "); - buffer.append(statement.getSequence()); + builder.append("ALTER SEQUENCE "); + builder.append(statement.getSequence()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AlterSessionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AlterSessionDeParser.java index 69bab62a5..a2f758486 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AlterSessionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AlterSessionDeParser.java @@ -19,7 +19,7 @@ public AlterSessionDeParser(StringBuilder buffer) { @Override public void deParse(AlterSession alterSession) { - buffer.append(alterSession.toString()); + builder.append(alterSession.toString()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AlterViewDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AlterViewDeParser.java index 99c310941..3c1c0bbaa 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AlterViewDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AlterViewDeParser.java @@ -15,7 +15,7 @@ public class AlterViewDeParser extends AbstractDeParser { - private SelectVisitor selectVisitor; + private final SelectVisitor selectVisitor; public AlterViewDeParser(StringBuilder buffer) { super(buffer); @@ -25,7 +25,7 @@ public AlterViewDeParser(StringBuilder buffer) { selectVisitor = selectDeParser; } - public AlterViewDeParser(StringBuilder buffer, SelectVisitor selectVisitor) { + public AlterViewDeParser(StringBuilder buffer, SelectVisitor selectVisitor) { super(buffer); this.selectVisitor = selectVisitor; } @@ -33,17 +33,17 @@ public AlterViewDeParser(StringBuilder buffer, SelectVisitor selectVisitor) { @Override public void deParse(AlterView alterView) { if (alterView.isUseReplace()) { - buffer.append("REPLACE "); + builder.append("REPLACE "); } else { - buffer.append("ALTER "); + builder.append("ALTER "); } - buffer.append("VIEW ").append(alterView.getView().getFullyQualifiedName()); + builder.append("VIEW ").append(alterView.getView().getFullyQualifiedName()); if (alterView.getColumnNames() != null) { - buffer.append(PlainSelect.getStringList(alterView.getColumnNames(), true, true)); + builder.append(PlainSelect.getStringList(alterView.getColumnNames(), true, true)); } - buffer.append(" AS "); + builder.append(" AS "); - alterView.getSelect().accept(selectVisitor); + alterView.getSelect().accept(selectVisitor, null); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java index a82f478d7..cc5d71ba1 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java @@ -24,46 +24,44 @@ public CreateIndexDeParser(StringBuilder buffer) { public void deParse(CreateIndex createIndex) { Index index = createIndex.getIndex(); - buffer.append("CREATE "); + builder.append("CREATE "); if (index.getType() != null) { - buffer.append(index.getType()); - buffer.append(" "); + builder.append(index.getType()); + builder.append(" "); } - buffer.append("INDEX "); + builder.append("INDEX "); if (createIndex.isUsingIfNotExists()) { - buffer.append("IF NOT EXISTS "); + builder.append("IF NOT EXISTS "); } - buffer.append(index.getName()); + builder.append(index.getName()); String using = index.getUsing(); if (using != null && createIndex.isIndexTypeBeforeOn()) { - buffer.append(" USING "); - buffer.append(using); + builder.append(" USING "); + builder.append(using); } - buffer.append(" ON "); - buffer.append(createIndex.getTable().getFullyQualifiedName()); + builder.append(" ON "); + builder.append(createIndex.getTable().getFullyQualifiedName()); if (using != null && !createIndex.isIndexTypeBeforeOn()) { - buffer.append(" USING "); - buffer.append(using); + builder.append(" USING "); + builder.append(using); } if (index.getColumnsNames() != null) { - buffer.append(" ("); - buffer.append(index.getColumnWithParams().stream() - .map(cp -> cp.columnName - + (cp.getParams() != null ? " " + String.join(" ", cp.getParams()) - : "")) + builder.append(" ("); + builder.append(index.getColumnWithParams().stream() + .map(Index.ColumnParams::toString) .collect(joining(", "))); - buffer.append(")"); + builder.append(")"); } if (createIndex.getTailParameters() != null) { for (String param : createIndex.getTailParameters()) { - buffer.append(" ").append(param); + builder.append(" ").append(param); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateSequenceDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateSequenceDeParser.java index b7206691d..d4f475098 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateSequenceDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateSequenceDeParser.java @@ -1,8 +1,8 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2020 JSQLParser + * Copyright (C) 2004 - 2024 JSQLParser * %% * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% @@ -15,7 +15,7 @@ * A class to de-parse (that is, transform from JSqlParser hierarchy into a string) a * {@link net.sf.jsqlparser.statement.create.sequence.CreateSequence} */ -public class CreateSequenceDeParser extends AbstractDeParser{ +public class CreateSequenceDeParser extends AbstractDeParser { /** * @param buffer the buffer that will be filled with the CreatSequence @@ -26,7 +26,7 @@ public CreateSequenceDeParser(StringBuilder buffer) { @Override public void deParse(CreateSequence statement) { - buffer.append("CREATE SEQUENCE "); - buffer.append(statement.getSequence()); + builder.append("CREATE SEQUENCE "); + builder.append(statement.getSequence()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateSynonymDeparser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateSynonymDeparser.java index 413249d16..4c8a1e1f2 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateSynonymDeparser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateSynonymDeparser.java @@ -23,15 +23,15 @@ public CreateSynonymDeparser(StringBuilder buffer) { @Override void deParse(CreateSynonym createSynonym) { - buffer.append("CREATE "); + builder.append("CREATE "); if (createSynonym.isOrReplace()) { - buffer.append("OR REPLACE "); + builder.append("OR REPLACE "); } if (createSynonym.isPublicSynonym()) { - buffer.append("PUBLIC "); + builder.append("PUBLIC "); } - buffer.append("SYNONYM " + createSynonym.getSynonym()); - buffer.append(' '); - buffer.append("FOR " + createSynonym.getFor()); + builder.append("SYNONYM " + createSynonym.getSynonym()); + builder.append(' '); + builder.append("FOR " + createSynonym.getFor()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateTableDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateTableDeParser.java index d930e944c..1d9fc85f3 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateTableDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateTableDeParser.java @@ -34,94 +34,97 @@ public CreateTableDeParser(StatementDeParser statementDeParser, StringBuilder bu @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(CreateTable createTable) { - buffer.append("CREATE "); + builder.append("CREATE "); if (createTable.isOrReplace()) { - buffer.append("OR REPLACE "); + builder.append("OR REPLACE "); } if (createTable.isUnlogged()) { - buffer.append("UNLOGGED "); + builder.append("UNLOGGED "); } - String params = PlainSelect.getStringList(createTable.getCreateOptionsStrings(), false, false); - if (!"".equals(params)) { - buffer.append(params).append(' '); + String params = + PlainSelect.getStringList(createTable.getCreateOptionsStrings(), false, false); + if (!params.isEmpty()) { + builder.append(params).append(' '); } - buffer.append("TABLE "); + builder.append("TABLE "); if (createTable.isIfNotExists()) { - buffer.append("IF NOT EXISTS "); + builder.append("IF NOT EXISTS "); } - buffer.append(createTable.getTable().getFullyQualifiedName()); + builder.append(createTable.getTable().getFullyQualifiedName()); if (createTable.getColumns() != null && !createTable.getColumns().isEmpty()) { - buffer.append(" ("); + builder.append(" ("); Iterator columnIterator = createTable.getColumns().iterator(); - buffer.append(columnIterator.next()); + builder.append(columnIterator.next()); while (columnIterator.hasNext()) { - buffer.append(", ").append(columnIterator.next()); + builder.append(", ").append(columnIterator.next()); } - buffer.append(")"); + builder.append(")"); } if (createTable.getColumnDefinitions() != null) { - buffer.append(" ("); - for (Iterator iter = createTable.getColumnDefinitions().iterator(); iter.hasNext();) { + builder.append(" ("); + for (Iterator iter = + createTable.getColumnDefinitions().iterator(); iter.hasNext();) { ColumnDefinition columnDefinition = iter.next(); - buffer.append(columnDefinition.getColumnName()); - buffer.append(" "); - buffer.append(columnDefinition.getColDataType().toString()); + builder.append(columnDefinition.getColumnName()); + builder.append(" "); + builder.append(columnDefinition.getColDataType().toString()); if (columnDefinition.getColumnSpecs() != null) { for (String s : columnDefinition.getColumnSpecs()) { - buffer.append(" "); - buffer.append(s); + builder.append(" "); + builder.append(s); } } if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } if (createTable.getIndexes() != null) { for (Index index : createTable.getIndexes()) { - buffer.append(", "); - buffer.append(index.toString()); + builder.append(", "); + builder.append(index.toString()); } } - buffer.append(")"); + builder.append(")"); } params = PlainSelect.getStringList(createTable.getTableOptionsStrings(), false, false); if (!"".equals(params)) { - buffer.append(' ').append(params); + builder.append(' ').append(params); } if (createTable.getRowMovement() != null) { - buffer.append(' ').append(createTable.getRowMovement().getMode().toString()).append(" ROW MOVEMENT"); + builder.append(' ').append(createTable.getRowMovement().getMode().toString()) + .append(" ROW MOVEMENT"); } if (createTable.getSelect() != null) { - buffer.append(" AS "); + builder.append(" AS "); if (createTable.isSelectParenthesis()) { - buffer.append("("); + builder.append("("); } Select sel = createTable.getSelect(); - sel.accept(this.statementDeParser); + sel.accept(this.statementDeParser, null); if (createTable.isSelectParenthesis()) { - buffer.append(")"); + builder.append(")"); } } if (createTable.getLikeTable() != null) { - buffer.append(" LIKE "); + builder.append(" LIKE "); if (createTable.isSelectParenthesis()) { - buffer.append("("); + builder.append("("); } Table table = createTable.getLikeTable(); - buffer.append(table.getFullyQualifiedName()); + builder.append(table.getFullyQualifiedName()); if (createTable.isSelectParenthesis()) { - buffer.append(")"); + builder.append(")"); } } if (createTable.getSpannerInterleaveIn() != null) { - buffer.append(", ").append(createTable.getSpannerInterleaveIn()); + builder.append(", ").append(createTable.getSpannerInterleaveIn()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java index c0afab53e..196b4d4d9 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java @@ -18,18 +18,18 @@ public class CreateViewDeParser extends AbstractDeParser { - private final SelectVisitor selectVisitor; + private final SelectVisitor selectVisitor; public CreateViewDeParser(StringBuilder buffer) { super(buffer); SelectDeParser selectDeParser = new SelectDeParser(); - selectDeParser.setBuffer(buffer); + selectDeParser.setBuilder(buffer); ExpressionDeParser expressionDeParser = new ExpressionDeParser(selectDeParser, buffer); selectDeParser.setExpressionVisitor(expressionDeParser); selectVisitor = selectDeParser; } - public CreateViewDeParser(StringBuilder buffer, SelectVisitor selectVisitor) { + public CreateViewDeParser(StringBuilder buffer, SelectVisitor selectVisitor) { super(buffer); this.selectVisitor = selectVisitor; } @@ -37,16 +37,16 @@ public CreateViewDeParser(StringBuilder buffer, SelectVisitor selectVisitor) { @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(CreateView createView) { - buffer.append("CREATE "); + builder.append("CREATE "); if (createView.isOrReplace()) { - buffer.append("OR REPLACE "); + builder.append("OR REPLACE "); } switch (createView.getForce()) { case FORCE: - buffer.append("FORCE "); + builder.append("FORCE "); break; case NO_FORCE: - buffer.append("NO FORCE "); + builder.append("NO FORCE "); break; case NONE: break; @@ -54,36 +54,36 @@ public void deParse(CreateView createView) { // nothing } if (createView.isSecure()) { - buffer.append("SECURE "); + builder.append("SECURE "); } if (createView.getTemporary() != TemporaryOption.NONE) { - buffer.append(createView.getTemporary().name()).append(" "); + builder.append(createView.getTemporary().name()).append(" "); } if (createView.isMaterialized()) { - buffer.append("MATERIALIZED "); + builder.append("MATERIALIZED "); } - buffer.append("VIEW ").append(createView.getView().getFullyQualifiedName()); + builder.append("VIEW ").append(createView.getView().getFullyQualifiedName()); if (createView.isIfNotExists()) { - buffer.append(" IF NOT EXISTS"); + builder.append(" IF NOT EXISTS"); } if (createView.getAutoRefresh() != AutoRefreshOption.NONE) { - buffer.append(" AUTO REFRESH ").append(createView.getAutoRefresh().name()); + builder.append(" AUTO REFRESH ").append(createView.getAutoRefresh().name()); } if (createView.getColumnNames() != null) { - buffer.append("("); - buffer.append(createView.getColumnNames()); - buffer.append(")"); + builder.append("("); + builder.append(createView.getColumnNames()); + builder.append(")"); } if (createView.getViewCommentOptions() != null) { - buffer.append( + builder.append( PlainSelect.getStringList(createView.getViewCommentOptions(), false, false)); } - buffer.append(" AS "); + builder.append(" AS "); Select select = createView.getSelect(); - select.accept(selectVisitor); + select.accept(selectVisitor, null); if (createView.isWithReadOnly()) { - buffer.append(" WITH READ ONLY"); + builder.append(" WITH READ ONLY"); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DeclareStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DeclareStatementDeParser.java index 42951127b..a24f63e9f 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DeclareStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DeclareStatementDeParser.java @@ -15,9 +15,10 @@ public class DeclareStatementDeParser extends AbstractDeParser { - private ExpressionVisitor expressionVisitor; + private ExpressionVisitor expressionVisitor; - public DeclareStatementDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public DeclareStatementDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @@ -25,53 +26,53 @@ public DeclareStatementDeParser(ExpressionVisitor expressionVisitor, StringBuild @Override @SuppressWarnings({"PMD.CyclomaticComplexity"}) public void deParse(DeclareStatement declare) { - buffer.append("DECLARE "); + builder.append("DECLARE "); if (declare.getUserVariable() != null) { - declare.getUserVariable().accept(expressionVisitor); + declare.getUserVariable().accept(expressionVisitor, null); } if (declare.getType() == DeclareType.AS) { - buffer.append(" AS "); - buffer.append(declare.getTypeName()); + builder.append(" AS "); + builder.append(declare.getTypeName()); return; } if (declare.getType() == DeclareType.TABLE) { - buffer.append(" TABLE ("); + builder.append(" TABLE ("); for (int i = 0; i < declare.getColumnDefinitions().size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } - buffer.append(declare.getColumnDefinitions().get(i).toString()); + builder.append(declare.getColumnDefinitions().get(i).toString()); } - buffer.append(")"); + builder.append(")"); } else { if (declare.getTypeDefinitions() != null) { for (int i = 0; i < declare.getTypeDefinitions().size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } DeclareStatement.TypeDefExpr type = declare.getTypeDefinitions().get(i); if (type.userVariable != null) { - type.userVariable.accept(expressionVisitor); - buffer.append(" "); + type.userVariable.accept(expressionVisitor, null); + builder.append(" "); } - buffer.append(type.colDataType.toString()); + builder.append(type.colDataType.toString()); if (type.defaultExpr != null) { - buffer.append(" = "); - type.defaultExpr.accept(expressionVisitor); + builder.append(" = "); + type.defaultExpr.accept(expressionVisitor, null); } } } } } - public ExpressionVisitor getExpressionVisitor() { + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public void setExpressionVisitor(ExpressionVisitor visitor) { + public void setExpressionVisitor(ExpressionVisitor visitor) { expressionVisitor = visitor; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java index ef4d0922d..2ab59ea14 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java @@ -22,13 +22,15 @@ public class DeleteDeParser extends AbstractDeParser { - private ExpressionVisitor expressionVisitor = new ExpressionVisitorAdapter(); + private ExpressionVisitor expressionVisitor = + new ExpressionVisitorAdapter(); public DeleteDeParser() { super(new StringBuilder()); } - public DeleteDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public DeleteDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @@ -37,82 +39,90 @@ public DeleteDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(Delete delete) { if (delete.getWithItemsList() != null && !delete.getWithItemsList().isEmpty()) { - buffer.append("WITH "); - for (Iterator iter = delete.getWithItemsList().iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); - buffer.append(withItem); + builder.append("WITH "); + for (Iterator> iter = delete.getWithItemsList().iterator(); iter + .hasNext();) { + WithItem withItem = iter.next(); + builder.append(withItem); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("DELETE"); + builder.append("DELETE"); if (delete.getOracleHint() != null) { - buffer.append(delete.getOracleHint()).append(" "); + builder.append(delete.getOracleHint()).append(" "); } if (delete.getModifierPriority() != null) { - buffer.append(" ").append(delete.getModifierPriority()); + builder.append(" ").append(delete.getModifierPriority()); } if (delete.isModifierQuick()) { - buffer.append(" QUICK"); + builder.append(" QUICK"); } if (delete.isModifierIgnore()) { - buffer.append(" IGNORE"); + builder.append(" IGNORE"); } if (delete.getTables() != null && !delete.getTables().isEmpty()) { - buffer.append( + builder.append( delete.getTables().stream().map(Table::getFullyQualifiedName) .collect(joining(", ", " ", ""))); } if (delete.getOutputClause() != null) { - delete.getOutputClause().appendTo(buffer); + delete.getOutputClause().appendTo(builder); } if (delete.isHasFrom()) { - buffer.append(" FROM"); + builder.append(" FROM"); } - buffer.append(" ").append(delete.getTable().toString()); + builder.append(" ").append(delete.getTable().toString()); - if (delete.getUsingList() != null && !delete.getUsingList().isEmpty()) { - buffer.append(" USING").append( - delete.getUsingList().stream().map(Table::toString) + if (delete.getUsingFromItemList() != null && !delete.getUsingFromItemList().isEmpty()) { + builder.append(" USING").append( + delete.getUsingFromItemList().stream().map(Object::toString) .collect(joining(", ", " ", ""))); } if (delete.getJoins() != null) { for (Join join : delete.getJoins()) { if (join.isSimple()) { - buffer.append(", ").append(join); + builder.append(", ").append(join); } else { - buffer.append(" ").append(join); + builder.append(" ").append(join); } } } - if (delete.getWhere() != null) { - buffer.append(" WHERE "); - delete.getWhere().accept(expressionVisitor); - } + deparseWhereClause(delete); + if (delete.getPreferringClause() != null) { + builder.append(" ").append(delete.getPreferringClause()); + } if (delete.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(delete.getOrderByElements()); + new OrderByDeParser(expressionVisitor, builder).deParse(delete.getOrderByElements()); } if (delete.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(delete.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(delete.getLimit()); } if (delete.getReturningClause() != null) { - delete.getReturningClause().appendTo(buffer); + delete.getReturningClause().appendTo(builder); } } - public ExpressionVisitor getExpressionVisitor() { + protected void deparseWhereClause(Delete delete) { + if (delete.getWhere() != null) { + builder.append(" WHERE "); + delete.getWhere().accept(expressionVisitor, null); + } + } + + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public void setExpressionVisitor(ExpressionVisitor visitor) { + public void setExpressionVisitor(ExpressionVisitor visitor) { expressionVisitor = visitor; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java index 090a2cad1..64c39b505 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java @@ -20,26 +20,27 @@ public DropDeParser(StringBuilder buffer) { @Override public void deParse(Drop drop) { - buffer.append("DROP "); + builder.append("DROP "); if (drop.isUsingTemporary()) { - buffer.append("TEMPORARY "); + builder.append("TEMPORARY "); } if (drop.isMaterialized()) { - buffer.append("MATERIALIZED "); + builder.append("MATERIALIZED "); } - buffer.append(drop.getType()); + builder.append(drop.getType()); if (drop.isIfExists()) { - buffer.append(" IF EXISTS"); + builder.append(" IF EXISTS"); } - buffer.append(" ").append(drop.getName()); + builder.append(" ").append(drop.getName()); if (drop.getType().equals("FUNCTION")) { - buffer.append(Drop.formatFuncParams(drop.getParamsByType("FUNCTION"))); + builder.append(Drop.formatFuncParams(drop.getParamsByType("FUNCTION"))); } if (drop.getParameters() != null && !drop.getParameters().isEmpty()) { - buffer.append(" ").append(PlainSelect.getStringList(drop.getParameters(), false, false)); + builder.append(" ") + .append(PlainSelect.getStringList(drop.getParameters(), false, false)); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExecuteDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExecuteDeParser.java index 3e257c1f6..4034bd152 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExecuteDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExecuteDeParser.java @@ -17,40 +17,41 @@ public class ExecuteDeParser extends AbstractDeParser { - private ExpressionVisitor expressionVisitor; + private ExpressionVisitor expressionVisitor; - public ExecuteDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public ExecuteDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @Override public void deParse(Execute execute) { - buffer.append(execute.getExecType().name()).append(" ").append(execute.getName()); + builder.append(execute.getExecType().name()).append(" ").append(execute.getName()); if (execute.isParenthesis()) { - buffer.append(" ("); + builder.append(" ("); } else if (execute.getExprList() != null) { - buffer.append(" "); + builder.append(" "); } if (execute.getExprList() != null) { List expressions = execute.getExprList().getExpressions(); for (int i = 0; i < expressions.size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } - expressions.get(i).accept(expressionVisitor); + expressions.get(i).accept(expressionVisitor, null); } } if (execute.isParenthesis()) { - buffer.append(")"); + builder.append(")"); } } - public ExpressionVisitor getExpressionVisitor() { + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public void setExpressionVisitor(ExpressionVisitor visitor) { + public void setExpressionVisitor(ExpressionVisitor visitor) { expressionVisitor = visitor; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index 310e7a56c..397d902aa 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -9,6 +9,11 @@ */ package net.sf.jsqlparser.util.deparser; +import static java.util.stream.Collectors.joining; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; import net.sf.jsqlparser.expression.AllValue; import net.sf.jsqlparser.expression.AnalyticExpression; import net.sf.jsqlparser.expression.AnalyticType; @@ -16,11 +21,14 @@ import net.sf.jsqlparser.expression.ArrayConstructor; import net.sf.jsqlparser.expression.ArrayExpression; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.BooleanValue; import net.sf.jsqlparser.expression.CaseExpression; import net.sf.jsqlparser.expression.CastExpression; import net.sf.jsqlparser.expression.CollateExpression; +import net.sf.jsqlparser.expression.ConnectByPriorOperator; import net.sf.jsqlparser.expression.ConnectByRootOperator; import net.sf.jsqlparser.expression.DateTimeLiteralExpression; +import net.sf.jsqlparser.expression.DateUnitExpression; import net.sf.jsqlparser.expression.DateValue; import net.sf.jsqlparser.expression.DoubleValue; import net.sf.jsqlparser.expression.Expression; @@ -28,15 +36,20 @@ import net.sf.jsqlparser.expression.ExtractExpression; import net.sf.jsqlparser.expression.Function; import net.sf.jsqlparser.expression.HexValue; +import net.sf.jsqlparser.expression.HighExpression; import net.sf.jsqlparser.expression.IntervalExpression; +import net.sf.jsqlparser.expression.Inverse; import net.sf.jsqlparser.expression.JdbcNamedParameter; import net.sf.jsqlparser.expression.JdbcParameter; import net.sf.jsqlparser.expression.JsonAggregateFunction; import net.sf.jsqlparser.expression.JsonExpression; import net.sf.jsqlparser.expression.JsonFunction; +import net.sf.jsqlparser.expression.JsonTableFunction; import net.sf.jsqlparser.expression.KeepExpression; +import net.sf.jsqlparser.expression.KeyExpression; import net.sf.jsqlparser.expression.LambdaExpression; import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.LowExpression; import net.sf.jsqlparser.expression.MySQLGroupConcat; import net.sf.jsqlparser.expression.NextValExpression; import net.sf.jsqlparser.expression.NotExpression; @@ -46,6 +59,7 @@ import net.sf.jsqlparser.expression.OracleHint; import net.sf.jsqlparser.expression.OracleNamedFunctionParameter; import net.sf.jsqlparser.expression.OverlapsCondition; +import net.sf.jsqlparser.expression.PostgresNamedFunctionParameter; import net.sf.jsqlparser.expression.RangeExpression; import net.sf.jsqlparser.expression.RowConstructor; import net.sf.jsqlparser.expression.RowGetExpression; @@ -81,6 +95,7 @@ import net.sf.jsqlparser.expression.operators.relational.Between; import net.sf.jsqlparser.expression.operators.relational.ContainedBy; import net.sf.jsqlparser.expression.operators.relational.Contains; +import net.sf.jsqlparser.expression.operators.relational.CosineSimilarity; import net.sf.jsqlparser.expression.operators.relational.DoubleAnd; import net.sf.jsqlparser.expression.operators.relational.EqualsTo; import net.sf.jsqlparser.expression.operators.relational.ExcludesExpression; @@ -95,6 +110,7 @@ import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression; import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression; import net.sf.jsqlparser.expression.operators.relational.IsNullExpression; +import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression; import net.sf.jsqlparser.expression.operators.relational.JsonOperator; import net.sf.jsqlparser.expression.operators.relational.LikeExpression; import net.sf.jsqlparser.expression.operators.relational.Matches; @@ -103,6 +119,8 @@ import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals; import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo; import net.sf.jsqlparser.expression.operators.relational.OldOracleJoinBinaryExpression; +import net.sf.jsqlparser.expression.operators.relational.Plus; +import net.sf.jsqlparser.expression.operators.relational.PriorTo; import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator; import net.sf.jsqlparser.expression.operators.relational.SimilarToExpression; import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax; @@ -111,8 +129,10 @@ import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.create.table.ColDataType; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; +import net.sf.jsqlparser.statement.select.FunctionAllColumns; import net.sf.jsqlparser.statement.select.OrderByElement; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.Select; @@ -120,30 +140,24 @@ import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.select.WithItem; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import static java.util.stream.Collectors.joining; - @SuppressWarnings({"PMD.CyclomaticComplexity"}) public class ExpressionDeParser extends AbstractDeParser // FIXME maybe we should implement an ItemsListDeparser too? - implements ExpressionVisitor { + implements ExpressionVisitor { private static final String NOT = "NOT "; - private SelectVisitor selectVisitor; + private SelectVisitor selectVisitor; private OrderByDeParser orderByDeParser = new OrderByDeParser(); public ExpressionDeParser() { super(new StringBuilder()); } - public ExpressionDeParser(SelectVisitor selectVisitor, StringBuilder buffer) { + public ExpressionDeParser(SelectVisitor selectVisitor, StringBuilder buffer) { this(selectVisitor, buffer, new OrderByDeParser()); } - ExpressionDeParser(SelectVisitor selectVisitor, StringBuilder buffer, + ExpressionDeParser(SelectVisitor selectVisitor, StringBuilder buffer, OrderByDeParser orderByDeParser) { super(buffer); this.selectVisitor = selectVisitor; @@ -151,416 +165,660 @@ public ExpressionDeParser(SelectVisitor selectVisitor, StringBuilder buffer) { } @Override - public void visit(Addition addition) { - visitBinaryExpression(addition, " + "); + public StringBuilder visit(Addition addition, S context) { + deparse(addition, " + ", null); + return builder; } @Override - public void visit(AndExpression andExpression) { - visitBinaryExpression(andExpression, andExpression.isUseOperator() ? " && " : " AND "); + public StringBuilder visit(AndExpression andExpression, S context) { + deparse(andExpression, andExpression.isUseOperator() ? " && " : " AND ", + null); + return builder; } @Override - public void visit(Between between) { - between.getLeftExpression().accept(this); + public StringBuilder visit(Between between, S context) { + between.getLeftExpression().accept(this, context); if (between.isNot()) { - buffer.append(" NOT"); + builder.append(" NOT"); + } + + builder.append(" BETWEEN "); + + if (between.isUsingSymmetric()) { + builder.append("SYMMETRIC "); + } else if (between.isUsingAsymmetric()) { + builder.append("ASYMMETRIC "); } - buffer.append(" BETWEEN "); - between.getBetweenExpressionStart().accept(this); - buffer.append(" AND "); - between.getBetweenExpressionEnd().accept(this); + between.getBetweenExpressionStart().accept(this, context); + builder.append(" AND "); + between.getBetweenExpressionEnd().accept(this, context); + return builder; } @Override - public void visit(OverlapsCondition overlapsCondition) { - buffer.append(overlapsCondition.toString()); + public StringBuilder visit(OverlapsCondition overlapsCondition, S context) { + builder.append(overlapsCondition.toString()); + return builder; } @Override - public void visit(EqualsTo equalsTo) { - visitOldOracleJoinBinaryExpression(equalsTo, " = "); + public StringBuilder visit(EqualsTo equalsTo, S context) { + deparse(equalsTo, " = ", null); + return builder; } @Override - public void visit(Division division) { - visitBinaryExpression(division, " / "); + public StringBuilder visit(Division division, S context) { + deparse(division, " / ", null); + return builder; } @Override - public void visit(IntegerDivision division) { - visitBinaryExpression(division, " DIV "); + public StringBuilder visit(IntegerDivision division, S context) { + deparse(division, " DIV ", null); + return builder; } @Override - public void visit(DoubleValue doubleValue) { - buffer.append(doubleValue.toString()); + public StringBuilder visit(DoubleValue doubleValue, S context) { + builder.append(doubleValue.toString()); + return builder; } @Override - public void visit(HexValue hexValue) { - buffer.append(hexValue.toString()); + public StringBuilder visit(HexValue hexValue, S context) { + builder.append(hexValue.toString()); + return builder; } @Override - public void visit(NotExpression notExpr) { + public StringBuilder visit(NotExpression notExpr, S context) { if (notExpr.isExclamationMark()) { - buffer.append("! "); + builder.append("! "); } else { - buffer.append(NOT); + builder.append(NOT); } - notExpr.getExpression().accept(this); + notExpr.getExpression().accept(this, context); + return builder; } @Override - public void visit(BitwiseRightShift expr) { - visitBinaryExpression(expr, " >> "); + public StringBuilder visit(BitwiseRightShift expr, S context) { + deparse(expr, " >> ", null); + return builder; } @Override - public void visit(BitwiseLeftShift expr) { - visitBinaryExpression(expr, " << "); + public StringBuilder visit(BitwiseLeftShift expr, S context) { + deparse(expr, " << ", null); + return builder; } - public void visitOldOracleJoinBinaryExpression(OldOracleJoinBinaryExpression expression, - String operator) { + public StringBuilder deparse( + OldOracleJoinBinaryExpression expression, + String operator, S context) { // if (expression.isNot()) { // buffer.append(NOT); // } - expression.getLeftExpression().accept(this); + expression.getLeftExpression().accept(this, context); if (expression.getOldOracleJoinSyntax() == EqualsTo.ORACLE_JOIN_RIGHT) { - buffer.append("(+)"); + builder.append("(+)"); } - buffer.append(operator); - expression.getRightExpression().accept(this); + builder.append(operator); + expression.getRightExpression().accept(this, context); if (expression.getOldOracleJoinSyntax() == EqualsTo.ORACLE_JOIN_LEFT) { - buffer.append("(+)"); + builder.append("(+)"); } + + return builder; } @Override - public void visit(GreaterThan greaterThan) { - visitOldOracleJoinBinaryExpression(greaterThan, " > "); + public StringBuilder visit(GreaterThan greaterThan, S context) { + deparse(greaterThan, " > ", null); + return builder; } @Override - public void visit(GreaterThanEquals greaterThanEquals) { - visitOldOracleJoinBinaryExpression(greaterThanEquals, " >= "); + public StringBuilder visit(GreaterThanEquals greaterThanEquals, S context) { + deparse(greaterThanEquals, " >= ", null); + + return builder; + } + + public void visit(Addition addition) { + visit(addition, null); + } + + public void visit(AndExpression andExpression) { + visit(andExpression, null); + } + + public void visit(Between between) { + visit(between, null); + } + + public void visit(OverlapsCondition overlapsCondition) { + visit(overlapsCondition, null); + } + + public void visit(EqualsTo equalsTo) { + visit(equalsTo, null); + } + + public void visit(Division division) { + visit(division, null); + } + public void visit(IntegerDivision division) { + visit(division, null); } + public void visit(DoubleValue doubleValue) { + visit(doubleValue, null); + } + + public void visit(HexValue hexValue) { + visit(hexValue, null); + } + + public void visit(NotExpression notExpr) { + visit(notExpr, null); + } + + public void visit(BitwiseRightShift expr) { + visit(expr, null); + } + + public void visit(BitwiseLeftShift expr) { + visit(expr, null); + } + + @Override - public void visit(InExpression inExpression) { - inExpression.getLeftExpression().accept(this); + public StringBuilder visit(InExpression inExpression, S context) { + inExpression.getLeftExpression().accept(this, context); if (inExpression .getOldOracleJoinSyntax() == SupportsOldOracleJoinSyntax.ORACLE_JOIN_RIGHT) { - buffer.append("(+)"); + builder.append("(+)"); } if (inExpression.isGlobal()) { - buffer.append(" GLOBAL"); + builder.append(" GLOBAL"); } if (inExpression.isNot()) { - buffer.append(" NOT"); + builder.append(" NOT"); } - buffer.append(" IN "); - inExpression.getRightExpression().accept(this); + builder.append(" IN "); + inExpression.getRightExpression().accept(this, context); + return builder; } @Override - public void visit(IncludesExpression includesExpression) { - includesExpression.getLeftExpression().accept(this); - buffer.append(" INCLUDES "); - includesExpression.getRightExpression().accept(this); + public StringBuilder visit(IncludesExpression includesExpression, S context) { + includesExpression.getLeftExpression().accept(this, context); + builder.append(" INCLUDES "); + includesExpression.getRightExpression().accept(this, context); + return builder; } @Override - public void visit(ExcludesExpression excludesExpression) { - excludesExpression.getLeftExpression().accept(this); - buffer.append(" EXCLUDES "); - excludesExpression.getRightExpression().accept(this); + public StringBuilder visit(ExcludesExpression excludesExpression, S context) { + excludesExpression.getLeftExpression().accept(this, context); + builder.append(" EXCLUDES "); + excludesExpression.getRightExpression().accept(this, context); + return builder; } @Override - public void visit(FullTextSearch fullTextSearch) { + public StringBuilder visit(FullTextSearch fullTextSearch, S context) { // Build a list of matched columns - String columnsListCommaSeperated = ""; + StringBuilder columnsListCommaSeperated = new StringBuilder(); Iterator iterator = fullTextSearch.getMatchColumns().iterator(); while (iterator.hasNext()) { Column col = iterator.next(); - columnsListCommaSeperated += col.getFullyQualifiedName(); + columnsListCommaSeperated.append(col.getFullyQualifiedName()); if (iterator.hasNext()) { - columnsListCommaSeperated += ","; + columnsListCommaSeperated.append(","); } } - buffer.append("MATCH (" + columnsListCommaSeperated + ") AGAINST (" - + fullTextSearch.getAgainstValue() - + (fullTextSearch.getSearchModifier() != null + builder.append("MATCH (").append(columnsListCommaSeperated).append(") AGAINST (") + .append(fullTextSearch.getAgainstValue()) + .append(fullTextSearch.getSearchModifier() != null ? " " + fullTextSearch.getSearchModifier() : "") - + ")"); + .append(")"); + return builder; } @Override - public void visit(SignedExpression signedExpression) { - buffer.append(signedExpression.getSign()); - signedExpression.getExpression().accept(this); + public StringBuilder visit(SignedExpression signedExpression, S context) { + builder.append(signedExpression.getSign()); + signedExpression.getExpression().accept(this, context); + return builder; } @Override - public void visit(IsNullExpression isNullExpression) { - isNullExpression.getLeftExpression().accept(this); + public StringBuilder visit(IsNullExpression isNullExpression, S context) { + isNullExpression.getLeftExpression().accept(this, context); if (isNullExpression.isUseNotNull()) { - buffer.append(" NOTNULL"); + builder.append(" NOTNULL"); } else if (isNullExpression.isUseIsNull()) { if (isNullExpression.isNot()) { - buffer.append(" NOT ISNULL"); + builder.append(" NOT ISNULL"); } else { - buffer.append(" ISNULL"); + builder.append(" ISNULL"); } } else { if (isNullExpression.isNot()) { - buffer.append(" IS NOT NULL"); + builder.append(" IS NOT NULL"); } else { - buffer.append(" IS NULL"); + builder.append(" IS NULL"); } } + return builder; } @Override - public void visit(IsBooleanExpression isBooleanExpression) { - isBooleanExpression.getLeftExpression().accept(this); + public StringBuilder visit(IsBooleanExpression isBooleanExpression, S context) { + isBooleanExpression.getLeftExpression().accept(this, context); if (isBooleanExpression.isTrue()) { if (isBooleanExpression.isNot()) { - buffer.append(" IS NOT TRUE"); + builder.append(" IS NOT TRUE"); } else { - buffer.append(" IS TRUE"); + builder.append(" IS TRUE"); } } else { if (isBooleanExpression.isNot()) { - buffer.append(" IS NOT FALSE"); + builder.append(" IS NOT FALSE"); } else { - buffer.append(" IS FALSE"); + builder.append(" IS FALSE"); } } + return builder; } @Override - public void visit(JdbcParameter jdbcParameter) { - buffer.append(jdbcParameter.getParameterCharacter()); + public StringBuilder visit(IsUnknownExpression isUnknownExpression, S context) { + isUnknownExpression.getLeftExpression().accept(this, context); + if (isUnknownExpression.isNot()) { + builder.append(" IS NOT UNKNOWN"); + } else { + builder.append(" IS UNKNOWN"); + } + return builder; + } + + @Override + public StringBuilder visit(JdbcParameter jdbcParameter, S context) { + builder.append(jdbcParameter.getParameterCharacter()); if (jdbcParameter.isUseFixedIndex()) { - buffer.append(jdbcParameter.getIndex()); + builder.append(jdbcParameter.getIndex()); } + return builder; } @Override - public void visit(LikeExpression likeExpression) { + public StringBuilder visit(LikeExpression likeExpression, S context) { String keywordStr = likeExpression.getLikeKeyWord() == LikeExpression.KeyWord.SIMILAR_TO ? " SIMILAR TO" : likeExpression.getLikeKeyWord().toString(); - likeExpression.getLeftExpression().accept(this); - buffer.append(" "); + likeExpression.getLeftExpression().accept(this, context); + builder.append(" "); if (likeExpression.isNot()) { - buffer.append("NOT "); + builder.append("NOT "); } - buffer.append(keywordStr).append(" "); + builder.append(keywordStr).append(" "); if (likeExpression.isUseBinary()) { - buffer.append("BINARY "); + builder.append("BINARY "); } - likeExpression.getRightExpression().accept(this); + likeExpression.getRightExpression().accept(this, context); Expression escape = likeExpression.getEscape(); if (escape != null) { - buffer.append(" ESCAPE "); - likeExpression.getEscape().accept(this); + builder.append(" ESCAPE "); + likeExpression.getEscape().accept(this, context); } + return builder; } @Override - public void visit(ExistsExpression existsExpression) { + public StringBuilder visit(ExistsExpression existsExpression, S context) { if (existsExpression.isNot()) { - buffer.append("NOT EXISTS "); + builder.append("NOT EXISTS "); } else { - buffer.append("EXISTS "); + builder.append("EXISTS "); } - existsExpression.getRightExpression().accept(this); + existsExpression.getRightExpression().accept(this, context); + return builder; } @Override - public void visit(MemberOfExpression memberOfExpression) { - memberOfExpression.getLeftExpression().accept(this); + public StringBuilder visit(MemberOfExpression memberOfExpression, S context) { + memberOfExpression.getLeftExpression().accept(this, context); if (memberOfExpression.isNot()) { - buffer.append(" NOT MEMBER OF "); + builder.append(" NOT MEMBER OF "); } else { - buffer.append(" MEMBER OF "); + builder.append(" MEMBER OF "); } - memberOfExpression.getRightExpression().accept(this); + memberOfExpression.getRightExpression().accept(this, context); + return builder; + } + + public void visit(InExpression inExpression) { + visit(inExpression, null); + } + + public void visit(IncludesExpression includesExpression) { + visit(includesExpression, null); + } + + public void visit(ExcludesExpression excludesExpression) { + visit(excludesExpression, null); + } + + public void visit(FullTextSearch fullTextSearch) { + visit(fullTextSearch, null); + } + + public void visit(SignedExpression signedExpression) { + visit(signedExpression, null); } + public void visit(IsNullExpression isNullExpression) { + visit(isNullExpression, null); + } + + public void visit(IsBooleanExpression isBooleanExpression) { + visit(isBooleanExpression, null); + } + + public void visit(IsUnknownExpression isUnknownExpression) { + visit(isUnknownExpression, null); + } + + public void visit(JdbcParameter jdbcParameter) { + visit(jdbcParameter, null); + } + + public void visit(LikeExpression likeExpression) { + visit(likeExpression, null); + } + + public void visit(ExistsExpression existsExpression) { + visit(existsExpression, null); + } + + public void visit(MemberOfExpression memberOfExpression) { + visit(memberOfExpression, null); + } + + @Override - public void visit(LongValue longValue) { - buffer.append(longValue.getStringValue()); + public StringBuilder visit(LongValue longValue, S context) { + builder.append(longValue.getStringValue()); + return builder; } @Override - public void visit(MinorThan minorThan) { - visitOldOracleJoinBinaryExpression(minorThan, " < "); + public StringBuilder visit(MinorThan minorThan, S context) { + deparse(minorThan, " < ", null); + return builder; } @Override - public void visit(MinorThanEquals minorThanEquals) { - visitOldOracleJoinBinaryExpression(minorThanEquals, " <= "); + public StringBuilder visit(MinorThanEquals minorThanEquals, S context) { + deparse(minorThanEquals, " <= ", null); + return builder; } @Override - public void visit(Multiplication multiplication) { - visitBinaryExpression(multiplication, " * "); + public StringBuilder visit(Multiplication multiplication, S context) { + deparse(multiplication, " * ", null); + return builder; } @Override - public void visit(NotEqualsTo notEqualsTo) { - visitOldOracleJoinBinaryExpression(notEqualsTo, - " " + notEqualsTo.getStringExpression() + " "); + public StringBuilder visit(NotEqualsTo notEqualsTo, S context) { + deparse(notEqualsTo, + " " + notEqualsTo.getStringExpression() + " ", null); + return builder; } @Override - public void visit(DoubleAnd doubleAnd) { - visitOldOracleJoinBinaryExpression(doubleAnd, " " + doubleAnd.getStringExpression() + " "); + public StringBuilder visit(DoubleAnd doubleAnd, S context) { + deparse(doubleAnd, " " + doubleAnd.getStringExpression() + " ", + null); + return builder; } @Override - public void visit(Contains contains) { - visitOldOracleJoinBinaryExpression(contains, " " + contains.getStringExpression() + " "); + public StringBuilder visit(Contains contains, S context) { + deparse(contains, " " + contains.getStringExpression() + " ", + null); + return builder; } @Override - public void visit(ContainedBy containedBy) { - visitOldOracleJoinBinaryExpression(containedBy, - " " + containedBy.getStringExpression() + " "); + public StringBuilder visit(ContainedBy containedBy, S context) { + deparse(containedBy, + " " + containedBy.getStringExpression() + " ", null); + return builder; } @Override - public void visit(NullValue nullValue) { - buffer.append(nullValue.toString()); + public StringBuilder visit(NullValue nullValue, S context) { + builder.append(nullValue.toString()); + return builder; } @Override - public void visit(OrExpression orExpression) { - visitBinaryExpression(orExpression, " OR "); + public StringBuilder visit(OrExpression orExpression, S context) { + deparse(orExpression, " OR ", null); + return builder; } @Override - public void visit(XorExpression xorExpression) { - visitBinaryExpression(xorExpression, " XOR "); + public StringBuilder visit(XorExpression xorExpression, S context) { + deparse(xorExpression, " XOR ", null); + return builder; } @Override - public void visit(StringValue stringValue) { + public StringBuilder visit(StringValue stringValue, S context) { if (stringValue.getPrefix() != null) { - buffer.append(stringValue.getPrefix()); + builder.append(stringValue.getPrefix()); } - buffer.append("'").append(stringValue.getValue()).append("'"); + builder.append(stringValue.getQuoteStr()).append(stringValue.getValue()) + .append(stringValue.getQuoteStr()); + return builder; } @Override - public void visit(Subtraction subtraction) { - visitBinaryExpression(subtraction, " - "); + public StringBuilder visit(BooleanValue booleanValue, S context) { + builder.append(booleanValue.getValue()); + + return builder; + } + + @Override + public StringBuilder visit(Subtraction subtraction, S context) { + deparse(subtraction, " - ", null); + return builder; } - protected void visitBinaryExpression(BinaryExpression binaryExpression, String operator) { - binaryExpression.getLeftExpression().accept(this); - buffer.append(operator); - binaryExpression.getRightExpression().accept(this); + protected void deparse(BinaryExpression binaryExpression, + String operator, S context) { + binaryExpression.getLeftExpression().accept(this, context); + builder.append(operator); + binaryExpression.getRightExpression().accept(this, context); } @Override - public void visit(Select selectBody) { + public StringBuilder visit(Select select, S context) { if (selectVisitor != null) { - if (selectBody.getWithItemsList() != null) { - buffer.append("WITH "); - for (Iterator iter = selectBody.getWithItemsList().iterator(); iter + if (select.getWithItemsList() != null) { + builder.append("WITH "); + for (Iterator> iter = select.getWithItemsList().iterator(); iter .hasNext();) { - iter.next().accept(selectVisitor); + iter.next().accept(selectVisitor, null); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } - buffer.append(" "); + builder.append(" "); } - buffer.append(" "); + builder.append(" "); } - selectBody.accept(selectVisitor); + select.accept(selectVisitor, null); } + return builder; } @Override - public void visit(TranscodingFunction transcodingFunction) { + public StringBuilder visit(TranscodingFunction transcodingFunction, S context) { if (transcodingFunction.isTranscodeStyle()) { - buffer.append("CONVERT( "); - transcodingFunction.getExpression().accept(this); - buffer.append(" USING ") + builder.append(transcodingFunction.getKeyword()); + builder.append("( "); + transcodingFunction.getExpression().accept(this, context); + builder.append(" USING ") .append(transcodingFunction.getTranscodingName()) .append(" )"); } else { - buffer - .append("CONVERT( ") + builder + .append(transcodingFunction.getKeyword()) + .append("( ") .append(transcodingFunction.getColDataType()) .append(", "); - transcodingFunction.getExpression().accept(this); + transcodingFunction.getExpression().accept(this, context); String transCodingName = transcodingFunction.getTranscodingName(); if (transCodingName != null && !transCodingName.isEmpty()) { - buffer.append(", ").append(transCodingName); + builder.append(", ").append(transCodingName); } - buffer.append(" )"); + builder.append(" )"); } + return builder; } - public void visit(TrimFunction trimFunction) { - buffer.append("Trim("); + public StringBuilder visit(TrimFunction trimFunction, S context) { + builder.append("Trim("); if (trimFunction.getTrimSpecification() != null) { - buffer.append(" ").append(trimFunction.getTrimSpecification()); + builder.append(" ").append(trimFunction.getTrimSpecification()); } if (trimFunction.getExpression() != null) { - buffer.append(" "); - trimFunction.getExpression().accept(this); + builder.append(" "); + trimFunction.getExpression().accept(this, context); } if (trimFunction.getFromExpression() != null) { - buffer.append(trimFunction.isUsingFromKeyword() ? " FROM " : ", "); - trimFunction.getFromExpression().accept(this); + builder.append(trimFunction.isUsingFromKeyword() ? " FROM " : ", "); + trimFunction.getFromExpression().accept(this, context); } - buffer.append(" )"); + builder.append(" )"); + return builder; + } + + public void visit(LongValue longValue) { + visit(longValue, null); + } + + public void visit(MinorThan minorThan) { + visit(minorThan, null); + } + + public void visit(MinorThanEquals minorThanEquals) { + visit(minorThanEquals, null); + } + + public void visit(Multiplication multiplication) { + visit(multiplication, null); + } + + public void visit(NotEqualsTo notEqualsTo) { + visit(notEqualsTo, null); + } + + public void visit(DoubleAnd doubleAnd) { + visit(doubleAnd, null); + } + + public void visit(Contains contains) { + visit(contains, null); + } + + public void visit(ContainedBy containedBy) { + visit(containedBy, null); + } + + public void visit(NullValue nullValue) { + visit(nullValue, null); + } + + public void visit(OrExpression orExpression) { + visit(orExpression, null); + } + + public void visit(XorExpression xorExpression) { + visit(xorExpression, null); + } + + public void visit(StringValue stringValue) { + visit(stringValue, null); + } + + public void visit(BooleanValue booleanValue) { + visit(booleanValue, null); + } + + public void visit(Subtraction subtraction) { + visit(subtraction, null); + } + + public void visit(Select select) { + visit(select, null); + } + + public void visit(TranscodingFunction transcodingFunction) { + visit(transcodingFunction, null); } + public void visit(TrimFunction trimFunction) { + visit(trimFunction, null); + } + + @Override - public void visit(RangeExpression rangeExpression) { - rangeExpression.getStartExpression().accept(this); - buffer.append(":"); - rangeExpression.getEndExpression().accept(this); + public StringBuilder visit(RangeExpression rangeExpression, S context) { + rangeExpression.getStartExpression().accept(this, context); + builder.append(":"); + rangeExpression.getEndExpression().accept(this, context); + return builder; } @Override - public void visit(Column tableColumn) { + public StringBuilder visit(Column tableColumn, S context) { final Table table = tableColumn.getTable(); String tableName = null; if (table != null) { @@ -571,347 +829,460 @@ public void visit(Column tableColumn) { } } if (tableName != null && !tableName.isEmpty()) { - buffer.append(tableName).append(tableColumn.getTableDelimiter()); + builder.append(tableName).append(tableColumn.getTableDelimiter()); } - buffer.append(tableColumn.getColumnName()); + builder.append(tableColumn.getColumnName()); + if (tableColumn.getOldOracleJoinSyntax() != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN) { + builder.append("(+)"); + } if (tableColumn.getArrayConstructor() != null) { - tableColumn.getArrayConstructor().accept(this); + tableColumn.getArrayConstructor().accept(this, context); + } + + if (tableColumn.getCommentText() != null) { + builder.append(" /* ").append(tableColumn.getCommentText()).append("*/ "); } + + return builder; } @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) - public void visit(Function function) { + public StringBuilder visit(Function function, S context) { if (function.isEscaped()) { - buffer.append("{fn "); + builder.append("{fn "); } - buffer.append(function.getName()); + builder.append(function.getName()); if (function.getParameters() == null && function.getNamedParameters() == null) { - buffer.append("()"); + builder.append("()"); } else { - buffer.append("("); + builder.append("("); if (function.isDistinct()) { - buffer.append("DISTINCT "); + builder.append("DISTINCT "); } else if (function.isAllColumns()) { - buffer.append("ALL "); + builder.append("ALL "); } else if (function.isUnique()) { - buffer.append("UNIQUE "); + builder.append("UNIQUE "); } + + if (function.getExtraKeyword() != null) { + builder.append(function.getExtraKeyword()).append(" "); + } + if (function.getNamedParameters() != null) { - function.getNamedParameters().accept(this); + function.getNamedParameters().accept(this, context); } if (function.getParameters() != null) { - function.getParameters().accept(this); + function.getParameters().accept(this, context); } Function.HavingClause havingClause = function.getHavingClause(); if (havingClause != null) { - buffer.append(" HAVING ").append(havingClause.getHavingType()).append(" "); - havingClause.getExpression().accept(this); + builder.append(" HAVING ").append(havingClause.getHavingType()).append(" "); + havingClause.getExpression().accept(this, context); } - if (function.getNullHandling() != null) { + if (function.getNullHandling() != null && !function.isIgnoreNullsOutside()) { switch (function.getNullHandling()) { case IGNORE_NULLS: - buffer.append(" IGNORE NULLS"); + builder.append(" IGNORE NULLS"); break; case RESPECT_NULLS: - buffer.append(" RESPECT NULLS"); + builder.append(" RESPECT NULLS"); break; } } if (function.getOrderByElements() != null) { - buffer.append(" ORDER BY "); + builder.append(" ORDER BY "); boolean comma = false; orderByDeParser.setExpressionVisitor(this); - orderByDeParser.setBuffer(buffer); + orderByDeParser.setBuilder(builder); for (OrderByElement orderByElement : function.getOrderByElements()) { if (comma) { - buffer.append(", "); + builder.append(", "); } else { comma = true; } orderByDeParser.deParseElement(orderByElement); } } + + if (function.getOnOverflowTruncate() != null) { + builder.append(" ON OVERFLOW ").append(function.getOnOverflowTruncate()); + } + if (function.getLimit() != null) { - new LimitDeparser(this, buffer).deParse(function.getLimit()); + new LimitDeparser(this, builder).deParse(function.getLimit()); + } + + // Generic keyword arguments (e.g. SEPARATOR ',', USING utf8) + if (function.getKeywordArguments() != null) { + for (Function.KeywordArgument ka : function.getKeywordArguments()) { + builder.append(" ").append(ka.getKeyword()).append(" "); + ka.getExpression().accept(this, context); + } + } + + builder.append(")"); + } + + if (function.getChainedParameters() != null) { + builder.append("("); + function.getChainedParameters().accept(this, context); + builder.append(")"); + } + + if (function.getNullHandling() != null && function.isIgnoreNullsOutside()) { + switch (function.getNullHandling()) { + case IGNORE_NULLS: + builder.append(" IGNORE NULLS"); + break; + case RESPECT_NULLS: + builder.append(" RESPECT NULLS"); + break; } - buffer.append(")"); } if (function.getAttribute() != null) { - buffer.append(".").append(function.getAttribute()); + builder.append(".").append(function.getAttribute()); } if (function.getKeep() != null) { - buffer.append(" ").append(function.getKeep()); + builder.append(" ").append(function.getKeep()); } if (function.isEscaped()) { - buffer.append("}"); + builder.append("}"); } + return builder; } @Override - public void visit(ParenthesedSelect selectBody) { - selectBody.getSelect().accept(this); + public StringBuilder visit(ParenthesedSelect selectBody, S context) { + selectBody.getSelect().accept(this, context); + return builder; } - public SelectVisitor getSelectVisitor() { + public SelectVisitor getSelectVisitor() { return selectVisitor; } - public void setSelectVisitor(SelectVisitor visitor) { + public void setSelectVisitor(SelectVisitor visitor) { selectVisitor = visitor; } @Override - public void visit(DateValue dateValue) { - buffer.append("{d '").append(dateValue.getValue().toString()).append("'}"); + public StringBuilder visit(DateValue dateValue, S context) { + builder.append("{d '").append(dateValue.getValue().toString()).append("'}"); + return builder; } @Override - public void visit(TimestampValue timestampValue) { - buffer.append("{ts '").append(timestampValue.getValue().toString()).append("'}"); + public StringBuilder visit(TimestampValue timestampValue, S context) { + builder.append("{ts '").append(timestampValue.getValue().toString()).append("'}"); + return builder; } @Override - public void visit(TimeValue timeValue) { - buffer.append("{t '").append(timeValue.getValue().toString()).append("'}"); + public StringBuilder visit(TimeValue timeValue, S context) { + builder.append("{t '").append(timeValue.getValue().toString()).append("'}"); + return builder; } @Override - public void visit(CaseExpression caseExpression) { - buffer.append(caseExpression.isUsingBrackets() ? "(" : "").append("CASE "); + public StringBuilder visit(CaseExpression caseExpression, S context) { + builder.append(caseExpression.isUsingBrackets() ? "(" : "").append("CASE "); Expression switchExp = caseExpression.getSwitchExpression(); if (switchExp != null) { - switchExp.accept(this); - buffer.append(" "); + switchExp.accept(this, context); + builder.append(" "); } for (Expression exp : caseExpression.getWhenClauses()) { - exp.accept(this); + exp.accept(this, context); } Expression elseExp = caseExpression.getElseExpression(); if (elseExp != null) { - buffer.append("ELSE "); - elseExp.accept(this); - buffer.append(" "); + builder.append("ELSE "); + elseExp.accept(this, context); + builder.append(" "); } - buffer.append("END").append(caseExpression.isUsingBrackets() ? ")" : ""); + builder.append("END").append(caseExpression.isUsingBrackets() ? ")" : ""); + return builder; } @Override - public void visit(WhenClause whenClause) { - buffer.append("WHEN "); - whenClause.getWhenExpression().accept(this); - buffer.append(" THEN "); - whenClause.getThenExpression().accept(this); - buffer.append(" "); + public StringBuilder visit(WhenClause whenClause, S context) { + builder.append("WHEN "); + whenClause.getWhenExpression().accept(this, context); + builder.append(" THEN "); + whenClause.getThenExpression().accept(this, context); + builder.append(" "); + return builder; } @Override - public void visit(AnyComparisonExpression anyComparisonExpression) { - buffer.append(anyComparisonExpression.getAnyType().name()); + public StringBuilder visit(AnyComparisonExpression anyComparisonExpression, S context) { + builder.append(anyComparisonExpression.getAnyType().name()); // VALUES or SELECT - anyComparisonExpression.getSelect().accept((ExpressionVisitor) this); + anyComparisonExpression.getSelect().accept(this, context); + return builder; } @Override + public StringBuilder visit(Concat concat, S context) { + deparse(concat, " || ", null); + return builder; + } + + public void visit(RangeExpression rangeExpression) { + visit(rangeExpression, null); + } + + public void visit(Column tableColumn) { + visit(tableColumn, null); + } + + public void visit(Function function) { + visit(function, null); + } + + public void visit(ParenthesedSelect selectBody) { + visit(selectBody, null); + } + + public void visit(DateValue dateValue) { + visit(dateValue, null); + } + + public void visit(TimestampValue timestampValue) { + visit(timestampValue, null); + } + + public void visit(TimeValue timeValue) { + visit(timeValue, null); + } + + public void visit(CaseExpression caseExpression) { + visit(caseExpression, null); + } + + public void visit(WhenClause whenClause) { + visit(whenClause, null); + } + + public void visit(AnyComparisonExpression anyComparisonExpression) { + visit(anyComparisonExpression, null); + } + public void visit(Concat concat) { - visitBinaryExpression(concat, " || "); + visit(concat, null); } + @Override - public void visit(Matches matches) { - visitOldOracleJoinBinaryExpression(matches, " @@ "); + public StringBuilder visit(Matches matches, S context) { + deparse(matches, " @@ ", null); + return builder; } @Override - public void visit(BitwiseAnd bitwiseAnd) { - visitBinaryExpression(bitwiseAnd, " & "); + public StringBuilder visit(BitwiseAnd bitwiseAnd, S context) { + deparse(bitwiseAnd, " & ", null); + return builder; } @Override - public void visit(BitwiseOr bitwiseOr) { - visitBinaryExpression(bitwiseOr, " | "); + public StringBuilder visit(BitwiseOr bitwiseOr, S context) { + deparse(bitwiseOr, " | ", null); + return builder; } @Override - public void visit(BitwiseXor bitwiseXor) { - visitBinaryExpression(bitwiseXor, " ^ "); + public StringBuilder visit(BitwiseXor bitwiseXor, S context) { + deparse(bitwiseXor, " ^ ", null); + return builder; } @Override - public void visit(CastExpression cast) { + public StringBuilder visit(CastExpression cast, S context) { if (cast.isImplicitCast()) { - buffer.append(cast.getColDataType()).append(" "); - cast.getLeftExpression().accept(this); + builder.append(cast.getColDataType()).append(" "); + cast.getLeftExpression().accept(this, context); } else if (cast.isUseCastKeyword()) { String formatStr = cast.getFormat() != null && !cast.getFormat().isEmpty() ? " FORMAT " + cast.getFormat() : ""; - buffer.append(cast.keyword).append("("); - cast.getLeftExpression().accept(this); - buffer.append(" AS "); - buffer.append( + builder.append(cast.keyword).append("("); + cast.getLeftExpression().accept(this, context); + builder.append(" AS "); + builder.append( cast.getColumnDefinitions().size() > 1 ? "ROW(" + Select.getStringList(cast.getColumnDefinitions()) + ")" : cast.getColDataType().toString()); - buffer.append(formatStr); - buffer.append(")"); + builder.append(formatStr); + builder.append(")"); } else { - cast.getLeftExpression().accept(this); - buffer.append("::"); - buffer.append(cast.getColDataType()); + cast.getLeftExpression().accept(this, context); + builder.append("::"); + builder.append(cast.getColDataType()); } + return builder; } @Override - public void visit(Modulo modulo) { - visitBinaryExpression(modulo, " % "); + public StringBuilder visit(Modulo modulo, S context) { + deparse(modulo, " % ", null); + return builder; } @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength", "PMD.MissingBreakInSwitch"}) - public void visit(AnalyticExpression aexpr) { - String name = aexpr.getName(); - Expression expression = aexpr.getExpression(); - Expression offset = aexpr.getOffset(); - Expression defaultValue = aexpr.getDefaultValue(); - boolean isAllColumns = aexpr.isAllColumns(); - KeepExpression keep = aexpr.getKeep(); - ExpressionList partitionExpressionList = aexpr.getPartitionExpressionList(); - List orderByElements = aexpr.getOrderByElements(); - WindowElement windowElement = aexpr.getWindowElement(); - - buffer.append(name).append("("); - if (aexpr.isDistinct()) { - buffer.append("DISTINCT "); - } - if (aexpr.isUnique()) { - buffer.append("UNIQUE "); + public StringBuilder visit(AnalyticExpression analyticExpression, S context) { + String name = analyticExpression.getName(); + Expression expression = analyticExpression.getExpression(); + Expression offset = analyticExpression.getOffset(); + Expression defaultValue = analyticExpression.getDefaultValue(); + boolean isAllColumns = analyticExpression.isAllColumns(); + KeepExpression keep = analyticExpression.getKeep(); + ExpressionList partitionExpressionList = analyticExpression.getPartitionExpressionList(); + List orderByElements = analyticExpression.getOrderByElements(); + WindowElement windowElement = analyticExpression.getWindowElement(); + + builder.append(name).append("("); + if (analyticExpression.isDistinct()) { + builder.append("DISTINCT "); + } + if (analyticExpression.isUnique()) { + builder.append("UNIQUE "); } if (expression != null) { - expression.accept(this); + expression.accept(this, context); if (offset != null) { - buffer.append(", "); - offset.accept(this); + builder.append(", "); + offset.accept(this, context); if (defaultValue != null) { - buffer.append(", "); - defaultValue.accept(this); + builder.append(", "); + defaultValue.accept(this, context); } } } else if (isAllColumns) { - buffer.append("*"); + builder.append("*"); } - Function.HavingClause havingClause = aexpr.getHavingClause(); + Function.HavingClause havingClause = analyticExpression.getHavingClause(); if (havingClause != null) { - buffer.append(" HAVING ").append(havingClause.getHavingType()).append(" "); - havingClause.getExpression().accept(this); + builder.append(" HAVING ").append(havingClause.getHavingType()).append(" "); + havingClause.getExpression().accept(this, context); } - if (aexpr.getNullHandling() != null && !aexpr.isIgnoreNullsOutside()) { - switch (aexpr.getNullHandling()) { + if (analyticExpression.getNullHandling() != null + && !analyticExpression.isIgnoreNullsOutside()) { + switch (analyticExpression.getNullHandling()) { case IGNORE_NULLS: - buffer.append(" IGNORE NULLS"); + builder.append(" IGNORE NULLS"); break; case RESPECT_NULLS: - buffer.append(" RESPECT NULLS"); + builder.append(" RESPECT NULLS"); break; } } - if (aexpr.getFuncOrderBy() != null) { - buffer.append(" ORDER BY "); - buffer.append(aexpr.getFuncOrderBy().stream().map(OrderByElement::toString) - .collect(joining(", "))); + if (analyticExpression.getFuncOrderBy() != null) { + builder.append(" ORDER BY "); + builder.append( + analyticExpression.getFuncOrderBy().stream().map(OrderByElement::toString) + .collect(joining(", "))); + } + + if (analyticExpression.getOnOverflowTruncate() != null) { + builder.append(" ON OVERFLOW ").append(analyticExpression.getOnOverflowTruncate()); } - if (aexpr.getLimit() != null) { - new LimitDeparser(this, buffer).deParse(aexpr.getLimit()); + if (analyticExpression.getLimit() != null) { + new LimitDeparser(this, builder).deParse(analyticExpression.getLimit()); } - buffer.append(") "); + builder.append(") "); if (keep != null) { - keep.accept(this); - buffer.append(" "); + keep.accept(this, context); + builder.append(" "); } - if (aexpr.getFilterExpression() != null) { - buffer.append("FILTER (WHERE "); - aexpr.getFilterExpression().accept(this); - buffer.append(")"); - if (aexpr.getType() != AnalyticType.FILTER_ONLY) { - buffer.append(" "); + if (analyticExpression.getFilterExpression() != null) { + builder.append("FILTER (WHERE "); + analyticExpression.getFilterExpression().accept(this, context); + builder.append(")"); + if (analyticExpression.getType() != AnalyticType.FILTER_ONLY) { + builder.append(" "); } } - if (aexpr.getNullHandling() != null && aexpr.isIgnoreNullsOutside()) { - switch (aexpr.getNullHandling()) { + if (analyticExpression.getNullHandling() != null + && analyticExpression.isIgnoreNullsOutside()) { + switch (analyticExpression.getNullHandling()) { case IGNORE_NULLS: - buffer.append(" IGNORE NULLS "); + builder.append(" IGNORE NULLS "); break; case RESPECT_NULLS: - buffer.append(" RESPECT NULLS "); + builder.append(" RESPECT NULLS "); break; } } - switch (aexpr.getType()) { + switch (analyticExpression.getType()) { case FILTER_ONLY: - return; + return null; case WITHIN_GROUP: - buffer.append("WITHIN GROUP"); + builder.append("WITHIN GROUP"); break; case WITHIN_GROUP_OVER: - buffer.append("WITHIN GROUP ("); - aexpr.getWindowDefinition().getOrderBy().toStringOrderByElements(buffer); - buffer.append(") OVER ("); - aexpr.getWindowDefinition().getPartitionBy().toStringPartitionBy(buffer); - buffer.append(")"); + builder.append("WITHIN GROUP ("); + analyticExpression.getWindowDefinition().getOrderBy() + .toStringOrderByElements(builder); + builder.append(") OVER ("); + analyticExpression.getWindowDefinition().getPartitionBy() + .toStringPartitionBy(builder); + builder.append(")"); break; default: - buffer.append("OVER"); + builder.append("OVER"); } - if (aexpr.getWindowName() != null) { - buffer.append(" ").append(aexpr.getWindowName()); - } else if (aexpr.getType() != AnalyticType.WITHIN_GROUP_OVER) { - buffer.append(" ("); + if (analyticExpression.getWindowName() != null) { + builder.append(" ").append(analyticExpression.getWindowName()); + } else if (analyticExpression.getType() != AnalyticType.WITHIN_GROUP_OVER) { + builder.append(" ("); if (partitionExpressionList != null - && !partitionExpressionList.getExpressions().isEmpty()) { - buffer.append("PARTITION BY "); - if (aexpr.isPartitionByBrackets()) { - buffer.append("("); + && !partitionExpressionList.isEmpty()) { + builder.append("PARTITION BY "); + if (analyticExpression.isPartitionByBrackets()) { + builder.append("("); } - List expressions = partitionExpressionList.getExpressions(); - for (int i = 0; i < expressions.size(); i++) { + for (int i = 0; i < ((List) partitionExpressionList).size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } - expressions.get(i).accept(this); + ((List) partitionExpressionList).get(i).accept(this, context); } - if (aexpr.isPartitionByBrackets()) { - buffer.append(")"); + if (analyticExpression.isPartitionByBrackets()) { + builder.append(")"); } - buffer.append(" "); + builder.append(" "); } if (orderByElements != null && !orderByElements.isEmpty()) { - buffer.append("ORDER BY "); + builder.append("ORDER BY "); orderByDeParser.setExpressionVisitor(this); - orderByDeParser.setBuffer(buffer); + orderByDeParser.setBuilder(builder); for (int i = 0; i < orderByElements.size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } orderByDeParser.deParseElement(orderByElements.get(i)); } @@ -919,364 +1290,595 @@ public void visit(AnalyticExpression aexpr) { if (windowElement != null) { if (orderByElements != null && !orderByElements.isEmpty()) { - buffer.append(' '); + builder.append(' '); } - buffer.append(windowElement); + builder.append(windowElement); } - buffer.append(")"); + builder.append(")"); } + return builder; } @Override - public void visit(ExtractExpression eexpr) { - buffer.append("EXTRACT(").append(eexpr.getName()); - buffer.append(" FROM "); - eexpr.getExpression().accept(this); - buffer.append(')'); + public StringBuilder visit(ExtractExpression extractExpression, S context) { + builder.append("EXTRACT(").append(extractExpression.getName()); + builder.append(" FROM "); + extractExpression.getExpression().accept(this, context); + builder.append(')'); + return builder; } @Override - public void visit(IntervalExpression intervalExpression) { + public StringBuilder visit(IntervalExpression intervalExpression, S context) { if (intervalExpression.isUsingIntervalKeyword()) { - buffer.append("INTERVAL "); + builder.append("INTERVAL "); } if (intervalExpression.getExpression() != null) { - intervalExpression.getExpression().accept(this); + intervalExpression.getExpression().accept(this, context); } else { - buffer.append(intervalExpression.getParameter()); + builder.append(intervalExpression.getParameter()); } if (intervalExpression.getIntervalType() != null) { - buffer.append(" ").append(intervalExpression.getIntervalType()); + builder.append(" ").append(intervalExpression.getIntervalType()); } + return builder; + } + + public void visit(Matches matches) { + visit(matches, null); + } + + public void visit(BitwiseAnd bitwiseAnd) { + visit(bitwiseAnd, null); + } + + public void visit(BitwiseOr bitwiseOr) { + visit(bitwiseOr, null); + } + + public void visit(BitwiseXor bitwiseXor) { + visit(bitwiseXor, null); + } + + public void visit(CastExpression cast) { + visit(cast, null); + } + + public void visit(AnalyticExpression analyticExpression) { + visit(analyticExpression, null); } + public void visit(ExtractExpression extractExpression) { + visit(extractExpression, null); + } + + public void visit(IntervalExpression intervalExpression) { + visit(intervalExpression, null); + } + + @Override - public void visit(JdbcNamedParameter jdbcNamedParameter) { - buffer.append(jdbcNamedParameter.toString()); + public StringBuilder visit(JdbcNamedParameter jdbcNamedParameter, S context) { + builder.append(jdbcNamedParameter.toString()); + return builder; } @Override - public void visit(OracleHierarchicalExpression oexpr) { - buffer.append(oexpr.toString()); + public StringBuilder visit(OracleHierarchicalExpression hierarchicalExpression, S context) { + builder.append(hierarchicalExpression.toString()); + return builder; } @Override - public void visit(RegExpMatchOperator rexpr) { - visitBinaryExpression(rexpr, " " + rexpr.getStringExpression() + " "); + public StringBuilder visit(RegExpMatchOperator regExpMatchOperator, S context) { + deparse(regExpMatchOperator, " " + regExpMatchOperator.getStringExpression() + " ", null); + return builder; } @Override - public void visit(JsonExpression jsonExpr) { - buffer.append(jsonExpr.toString()); + public StringBuilder visit(JsonExpression jsonExpr, S context) { + builder.append(jsonExpr.toString()); + return builder; } @Override - public void visit(JsonOperator jsonExpr) { - visitBinaryExpression(jsonExpr, " " + jsonExpr.getStringExpression() + " "); + public StringBuilder visit(JsonOperator jsonExpr, S context) { + deparse(jsonExpr, " " + jsonExpr.getStringExpression() + " ", null); + return builder; } @Override - public void visit(UserVariable var) { - buffer.append(var.toString()); + public StringBuilder visit(UserVariable var, S context) { + builder.append(var.toString()); + return builder; } @Override - public void visit(NumericBind bind) { - buffer.append(bind.toString()); + public StringBuilder visit(NumericBind bind, S context) { + builder.append(bind.toString()); + return builder; } @Override - public void visit(KeepExpression aexpr) { - buffer.append(aexpr.toString()); + public StringBuilder visit(KeepExpression keepExpression, S context) { + builder.append(keepExpression.toString()); + return builder; } @Override - public void visit(MySQLGroupConcat groupConcat) { - buffer.append(groupConcat.toString()); + public StringBuilder visit(MySQLGroupConcat groupConcat, S context) { + builder.append(groupConcat.toString()); + return builder; } @Override - public void visit(ExpressionList expressionList) { + public StringBuilder visit(ExpressionList expressionList, S context) { ExpressionListDeParser expressionListDeParser = - new ExpressionListDeParser<>(this, buffer); + new ExpressionListDeParser<>(this, builder); expressionListDeParser.deParse(expressionList); + return builder; } @Override - public void visit(RowConstructor rowConstructor) { + public StringBuilder visit(RowConstructor rowConstructor, S context) { if (rowConstructor.getName() != null) { - buffer.append(rowConstructor.getName()); + builder.append(rowConstructor.getName()); } ExpressionListDeParser expressionListDeParser = - new ExpressionListDeParser<>(this, buffer); + new ExpressionListDeParser<>(this, builder); expressionListDeParser.deParse(rowConstructor); + return builder; } @Override - public void visit(RowGetExpression rowGetExpression) { - rowGetExpression.getExpression().accept(this); - buffer.append(".").append(rowGetExpression.getColumnName()); + public StringBuilder visit(RowGetExpression rowGetExpression, S context) { + rowGetExpression.getExpression().accept(this, context); + builder.append(".").append(rowGetExpression.getColumnName()); + return null; } @Override - public void visit(OracleHint hint) { - buffer.append(hint.toString()); + public StringBuilder visit(OracleHint hint, S context) { + builder.append(hint.toString()); + return builder; } @Override - public void visit(TimeKeyExpression timeKeyExpression) { - buffer.append(timeKeyExpression.toString()); + public StringBuilder visit(TimeKeyExpression timeKeyExpression, S context) { + builder.append(timeKeyExpression.toString()); + return builder; } @Override - public void visit(DateTimeLiteralExpression literal) { - buffer.append(literal.toString()); + public StringBuilder visit(DateTimeLiteralExpression literal, S context) { + builder.append(literal.toString()); + return builder; } @Override - public void visit(NextValExpression nextVal) { - buffer.append(nextVal.isUsingNextValueFor() ? "NEXT VALUE FOR " : "NEXTVAL FOR ") + public StringBuilder visit(NextValExpression nextVal, S context) { + builder.append(nextVal.isUsingNextValueFor() ? "NEXT VALUE FOR " : "NEXTVAL FOR ") .append(nextVal.getName()); + return builder; } @Override - public void visit(CollateExpression col) { - buffer.append(col.getLeftExpression().toString()).append(" COLLATE ") + public StringBuilder visit(CollateExpression col, S context) { + builder.append(col.getLeftExpression().toString()).append(" COLLATE ") .append(col.getCollate()); + return builder; } @Override + public StringBuilder visit(SimilarToExpression expr, S context) { + deparse(expr, (expr.isNot() ? " NOT" : "") + " SIMILAR TO ", null); + return builder; + } + + public void visit(JdbcNamedParameter jdbcNamedParameter) { + visit(jdbcNamedParameter, null); + } + + public void visit(OracleHierarchicalExpression hierarchicalExpression) { + visit(hierarchicalExpression, null); + } + + public void visit(RegExpMatchOperator regExpMatchOperator) { + visit(regExpMatchOperator, null); + } + + public void visit(JsonExpression jsonExpr) { + visit(jsonExpr, null); + } + + public void visit(JsonOperator jsonExpr) { + visit(jsonExpr, null); + } + + public void visit(UserVariable userVariable) { + visit(userVariable, null); + } + + public void visit(NumericBind numericBind) { + visit(numericBind, null); + } + + public void visit(KeepExpression keepExpression) { + visit(keepExpression, null); + } + + public void visit(MySQLGroupConcat groupConcat) { + visit(groupConcat, null); + } + + public void visit(ExpressionList expressionList) { + visit(expressionList, null); + } + + public void visit(RowConstructor rowConstructor) { + visit(rowConstructor, null); + } + + public void visit(RowGetExpression rowGetExpression) { + visit(rowGetExpression, null); + } + + public void visit(OracleHint hint) { + visit(hint, null); + } + + public void visit(TimeKeyExpression timeKeyExpression) { + visit(timeKeyExpression, null); + } + + public void visit(DateTimeLiteralExpression literal) { + visit(literal, null); + } + + public void visit(NextValExpression nextVal) { + visit(nextVal, null); + } + + public void visit(CollateExpression col) { + visit(col, null); + } + public void visit(SimilarToExpression expr) { - visitBinaryExpression(expr, (expr.isNot() ? " NOT" : "") + " SIMILAR TO "); + visit(expr, null); + } + + public void visit(KeyExpression keyExpression) { + visit(keyExpression, null); } + @Override - public void visit(ArrayExpression array) { - array.getObjExpression().accept(this); - buffer.append("["); + public StringBuilder visit(ArrayExpression array, S context) { + array.getObjExpression().accept(this, context); + builder.append("["); if (array.getIndexExpression() != null) { - array.getIndexExpression().accept(this); + array.getIndexExpression().accept(this, context); } else { if (array.getStartIndexExpression() != null) { - array.getStartIndexExpression().accept(this); + array.getStartIndexExpression().accept(this, context); } - buffer.append(":"); + builder.append(":"); if (array.getStopIndexExpression() != null) { - array.getStopIndexExpression().accept(this); + array.getStopIndexExpression().accept(this, context); } } - buffer.append("]"); + builder.append("]"); + return builder; } @Override - public void visit(ArrayConstructor aThis) { - if (aThis.isArrayKeyword()) { - buffer.append("ARRAY"); + public StringBuilder visit(ArrayConstructor arrayConstructor, S context) { + if (arrayConstructor.isArrayKeyword()) { + builder.append("ARRAY"); + + ColDataType dataType = arrayConstructor.getDataType(); + if (dataType != null) { + builder.append("<").append(dataType).append(">"); + } } - buffer.append("["); + builder.append("["); boolean first = true; - for (Expression expression : aThis.getExpressions()) { + for (Expression expression : arrayConstructor.getExpressions()) { if (!first) { - buffer.append(", "); + builder.append(", "); } else { first = false; } - expression.accept(this); + expression.accept(this, context); } - buffer.append("]"); + builder.append("]"); + return builder; } @Override void deParse(Expression statement) { - statement.accept(this); + statement.accept(this, null); } @Override - public void visit(VariableAssignment var) { - var.getVariable().accept(this); - buffer.append(" ").append(var.getOperation()).append(" "); - var.getExpression().accept(this); + public StringBuilder visit(VariableAssignment var, S context) { + var.getVariable().accept(this, context); + builder.append(" ").append(var.getOperation()).append(" "); + var.getExpression().accept(this, context); + return builder; } @Override - public void visit(XMLSerializeExpr expr) { + public StringBuilder visit(XMLSerializeExpr expr, S context) { // xmlserialize(xmlagg(xmltext(COMMENT_LINE) ORDER BY COMMENT_SEQUENCE) as varchar(1024)) - buffer.append("xmlserialize(xmlagg(xmltext("); - expr.getExpression().accept(this); - buffer.append(")"); + builder.append("xmlserialize(xmlagg(xmltext("); + expr.getExpression().accept(this, context); + builder.append(")"); if (expr.getOrderByElements() != null) { - buffer.append(" ORDER BY "); + builder.append(" ORDER BY "); for (Iterator i = expr.getOrderByElements().iterator(); i.hasNext();) { - buffer.append(i.next().toString()); + builder.append(i.next().toString()); if (i.hasNext()) { - buffer.append(", "); + builder.append(", "); } } } - buffer.append(") AS ").append(expr.getDataType()).append(")"); + builder.append(") AS ").append(expr.getDataType()).append(")"); + return builder; } @Override - public void visit(TimezoneExpression var) { - var.getLeftExpression().accept(this); + public StringBuilder visit(TimezoneExpression var, S context) { + var.getLeftExpression().accept(this, context); for (Expression expr : var.getTimezoneExpressions()) { - buffer.append(" AT TIME ZONE "); - expr.accept(this); + builder.append(" AT TIME ZONE "); + expr.accept(this, context); } + return builder; + } + + @Override + public StringBuilder visit(JsonAggregateFunction expression, S context) { + expression.append(builder); + return builder; } @Override - public void visit(JsonAggregateFunction expression) { - expression.append(buffer); + public StringBuilder visit(JsonFunction expression, S context) { + expression.append(builder); + return builder; } @Override - public void visit(JsonFunction expression) { - expression.append(buffer); + public StringBuilder visit(JsonTableFunction expression, S context) { + builder.append(expression); + return builder; } @Override - public void visit(ConnectByRootOperator connectByRootOperator) { - buffer.append("CONNECT_BY_ROOT "); - connectByRootOperator.getColumn().accept(this); + public StringBuilder visit(ConnectByRootOperator connectByRootOperator, S context) { + builder.append("CONNECT_BY_ROOT "); + connectByRootOperator.getColumn().accept(this, context); + return builder; } @Override - public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) { - buffer.append(oracleNamedFunctionParameter.getName()).append(" => "); + public StringBuilder visit(ConnectByPriorOperator connectByPriorOperator, S context) { + builder.append("PRIOR "); + connectByPriorOperator.getColumn().accept(this, context); + return builder; + } + + @Override + public StringBuilder visit(KeyExpression keyExpression, S context) { + builder.append("KEY "); + keyExpression.getExpression().accept(this, context); + return builder; + } + + @Override + public StringBuilder visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, + S context) { + builder.append(oracleNamedFunctionParameter.getName()).append(" => "); - oracleNamedFunctionParameter.getExpression().accept(this); + oracleNamedFunctionParameter.getExpression().accept(this, context); + return builder; } @Override - public void visit(AllColumns allColumns) { - buffer.append(allColumns.toString()); + public StringBuilder visit(AllColumns allColumns, S context) { + builder.append(allColumns.toString()); + return builder; } @Override - public void visit(AllTableColumns allTableColumns) { - buffer.append(allTableColumns.toString()); + public StringBuilder visit(AllTableColumns allTableColumns, S context) { + builder.append(allTableColumns.toString()); + return builder; } @Override - public void visit(AllValue allValue) { - buffer.append(allValue); + public StringBuilder visit(FunctionAllColumns functionAllColumns, S context) { + builder.append(functionAllColumns.toString()); + return builder; } @Override - public void visit(IsDistinctExpression isDistinctExpression) { - buffer.append(isDistinctExpression.getLeftExpression()) + public StringBuilder visit(AllValue allValue, S context) { + builder.append(allValue); + return builder; + } + + @Override + public StringBuilder visit(IsDistinctExpression isDistinctExpression, S context) { + builder.append(isDistinctExpression.getLeftExpression()) .append(isDistinctExpression.getStringExpression()) .append(isDistinctExpression.getRightExpression()); + return builder; } @Override - public void visit(GeometryDistance geometryDistance) { - visitOldOracleJoinBinaryExpression(geometryDistance, - " " + geometryDistance.getStringExpression() + " "); + public StringBuilder visit(GeometryDistance geometryDistance, S context) { + deparse(geometryDistance, + " " + geometryDistance.getStringExpression() + " ", null); + return builder; } @Override - public void visit(TSQLLeftJoin tsqlLeftJoin) { - visitBinaryExpression(tsqlLeftJoin, " *= "); + public StringBuilder visit(TSQLLeftJoin tsqlLeftJoin, S context) { + this.deparse(tsqlLeftJoin, " *= ", null); + return builder; } @Override - public void visit(TSQLRightJoin tsqlRightJoin) { - visitBinaryExpression(tsqlRightJoin, " =* "); + public StringBuilder visit(TSQLRightJoin tsqlRightJoin, S context) { + this.deparse(tsqlRightJoin, " =* ", null); + return builder; } @Override - public void visit(StructType structType) { + public StringBuilder visit(StructType structType, S context) { if (structType.getDialect() != StructType.Dialect.DUCKDB && structType.getKeyword() != null) { - buffer.append(structType.getKeyword()); + builder.append(structType.getKeyword()); } if (structType.getDialect() != StructType.Dialect.DUCKDB && structType.getParameters() != null && !structType.getParameters().isEmpty()) { - buffer.append("<"); + builder.append("<"); int i = 0; for (Map.Entry e : structType.getParameters()) { if (0 < i++) { - buffer.append(","); + builder.append(","); } // optional name if (e.getKey() != null && !e.getKey().isEmpty()) { - buffer.append(e.getKey()).append(" "); + builder.append(e.getKey()).append(" "); } // mandatory type - buffer.append(e.getValue()); + builder.append(e.getValue()); } - buffer.append(">"); + builder.append(">"); } if (structType.getArguments() != null && !structType.getArguments().isEmpty()) { if (structType.getDialect() == StructType.Dialect.DUCKDB) { - buffer.append("{ "); + builder.append("{ "); int i = 0; for (SelectItem e : structType.getArguments()) { if (0 < i++) { - buffer.append(","); + builder.append(","); } - buffer.append(e.getAlias().getName()); - buffer.append(" : "); - e.getExpression().accept(this); + builder.append(e.getAlias().getName()); + builder.append(" : "); + e.getExpression().accept(this, context); } - buffer.append(" }"); + builder.append(" }"); } else { - buffer.append("("); + builder.append("("); int i = 0; for (SelectItem e : structType.getArguments()) { if (0 < i++) { - buffer.append(","); + builder.append(","); } - e.getExpression().accept(this); + e.getExpression().accept(this, context); if (e.getAlias() != null) { - buffer.append(" as "); - buffer.append(e.getAlias().getName()); + builder.append(" as "); + builder.append(e.getAlias().getName()); } } - buffer.append(")"); + builder.append(")"); } } if (structType.getDialect() == StructType.Dialect.DUCKDB && structType.getParameters() != null && !structType.getParameters().isEmpty()) { - buffer.append("::STRUCT( "); + builder.append("::STRUCT( "); int i = 0; for (Map.Entry e : structType.getParameters()) { if (0 < i++) { - buffer.append(","); + builder.append(","); } - buffer.append(e.getKey()).append(" "); - buffer.append(e.getValue()); + builder.append(e.getKey()).append(" "); + builder.append(e.getValue()); } - buffer.append(")"); + builder.append(")"); } + return builder; } @Override - public void visit(LambdaExpression lambdaExpression) { + public StringBuilder visit(LambdaExpression lambdaExpression, S context) { if (lambdaExpression.getIdentifiers().size() == 1) { - buffer.append(lambdaExpression.getIdentifiers().get(0)); + builder.append(lambdaExpression.getIdentifiers().get(0)); } else { int i = 0; - buffer.append("( "); + builder.append("( "); for (String s : lambdaExpression.getIdentifiers()) { - buffer.append(i++ > 0 ? ", " : "").append(s); + builder.append(i++ > 0 ? ", " : "").append(s); } - buffer.append(" )"); + builder.append(" )"); } - buffer.append(" -> "); - lambdaExpression.getExpression().accept(this); + builder.append(" -> "); + lambdaExpression.getExpression().accept(this, context); + return builder; + } + + @Override + public StringBuilder visit(HighExpression highExpression, S context) { + return builder.append(highExpression.toString()); + } + + @Override + public StringBuilder visit(LowExpression lowExpression, S context) { + return builder.append(lowExpression.toString()); + } + + @Override + public StringBuilder visit(Plus plus, S context) { + return builder.append(plus.toString()); + } + + @Override + public StringBuilder visit(PriorTo priorTo, S context) { + return builder.append(priorTo.toString()); + } + + @Override + public StringBuilder visit(Inverse inverse, S context) { + return builder.append(inverse.toString()); + } + + @Override + public StringBuilder visit(CosineSimilarity cosineSimilarity, S context) { + deparse(cosineSimilarity, + " " + cosineSimilarity.getStringExpression() + " ", context); + return builder; + } + + @Override + public StringBuilder visit(FromQuery fromQuery, S context) { + return null; + } + + @Override + public StringBuilder visit(DateUnitExpression dateUnitExpression, S context) { + return builder.append(dateUnitExpression.toString()); } + @Override + public StringBuilder visit(PostgresNamedFunctionParameter postgresNamedFunctionParameter, + S context) { + builder.append(postgresNamedFunctionParameter.getName()).append(" := "); + + postgresNamedFunctionParameter.getExpression().accept(this, context); + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionListDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionListDeParser.java index f13066ff2..62b4c829b 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionListDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionListDeParser.java @@ -21,9 +21,10 @@ public class ExpressionListDeParser extends AbstractDeParser> { - private final ExpressionVisitor expressionVisitor; + private final ExpressionVisitor expressionVisitor; - public ExpressionListDeParser(ExpressionVisitor expressionVisitor, StringBuilder builder) { + public ExpressionListDeParser(ExpressionVisitor expressionVisitor, + StringBuilder builder) { super(builder); this.expressionVisitor = expressionVisitor; } @@ -36,32 +37,30 @@ public void deParse(ExpressionList expressionList) { : ", "; // @todo: remove this NameExpressionList related part List names = expressionList instanceof NamedExpressionList - ? ((NamedExpressionList) expressionList).getNames() + ? ((NamedExpressionList) expressionList).getNames() : Collections.nCopies(expressionList.size(), ""); - if (expressionList != null) { - if (expressionList instanceof ParenthesedExpressionList) { - buffer.append("("); + if (expressionList instanceof ParenthesedExpressionList) { + builder.append("("); + } + int i = 0; + for (Expression expression : expressionList) { + if (i > 0) { + builder.append(comma); } - int i = 0; - for (Expression expression : expressionList) { - if (i > 0) { - buffer.append(comma); - } - // @todo: remove this NameExpressionList related part - String name = names.get(i); - if (!name.equals("")) { - buffer.append(name); - buffer.append(" "); - } - expression.accept(expressionVisitor); - i++; + // @todo: remove this NameExpressionList related part + String name = names.get(i); + if (!name.isEmpty()) { + builder.append(name); + builder.append(" "); } + expression.accept(expressionVisitor, null); + i++; + } - if (expressionList instanceof ParenthesedExpressionList) { - buffer.append(")"); - } + if (expressionList instanceof ParenthesedExpressionList) { + builder.append(")"); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/GrantDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/GrantDeParser.java index 212409e99..4a0f997f6 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/GrantDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/GrantDeParser.java @@ -21,26 +21,26 @@ public GrantDeParser(StringBuilder buffer) { @Override public void deParse(Grant grant) { - buffer.append("GRANT "); + builder.append("GRANT "); if (grant.getRole() != null) { - buffer.append(grant.getRole()); + builder.append(grant.getRole()); } else { for (Iterator iter = grant.getPrivileges().iterator(); iter.hasNext();) { String privilege = iter.next(); - buffer.append(privilege); + builder.append(privilege); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } - buffer.append(" ON "); - buffer.append(grant.getObjectName()); + builder.append(" ON "); + builder.append(grant.getObjectName()); } - buffer.append(" TO "); + builder.append(" TO "); for (Iterator iter = grant.getUsers().iterator(); iter.hasNext();) { String user = iter.next(); - buffer.append(user); + builder.append(user); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java index 694a97d38..fc20bd4cd 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java @@ -15,39 +15,36 @@ public class GroupByDeParser extends AbstractDeParser { - private ExpressionListDeParser expressionListDeParser; + private final ExpressionListDeParser expressionListDeParser; - GroupByDeParser() { - this(null, new StringBuilder()); - } - - public GroupByDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public GroupByDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); - this.expressionListDeParser = new ExpressionListDeParser(expressionVisitor, buffer); - this.buffer = buffer; + this.expressionListDeParser = new ExpressionListDeParser<>(expressionVisitor, buffer); + this.builder = buffer; } @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(GroupByElement groupBy) { - buffer.append("GROUP BY "); + builder.append("GROUP BY "); expressionListDeParser.deParse(groupBy.getGroupByExpressionList()); int i = 0; if (!groupBy.getGroupingSets().isEmpty()) { - if (buffer.charAt(buffer.length() - 1) != ' ') { - buffer.append(' '); + if (builder.charAt(builder.length() - 1) != ' ') { + builder.append(' '); } - buffer.append("GROUPING SETS ("); - for (ExpressionList expressionList : groupBy.getGroupingSets()) { - buffer.append(i++ > 0 ? ", " : ""); + builder.append("GROUPING SETS ("); + for (ExpressionList expressionList : groupBy.getGroupingSets()) { + builder.append(i++ > 0 ? ", " : ""); expressionListDeParser.deParse(expressionList); } - buffer.append(")"); + builder.append(")"); } if (groupBy.isMysqlWithRollup()) { - buffer.append(" WITH ROLLUP"); + builder.append(" WITH ROLLUP"); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java index dec9f6c0a..901e32865 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java @@ -9,26 +9,29 @@ */ package net.sf.jsqlparser.util.deparser; +import java.util.Iterator; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Partition; +import net.sf.jsqlparser.statement.insert.ConflictActionType; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.OracleMultiInsertBranch; +import net.sf.jsqlparser.statement.insert.OracleMultiInsertClause; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.select.WithItem; -import java.util.Iterator; - public class InsertDeParser extends AbstractDeParser { - private ExpressionVisitor expressionVisitor; - private SelectVisitor selectVisitor; + private ExpressionVisitor expressionVisitor; + private SelectVisitor selectVisitor; public InsertDeParser() { super(new StringBuilder()); } - public InsertDeParser(ExpressionVisitor expressionVisitor, SelectVisitor selectVisitor, - StringBuilder buffer) { + public InsertDeParser(ExpressionVisitor expressionVisitor, + SelectVisitor selectVisitor, StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; this.selectVisitor = selectVisitor; @@ -39,90 +42,176 @@ public InsertDeParser(ExpressionVisitor expressionVisitor, SelectVisitor selectV "PMD.NPathComplexity"}) public void deParse(Insert insert) { if (insert.getWithItemsList() != null && !insert.getWithItemsList().isEmpty()) { - buffer.append("WITH "); - for (Iterator iter = insert.getWithItemsList().iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); - withItem.accept(this.selectVisitor); + builder.append("WITH "); + for (Iterator> iter = insert.getWithItemsList().iterator(); iter + .hasNext();) { + WithItem withItem = iter.next(); + withItem.accept(this.selectVisitor, null); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("INSERT "); + builder.append("INSERT "); if (insert.getModifierPriority() != null) { - buffer.append(insert.getModifierPriority()).append(" "); + builder.append(insert.getModifierPriority()).append(" "); } if (insert.getOracleHint() != null) { - buffer.append(insert.getOracleHint()).append(" "); + builder.append(insert.getOracleHint()).append(" "); } if (insert.isModifierIgnore()) { - buffer.append("IGNORE "); + builder.append("IGNORE "); + } + if (insert.isOracleMultiInsert()) { + builder.append(insert.isOracleMultiInsertFirst() ? "FIRST" : "ALL"); + if (insert.getOracleMultiInsertBranches() != null) { + for (OracleMultiInsertBranch branch : insert.getOracleMultiInsertBranches()) { + appendOracleMultiInsertBranch(branch); + } + } + if (insert.getSelect() != null) { + builder.append(" "); + insert.getSelect().accept(selectVisitor, null); + } + return; + } + if (insert.isOverwrite()) { + builder.append("OVERWRITE "); + } else { + builder.append("INTO "); + } + if (insert.isTableKeyword()) { + builder.append("TABLE "); + } + + builder.append(insert.getTable().toString()); + + if (insert.isOnlyDefaultValues()) { + builder.append(" DEFAULT VALUES"); } - buffer.append("INTO "); - buffer.append(insert.getTable().toString()); if (insert.getColumns() != null) { - buffer.append(" ("); + builder.append(" ("); for (Iterator iter = insert.getColumns().iterator(); iter.hasNext();) { Column column = iter.next(); - buffer.append(column.getColumnName()); + builder.append(column.getColumnName()); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } - buffer.append(")"); + builder.append(")"); + } + + if (insert.isOverriding()) { + builder.append("OVERRIDING SYSTEM VALUE "); + } + + if (insert.getPartitions() != null) { + builder.append(" PARTITION ("); + Partition.appendPartitionsTo(builder, insert.getPartitions()); + builder.append(")"); } if (insert.getOutputClause() != null) { - buffer.append(insert.getOutputClause().toString()); + builder.append(insert.getOutputClause().toString()); } if (insert.getSelect() != null) { - buffer.append(" "); + builder.append(" "); Select select = insert.getSelect(); - select.accept(selectVisitor); + select.accept(selectVisitor, null); } if (insert.getSetUpdateSets() != null) { - buffer.append(" SET "); - deparseUpdateSets(insert.getSetUpdateSets(), buffer, expressionVisitor); + builder.append(" SET "); + deparseUpdateSets(insert.getSetUpdateSets(), builder, expressionVisitor); + if (insert.getRowAlias() != null) { + builder.append(" ").append(insert.getRowAlias()); + } } - if (insert.getDuplicateUpdateSets() != null) { - buffer.append(" ON DUPLICATE KEY UPDATE "); - deparseUpdateSets(insert.getDuplicateUpdateSets(), buffer, expressionVisitor); + if (insert.getDuplicateAction() != null) { + builder.append(" ON DUPLICATE KEY UPDATE "); + if (ConflictActionType.DO_UPDATE + .equals(insert.getDuplicateAction().getConflictActionType())) { + deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor); + } else { + insert.getDuplicateAction().appendTo(builder); + } } // @todo: Accept some Visitors for the involved Expressions if (insert.getConflictAction() != null) { - buffer.append(" ON CONFLICT"); + builder.append(" ON CONFLICT"); if (insert.getConflictTarget() != null) { - insert.getConflictTarget().appendTo(buffer); + insert.getConflictTarget().appendTo(builder); } - insert.getConflictAction().appendTo(buffer); + insert.getConflictAction().appendTo(builder); } if (insert.getReturningClause() != null) { - insert.getReturningClause().appendTo(buffer); + insert.getReturningClause().appendTo(builder); } } - public ExpressionVisitor getExpressionVisitor() { + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public SelectVisitor getSelectVisitor() { - return selectVisitor; + public void setExpressionVisitor(ExpressionVisitor visitor) { + expressionVisitor = visitor; } - public void setExpressionVisitor(ExpressionVisitor visitor) { - expressionVisitor = visitor; + public SelectVisitor getSelectVisitor() { + return selectVisitor; } - public void setSelectVisitor(SelectVisitor visitor) { + public void setSelectVisitor(SelectVisitor visitor) { selectVisitor = visitor; } + + private void appendOracleIntoClause(OracleMultiInsertClause clause) { + builder.append("INTO ").append(clause.getTable().toString()); + if (clause.getColumns() != null && !clause.getColumns().isEmpty()) { + builder.append(" ("); + for (Iterator iter = clause.getColumns().iterator(); iter.hasNext();) { + Column column = iter.next(); + builder.append(column.getColumnName()); + if (iter.hasNext()) { + builder.append(", "); + } + } + builder.append(")"); + } + if (clause.getSelect() != null) { + builder.append(" "); + clause.getSelect().accept(selectVisitor, null); + } + } + + private void appendOracleMultiInsertBranch(OracleMultiInsertBranch branch) { + if (branch == null || branch.getClauses() == null || branch.getClauses().isEmpty()) { + return; + } + + if (branch.getWhenExpression() != null) { + builder.append(" WHEN "); + if (expressionVisitor != null) { + branch.getWhenExpression().accept(expressionVisitor, null); + } else { + builder.append(branch.getWhenExpression().toString()); + } + builder.append(" THEN"); + } else if (branch.isElseClause()) { + builder.append(" ELSE"); + } + + for (OracleMultiInsertClause clause : branch.getClauses()) { + builder.append(" "); + appendOracleIntoClause(clause); + } + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/LimitDeparser.java b/src/main/java/net/sf/jsqlparser/util/deparser/LimitDeparser.java index 88aec177d..ff6b6dbf0 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/LimitDeparser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/LimitDeparser.java @@ -13,44 +13,44 @@ import net.sf.jsqlparser.statement.select.Limit; public class LimitDeparser extends AbstractDeParser { - private ExpressionVisitor expressionVisitor; + private ExpressionVisitor expressionVisitor; - public LimitDeparser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public LimitDeparser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @Override public void deParse(Limit limit) { - buffer.append(" LIMIT "); + builder.append(" LIMIT "); if (limit.isLimitNull()) { - buffer.append("NULL"); + builder.append("NULL"); } else { if (limit.isLimitAll()) { - buffer.append("ALL"); + builder.append("ALL"); } else { if (null != limit.getOffset()) { - limit.getOffset().accept(expressionVisitor); - buffer.append(", "); + limit.getOffset().accept(expressionVisitor, null); + builder.append(", "); } if (null != limit.getRowCount()) { - limit.getRowCount().accept(expressionVisitor); + limit.getRowCount().accept(expressionVisitor, null); } } } if (limit.getByExpressions() != null) { - buffer.append(" BY "); - limit.getByExpressions().accept(expressionVisitor); + builder.append(" BY "); + limit.getByExpressions().accept(expressionVisitor, null); } } - public ExpressionVisitor getExpressionVisitor() { + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public void setExpressionVisitor(ExpressionVisitor expressionVisitor) { + public void setExpressionVisitor(ExpressionVisitor expressionVisitor) { this.expressionVisitor = expressionVisitor; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java index dfcf83399..5ce81c2dd 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java @@ -15,7 +15,8 @@ import java.util.Iterator; import java.util.List; -public class MergeDeParser extends AbstractDeParser implements MergeOperationVisitor { +public class MergeDeParser extends AbstractDeParser + implements MergeOperationVisitor { private final ExpressionDeParser expressionDeParser; private final SelectDeParser selectDeParser; @@ -28,91 +29,115 @@ public MergeDeParser(ExpressionDeParser expressionDeParser, SelectDeParser selec } @Override - void deParse(Merge merge) { - List withItemsList = merge.getWithItemsList(); + public void deParse(Merge merge) { + List> withItemsList = merge.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - iter.next().accept(expressionDeParser); + builder.append("WITH "); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + iter.next().accept(selectDeParser, null); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("MERGE "); + builder.append("MERGE "); if (merge.getOracleHint() != null) { - buffer.append(merge.getOracleHint()).append(" "); + builder.append(merge.getOracleHint()).append(" "); } - buffer.append("INTO "); - merge.getTable().accept(selectDeParser); + builder.append("INTO "); + merge.getTable().accept(selectDeParser, null); - buffer.append(" USING "); - merge.getFromItem().accept(selectDeParser); + builder.append(" USING "); + merge.getFromItem().accept(selectDeParser, null); - buffer.append(" ON "); - merge.getOnCondition().accept(expressionDeParser); + builder.append(" ON "); + merge.getOnCondition().accept(expressionDeParser, null); List operations = merge.getOperations(); if (operations != null && !operations.isEmpty()) { - operations.forEach(operation -> operation.accept(this)); + operations.forEach(operation -> operation.accept(this, null)); } if (merge.getOutputClause() != null) { - merge.getOutputClause().appendTo(buffer); + merge.getOutputClause().appendTo(builder); } } @Override - public void visit(MergeDelete mergeDelete) { - buffer.append(" WHEN MATCHED"); + public StringBuilder visit(MergeDelete mergeDelete, S context) { + builder.append(" WHEN MATCHED"); if (mergeDelete.getAndPredicate() != null) { - buffer.append(" AND "); - mergeDelete.getAndPredicate().accept(expressionDeParser); + builder.append(" AND "); + mergeDelete.getAndPredicate().accept(expressionDeParser, context); } - buffer.append(" THEN DELETE"); + builder.append(" THEN DELETE"); + return builder; + } + + public void visit(MergeDelete mergeDelete) { + visit(mergeDelete, null); } @Override - public void visit(MergeUpdate mergeUpdate) { - buffer.append(" WHEN MATCHED"); + public StringBuilder visit(MergeUpdate mergeUpdate, S context) { + builder.append(" WHEN MATCHED"); if (mergeUpdate.getAndPredicate() != null) { - buffer.append(" AND "); - mergeUpdate.getAndPredicate().accept(expressionDeParser); + builder.append(" AND "); + mergeUpdate.getAndPredicate().accept(expressionDeParser, context); } - buffer.append(" THEN UPDATE SET "); - deparseUpdateSets(mergeUpdate.getUpdateSets(), buffer, expressionDeParser); + builder.append(" THEN UPDATE SET "); + deparseUpdateSets(mergeUpdate.getUpdateSets(), builder, expressionDeParser); if (mergeUpdate.getWhereCondition() != null) { - buffer.append(" WHERE "); - mergeUpdate.getWhereCondition().accept(expressionDeParser); + builder.append(" WHERE "); + mergeUpdate.getWhereCondition().accept(expressionDeParser, context); } if (mergeUpdate.getDeleteWhereCondition() != null) { - buffer.append(" DELETE WHERE "); - mergeUpdate.getDeleteWhereCondition().accept(expressionDeParser); + builder.append(" DELETE WHERE "); + mergeUpdate.getDeleteWhereCondition().accept(expressionDeParser, context); } + + return builder; + } + + public void visit(MergeUpdate mergeUpdate) { + visit(mergeUpdate, null); } @Override - public void visit(MergeInsert mergeInsert) { - buffer.append(" WHEN NOT MATCHED"); + public StringBuilder visit(MergeInsert mergeInsert, S context) { + builder.append(" WHEN NOT MATCHED"); if (mergeInsert.getAndPredicate() != null) { - buffer.append(" AND "); - mergeInsert.getAndPredicate().accept(expressionDeParser); + builder.append(" AND "); + mergeInsert.getAndPredicate().accept(expressionDeParser, context); } - buffer.append(" THEN INSERT "); + builder.append(" THEN INSERT "); if (mergeInsert.getColumns() != null) { - mergeInsert.getColumns().accept(expressionDeParser); + mergeInsert.getColumns().accept(expressionDeParser, context); } - buffer.append(" VALUES "); - mergeInsert.getValues().accept(expressionDeParser); + builder.append(" VALUES "); + mergeInsert.getValues().accept(expressionDeParser, context); if (mergeInsert.getWhereCondition() != null) { - buffer.append(" WHERE "); - mergeInsert.getWhereCondition().accept(expressionDeParser); + builder.append(" WHERE "); + mergeInsert.getWhereCondition().accept(expressionDeParser, context); } + + return builder; + } + + public void visit(MergeInsert mergeInsert) { + visit(mergeInsert, null); + } + + public ExpressionDeParser getExpressionDeParser() { + return expressionDeParser; } + public SelectDeParser getSelectDeParser() { + return selectDeParser; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java index 8eb137051..605c54dc2 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java @@ -11,18 +11,20 @@ import java.util.Iterator; import java.util.List; + import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.statement.select.OrderByElement; public class OrderByDeParser extends AbstractDeParser> { - private ExpressionVisitor expressionVisitor; + private ExpressionVisitor expressionVisitor; OrderByDeParser() { super(new StringBuilder()); } - public OrderByDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public OrderByDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @@ -34,39 +36,40 @@ public void deParse(List orderByElementList) { public void deParse(boolean oracleSiblings, List orderByElementList) { if (oracleSiblings) { - buffer.append(" ORDER SIBLINGS BY "); + builder.append(" ORDER SIBLINGS BY "); } else { - buffer.append(" ORDER BY "); + builder.append(" ORDER BY "); } - for (Iterator iter = orderByElementList.iterator(); iter.hasNext();) { - OrderByElement orderByElement = iter.next(); + for (Iterator iterator = orderByElementList.iterator(); iterator + .hasNext();) { + OrderByElement orderByElement = iterator.next(); deParseElement(orderByElement); - if (iter.hasNext()) { - buffer.append(", "); + if (iterator.hasNext()) { + builder.append(", "); } } } public void deParseElement(OrderByElement orderBy) { - orderBy.getExpression().accept(expressionVisitor); + orderBy.getExpression().accept(expressionVisitor, null); if (!orderBy.isAsc()) { - buffer.append(" DESC"); + builder.append(" DESC"); } else if (orderBy.isAscDescPresent()) { - buffer.append(" ASC"); + builder.append(" ASC"); } if (orderBy.getNullOrdering() != null) { - buffer.append(' '); - buffer.append(orderBy.getNullOrdering() == OrderByElement.NullOrdering.NULLS_FIRST + builder.append(' '); + builder.append(orderBy.getNullOrdering() == OrderByElement.NullOrdering.NULLS_FIRST ? "NULLS FIRST" : "NULLS LAST"); } if (orderBy.isMysqlWithRollup()) { - buffer.append(" WITH ROLLUP"); + builder.append(" WITH ROLLUP"); } } - void setExpressionVisitor(ExpressionVisitor expressionVisitor) { + void setExpressionVisitor(ExpressionVisitor expressionVisitor) { this.expressionVisitor = expressionVisitor; } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/RefreshMaterializedViewStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/RefreshMaterializedViewStatementDeParser.java index 0646a65fe..444279ee6 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/RefreshMaterializedViewStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/RefreshMaterializedViewStatementDeParser.java @@ -25,26 +25,26 @@ public RefreshMaterializedViewStatementDeParser(StringBuilder buffer) { @SuppressWarnings("PMD.SwitchStmtsShouldHaveDefault") @Override public void deParse(RefreshMaterializedViewStatement view) { - buffer.append("REFRESH MATERIALIZED VIEW "); + builder.append("REFRESH MATERIALIZED VIEW "); if (view.getRefreshMode() == null) { if (view.isConcurrently()) { - buffer.append("CONCURRENTLY "); + builder.append("CONCURRENTLY "); } - buffer.append(view.getView()); + builder.append(view.getView()); return; } switch (view.getRefreshMode()) { case WITH_DATA: if (view.isConcurrently()) { - buffer.append("CONCURRENTLY "); + builder.append("CONCURRENTLY "); } - buffer.append(view.getView()); - buffer.append(" WITH DATA"); + builder.append(view.getView()); + builder.append(" WITH DATA"); break; case WITH_NO_DATA: - buffer.append(view.getView()); + builder.append(view.getView()); if (view.isConcurrently()) { - buffer.append(" WITH NO DATA"); + builder.append(" WITH NO DATA"); } break; } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ResetStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ResetStatementDeParser.java index 9f566d93e..22eaca518 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ResetStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ResetStatementDeParser.java @@ -14,24 +14,25 @@ public class ResetStatementDeParser extends AbstractDeParser { - private ExpressionVisitor expressionVisitor; + private ExpressionVisitor expressionVisitor; - public ResetStatementDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public ResetStatementDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @Override public void deParse(ResetStatement set) { - buffer.append("RESET "); - buffer.append(set.getName()); + builder.append("RESET "); + builder.append(set.getName()); } - public ExpressionVisitor getExpressionVisitor() { + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public void setExpressionVisitor(ExpressionVisitor visitor) { + public void setExpressionVisitor(ExpressionVisitor visitor) { expressionVisitor = visitor; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index fba4cdc76..69f9412ac 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -9,6 +9,13 @@ */ package net.sf.jsqlparser.util.deparser; +import static java.util.stream.Collectors.joining; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; @@ -18,6 +25,28 @@ import net.sf.jsqlparser.expression.WindowDefinition; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.Import; +import net.sf.jsqlparser.statement.piped.AggregatePipeOperator; +import net.sf.jsqlparser.statement.piped.AsPipeOperator; +import net.sf.jsqlparser.statement.piped.CallPipeOperator; +import net.sf.jsqlparser.statement.piped.DropPipeOperator; +import net.sf.jsqlparser.statement.piped.ExtendPipeOperator; +import net.sf.jsqlparser.statement.piped.FromQuery; +import net.sf.jsqlparser.statement.piped.JoinPipeOperator; +import net.sf.jsqlparser.statement.piped.LimitPipeOperator; +import net.sf.jsqlparser.statement.piped.OrderByPipeOperator; +import net.sf.jsqlparser.statement.piped.PipeOperator; +import net.sf.jsqlparser.statement.piped.PipeOperatorVisitor; +import net.sf.jsqlparser.statement.piped.PivotPipeOperator; +import net.sf.jsqlparser.statement.piped.RenamePipeOperator; +import net.sf.jsqlparser.statement.piped.SelectPipeOperator; +import net.sf.jsqlparser.statement.piped.SetOperationPipeOperator; +import net.sf.jsqlparser.statement.piped.SetPipeOperator; +import net.sf.jsqlparser.statement.piped.TableSamplePipeOperator; +import net.sf.jsqlparser.statement.piped.UnPivotPipeOperator; +import net.sf.jsqlparser.statement.piped.WherePipeOperator; +import net.sf.jsqlparser.statement.piped.WindowPipeOperator; +import net.sf.jsqlparser.statement.select.Distinct; import net.sf.jsqlparser.statement.select.Fetch; import net.sf.jsqlparser.statement.select.First; import net.sf.jsqlparser.statement.select.FromItem; @@ -25,14 +54,18 @@ import net.sf.jsqlparser.statement.select.Join; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.LateralView; +import net.sf.jsqlparser.statement.select.MySqlSelectIntoClause; import net.sf.jsqlparser.statement.select.Offset; import net.sf.jsqlparser.statement.select.OptimizeFor; +import net.sf.jsqlparser.statement.select.OrderByElement; import net.sf.jsqlparser.statement.select.ParenthesedFromItem; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.Pivot; import net.sf.jsqlparser.statement.select.PivotVisitor; import net.sf.jsqlparser.statement.select.PivotXml; import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SampleClause; +import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.statement.select.SelectItemVisitor; import net.sf.jsqlparser.statement.select.SelectVisitor; @@ -44,17 +77,15 @@ import net.sf.jsqlparser.statement.select.UnPivot; import net.sf.jsqlparser.statement.select.Values; import net.sf.jsqlparser.statement.select.WithItem; - -import java.util.Iterator; -import java.util.List; - -import static java.util.stream.Collectors.joining; +import net.sf.jsqlparser.statement.update.UpdateSet; @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) -public class SelectDeParser extends AbstractDeParser implements SelectVisitor, - SelectItemVisitor, FromItemVisitor, PivotVisitor { +public class SelectDeParser extends AbstractDeParser + implements SelectVisitor, SelectItemVisitor, + FromItemVisitor, PivotVisitor, + PipeOperatorVisitor { - private ExpressionVisitor expressionVisitor; + private ExpressionVisitor expressionVisitor; public SelectDeParser() { this(new StringBuilder()); @@ -65,118 +96,134 @@ public SelectDeParser(StringBuilder buffer) { this.expressionVisitor = new ExpressionDeParser(this, buffer); } - public SelectDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public SelectDeParser(Class expressionDeparserClass, + StringBuilder builder) throws NoSuchMethodException, InvocationTargetException, + InstantiationException, IllegalAccessException { + super(builder); + this.expressionVisitor = + expressionDeparserClass.getConstructor(SelectDeParser.class, StringBuilder.class) + .newInstance(this, builder); + } + + public SelectDeParser(Class expressionDeparserClass) + throws NoSuchMethodException, InvocationTargetException, InstantiationException, + IllegalAccessException { + this(expressionDeparserClass, new StringBuilder()); + } + + + public SelectDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @Override - public void visit(ParenthesedSelect selectBody) { - List withItemsList = selectBody.getWithItemsList(); + public StringBuilder visit(ParenthesedSelect select, S context) { + List> withItemsList = select.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); - for (WithItem withItem : withItemsList) { - withItem.accept((SelectVisitor) this); - buffer.append(" "); + builder.append("WITH "); + for (WithItem withItem : withItemsList) { + withItem.accept((SelectVisitor) this, context); + builder.append(" "); } } - buffer.append("("); - selectBody.getSelect().accept((SelectVisitor) this); - buffer.append(")"); + builder.append("("); + select.getSelect().accept((SelectVisitor) this, context); + builder.append(")"); - if (selectBody.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(selectBody.isOracleSiblings(), - selectBody.getOrderByElements()); + if (select.getOrderByElements() != null) { + new OrderByDeParser(expressionVisitor, builder).deParse(select.isOracleSiblings(), + select.getOrderByElements()); } - Alias alias = selectBody.getAlias(); + Alias alias = select.getAlias(); if (alias != null) { - buffer.append(alias); + builder.append(alias); + } + + SampleClause sampleClause = select.getSampleClause(); + if (sampleClause != null) { + builder.append(sampleClause); } - Pivot pivot = selectBody.getPivot(); + + Pivot pivot = select.getPivot(); if (pivot != null) { - pivot.accept(this); + pivot.accept(this, context); } - UnPivot unpivot = selectBody.getUnPivot(); + UnPivot unpivot = select.getUnPivot(); if (unpivot != null) { - unpivot.accept(this); + unpivot.accept(this, context); } - if (selectBody.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(selectBody.getLimit()); + if (select.getLimit() != null) { + new LimitDeparser(expressionVisitor, builder).deParse(select.getLimit()); } - if (selectBody.getOffset() != null) { - visit(selectBody.getOffset()); + if (select.getOffset() != null) { + visit(select.getOffset()); } - if (selectBody.getFetch() != null) { - visit(selectBody.getFetch()); + if (select.getFetch() != null) { + visit(select.getFetch()); } - if (selectBody.getIsolation() != null) { - buffer.append(selectBody.getIsolation().toString()); + if (select.getIsolation() != null) { + builder.append(select.getIsolation().toString()); } + return builder; } public void visit(Top top) { - buffer.append(top).append(" "); + builder.append(top).append(" "); } @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength", "PMD.NPathComplexity"}) - public void visit(PlainSelect plainSelect) { - List withItemsList = plainSelect.getWithItemsList(); + public StringBuilder visit(PlainSelect plainSelect, S context) { + List> withItemsList = plainSelect.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - iter.next().accept((SelectVisitor) this); + builder.append("WITH "); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + iter.next().accept((SelectVisitor) this, context); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("SELECT "); + builder.append("SELECT "); if (plainSelect.getMySqlHintStraightJoin()) { - buffer.append("STRAIGHT_JOIN "); + builder.append("STRAIGHT_JOIN "); } OracleHint hint = plainSelect.getOracleHint(); if (hint != null) { - buffer.append(hint).append(" "); + builder.append(hint).append(" "); } Skip skip = plainSelect.getSkip(); if (skip != null) { - buffer.append(skip).append(" "); + builder.append(skip).append(" "); } First first = plainSelect.getFirst(); if (first != null) { - buffer.append(first).append(" "); + builder.append(first).append(" "); } - if (plainSelect.getDistinct() != null) { - if (plainSelect.getDistinct().isUseUnique()) { - buffer.append("UNIQUE "); - } else { - buffer.append("DISTINCT "); - } - if (plainSelect.getDistinct().getOnSelectItems() != null) { - buffer.append("ON ("); - for (Iterator> iter = - plainSelect.getDistinct().getOnSelectItems().iterator(); iter.hasNext();) { - SelectItem selectItem = iter.next(); - selectItem.accept(this); - if (iter.hasNext()) { - buffer.append(", "); - } - } - buffer.append(") "); - } + deparseDistinctClause(plainSelect.getDistinct()); + if (plainSelect.getBigQuerySelectQualifier() != null) { + switch (plainSelect.getBigQuerySelectQualifier()) { + case AS_STRUCT: + builder.append("AS STRUCT "); + break; + case AS_VALUE: + builder.append("AS VALUE "); + break; + } } Top top = plainSelect.getTop(); @@ -185,45 +232,42 @@ public void visit(PlainSelect plainSelect) { } if (plainSelect.getMySqlSqlCacheFlag() != null) { - buffer.append(plainSelect.getMySqlSqlCacheFlag().name()).append(" "); + builder.append(plainSelect.getMySqlSqlCacheFlag().name()).append(" "); } if (plainSelect.getMySqlSqlCalcFoundRows()) { - buffer.append("SQL_CALC_FOUND_ROWS").append(" "); + builder.append("SQL_CALC_FOUND_ROWS").append(" "); } - final List> selectItems = plainSelect.getSelectItems(); - if (selectItems != null) { - for (Iterator> iter = selectItems.iterator(); iter.hasNext();) { - SelectItem selectItem = iter.next(); - selectItem.accept(this); - if (iter.hasNext()) { - buffer.append(", "); - } - } - } + deparseSelectItemsClause(plainSelect.getSelectItems()); if (plainSelect.getIntoTables() != null) { - buffer.append(" INTO "); + builder.append(" INTO "); for (Iterator

iter = plainSelect.getIntoTables().iterator(); iter.hasNext();) { - visit(iter.next()); + visit(iter.next(), context); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } } + if (plainSelect.getMySqlSelectIntoClause() != null + && plainSelect.getMySqlSelectIntoClause() + .getPosition() == MySqlSelectIntoClause.Position.BEFORE_FROM) { + builder.append(" ").append(plainSelect.getMySqlSelectIntoClause()); + } + if (plainSelect.getFromItem() != null) { - buffer.append(" FROM "); + builder.append(" FROM "); if (plainSelect.isUsingOnly()) { - buffer.append("ONLY "); + builder.append("ONLY "); } - plainSelect.getFromItem().accept(this); + plainSelect.getFromItem().accept(this, context); if (plainSelect.getFromItem() instanceof Table) { Table table = (Table) plainSelect.getFromItem(); if (table.getSampleClause() != null) { - table.getSampleClause().appendTo(buffer); + table.getSampleClause().appendTo(builder); } } } @@ -241,57 +285,72 @@ public void visit(PlainSelect plainSelect) { } if (plainSelect.isUsingFinal()) { - buffer.append(" FINAL"); + builder.append(" FINAL"); } if (plainSelect.getKsqlWindow() != null) { - buffer.append(" WINDOW "); - buffer.append(plainSelect.getKsqlWindow().toString()); + builder.append(" WINDOW "); + builder.append(plainSelect.getKsqlWindow().toString()); } - if (plainSelect.getWhere() != null) { - buffer.append(" WHERE "); - plainSelect.getWhere().accept(expressionVisitor); - } + deparsePreWhereClause(plainSelect); + deparseWhereClause(plainSelect); if (plainSelect.getOracleHierarchical() != null) { - plainSelect.getOracleHierarchical().accept(expressionVisitor); + plainSelect.getOracleHierarchical().accept(expressionVisitor, context); + } + + if (plainSelect.getPreferringClause() != null) { + builder.append(" ").append(plainSelect.getPreferringClause().toString()); } if (plainSelect.getGroupBy() != null) { - buffer.append(" "); - new GroupByDeParser(expressionVisitor, buffer).deParse(plainSelect.getGroupBy()); + builder.append(" "); + new GroupByDeParser(expressionVisitor, builder).deParse(plainSelect.getGroupBy()); } if (plainSelect.getHaving() != null) { - buffer.append(" HAVING "); - plainSelect.getHaving().accept(expressionVisitor); + builder.append(" HAVING "); + plainSelect.getHaving().accept(expressionVisitor, context); } if (plainSelect.getQualify() != null) { - buffer.append(" QUALIFY "); - plainSelect.getQualify().accept(expressionVisitor); + builder.append(" QUALIFY "); + plainSelect.getQualify().accept(expressionVisitor, context); } if (plainSelect.getWindowDefinitions() != null) { - buffer.append(" WINDOW "); - buffer.append(plainSelect.getWindowDefinitions().stream() + builder.append(" WINDOW "); + builder.append(plainSelect.getWindowDefinitions().stream() .map(WindowDefinition::toString).collect(joining(", "))); } - if (plainSelect.getForClause() != null) { - plainSelect.getForClause().appendTo(buffer); + Alias alias = plainSelect.getAlias(); + if (alias != null) { + builder.append(alias); + } + Pivot pivot = plainSelect.getPivot(); + if (pivot != null) { + pivot.accept(this, context); + } + UnPivot unpivot = plainSelect.getUnPivot(); + if (unpivot != null) { + unpivot.accept(this, context); } - if (plainSelect.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(plainSelect.isOracleSiblings(), - plainSelect.getOrderByElements()); + if (!plainSelect.isForUpdateBeforeOrderBy()) { + deparseOrderByElementsClause(plainSelect, plainSelect.getOrderByElements()); } + + if (plainSelect.getForClause() != null) { + plainSelect.getForClause().appendTo(builder); + } + if (plainSelect.isEmitChanges()) { - buffer.append(" EMIT CHANGES"); + builder.append(" EMIT CHANGES"); } if (plainSelect.getLimitBy() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(plainSelect.getLimitBy()); + new LimitDeparser(expressionVisitor, builder).deParse(plainSelect.getLimitBy()); } if (plainSelect.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(plainSelect.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(plainSelect.getLimit()); } if (plainSelect.getOffset() != null) { visit(plainSelect.getOffset()); @@ -300,98 +359,188 @@ public void visit(PlainSelect plainSelect) { visit(plainSelect.getFetch()); } if (plainSelect.getIsolation() != null) { - buffer.append(plainSelect.getIsolation().toString()); + builder.append(plainSelect.getIsolation().toString()); } if (plainSelect.getForMode() != null) { - buffer.append(" FOR "); - buffer.append(plainSelect.getForMode().getValue()); - - if (plainSelect.getForUpdateTable() != null) { - buffer.append(" OF ").append(plainSelect.getForUpdateTable()); + builder.append(" FOR "); + builder.append(plainSelect.getForMode().getValue()); + + List
forUpdateTables = plainSelect.getForUpdateTables(); + if (forUpdateTables != null && !forUpdateTables.isEmpty()) { + builder.append(" OF "); + for (int i = 0; i < forUpdateTables.size(); i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(forUpdateTables.get(i)); + } } if (plainSelect.getWait() != null) { // wait's toString will do the formatting for us - buffer.append(plainSelect.getWait()); + builder.append(plainSelect.getWait()); } if (plainSelect.isNoWait()) { - buffer.append(" NOWAIT"); + builder.append(" NOWAIT"); } else if (plainSelect.isSkipLocked()) { - buffer.append(" SKIP LOCKED"); + builder.append(" SKIP LOCKED"); } } + + if (plainSelect.isForUpdateBeforeOrderBy()) { + deparseOrderByElementsClause(plainSelect, plainSelect.getOrderByElements()); + } + if (plainSelect.getMySqlSelectIntoClause() != null + && plainSelect.getMySqlSelectIntoClause() + .getPosition() == MySqlSelectIntoClause.Position.TRAILING) { + builder.append(" ").append(plainSelect.getMySqlSelectIntoClause()); + } + if (plainSelect.getSettings() != null && !plainSelect.getSettings().isEmpty()) { + builder.append(" SETTINGS "); + deparseUpdateSets(plainSelect.getSettings(), builder, expressionVisitor); + } if (plainSelect.getOptimizeFor() != null) { deparseOptimizeFor(plainSelect.getOptimizeFor()); } if (plainSelect.getForXmlPath() != null) { - buffer.append(" FOR XML PATH(").append(plainSelect.getForXmlPath()).append(")"); + builder.append(" FOR XML PATH(").append(plainSelect.getForXmlPath()).append(")"); } if (plainSelect.getIntoTempTable() != null) { - buffer.append(" INTO TEMP ").append(plainSelect.getIntoTempTable()); + builder.append(" INTO TEMP ").append(plainSelect.getIntoTempTable()); } if (plainSelect.isUseWithNoLog()) { - buffer.append(" WITH NO LOG"); + builder.append(" WITH NO LOG"); + } + + + + return builder; + } + + protected void deparseWhereClause(PlainSelect plainSelect) { + if (plainSelect.getWhere() != null) { + builder.append(" WHERE "); + plainSelect.getWhere().accept(expressionVisitor, null); + } + } + + protected void deparsePreWhereClause(PlainSelect plainSelect) { + if (plainSelect.getPreWhere() != null) { + builder.append(" PREWHERE "); + plainSelect.getPreWhere().accept(expressionVisitor, null); } + } + protected void deparseDistinctClause(Distinct distinct) { + if (distinct != null) { + if (distinct.isUseUnique()) { + builder.append("UNIQUE "); + } else if (distinct.isUseDistinctRow()) { + builder.append("DISTINCTROW "); + } else { + builder.append("DISTINCT "); + } + if (distinct.getOnSelectItems() != null) { + builder.append("ON ("); + for (Iterator> iter = distinct.getOnSelectItems().iterator(); iter + .hasNext();) { + SelectItem selectItem = iter.next(); + selectItem.accept(this, null); + if (iter.hasNext()) { + builder.append(", "); + } + } + builder.append(") "); + } + } + } + + protected void deparseSelectItemsClause(List> selectItems) { + if (selectItems != null) { + for (Iterator> iter = selectItems.iterator(); iter.hasNext();) { + SelectItem selectItem = iter.next(); + selectItem.accept(this, null); + if (iter.hasNext()) { + builder.append(", "); + } + } + } + } + + protected void deparseOrderByElementsClause(PlainSelect plainSelect, + List orderByElements) { + if (orderByElements != null) { + new OrderByDeParser(expressionVisitor, builder).deParse(plainSelect.isOracleSiblings(), + orderByElements); + } } @Override - public void visit(SelectItem selectExpressionItem) { - selectExpressionItem.getExpression().accept(expressionVisitor); - if (selectExpressionItem.getAlias() != null) { - buffer.append(selectExpressionItem.getAlias().toString()); + public StringBuilder visit(SelectItem selectItem, S context) { + selectItem.getExpression().accept(expressionVisitor, context); + if (selectItem.getAlias() != null) { + builder.append(selectItem.getAlias().toString()); } + return builder; } @Override - public void visit(Table tableName) { - buffer.append(tableName.getFullyQualifiedName()); - Alias alias = tableName.getAlias(); + public StringBuilder visit(Table table, S context) { + builder.append(table.getFullyQualifiedName()); + if (table.getTimeTravel() != null) { + builder.append(" ").append(table.getTimeTravel()); + } + Alias alias = table.getAlias(); if (alias != null) { - buffer.append(alias); + builder.append(alias); + } + if (table.getTimeTravelStrAfterAlias() != null) { + builder.append(" ").append(table.getTimeTravelStrAfterAlias()); } - Pivot pivot = tableName.getPivot(); + Pivot pivot = table.getPivot(); if (pivot != null) { - pivot.accept(this); + pivot.accept(this, context); } - UnPivot unpivot = tableName.getUnPivot(); + UnPivot unpivot = table.getUnPivot(); if (unpivot != null) { - unpivot.accept(this); + unpivot.accept(this, context); } - MySQLIndexHint indexHint = tableName.getIndexHint(); + MySQLIndexHint indexHint = table.getIndexHint(); if (indexHint != null) { - buffer.append(indexHint); + builder.append(indexHint); } - SQLServerHints sqlServerHints = tableName.getSqlServerHints(); + SQLServerHints sqlServerHints = table.getSqlServerHints(); if (sqlServerHints != null) { - buffer.append(sqlServerHints); + builder.append(sqlServerHints); } + return builder; } @Override - public void visit(Pivot pivot) { + public StringBuilder visit(Pivot pivot, S context) { // @todo: implement this as Visitor - buffer.append(" PIVOT (").append(PlainSelect.getStringList(pivot.getFunctionItems())); + builder.append(" PIVOT (").append(PlainSelect.getStringList(pivot.getFunctionItems())); - buffer.append(" FOR "); - pivot.getForColumns().accept(expressionVisitor); + builder.append(" FOR "); + pivot.getForColumns().accept(expressionVisitor, context); // @todo: implement this as Visitor - buffer.append(" IN ").append(PlainSelect.getStringList(pivot.getInItems(), true, true)); + builder.append(" IN ").append(PlainSelect.getStringList(pivot.getInItems(), true, true)); - buffer.append(")"); + builder.append(")"); if (pivot.getAlias() != null) { - buffer.append(pivot.getAlias().toString()); + builder.append(pivot.getAlias().toString()); } + return builder; } @Override - public void visit(UnPivot unpivot) { + public StringBuilder visit(UnPivot unpivot, S context) { boolean showOptions = unpivot.getIncludeNullsSpecified(); boolean includeNulls = unpivot.getIncludeNulls(); List unPivotClause = unpivot.getUnPivotClause(); List unpivotForClause = unpivot.getUnPivotForClause(); - buffer.append(" UNPIVOT").append(showOptions && includeNulls ? " INCLUDE NULLS" : "") + builder.append(" UNPIVOT").append(showOptions && includeNulls ? " INCLUDE NULLS" : "") .append(showOptions && !includeNulls ? " EXCLUDE NULLS" : "").append(" (") .append(PlainSelect.getStringList(unPivotClause, true, unPivotClause != null && unPivotClause.size() > 1)) @@ -402,177 +551,188 @@ public void visit(UnPivot unpivot) { .append(PlainSelect.getStringList(unpivot.getUnPivotInClause(), true, true)) .append(")"); if (unpivot.getAlias() != null) { - buffer.append(unpivot.getAlias().toString()); + builder.append(unpivot.getAlias().toString()); } + return builder; } @Override - public void visit(PivotXml pivot) { + public StringBuilder visit(PivotXml pivot, S context) { List forColumns = pivot.getForColumns(); - buffer.append(" PIVOT XML (").append(PlainSelect.getStringList(pivot.getFunctionItems())) + builder.append(" PIVOT XML (").append(PlainSelect.getStringList(pivot.getFunctionItems())) .append(" FOR ").append(PlainSelect.getStringList(forColumns, true, forColumns != null && forColumns.size() > 1)) .append(" IN ("); if (pivot.isInAny()) { - buffer.append("ANY"); + builder.append("ANY"); } else if (pivot.getInSelect() != null) { - buffer.append(pivot.getInSelect()); + builder.append(pivot.getInSelect()); } else { - buffer.append(PlainSelect.getStringList(pivot.getInItems())); + builder.append(PlainSelect.getStringList(pivot.getInItems())); } - buffer.append("))"); + builder.append("))"); + return builder; } public void visit(Offset offset) { // OFFSET offset // or OFFSET offset (ROW | ROWS) - buffer.append(" OFFSET "); - offset.getOffset().accept(expressionVisitor); + builder.append(" OFFSET "); + offset.getOffset().accept(expressionVisitor, null); if (offset.getOffsetParam() != null) { - buffer.append(" ").append(offset.getOffsetParam()); + builder.append(" ").append(offset.getOffsetParam()); } } public void visit(Fetch fetch) { - buffer.append(" FETCH "); + builder.append(" FETCH "); if (fetch.isFetchParamFirst()) { - buffer.append("FIRST "); + builder.append("FIRST "); } else { - buffer.append("NEXT "); + builder.append("NEXT "); } if (fetch.getExpression() != null) { - fetch.getExpression().accept(expressionVisitor); + fetch.getExpression().accept(expressionVisitor, null); } for (String p : fetch.getFetchParameters()) { - buffer.append(" ").append(p); + builder.append(" ").append(p); } } - public ExpressionVisitor getExpressionVisitor() { + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public void setExpressionVisitor(ExpressionVisitor visitor) { + public void setExpressionVisitor(ExpressionVisitor visitor) { expressionVisitor = visitor; } @SuppressWarnings({"PMD.CyclomaticComplexity"}) public void deparseJoin(Join join) { if (join.isGlobal()) { - buffer.append(" GLOBAL "); + builder.append(" GLOBAL "); } if (join.isSimple() && join.isOuter()) { - buffer.append(", OUTER "); + builder.append(", OUTER "); } else if (join.isSimple()) { - buffer.append(", "); + builder.append(", "); } else { if (join.isNatural()) { - buffer.append(" NATURAL"); + builder.append(" NATURAL"); + } + + if (join.isAny()) { + builder.append(" ANY"); + } else if (join.isAll()) { + builder.append(" ALL"); } if (join.isRight()) { - buffer.append(" RIGHT"); + builder.append(" RIGHT"); } else if (join.isFull()) { - buffer.append(" FULL"); + builder.append(" FULL"); } else if (join.isLeft()) { - buffer.append(" LEFT"); + builder.append(" LEFT"); } else if (join.isCross()) { - buffer.append(" CROSS"); + builder.append(" CROSS"); } if (join.isOuter()) { - buffer.append(" OUTER"); + builder.append(" OUTER"); } else if (join.isInner()) { - buffer.append(" INNER"); + builder.append(" INNER"); } else if (join.isSemi()) { - buffer.append(" SEMI"); + builder.append(" SEMI"); } if (join.isStraight()) { - buffer.append(" STRAIGHT_JOIN "); + builder.append(" STRAIGHT_JOIN "); } else if (join.isApply()) { - buffer.append(" APPLY "); + builder.append(" APPLY "); } else { if (join.getJoinHint() != null) { - buffer.append(" ").append(join.getJoinHint()); + builder.append(" ").append(join.getJoinHint()); + } + builder.append(" JOIN "); + if (join.isFetch()) { + builder.append("FETCH "); } - buffer.append(" JOIN "); } } FromItem fromItem = join.getFromItem(); - fromItem.accept(this); + fromItem.accept(this, null); if (join.isWindowJoin()) { - buffer.append(" WITHIN "); - buffer.append(join.getJoinWindow().toString()); + builder.append(" WITHIN "); + builder.append(join.getJoinWindow().toString()); } for (Expression onExpression : join.getOnExpressions()) { - buffer.append(" ON "); - onExpression.accept(expressionVisitor); + builder.append(" ON "); + onExpression.accept(expressionVisitor, null); } - if (join.getUsingColumns().size() > 0) { - buffer.append(" USING ("); + if (!join.getUsingColumns().isEmpty()) { + builder.append(" USING ("); for (Iterator iterator = join.getUsingColumns().iterator(); iterator .hasNext();) { Column column = iterator.next(); - buffer.append(column.toString()); + builder.append(column.toString()); if (iterator.hasNext()) { - buffer.append(", "); + builder.append(", "); } } - buffer.append(")"); + builder.append(")"); } } public void deparseLateralView(LateralView lateralView) { - buffer.append(" LATERAL VIEW"); + builder.append(" LATERAL VIEW"); if (lateralView.isUsingOuter()) { - buffer.append(" OUTER"); + builder.append(" OUTER"); } - buffer.append(" "); - lateralView.getGeneratorFunction().accept(expressionVisitor); + builder.append(" "); + lateralView.getGeneratorFunction().accept(expressionVisitor, null); if (lateralView.getTableAlias() != null) { - buffer.append(" ").append(lateralView.getTableAlias()); + builder.append(" ").append(lateralView.getTableAlias()); } - buffer.append(" ").append(lateralView.getColumnAlias()); + builder.append(" ").append(lateralView.getColumnAlias()); } @Override - public void visit(SetOperationList list) { - List withItemsList = list.getWithItemsList(); + public StringBuilder visit(SetOperationList list, S context) { + List> withItemsList = list.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); - for (Iterator iter = withItemsList.iterator(); iter.hasNext();) { - iter.next().accept((SelectVisitor) this); + builder.append("WITH "); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + iter.next().accept((SelectVisitor) this, context); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } for (int i = 0; i < list.getSelects().size(); i++) { if (i != 0) { - buffer.append(' ').append(list.getOperations().get(i - 1)).append(' '); + builder.append(' ').append(list.getOperations().get(i - 1)).append(' '); } - list.getSelects().get(i).accept(this); + list.getSelects().get(i).accept((SelectVisitor) this, context); } if (list.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(list.getOrderByElements()); + new OrderByDeParser(expressionVisitor, builder).deParse(list.getOrderByElements()); } if (list.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(list.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(list.getLimit()); } if (list.getOffset() != null) { visit(list.getOffset()); @@ -581,84 +741,439 @@ public void visit(SetOperationList list) { visit(list.getFetch()); } if (list.getIsolation() != null) { - buffer.append(list.getIsolation().toString()); + builder.append(list.getIsolation().toString()); } + + Alias alias = list.getAlias(); + if (alias != null) { + builder.append(alias); + } + Pivot pivot = list.getPivot(); + if (pivot != null) { + pivot.accept(this, context); + } + UnPivot unpivot = list.getUnPivot(); + if (unpivot != null) { + unpivot.accept(this, context); + } + + return builder; } @Override - public void visit(WithItem withItem) { - if (withItem.isRecursive()) { - buffer.append("RECURSIVE "); - } - buffer.append(withItem.getAlias().getName()); - if (withItem.getWithItemList() != null) { - buffer.append(" ") - .append(PlainSelect.getStringList(withItem.getWithItemList(), true, true)); + public StringBuilder visit(WithItem withItem, S context) { + if (withItem.getWithFunctionDeclaration() == null) { + if (withItem.isRecursive()) { + builder.append("RECURSIVE "); + } + builder.append(withItem.getAlias().getName()); + if (withItem.getWithItemList() != null) { + builder.append(" ") + .append(PlainSelect.getStringList(withItem.getWithItemList(), true, true)); + } + builder.append(" AS "); + if (withItem.isMaterialized()) { + builder.append(withItem.isUsingNot() + ? "NOT MATERIALIZED " + : "MATERIALIZED "); + } + StatementDeParser statementDeParser = + new StatementDeParser((ExpressionDeParser) expressionVisitor, this, builder); + statementDeParser.deParse(withItem.getParenthesedStatement()); + if (withItem.getSearchClause() != null) { + builder.append(" ").append(withItem.getSearchClause()); + } + } else { + builder.append(withItem.getWithFunctionDeclaration().toString()); } - buffer.append(" AS "); - withItem.getSelect().accept(this); + return builder; } @Override - public void visit(LateralSubSelect lateralSubSelect) { - buffer.append(lateralSubSelect.getPrefix()); - visit((ParenthesedSelect) lateralSubSelect); + public StringBuilder visit(LateralSubSelect lateralSubSelect, S context) { + builder.append(lateralSubSelect.getPrefix()); + visit((ParenthesedSelect) lateralSubSelect, context); + + return builder; } @Override - public void visit(TableStatement tableStatement) { - new TableStatementDeParser(expressionVisitor, buffer).deParse(tableStatement); + public StringBuilder visit(TableStatement tableStatement, S context) { + new TableStatementDeParser(expressionVisitor, builder).deParse(tableStatement); + return builder; } @Override - public void visit(TableFunction tableFunction) { - buffer.append(tableFunction.toString()); + public StringBuilder visit(TableFunction tableFunction, S context) { + if (tableFunction.getPrefix() != null) { + builder.append(tableFunction.getPrefix()).append(" "); + } + tableFunction.getFunction().accept(this.expressionVisitor, context); + + if (tableFunction.getWithClause() != null) { + builder.append(" WITH ").append(tableFunction.getWithClause()); + } + + if (tableFunction.getAlias() != null) { + builder.append(tableFunction.getAlias()); + } + return builder; } @Override - public void visit(ParenthesedFromItem fromItem) { + public StringBuilder visit(ParenthesedFromItem fromItem, S context) { - buffer.append("("); - fromItem.getFromItem().accept(this); + builder.append("("); + fromItem.getFromItem().accept(this, context); List joins = fromItem.getJoins(); if (joins != null) { for (Join join : joins) { if (join.isSimple()) { - buffer.append(", ").append(join); + builder.append(", ").append(join); } else { - buffer.append(" ").append(join); + builder.append(" ").append(join); } } } - buffer.append(")"); + builder.append(")"); if (fromItem.getAlias() != null) { - buffer.append(fromItem.getAlias().toString()); + builder.append(fromItem.getAlias().toString()); } if (fromItem.getPivot() != null) { - visit(fromItem.getPivot()); + visit(fromItem.getPivot(), context); } if (fromItem.getUnPivot() != null) { - visit(fromItem.getUnPivot()); + visit(fromItem.getUnPivot(), context); } + return builder; + } + + @Override + public StringBuilder visit(Values values, S context) { + new ValuesStatementDeParser(expressionVisitor, builder).deParse(values); + return builder; + } + + @Override + public StringBuilder visit(Import imprt, S context) { + builder.append(imprt.toString()); + return builder; } @Override public void visit(Values values) { - new ValuesStatementDeParser(expressionVisitor, buffer).deParse(values); + SelectVisitor.super.visit(values); + } + + public void visit(ParenthesedSelect select) { + visit(select, null); } + public void visit(PlainSelect plainSelect) { + visit(plainSelect, null); + } + + public void visit(SelectItem selectExpressionItem) { + visit(selectExpressionItem, null); + } + + public void visit(Table tableName) { + visit(tableName, null); + } + + public void visit(Pivot pivot) { + visit(pivot, null); + } + + public void visit(UnPivot unpivot) { + visit(unpivot, null); + } + + public void visit(PivotXml pivot) { + visit(pivot, null); + } + + public void visit(SetOperationList list) { + visit(list, null); + } + + public void visit(WithItem withItem) { + visit(withItem, null); + } + + public void visit(LateralSubSelect lateralSubSelect) { + visit(lateralSubSelect, null); + } + + public void visit(TableStatement tableStatement) { + visit(tableStatement, null); + } + + @Override + public StringBuilder visit(FromQuery fromQuery, S context) { + List> withItemsList = fromQuery.getWithItemsList(); + if (withItemsList != null && !withItemsList.isEmpty()) { + builder.append("WITH "); + for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { + iter.next().accept((SelectVisitor) this, context); + if (iter.hasNext()) { + builder.append(","); + } + builder.append(" "); + } + } + + if (fromQuery.isUsingFromKeyword()) { + builder.append("FROM "); + } + fromQuery.getFromItem().accept(this, context); + builder.append("\n"); + + if (fromQuery.getLateralViews() != null) { + for (LateralView lateralView : fromQuery.getLateralViews()) { + deparseLateralView(lateralView); + } + } + + if (fromQuery.getJoins() != null) { + for (Join join : fromQuery.getJoins()) { + deparseJoin(join); + } + } + + for (PipeOperator operator : fromQuery.getPipeOperators()) { + operator.accept(this, null); + } + return builder; + } + + public void visit(TableFunction tableFunction) { + visit(tableFunction, null); + } + + public void visit(ParenthesedFromItem fromItem) { + visit(fromItem, null); + } + + public void visit(Import imprt) { + visit(imprt, null); + } + + private void deparseOptimizeFor(OptimizeFor optimizeFor) { - buffer.append(" OPTIMIZE FOR "); - buffer.append(optimizeFor.getRowCount()); - buffer.append(" ROWS"); + builder.append(" OPTIMIZE FOR "); + builder.append(optimizeFor.getRowCount()); + builder.append(" ROWS"); } @Override void deParse(PlainSelect statement) { - statement.accept((SelectVisitor) this); + statement.accept((SelectVisitor) this, Optional.ofNullable(null)); } + @Override + public StringBuilder visit(AggregatePipeOperator aggregate, Void context) { + builder.append("|> ").append("AGGREGATE"); + int i = 0; + for (SelectItem selectItem : aggregate.getSelectItems()) { + builder.append(i > 0 ? ", " : " "); + selectItem.accept(this, context); + ArrayList selectItemsOrderSuffices = aggregate.getSelectItemsOrderSuffices(); + if (i < selectItemsOrderSuffices.size() && selectItemsOrderSuffices.get(i) != null + && !selectItemsOrderSuffices.get(i).isEmpty()) { + builder.append(" ").append(selectItemsOrderSuffices.get(i)); + } + i++; + } + builder.append("\n"); + + if (!aggregate.getGroupItems().isEmpty()) { + builder.append("\t").append("GROUP"); + if (aggregate.isUsingShortHandOrdering()) { + builder.append(" AND ORDER"); + } + builder.append(" BY"); + i = 0; + for (SelectItem selectItem : aggregate.getGroupItems()) { + builder.append(i > 0 ? ", " : " "); + selectItem.accept(this, context); + + ArrayList groupItemsOrderSuffices = aggregate.getGroupItemsOrderSuffices(); + if (i < groupItemsOrderSuffices.size() && groupItemsOrderSuffices.get(i) != null + && !groupItemsOrderSuffices.get(i).isEmpty()) { + builder.append(" ").append(groupItemsOrderSuffices.get(i)); + } + + i++; + } + builder.append("\n"); + } + + return builder; + } + + @Override + public StringBuilder visit(AsPipeOperator as, Void context) { + builder.append("|> ").append(as.getAlias()); + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(CallPipeOperator call, Void context) { + builder.append("|> CALL "); + call.getTableFunction().accept(this); + if (call.getAlias() != null) { + builder.append(" ").append(call.getAlias()); + } + + return builder; + } + + @Override + public StringBuilder visit(DropPipeOperator drop, Void context) { + builder.append("|> ").append("DROP "); + drop.getColumns().accept(expressionVisitor, context); + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(ExtendPipeOperator extend, Void context) { + return visit((SelectPipeOperator) extend, context); + } + + @Override + public StringBuilder visit(JoinPipeOperator join, Void context) { + builder.append("|> "); + deparseJoin(join.getJoin()); + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(LimitPipeOperator limit, Void context) { + builder.append("|> ").append("LIMIT ").append(limit.getLimitExpression()); + if (limit.getOffsetExpression() != null) { + builder.append(" OFFSET ").append(limit.getOffsetExpression()); + } + return builder; + } + + @Override + public StringBuilder visit(OrderByPipeOperator orderBy, Void context) { + builder.append("|> "); + new OrderByDeParser(expressionVisitor, builder).deParse(orderBy.getOrderByElements()); + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(PivotPipeOperator pivot, Void context) { + builder + .append("|> ") + .append("PIVOT( ") + .append(pivot.getAggregateExpression()) + .append(" FOR ") + .append(pivot.getInputColumn()) + .append(" IN (") + .append(Select.getStringList(pivot.getPivotColumns())) + .append("))"); + if (pivot.getAlias() != null) { + builder.append(" ").append(pivot.getAlias()); + } + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(RenamePipeOperator rename, Void context) { + return builder; + } + + @Override + public StringBuilder visit(SelectPipeOperator select, Void context) { + builder.append("|> ").append(select.getOperatorName()); + if (select.getModifier() != null && !select.getModifier().isEmpty()) { + builder.append(" ").append(select.getModifier()); + } + + int i = 0; + for (SelectItem selectItem : select.getSelectItems()) { + builder.append(i++ > 0 ? ", " : " ").append(selectItem); + } + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(SetPipeOperator set, Void context) { + builder.append("|> ").append("SET"); + int i = 0; + for (UpdateSet updateSet : set.getUpdateSets()) { + builder.append(i++ > 0 ? ", " : " ").append(updateSet); + } + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(TableSamplePipeOperator tableSample, Void context) { + builder.append("|> ").append("TABLESAMPLE SYSTEM (").append(tableSample.getPercent()) + .append(" PERCENT)"); + return builder; + } + + @Override + public StringBuilder visit(SetOperationPipeOperator setOperationPipeOperator, Void context) { + builder.append("|> ").append(setOperationPipeOperator.getSetOperationType()); + if (setOperationPipeOperator.getModifier() != null) { + builder.append(" ").append(setOperationPipeOperator.getModifier()); + } + + int i = 0; + for (ParenthesedSelect select : setOperationPipeOperator.getSelects()) { + if (i++ > 0) { + builder.append(", "); + } + builder.append(select); + } + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(UnPivotPipeOperator unPivot, Void context) { + builder + .append("|> ") + .append("UNPIVOT( ") + .append(unPivot.getValuesColumn()) + .append(" FOR ") + .append(unPivot.getNameColumn()) + .append(" IN (") + .append(Select.getStringList(unPivot.getPivotColumns())) + .append("))"); + if (unPivot.getAlias() != null) { + builder.append(" ").append(unPivot.getAlias()); + } + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(WherePipeOperator where, Void context) { + builder.append("|> ") + .append("WHERE "); + where.getExpression().accept(expressionVisitor, context); + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(WindowPipeOperator window, Void context) { + return visit((SelectPipeOperator) window, context); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SetStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SetStatementDeParser.java index d6371b8f3..31ff0f599 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SetStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SetStatementDeParser.java @@ -17,44 +17,45 @@ public class SetStatementDeParser extends AbstractDeParser { - private ExpressionVisitor expressionVisitor; + private ExpressionVisitor expressionVisitor; - public SetStatementDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public SetStatementDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @Override public void deParse(SetStatement set) { - buffer.append("SET "); + builder.append("SET "); if (set.getEffectParameter() != null) { - buffer.append(set.getEffectParameter()).append(" "); + builder.append(set.getEffectParameter()).append(" "); } for (int i = 0; i < set.getCount(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } - buffer.append(set.getName(i)); + builder.append(set.getName(i)); if (set.isUseEqual(i)) { - buffer.append(" ="); + builder.append(" ="); } - buffer.append(" "); + builder.append(" "); List expressions = set.getExpressions(i); for (int j = 0; j < expressions.size(); j++) { if (j > 0) { - buffer.append(", "); + builder.append(", "); } - expressions.get(j).accept(expressionVisitor); + expressions.get(j).accept(expressionVisitor, null); } } } - public ExpressionVisitor getExpressionVisitor() { + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public void setExpressionVisitor(ExpressionVisitor visitor) { + public void setExpressionVisitor(ExpressionVisitor visitor) { expressionVisitor = visitor; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ShowColumnsStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ShowColumnsStatementDeParser.java index ad4627a2d..9fc744010 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ShowColumnsStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ShowColumnsStatementDeParser.java @@ -19,6 +19,6 @@ public ShowColumnsStatementDeParser(StringBuilder buffer) { @Override public void deParse(ShowColumnsStatement show) { - buffer.append("SHOW COLUMNS FROM ").append(show.getTableName()); + builder.append("SHOW COLUMNS FROM ").append(show.getTableName()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ShowIndexStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ShowIndexStatementDeParser.java index b79d0bdda..1d81d5af6 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ShowIndexStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ShowIndexStatementDeParser.java @@ -12,19 +12,18 @@ import net.sf.jsqlparser.statement.show.ShowIndexStatement; /** -* -* @author Jayant Kumar Yadav -*/ + * @author Jayant Kumar Yadav + */ public class ShowIndexStatementDeParser extends AbstractDeParser { - + public ShowIndexStatementDeParser(StringBuilder buffer) { super(buffer); } @Override public void deParse(ShowIndexStatement show) { - buffer.append("SHOW INDEX FROM ").append(show.getTableName()); + builder.append("SHOW INDEX FROM ").append(show.getTableName()); } - -} \ No newline at end of file + +} diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ShowStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ShowStatementDeParser.java index 70c5d9b2e..e03bdc963 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ShowStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ShowStatementDeParser.java @@ -19,6 +19,6 @@ public ShowStatementDeParser(StringBuilder buffer) { @Override public void deParse(ShowStatement show) { - buffer.append("SHOW ").append(show.getName()); + builder.append("SHOW ").append(show.getName()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ShowTablesStatementDeparser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ShowTablesStatementDeparser.java index a218f3f1c..127b12015 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ShowTablesStatementDeparser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ShowTablesStatementDeparser.java @@ -19,6 +19,6 @@ public ShowTablesStatementDeparser(StringBuilder buffer) { @Override void deParse(ShowTablesStatement statement) { - buffer.append(statement); + builder.append(statement); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java index f9d314642..751c4bf64 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java @@ -9,7 +9,11 @@ */ package net.sf.jsqlparser.util.deparser; +import java.lang.reflect.InvocationTargetException; +import java.util.List; import java.util.stream.Collectors; + +import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Block; import net.sf.jsqlparser.statement.Commit; import net.sf.jsqlparser.statement.CreateFunctionalStatement; @@ -21,6 +25,7 @@ import net.sf.jsqlparser.statement.ResetStatement; import net.sf.jsqlparser.statement.RollbackStatement; import net.sf.jsqlparser.statement.SavepointStatement; +import net.sf.jsqlparser.statement.SessionStatement; import net.sf.jsqlparser.statement.SetStatement; import net.sf.jsqlparser.statement.ShowColumnsStatement; import net.sf.jsqlparser.statement.ShowStatement; @@ -37,6 +42,7 @@ import net.sf.jsqlparser.statement.analyze.Analyze; import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; @@ -44,25 +50,57 @@ import net.sf.jsqlparser.statement.create.view.AlterView; import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.delete.ParenthesedDelete; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.export.Export; import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.imprt.Import; import net.sf.jsqlparser.statement.insert.Insert; -import net.sf.jsqlparser.statement.merge.*; +import net.sf.jsqlparser.statement.insert.ParenthesedInsert; +import net.sf.jsqlparser.statement.lock.LockStatement; +import net.sf.jsqlparser.statement.merge.Merge; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectVisitor; +import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.statement.show.ShowIndexStatement; import net.sf.jsqlparser.statement.show.ShowTablesStatement; import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.ParenthesedUpdate; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.upsert.Upsert; -public class StatementDeParser extends AbstractDeParser implements StatementVisitor { +public class StatementDeParser extends AbstractDeParser + implements StatementVisitor { private final ExpressionDeParser expressionDeParser; private final SelectDeParser selectDeParser; + public StatementDeParser(Class expressionDeparserClass, + Class selectDeparserClass, StringBuilder builder) + throws NoSuchMethodException, InvocationTargetException, InstantiationException, + IllegalAccessException { + super(builder); + + this.selectDeParser = selectDeparserClass + .getConstructor(Class.class, StringBuilder.class) + .newInstance(expressionDeparserClass, builder); + + + this.expressionDeParser = + expressionDeparserClass.cast(this.selectDeParser.getExpressionVisitor()); + + } + + public StatementDeParser(Class expressionDeparserClass, + Class selectDeparserClass) + throws NoSuchMethodException, InvocationTargetException, InstantiationException, + IllegalAccessException { + this(expressionDeparserClass, selectDeparserClass, new StringBuilder()); + } + public StatementDeParser(StringBuilder buffer) { this(new ExpressionDeParser(), new SelectDeParser(), buffer); } @@ -74,291 +112,419 @@ public StatementDeParser(ExpressionDeParser expressionDeParser, SelectDeParser s this.expressionDeParser = expressionDeParser; this.selectDeParser = selectDeParser; - this.selectDeParser.setBuffer(buffer); + this.selectDeParser.setBuilder(buffer); this.selectDeParser.setExpressionVisitor(expressionDeParser); this.expressionDeParser.setSelectVisitor(selectDeParser); - this.expressionDeParser.setBuffer(buffer); + this.expressionDeParser.setBuilder(buffer); } @Override - public void visit(CreateIndex createIndex) { - CreateIndexDeParser createIndexDeParser = new CreateIndexDeParser(buffer); + public StringBuilder visit(CreateIndex createIndex, S context) { + CreateIndexDeParser createIndexDeParser = new CreateIndexDeParser(builder); createIndexDeParser.deParse(createIndex); + return builder; } @Override - public void visit(CreateTable createTable) { - CreateTableDeParser createTableDeParser = new CreateTableDeParser(this, buffer); + public StringBuilder visit(CreateTable createTable, S context) { + CreateTableDeParser createTableDeParser = new CreateTableDeParser(this, builder); createTableDeParser.deParse(createTable); + return builder; } @Override - public void visit(CreateView createView) { - CreateViewDeParser createViewDeParser = new CreateViewDeParser(buffer); + public StringBuilder visit(CreateView createView, S context) { + CreateViewDeParser createViewDeParser = new CreateViewDeParser(builder); createViewDeParser.deParse(createView); + return builder; } @Override - public void visit(RefreshMaterializedViewStatement materializedViewStatement) { - new RefreshMaterializedViewStatementDeParser(buffer).deParse(materializedViewStatement); + public StringBuilder visit(RefreshMaterializedViewStatement materializedViewStatement, + S context) { + new RefreshMaterializedViewStatementDeParser(builder).deParse(materializedViewStatement); + return builder; } @Override - public void visit(AlterView alterView) { - AlterViewDeParser alterViewDeParser = new AlterViewDeParser(buffer); + public StringBuilder visit(AlterView alterView, S context) { + AlterViewDeParser alterViewDeParser = new AlterViewDeParser(builder); alterViewDeParser.deParse(alterView); + return builder; } @Override - public void visit(Delete delete) { - DeleteDeParser deleteDeParser = new DeleteDeParser(expressionDeParser, buffer); + public StringBuilder visit(Delete delete, S context) { + DeleteDeParser deleteDeParser = new DeleteDeParser(expressionDeParser, builder); deleteDeParser.deParse(delete); + return builder; } @Override - public void visit(Drop drop) { - DropDeParser dropDeParser = new DropDeParser(buffer); + public StringBuilder visit(Drop drop, S context) { + DropDeParser dropDeParser = new DropDeParser(builder); dropDeParser.deParse(drop); + return builder; } @Override - public void visit(Insert insert) { + public StringBuilder visit(Insert insert, S context) { InsertDeParser insertDeParser = - new InsertDeParser(expressionDeParser, selectDeParser, buffer); + new InsertDeParser(expressionDeParser, selectDeParser, builder); insertDeParser.deParse(insert); + return builder; + } + + @Override + public StringBuilder visit(ParenthesedInsert insert, S context) { + List> withItemsList = insert.getWithItemsList(); + addWithItemsToBuffer(withItemsList, context); + builder.append("("); + insert.getInsert().accept(this, context); + builder.append(")"); + return builder; } @Override - public void visit(Select select) { - select.accept(selectDeParser); + public StringBuilder visit(ParenthesedUpdate update, S context) { + List> withItemsList = update.getWithItemsList(); + addWithItemsToBuffer(withItemsList, context); + builder.append("("); + update.getUpdate().accept(this, context); + builder.append(")"); + return builder; + } + + @Override + public StringBuilder visit(ParenthesedDelete delete, S context) { + List> withItemsList = delete.getWithItemsList(); + addWithItemsToBuffer(withItemsList, context); + builder.append("("); + delete.getDelete().accept(this, context); + builder.append(")"); + return builder; + } + + @Override + public StringBuilder visit(SessionStatement sessionStatement, S context) { + return builder.append(sessionStatement.toString()); + } + + + private StringBuilder addWithItemsToBuffer(List> withItemsList, S context) { + if (withItemsList != null && !withItemsList.isEmpty()) { + builder.append("WITH "); + for (WithItem withItem : withItemsList) { + withItem.accept((SelectVisitor) this, context); + builder.append(" "); + } + } + return builder; } @Override - public void visit(Truncate truncate) { - buffer.append("TRUNCATE"); + public StringBuilder visit(Select select, S context) { + select.accept((SelectVisitor) selectDeParser, context); + return builder; + } + + @Override + public StringBuilder visit(Truncate truncate, S context) { + builder.append("TRUNCATE"); if (truncate.isTableToken()) { - buffer.append(" TABLE"); + builder.append(" TABLE"); } if (truncate.isOnly()) { - buffer.append(" ONLY"); + builder.append(" ONLY"); + } + builder.append(" "); + if (truncate.getTables() != null && !truncate.getTables().isEmpty()) { + builder.append(truncate.getTables().stream() + .map(Table::toString) + .collect(Collectors.joining(", "))); + } else { + builder.append(truncate.getTable()); } - buffer.append(" "); - buffer.append(truncate.getTable()); - if (truncate.getCascade()) { - buffer.append(" CASCADE"); + builder.append(" CASCADE"); } + return builder; } @Override - public void visit(Update update) { - UpdateDeParser updateDeParser = new UpdateDeParser(expressionDeParser, buffer); + public StringBuilder visit(Update update, S context) { + UpdateDeParser updateDeParser = new UpdateDeParser(expressionDeParser, builder); updateDeParser.deParse(update); + return builder; } - public void visit(Analyze analyzer) { - buffer.append("ANALYZE "); - buffer.append(analyzer.getTable()); + public StringBuilder visit(Analyze analyzer, S context) { + builder.append("ANALYZE "); + builder.append(analyzer.getTable()); + return builder; } @Override - public void visit(Alter alter) { - AlterDeParser alterDeParser = new AlterDeParser(buffer); + public StringBuilder visit(Alter alter, S context) { + AlterDeParser alterDeParser = new AlterDeParser(builder); alterDeParser.deParse(alter); + return builder; } @Override - public void visit(Statements stmts) { - stmts.accept(this); + public StringBuilder visit(Statements statements, S context) { + statements.accept(this, context); + return builder; } @Override - public void visit(Execute execute) { - ExecuteDeParser executeDeParser = new ExecuteDeParser(expressionDeParser, buffer); + public StringBuilder visit(Execute execute, S context) { + ExecuteDeParser executeDeParser = new ExecuteDeParser(expressionDeParser, builder); executeDeParser.deParse(execute); + return builder; } @Override - public void visit(SetStatement set) { + public StringBuilder visit(SetStatement set, S context) { SetStatementDeParser setStatementDeparser = - new SetStatementDeParser(expressionDeParser, buffer); + new SetStatementDeParser(expressionDeParser, builder); setStatementDeparser.deParse(set); + return builder; } @Override - public void visit(ResetStatement reset) { + public StringBuilder visit(ResetStatement reset, S context) { ResetStatementDeParser setStatementDeparser = - new ResetStatementDeParser(expressionDeParser, buffer); + new ResetStatementDeParser(expressionDeParser, builder); setStatementDeparser.deParse(reset); + return builder; } @SuppressWarnings({"PMD.CyclomaticComplexity"}) @Override - public void visit(Merge merge) { - new MergeDeParser(expressionDeParser, selectDeParser, buffer).deParse(merge); + public StringBuilder visit(Merge merge, S context) { + new MergeDeParser(expressionDeParser, selectDeParser, builder).deParse(merge); + return builder; } @Override - public void visit(SavepointStatement savepointStatement) { - buffer.append(savepointStatement.toString()); + public StringBuilder visit(SavepointStatement savepointStatement, S context) { + builder.append(savepointStatement.toString()); + return builder; } @Override - public void visit(RollbackStatement rollbackStatement) { - buffer.append(rollbackStatement.toString()); + public StringBuilder visit(RollbackStatement rollbackStatement, S context) { + builder.append(rollbackStatement.toString()); + return builder; } @Override - public void visit(Commit commit) { - buffer.append(commit.toString()); + public StringBuilder visit(Commit commit, S context) { + builder.append(commit.toString()); + return builder; } @Override - public void visit(Upsert upsert) { + public StringBuilder visit(Upsert upsert, S context) { UpsertDeParser upsertDeParser = - new UpsertDeParser(expressionDeParser, selectDeParser, buffer); + new UpsertDeParser(expressionDeParser, selectDeParser, builder); upsertDeParser.deParse(upsert); + return builder; } @Override - public void visit(UseStatement use) { - new UseStatementDeParser(buffer).deParse(use); + public StringBuilder visit(UseStatement use, S context) { + new UseStatementDeParser(builder).deParse(use); + return builder; } @Override - public void visit(ShowColumnsStatement show) { - new ShowColumnsStatementDeParser(buffer).deParse(show); + public StringBuilder visit(ShowColumnsStatement show, S context) { + new ShowColumnsStatementDeParser(builder).deParse(show); + return builder; } @Override - public void visit(ShowIndexStatement showIndexes) { - new ShowIndexStatementDeParser(buffer).deParse(showIndexes); + public StringBuilder visit(ShowIndexStatement showIndexes, S context) { + new ShowIndexStatementDeParser(builder).deParse(showIndexes); + return builder; } @Override - public void visit(ShowTablesStatement showTables) { - new ShowTablesStatementDeparser(buffer).deParse(showTables); + public StringBuilder visit(ShowTablesStatement showTables, S context) { + new ShowTablesStatementDeparser(builder).deParse(showTables); + return builder; } @Override - public void visit(Block block) { - buffer.append("BEGIN\n"); + public StringBuilder visit(Block block, S context) { + builder.append("BEGIN\n"); if (block.getStatements() != null) { - for (Statement stmt : block.getStatements().getStatements()) { - stmt.accept(this); - buffer.append(";\n"); + for (Statement stmt : block.getStatements()) { + stmt.accept(this, context); + builder.append(";\n"); } } - buffer.append("END"); + builder.append("END"); if (block.hasSemicolonAfterEnd()) { - buffer.append(";"); + builder.append(";"); } + return builder; } @Override - public void visit(Comment comment) { - buffer.append(comment.toString()); + public StringBuilder visit(Comment comment, S context) { + builder.append(comment.toString()); + return builder; } @Override - public void visit(DescribeStatement describe) { - buffer.append(describe.getDescribeType()); - buffer.append(" "); - buffer.append(describe.getTable()); + public StringBuilder visit(DescribeStatement describe, S context) { + builder.append(describe.getDescribeType()); + builder.append(" "); + builder.append(describe.getTable()); + return builder; } @Override - public void visit(ExplainStatement explain) { - buffer.append("EXPLAIN "); - if (explain.getTable() != null) { - buffer.append(explain.getTable()); - } else if (explain.getOptions() != null) { - buffer.append(explain.getOptions().values().stream() + public StringBuilder visit(ExplainStatement explainStatement, S context) { + builder.append(explainStatement.getKeyword()).append(" "); + if (explainStatement.getTable() != null) { + builder.append(explainStatement.getTable()); + } else if (explainStatement.getOptions() != null) { + builder.append(explainStatement.getOptions().values().stream() .map(ExplainStatement.Option::formatOption).collect(Collectors.joining(" "))); - buffer.append(" "); + builder.append(" "); } - if (explain.getStatement() != null) { - explain.getStatement().accept(this); - + if (explainStatement.getStatement() != null) { + explainStatement.getStatement().accept(this, context); } + return builder; } @Override - public void visit(ShowStatement show) { - new ShowStatementDeParser(buffer).deParse(show); + public StringBuilder visit(ShowStatement showStatement, S context) { + new ShowStatementDeParser(builder).deParse(showStatement); + return builder; } @Override - public void visit(DeclareStatement declare) { - new DeclareStatementDeParser(expressionDeParser, buffer).deParse(declare); + public StringBuilder visit(DeclareStatement declareStatement, S context) { + new DeclareStatementDeParser(expressionDeParser, builder).deParse(declareStatement); + return builder; } @Override - public void visit(Grant grant) { - GrantDeParser grantDeParser = new GrantDeParser(buffer); + public StringBuilder visit(Grant grant, S context) { + GrantDeParser grantDeParser = new GrantDeParser(builder); grantDeParser.deParse(grant); + return builder; } @Override - public void visit(CreateSchema aThis) { - buffer.append(aThis.toString()); + public StringBuilder visit(CreateSchema aThis, S context) { + builder.append(aThis.toString()); + return builder; } @Override - public void visit(CreateSequence createSequence) { - new CreateSequenceDeParser(buffer).deParse(createSequence); + public StringBuilder visit(CreateSequence createSequence, S context) { + new CreateSequenceDeParser(builder).deParse(createSequence); + return builder; } @Override - public void visit(AlterSequence alterSequence) { - new AlterSequenceDeParser(buffer).deParse(alterSequence); + public StringBuilder visit(AlterSequence alterSequence, S context) { + new AlterSequenceDeParser(builder).deParse(alterSequence); + return builder; } @Override - public void visit(CreateFunctionalStatement createFunctionalStatement) { - buffer.append(createFunctionalStatement.toString()); + public StringBuilder visit(CreateFunctionalStatement createFunctionalStatement, S context) { + builder.append(createFunctionalStatement.toString()); + return builder; } @Override - public void visit(CreateSynonym createSynonym) { - new CreateSynonymDeparser(buffer).deParse(createSynonym); + public StringBuilder visit(CreateSynonym createSynonym, S context) { + new CreateSynonymDeparser(builder).deParse(createSynonym); + return builder; } @Override void deParse(Statement statement) { - statement.accept(this); + statement.accept(this, null); + } + + @Override + public StringBuilder visit(AlterSession alterSession, S context) { + new AlterSessionDeParser(builder).deParse(alterSession); + return builder; + } + + @Override + public StringBuilder visit(IfElseStatement ifElseStatement, S context) { + ifElseStatement.appendTo(builder); + return builder; + } + + @Override + public StringBuilder visit(RenameTableStatement renameTableStatement, S context) { + renameTableStatement.appendTo(builder); + return builder; } @Override - public void visit(AlterSession alterSession) { - new AlterSessionDeParser(buffer).deParse(alterSession); + public StringBuilder visit(PurgeStatement purgeStatement, S context) { + purgeStatement.appendTo(builder); + return builder; } @Override - public void visit(IfElseStatement ifElseStatement) { - ifElseStatement.appendTo(buffer); + public StringBuilder visit(AlterSystemStatement alterSystemStatement, S context) { + alterSystemStatement.appendTo(builder); + return builder; + } + + @Override + public StringBuilder visit(UnsupportedStatement unsupportedStatement, S context) { + unsupportedStatement.appendTo(builder); + return builder; + } + + public ExpressionDeParser getExpressionDeParser() { + return expressionDeParser; + } + + public SelectDeParser getSelectDeParser() { + return selectDeParser; } @Override - public void visit(RenameTableStatement renameTableStatement) { - renameTableStatement.appendTo(buffer); + public StringBuilder visit(Import imprt, S context) { + builder.append(imprt.toString()); + return builder; } @Override - public void visit(PurgeStatement purgeStatement) { - purgeStatement.appendTo(buffer); + public StringBuilder visit(Export export, S context) { + builder.append(export.toString()); + return builder; } @Override - public void visit(AlterSystemStatement alterSystemStatement) { - alterSystemStatement.appendTo(buffer); + public StringBuilder visit(LockStatement lock, S context) { + builder.append(lock.toString()); + return builder; } @Override - public void visit(UnsupportedStatement unsupportedStatement) { - unsupportedStatement.appendTo(buffer); + public StringBuilder visit(CreatePolicy createPolicy, S context) { + builder.append(createPolicy.toString()); + return builder; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java index 962849c6e..34aba2a86 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java @@ -10,89 +10,100 @@ package net.sf.jsqlparser.util.deparser; import net.sf.jsqlparser.expression.ExpressionVisitor; -import net.sf.jsqlparser.statement.select.LateralSubSelect; -import net.sf.jsqlparser.statement.select.Offset; -import net.sf.jsqlparser.statement.select.ParenthesedSelect; -import net.sf.jsqlparser.statement.select.PlainSelect; -import net.sf.jsqlparser.statement.select.SelectVisitor; -import net.sf.jsqlparser.statement.select.SetOperationList; -import net.sf.jsqlparser.statement.select.TableStatement; -import net.sf.jsqlparser.statement.select.Values; -import net.sf.jsqlparser.statement.select.WithItem; +import net.sf.jsqlparser.statement.piped.FromQuery; +import net.sf.jsqlparser.statement.select.*; /** * @author jxnu-liguobin */ public class TableStatementDeParser extends AbstractDeParser - implements SelectVisitor { + implements SelectVisitor { - private final ExpressionVisitor expressionVisitor; + private final ExpressionVisitor expressionVisitor; - public TableStatementDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public TableStatementDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @Override public void deParse(TableStatement tableStatement) { - tableStatement.accept(this); + tableStatement.accept(this, null); } - public void visit(Offset offset) { - buffer.append(" OFFSET "); - offset.getOffset().accept(expressionVisitor); + public void deparse(Offset offset) { + builder.append(" OFFSET "); + offset.getOffset().accept(expressionVisitor, null); if (offset.getOffsetParam() != null) { - buffer.append(" ").append(offset.getOffsetParam()); + builder.append(" ").append(offset.getOffsetParam()); } } @Override - public void visit(ParenthesedSelect parenthesedSelect) { + public StringBuilder visit(ParenthesedSelect parenthesedSelect, S context) { + return builder; } @Override - public void visit(PlainSelect plainSelect) { + public StringBuilder visit(PlainSelect plainSelect, S context) { + return builder; } @Override - public void visit(SetOperationList setOpList) { + public StringBuilder visit(FromQuery fromQuery, S context) { + return builder; + } + + @Override + public StringBuilder visit(SetOperationList setOperationList, S context) { + return builder; } @Override - public void visit(WithItem withItem) { + public StringBuilder visit(WithItem withItem, S context) { + return builder; } @Override - public void visit(Values aThis) { + public StringBuilder visit(Values values, S context) { + return builder; } @Override - public void visit(LateralSubSelect lateralSubSelect) { + public StringBuilder visit(LateralSubSelect lateralSubSelect, S context) { + return builder; } @Override - public void visit(TableStatement tableStatement) { - buffer.append("TABLE "); - buffer.append(tableStatement.getTable()); + public StringBuilder visit(TableStatement tableStatement, S context) { + builder.append("TABLE "); + builder.append(tableStatement.getTable()); if (tableStatement.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer) + new OrderByDeParser(expressionVisitor, builder) .deParse(tableStatement.getOrderByElements()); } if (tableStatement.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(tableStatement.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(tableStatement.getLimit()); } if (tableStatement.getOffset() != null) { - visit(tableStatement.getOffset()); + deparse(tableStatement.getOffset()); } // TODO UNION + + tableStatement.appendTo( + builder, tableStatement.getAlias(), null, + tableStatement.getPivot(), tableStatement.getUnPivot()); + + return builder; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java index 0ba4003c4..d5dcac7f1 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java @@ -19,15 +19,17 @@ import java.util.Iterator; -public class UpdateDeParser extends AbstractDeParser implements OrderByVisitor { +public class UpdateDeParser extends AbstractDeParser + implements OrderByVisitor { - private ExpressionVisitor expressionVisitor = new ExpressionVisitorAdapter(); + private ExpressionVisitor expressionVisitor = new ExpressionVisitorAdapter<>(); public UpdateDeParser() { super(new StringBuilder()); } - public UpdateDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public UpdateDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @@ -37,94 +39,109 @@ public UpdateDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) "PMD.ExcessiveMethodLength"}) public void deParse(Update update) { if (update.getWithItemsList() != null && !update.getWithItemsList().isEmpty()) { - buffer.append("WITH "); - for (Iterator iter = update.getWithItemsList().iterator(); iter.hasNext();) { - WithItem withItem = iter.next(); - buffer.append(withItem); + builder.append("WITH "); + for (Iterator> iter = update.getWithItemsList().iterator(); iter + .hasNext();) { + WithItem withItem = iter.next(); + builder.append(withItem); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("UPDATE "); + builder.append("UPDATE "); if (update.getOracleHint() != null) { - buffer.append(update.getOracleHint()).append(" "); + builder.append(update.getOracleHint()).append(" "); } if (update.getModifierPriority() != null) { - buffer.append(update.getModifierPriority()).append(" "); + builder.append(update.getModifierPriority()).append(" "); } if (update.isModifierIgnore()) { - buffer.append("IGNORE "); + builder.append("IGNORE "); } - buffer.append(update.getTable()); + builder.append(update.getTable()); if (update.getStartJoins() != null) { for (Join join : update.getStartJoins()) { if (join.isSimple()) { - buffer.append(", ").append(join); + builder.append(", ").append(join); } else { - buffer.append(" ").append(join); + builder.append(" ").append(join); } } } - buffer.append(" SET "); + builder.append(" SET "); - deparseUpdateSets(update.getUpdateSets(), buffer, expressionVisitor); + deparseUpdateSetsClause(update); if (update.getOutputClause() != null) { - update.getOutputClause().appendTo(buffer); + update.getOutputClause().appendTo(builder); } if (update.getFromItem() != null) { - buffer.append(" FROM ").append(update.getFromItem()); + builder.append(" FROM ").append(update.getFromItem()); if (update.getJoins() != null) { for (Join join : update.getJoins()) { if (join.isSimple()) { - buffer.append(", ").append(join); + builder.append(", ").append(join); } else { - buffer.append(" ").append(join); + builder.append(" ").append(join); } } } } - if (update.getWhere() != null) { - buffer.append(" WHERE "); - update.getWhere().accept(expressionVisitor); + deparseWhereClause(update); + + if (update.getPreferringClause() != null) { + builder.append(" ").append(update.getPreferringClause()); } if (update.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(update.getOrderByElements()); + new OrderByDeParser(expressionVisitor, builder).deParse(update.getOrderByElements()); } if (update.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(update.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(update.getLimit()); } if (update.getReturningClause() != null) { - update.getReturningClause().appendTo(buffer); + update.getReturningClause().appendTo(builder); } } - public ExpressionVisitor getExpressionVisitor() { + protected void deparseWhereClause(Update update) { + if (update.getWhere() != null) { + builder.append(" WHERE "); + update.getWhere().accept(expressionVisitor, null); + } + } + + protected void deparseUpdateSetsClause(Update update) { + deparseUpdateSets(update.getUpdateSets(), builder, expressionVisitor); + } + + + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public void setExpressionVisitor(ExpressionVisitor visitor) { + public void setExpressionVisitor(ExpressionVisitor visitor) { expressionVisitor = visitor; } @Override - public void visit(OrderByElement orderBy) { - orderBy.getExpression().accept(expressionVisitor); + public StringBuilder visit(OrderByElement orderBy, S context) { + orderBy.getExpression().accept(expressionVisitor, context); if (!orderBy.isAsc()) { - buffer.append(" DESC"); + builder.append(" DESC"); } else if (orderBy.isAscDescPresent()) { - buffer.append(" ASC"); + builder.append(" ASC"); } if (orderBy.getNullOrdering() != null) { - buffer.append(' '); - buffer.append(orderBy.getNullOrdering() == OrderByElement.NullOrdering.NULLS_FIRST + builder.append(' '); + builder.append(orderBy.getNullOrdering() == OrderByElement.NullOrdering.NULLS_FIRST ? "NULLS FIRST" : "NULLS LAST"); } + return builder; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java index 407a4c6e7..218ca1db3 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.util.deparser; import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.statement.insert.ConflictActionType; import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.upsert.Upsert; @@ -34,69 +35,74 @@ public void deParse(Upsert upsert) { switch (upsert.getUpsertType()) { case REPLACE: case REPLACE_SET: - buffer.append("REPLACE "); + builder.append("REPLACE "); break; case INSERT_OR_ABORT: - buffer.append("INSERT OR ABORT "); + builder.append("INSERT OR ABORT "); break; case INSERT_OR_FAIL: - buffer.append("INSERT OR FAIL "); + builder.append("INSERT OR FAIL "); break; case INSERT_OR_IGNORE: - buffer.append("INSERT OR IGNORE "); + builder.append("INSERT OR IGNORE "); break; case INSERT_OR_REPLACE: - buffer.append("INSERT OR REPLACE "); + builder.append("INSERT OR REPLACE "); break; case INSERT_OR_ROLLBACK: - buffer.append("INSERT OR ROLLBACK "); + builder.append("INSERT OR ROLLBACK "); break; case UPSERT: default: - buffer.append("UPSERT "); + builder.append("UPSERT "); } if (upsert.isUsingInto()) { - buffer.append("INTO "); + builder.append("INTO "); } - buffer.append(upsert.getTable().getFullyQualifiedName()); + builder.append(upsert.getTable().getFullyQualifiedName()); if (upsert.getUpdateSets() != null) { - buffer.append(" SET "); - deparseUpdateSets(upsert.getUpdateSets(), buffer, expressionVisitor); + builder.append(" SET "); + deparseUpdateSets(upsert.getUpdateSets(), builder, expressionVisitor); } else { if (upsert.getColumns() != null) { - upsert.getColumns().accept(expressionVisitor); + upsert.getColumns().accept(expressionVisitor, null); } if (upsert.getExpressions() != null) { - upsert.getExpressions().accept(expressionVisitor); + upsert.getExpressions().accept(expressionVisitor, null); } if (upsert.getSelect() != null) { - buffer.append(" "); - upsert.getSelect().accept(selectVisitor); + builder.append(" "); + upsert.getSelect().accept((SelectVisitor) selectVisitor, null); } - if (upsert.getDuplicateUpdateSets() != null) { - buffer.append(" ON DUPLICATE KEY UPDATE "); - deparseUpdateSets(upsert.getDuplicateUpdateSets(), buffer, expressionVisitor); + if (upsert.getDuplicateAction() != null) { + builder.append(" ON DUPLICATE KEY UPDATE "); + if (ConflictActionType.DO_UPDATE + .equals(upsert.getDuplicateAction().getConflictActionType())) { + deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor); + } else { + upsert.getDuplicateAction().appendTo(builder); + } } } } - public ExpressionVisitor getExpressionVisitor() { + public ExpressionVisitor getExpressionVisitor() { return expressionVisitor; } - public SelectVisitor getSelectVisitor() { - return selectVisitor; - } - public void setExpressionVisitor(ExpressionDeParser visitor) { expressionVisitor = visitor; } + public SelectVisitor getSelectVisitor() { + return selectVisitor; + } + public void setSelectVisitor(SelectDeParser visitor) { selectVisitor = visitor; } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UseStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UseStatementDeParser.java index c0f4a8f48..7787a37cb 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UseStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UseStatementDeParser.java @@ -19,10 +19,10 @@ public UseStatementDeParser(StringBuilder buffer) { @Override public void deParse(UseStatement set) { - buffer.append("USE "); + builder.append("USE "); if (set.hasSchemaKeyword()) { - buffer.append("SCHEMA "); + builder.append("SCHEMA "); } - buffer.append(set.getName()); + builder.append(set.getName()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java index 233ec71c3..eb39481d0 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java @@ -14,16 +14,20 @@ public class ValuesStatementDeParser extends AbstractDeParser { - private final ExpressionVisitor expressionVisitor; + private final ExpressionVisitor expressionVisitor; - public ValuesStatementDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + public ValuesStatementDeParser(ExpressionVisitor expressionVisitor, + StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; } @Override public void deParse(Values values) { - buffer.append("VALUES "); - values.getExpressions().accept(expressionVisitor); + builder.append("VALUES "); + values.getExpressions().accept(expressionVisitor, null); + if (values.getAlias() != null) { + builder.append(" ").append(values.getAlias()); + } } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ContextKey.java b/src/main/java/net/sf/jsqlparser/util/validation/ContextKey.java index ffd95f652..774d4fb3b 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/ContextKey.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/ContextKey.java @@ -10,8 +10,8 @@ package net.sf.jsqlparser.util.validation; /** - * the context key - a ValidationCapability should define constants of expected - * context - values needed for validation. + * the context key - a ValidationCapability should define constants of expected context - values + * needed for validation. */ public interface ContextKey { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ParseCapability.java b/src/main/java/net/sf/jsqlparser/util/validation/ParseCapability.java index b0cf02ff0..a57cf3e5c 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/ParseCapability.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/ParseCapability.java @@ -12,6 +12,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; + import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statements; diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ParseException.java b/src/main/java/net/sf/jsqlparser/util/validation/ParseException.java index 16a226a38..f9cee3ce3 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/ParseException.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/ParseException.java @@ -12,9 +12,8 @@ import net.sf.jsqlparser.JSQLParserException; /** - * wraps a {@link JSQLParserException} to add to the errors collected by - * validation - * + * wraps a {@link JSQLParserException} to add to the errors collected by validation + * * @author gitmotte */ public class ParseException extends ValidationException { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/UnexpectedValidationException.java b/src/main/java/net/sf/jsqlparser/util/validation/UnexpectedValidationException.java index 0cec642ff..5f1f28be6 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/UnexpectedValidationException.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/UnexpectedValidationException.java @@ -11,7 +11,7 @@ /** * can be used on unexpected errors during validation - * + * * @author gitmotte */ public class UnexpectedValidationException extends ValidationException { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/Validation.java b/src/main/java/net/sf/jsqlparser/util/validation/Validation.java index 9fdeaf878..3d7c4f7af 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/Validation.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/Validation.java @@ -16,17 +16,18 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; + import net.sf.jsqlparser.parser.feature.FeatureConfiguration; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; import net.sf.jsqlparser.util.validation.validator.StatementValidator; /** - * Parses the given statement list with {@link ParseCapability} and performs - * validation with configured {@link ValidationCapability}'s. - * + * Parses the given statement list with {@link ParseCapability} and performs validation with + * configured {@link ValidationCapability}'s. + *

* Errors are are reported by calling {@link #validate()}. - * + * * @author gitmotte * @see #getErrors() * @see #validate() @@ -40,7 +41,8 @@ public class Validation { private List errors; private Statements parsedStatements; - public Validation(Collection capabilities, String... statements) { + public Validation(Collection capabilities, + String... statements) { this(new FeatureConfiguration(), capabilities, statements); } @@ -51,58 +53,13 @@ public Validation(FeatureConfiguration featureConfiguration, this.statementsList = Arrays.asList(statements); } - /** - * @return the errors - may be an empty list. - */ - public List validate() { - this.errors = new ArrayList<>(); - - ValidationContext context = createValidationContext(featureConfiguration, capabilities); - for (String statements : statementsList) { - - ParseCapability parse = new ParseCapability(statements); - parse.validate(context, e -> errors.add(new ValidationError(statements).withCapability(parse).addError(e))); - - parsedStatements = parse.getParsedStatements(); - if (parsedStatements != null && parsedStatements.getStatements() != null && !capabilities.isEmpty() ) { - for (Statement parsedStatement : parsedStatements.getStatements()) { - Map> errorMap = validate(parsedStatement, context); - errors.addAll(toValidationErrors(statements, parsedStatement, errorMap)); - } - } - - } - return errors; - } - - public FeatureConfiguration getFeatureConfiguration() { - return featureConfiguration; - } - - public Collection getCapabilities() { - return capabilities; - } - - public List getStatements() { - return statementsList; - } - - public List getErrors() { - return errors; - } - - public Statements getParsedStatements() { - return parsedStatements; - } - - // STATIC util-methods - /** * @param capabilities * @param statements * @return a list of {@link ValidationError}'s */ - public static List validate(Collection capabilities, + public static List validate( + Collection capabilities, String... statements) { return new Validation(capabilities, statements).validate(); } @@ -127,7 +84,8 @@ public static ValidationContext createValidationContext(FeatureConfiguration con * @return a list of {@link ValidationError}' */ public static List toValidationErrors(String statements, - Statement parsedStatement, Map> errorMap) { + Statement parsedStatement, + Map> errorMap) { List errors = new ArrayList<>(); for (Entry> e : errorMap.entrySet()) { errors.add(new ValidationError(statements).withParsedStatement(parsedStatement) @@ -150,4 +108,53 @@ public static Map> validate(State return validator.getValidationErrors(); } + /** + * @return the errors - may be an empty list. + */ + public List validate() { + this.errors = new ArrayList<>(); + + ValidationContext context = createValidationContext(featureConfiguration, capabilities); + for (String statements : statementsList) { + + ParseCapability parse = new ParseCapability(statements); + parse.validate(context, e -> errors + .add(new ValidationError(statements).withCapability(parse).addError(e))); + + parsedStatements = parse.getParsedStatements(); + if (parsedStatements != null && parsedStatements.getStatements() != null + && !capabilities.isEmpty()) { + for (Statement parsedStatement : parsedStatements.getStatements()) { + Map> errorMap = + validate(parsedStatement, context); + errors.addAll(toValidationErrors(statements, parsedStatement, errorMap)); + } + } + + } + return errors; + } + + public FeatureConfiguration getFeatureConfiguration() { + return featureConfiguration; + } + + // STATIC util-methods + + public Collection getCapabilities() { + return capabilities; + } + + public List getStatements() { + return statementsList; + } + + public List getErrors() { + return errors; + } + + public Statements getParsedStatements() { + return parsedStatements; + } + } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ValidationContext.java b/src/main/java/net/sf/jsqlparser/util/validation/ValidationContext.java index 3f71822d0..994be3b4a 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/ValidationContext.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/ValidationContext.java @@ -46,15 +46,15 @@ public ValidationContext reinit(boolean reInit) { return this; } + public FeatureConfiguration getConfiguration() { + return configuration; + } + public ValidationContext setConfiguration(FeatureConfiguration configuration) { this.configuration = configuration; return this; } - public FeatureConfiguration getConfiguration() { - return configuration; - } - public boolean getAsBoolean(Feature f) { return getConfiguration().getAsBoolean(f); } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ValidationError.java b/src/main/java/net/sf/jsqlparser/util/validation/ValidationError.java index 45bf5810c..f0ef8c5e1 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/ValidationError.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/ValidationError.java @@ -12,6 +12,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; + import net.sf.jsqlparser.statement.Statement; public class ValidationError { @@ -50,6 +51,10 @@ public ValidationCapability getCapability() { return capability; } + public void setCapability(ValidationCapability databaseType) { + this.capability = databaseType; + } + /** * @return the parsed {@link Statement}, if parsing was possible */ @@ -57,6 +62,10 @@ public Statement getParsedStatement() { return parsedStatement; } + public void setParsedStatement(Statement parsedStatement) { + this.parsedStatement = parsedStatement; + } + /** * @return the statements (may be more than one) given for validation */ @@ -64,14 +73,6 @@ public String getStatements() { return statements; } - public void setCapability(ValidationCapability databaseType) { - this.capability = databaseType; - } - - public void setParsedStatement(Statement parsedStatement) { - this.parsedStatement = parsedStatement; - } - public ValidationError withCapability(ValidationCapability databaseType) { setCapability(databaseType); return this; @@ -85,7 +86,8 @@ public ValidationError withParsedStatement(Statement parsedStatement) { @Override public String toString() { return "ValidationError [\nstatement=" + statements + "\ncapability=" - + (capability != null ? capability.getName() : "") + "\nerrors=" + errors + "\n]"; + + (capability != null ? capability.getName() : "") + "\nerrors=" + errors + + "\n]"; } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ValidationException.java b/src/main/java/net/sf/jsqlparser/util/validation/ValidationException.java index a154eaa52..99295f469 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/ValidationException.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/ValidationException.java @@ -39,7 +39,8 @@ public boolean equals(Object o) { if (o.getClass().equals(this.getClass())) { // exact type match! ValidationException ve = (ValidationException) o; - return Objects.equals(getMessage(), ve.getMessage()) && Objects.equals(getCause(), ve.getCause()); + return Objects.equals(getMessage(), ve.getMessage()) + && Objects.equals(getCause(), ve.getCause()); } else { return false; } @@ -47,11 +48,12 @@ public boolean equals(Object o) { @Override public int hashCode() { - return getMessage().hashCode() + (getCause() == null ? 0 : getCause().toString().hashCode()); + return getMessage().hashCode() + + (getCause() == null ? 0 : getCause().toString().hashCode()); } @Override - public String toString () { + public String toString() { return getClass().getSimpleName() + ": " + getMessage(); } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ValidationUtil.java b/src/main/java/net/sf/jsqlparser/util/validation/ValidationUtil.java index 378a6707d..cb83662d5 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/ValidationUtil.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/ValidationUtil.java @@ -13,6 +13,7 @@ import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; + import net.sf.jsqlparser.expression.Alias; public class ValidationUtil { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/Validator.java b/src/main/java/net/sf/jsqlparser/util/validation/Validator.java index 80ac8d326..c1cc3d276 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/Validator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/Validator.java @@ -1,102 +1,103 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2020 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.util.validation; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import java.util.Set; - -/** - * @author gitmotte - * @param - */ -public interface Validator { - - /** - * @return true, all {@link ValidationCapability}'s have no errors - */ - default boolean isValid() { - return getValidationErrors().isEmpty(); - } - - /** - * @param capabilities - * @return true, if the given {@link ValidationCapability}'s have no errors. - * false otherwise. - */ - default boolean isValid(ValidationCapability... capabilities) { - return getValidationErrors(capabilities).isEmpty(); - } - - /** - * @return the {@link ValidationCapability}'s requested mapped to a set of error-messages - */ - Map> getValidationErrors(); - - /** - * @param capabilities - * @return the filtered view of requested {@link ValidationCapability}'s mapped to a set - * of error-messages - */ - default Map> getValidationErrors( - ValidationCapability... capabilities) { - return getValidationErrors(Arrays.asList(capabilities)); - } - - /** - * @param capabilities - * @return the filtered view of requested {@link ValidationCapability}'s mapped - * to a set of error-messages - */ - default Map> getValidationErrors( - Collection capabilities) { - Map> map = new HashMap<>(); - for (Entry> e : getValidationErrors().entrySet()) { - if (capabilities.contains(e.getKey())) { - map.put(e.getKey(), e.getValue()); - } - } - return map; - } - - // /** - // * Set the {@link ValidationCapability}'s this {@link Validator} should - // check. - // * - // * @param capabilities - // */ - // public void setCapabilities(Collection - // capabilities); - // - // /** - // * @param configuration - // */ - // public void setConfiguration(FeatureConfiguration configuration); - - /** - * @param ctx - */ - void setContext(ValidationContext ctx); - - /** - * validates given statement. - * - * @param statement - * @see #getValidationErrors() - * @see #getValidationErrors(Collection) - * @see #getValidationErrors(ValidationCapability...) - */ - void validate(S statement); - -} +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.util.validation; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import java.util.Set; + +/** + * @param + * @author gitmotte + */ +public interface Validator { + + /** + * @return true, all {@link ValidationCapability}'s have no errors + */ + default boolean isValid() { + return getValidationErrors().isEmpty(); + } + + /** + * @param capabilities + * @return true, if the given {@link ValidationCapability}'s have no errors. + * false otherwise. + */ + default boolean isValid(ValidationCapability... capabilities) { + return getValidationErrors(capabilities).isEmpty(); + } + + /** + * @return the {@link ValidationCapability}'s requested mapped to a set of error-messages + */ + Map> getValidationErrors(); + + /** + * @param capabilities + * @return the filtered view of requested {@link ValidationCapability}'s mapped to a set of + * error-messages + */ + default Map> getValidationErrors( + ValidationCapability... capabilities) { + return getValidationErrors(Arrays.asList(capabilities)); + } + + /** + * @param capabilities + * @return the filtered view of requested {@link ValidationCapability}'s mapped to a set of + * error-messages + */ + default Map> getValidationErrors( + Collection capabilities) { + Map> map = new HashMap<>(); + for (Entry> e : getValidationErrors() + .entrySet()) { + if (capabilities.contains(e.getKey())) { + map.put(e.getKey(), e.getValue()); + } + } + return map; + } + + // /** + // * Set the {@link ValidationCapability}'s this {@link Validator} should + // check. + // * + // * @param capabilities + // */ + // public void setCapabilities(Collection + // capabilities); + // + // /** + // * @param configuration + // */ + // public void setConfiguration(FeatureConfiguration configuration); + + /** + * @param ctx + */ + void setContext(ValidationContext ctx); + + /** + * validates given statement. + * + * @param statement + * @see #getValidationErrors() + * @see #getValidationErrors(Collection) + * @see #getValidationErrors(ValidationCapability...) + */ + void validate(S statement); + +} diff --git a/src/main/java/net/sf/jsqlparser/util/validation/allowedtypes/AllowedTypesValidation.java b/src/main/java/net/sf/jsqlparser/util/validation/allowedtypes/AllowedTypesValidation.java index b5e27b91f..14b0a403a 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/allowedtypes/AllowedTypesValidation.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/allowedtypes/AllowedTypesValidation.java @@ -25,7 +25,8 @@ public void validate(ValidationContext context, Consumer er Object arg = context.getOptional(AllowedTypesContext.argument, Object.class); Boolean allowNull = context.getOptional(AllowedTypesContext.allow_null, Boolean.class); @SuppressWarnings("unchecked") - Collection> allowedTypes = context.get(AllowedTypesContext.allowed_types, Collection.class); + Collection> allowedTypes = + context.get(AllowedTypesContext.allowed_types, Collection.class); if (arg != null) { boolean error = true; for (Class cls : allowedTypes) { @@ -35,7 +36,8 @@ public void validate(ValidationContext context, Consumer er } } if (error) { - errorConsumer.accept(toError(arg.getClass() + " is not a valid argument - expected one of " + allowedTypes)); + errorConsumer.accept(toError(arg.getClass() + + " is not a valid argument - expected one of " + allowedTypes)); } } else if (Boolean.FALSE.equals(allowNull)) { errorConsumer.accept(toError("argument is missing one of " + allowedTypes)); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/DatabaseType.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/DatabaseType.java index b402fb322..2359f93d0 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/DatabaseType.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/DatabaseType.java @@ -11,28 +11,27 @@ import java.util.EnumSet; import java.util.Set; + import net.sf.jsqlparser.parser.feature.Feature; /** *

- * The DatabaseType is named like the identifier used within the - * jdbc-connection-url (upper case), this may change in future, therefore use - * {@link #get(String)} to retrieve the {@link DatabaseType}. + * The DatabaseType is named like the identifier used within the jdbc-connection-url (upper case), + * this may change in future, therefore use {@link #get(String)} to retrieve the + * {@link DatabaseType}. *

*/ public enum DatabaseType implements FeatureSetValidation, Version { ANSI_SQL("ANSI SQL", SQLVersion.values()), // DBMS - ORACLE(OracleVersion.values()), - MYSQL(MySqlVersion.values()), - SQLSERVER(SqlServerVersion.values()), - MARIADB(MariaDbVersion.values()), - POSTGRESQL(PostgresqlVersion.values()), - H2(H2Version.values()); + ORACLE(OracleVersion.values()), MYSQL(MySqlVersion.values()), SQLSERVER( + SqlServerVersion.values()), MARIADB(MariaDbVersion.values()), POSTGRESQL( + PostgresqlVersion.values()), H2(H2Version.values()); - public static final DatabaseType[] DATABASES = new DatabaseType[] { ORACLE, MYSQL, SQLSERVER, MARIADB, POSTGRESQL, - H2 }; + public static final DatabaseType[] DATABASES = + new DatabaseType[] {ORACLE, MYSQL, SQLSERVER, MARIADB, POSTGRESQL, + H2}; private String name; private Version[] versions; @@ -55,7 +54,8 @@ public enum DatabaseType implements FeatureSetValidation, Version { /** * @param jdbcIdentifier - the database-identifier-part of jdbc-url * @return the {@link DatabaseType} - * @throws IllegalArgumentException - if the specified jdbcIdentifier cannot be mapped to a {@link DatabaseType} + * @throws IllegalArgumentException - if the specified jdbcIdentifier cannot be mapped to a + * {@link DatabaseType} * @throws NullPointerException if {@code jdbcIdentifier} is null */ public static DatabaseType get(String jdbcIdentifier) { @@ -63,7 +63,7 @@ public static DatabaseType get(String jdbcIdentifier) { } /** - * + * */ @Override public String getName() { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/FeatureSetValidation.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/FeatureSetValidation.java index 2b29f366f..e4e52a085 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/FeatureSetValidation.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/FeatureSetValidation.java @@ -11,6 +11,7 @@ import java.util.Set; import java.util.function.Consumer; + import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.parser.feature.FeatureSet; import net.sf.jsqlparser.util.validation.ValidationCapability; diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java index 3ada0ec28..431e4d762 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java @@ -18,6 +18,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; + import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.parser.feature.FeatureSet; import net.sf.jsqlparser.parser.feature.ModifyableFeatureSet; @@ -30,18 +31,13 @@ */ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureSet { - private static final String SEPERATOR_REGEX = " \\+ "; - private static final String SEPERATOR = " + "; - public static final FeaturesAllowed JDBC = new FeaturesAllowed("jdbc", // always allowed if used with jdbc Feature.jdbcParameter, Feature.jdbcNamedParameter).unmodifyable(); - public static final FeaturesAllowed EXPRESSIONS = new FeaturesAllowed("EXPRESSIONS", Feature.exprLike, Feature.exprSimilarTo); - /** * all {@link Feature}' within SQL SELECT without modification features like * {@link Feature#selectInto}, but jdbc-features like {@link Feature#jdbcParameter} and @@ -90,53 +86,14 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS Feature.tableStatement, Feature.function).unmodifyable(); - - /** - * all {@link Feature}' for SQL INSERT including {@link #SELECT} and {@link Feature#selectInto} - */ - public static final FeaturesAllowed INSERT = - new FeaturesAllowed("INSERT", Feature.insert, Feature.insertFromSelect, - Feature.insertModifierIgnore, Feature.insertModifierPriority, - Feature.insertReturningAll, - Feature.insertReturningExpressionList, Feature.insertUseSet, - Feature.insertValues, Feature.selectInto).add(SELECT).unmodifyable(); - - /** - * all {@link Feature}' for SQL UPDATE including {@link #SELECT} - */ - public static final FeaturesAllowed UPDATE = new FeaturesAllowed("UPDATE", Feature.update, - Feature.updateJoins, - Feature.updateFrom, Feature.updateLimit, Feature.updateOrderBy, Feature.updateReturning, - Feature.updateUseSelect) - .add(SELECT).unmodifyable(); - - /** - * all {@link Feature}' for SQL UPDATE including {@link #SELECT} - */ - public static final FeaturesAllowed DELETE = - new FeaturesAllowed("DELETE", Feature.delete, Feature.deleteJoin, - Feature.deleteLimit, Feature.deleteOrderBy, Feature.deleteTables, - Feature.deleteReturningExpressionList, - Feature.truncate) - .add(SELECT).unmodifyable(); - /** * all {@link Feature}' for SQL MERGE other similar commands */ public static final FeaturesAllowed MERGE = new FeaturesAllowed("MERGE", Feature.merge, Feature.upsert, Feature.insertUseDuplicateKeyUpdate).unmodifyable(); - - /** - * all DML {@link Feature}'s - */ - public static final FeaturesAllowed DML = - new FeaturesAllowed("DML").add(SELECT, INSERT, UPDATE, DELETE, MERGE) - .unmodifyable(); - public static final FeaturesAllowed EXECUTE = new FeaturesAllowed("EXECUTE", Feature.execute).unmodifyable(); - /** * all "CREATE" {@link Feature}'s */ @@ -148,7 +105,6 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS Feature.createTableFromSelect, Feature.createTrigger, Feature.createView).unmodifyable(); - /** * all "ALTER" {@link Feature}'s */ @@ -156,7 +112,6 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS new FeaturesAllowed("ALTER", Feature.alterTable, Feature.alterSequence, Feature.alterView, Feature.alterIndex) .unmodifyable(); - /** * all "DROP" {@link Feature}'s */ @@ -167,13 +122,45 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS Feature.dropIndexIfExists, Feature.dropViewIfExists, Feature.dropSchemaIfExists, Feature.dropSequenceIfExists) .unmodifyable(); - + private static final String SEPERATOR_REGEX = " \\+ "; + /** + * all {@link Feature}' for SQL INSERT including {@link #SELECT} and {@link Feature#selectInto} + */ + public static final FeaturesAllowed INSERT = + new FeaturesAllowed("INSERT", Feature.insert, Feature.insertFromSelect, + Feature.insertModifierIgnore, Feature.insertModifierPriority, + Feature.insertReturningAll, + Feature.insertReturningExpressionList, Feature.insertUseSet, + Feature.insertValues, Feature.selectInto).add(SELECT).unmodifyable(); + /** + * all {@link Feature}' for SQL UPDATE including {@link #SELECT} + */ + public static final FeaturesAllowed UPDATE = new FeaturesAllowed("UPDATE", Feature.update, + Feature.updateJoins, + Feature.updateFrom, Feature.updateLimit, Feature.updateOrderBy, Feature.updateReturning, + Feature.updateUseSelect) + .add(SELECT).unmodifyable(); + /** + * all {@link Feature}' for SQL UPDATE including {@link #SELECT} + */ + public static final FeaturesAllowed DELETE = + new FeaturesAllowed("DELETE", Feature.delete, Feature.deleteJoin, + Feature.deleteLimit, Feature.deleteOrderBy, Feature.deleteTables, + Feature.deleteReturningExpressionList, + Feature.truncate) + .add(SELECT).unmodifyable(); + /** + * all DML {@link Feature}'s + */ + public static final FeaturesAllowed DML = + new FeaturesAllowed("DML").add(SELECT, INSERT, UPDATE, DELETE, MERGE) + .unmodifyable(); /** * all DDL {@link Feature}'s */ public static final FeaturesAllowed DDL = new FeaturesAllowed("DDL").add(CREATE, ALTER, DROP).unmodifyable(); - + private static final String SEPERATOR = " + "; private Set names = new LinkedHashSet<>(); private Set features = new HashSet<>(); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/H2Version.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/H2Version.java index 9cd733acf..3984e7fe6 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/H2Version.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/H2Version.java @@ -137,8 +137,7 @@ public enum H2Version implements Version { // http://www.h2database.com/html/commands.html#grant_role Feature.grant, // http://h2database.com/html/commands.html#commit - Feature.commit - )); + Feature.commit)); private Set features; private String versionString; diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java index 983adb4fd..742e84b97 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Set; + import net.sf.jsqlparser.parser.feature.Feature; /** diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java index a7aeeaae0..cd6c2c038 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java @@ -12,11 +12,12 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Set; + import net.sf.jsqlparser.parser.feature.Feature; /** * Please add Features supported and place a link to public documentation - * + * * @author gitmotte * @see https://dev.mysql.com/doc/refman/8.0/en/ diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/OracleVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/OracleVersion.java index 26d4e678e..37b193820 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/OracleVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/OracleVersion.java @@ -55,7 +55,8 @@ public enum OracleVersion implements Version { // https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html // see "row_limiting_clause" - Feature.offset, Feature.offsetParam, Feature.fetch, Feature.fetchFirst, Feature.fetchNext, + Feature.offset, Feature.offsetParam, Feature.fetch, Feature.fetchFirst, + Feature.fetchNext, // https://www.oracletutorial.com/oracle-basics/oracle-select-distinct/ Feature.distinct, Feature.selectUnique, @@ -129,7 +130,8 @@ public enum OracleVersion implements Version { // https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CREATE-MATERIALIZED-VIEW.htm Feature.createViewMaterialized, // https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CREATE-TABLE.html - Feature.createTable, Feature.createTableCreateOptionStrings, Feature.createTableTableOptionStrings, + Feature.createTable, Feature.createTableCreateOptionStrings, + Feature.createTableTableOptionStrings, Feature.createTableFromSelect, Feature.createTableRowMovement, // https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CREATE-INDEX.html Feature.createIndex, @@ -143,7 +145,8 @@ public enum OracleVersion implements Version { Feature.commit, // https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/COMMENT.html - Feature.comment, Feature.commentOnTable, Feature.commentOnColumn, Feature.commentOnView, + Feature.comment, Feature.commentOnTable, Feature.commentOnColumn, + Feature.commentOnView, // https://docs.oracle.com/en/database/oracle/oracle-database/19/rcmrf/DESCRIBE.html Feature.describe, @@ -154,7 +157,8 @@ public enum OracleVersion implements Version { // https://www.oracletutorial.com/oracle-basics/oracle-merge/ Feature.merge, - Feature.createFunction, Feature.createProcedure, Feature.functionalStatement, Feature.block, + Feature.createFunction, Feature.createProcedure, Feature.functionalStatement, + Feature.block, Feature.declare, // special oracle features diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/PostgresqlVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/PostgresqlVersion.java index 08bf3bf1a..386274fa1 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/PostgresqlVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/PostgresqlVersion.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Set; + import net.sf.jsqlparser.parser.feature.Feature; /** diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/SQLVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/SQLVersion.java index 3b8266c83..225cd0040 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/SQLVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/SQLVersion.java @@ -12,12 +12,12 @@ import java.util.Collections; import java.util.EnumSet; import java.util.Set; + import net.sf.jsqlparser.parser.feature.Feature; /** - * Enum containing the ANSI SQL Standard Versions - features are not guaranteed - * to be complete, just add them if you are sure they are part of the standard - * :) + * Enum containing the ANSI SQL Standard Versions - features are not guaranteed to be complete, just + * add them if you are sure they are part of the standard :) * * @author gitmotte * @see features; private String versionString; @@ -154,7 +155,8 @@ public enum SqlServerVersion implements Version { * @param unsupported * @see #copy() to copy from previous version */ - SqlServerVersion(String versionString, Set featuresSupported, Set unsupported) { + SqlServerVersion(String versionString, Set featuresSupported, + Set unsupported) { this.versionString = versionString; this.features = featuresSupported; this.features.removeAll(unsupported); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/metadata/AbstractDatabaseMetaDataCapability.java b/src/main/java/net/sf/jsqlparser/util/validation/metadata/AbstractDatabaseMetaDataCapability.java index ffb5d1ddc..22f8b6f5f 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/metadata/AbstractDatabaseMetaDataCapability.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/metadata/AbstractDatabaseMetaDataCapability.java @@ -18,11 +18,9 @@ import java.util.function.UnaryOperator; /** - * Adapter class always throwing {@link UnsupportedOperationException} for all - * exists - methods. + * Adapter class always throwing {@link UnsupportedOperationException} for all exists - methods. * * @author gitmotte - * */ public abstract class AbstractDatabaseMetaDataCapability implements DatabaseMetaDataValidation { @@ -33,22 +31,24 @@ public abstract class AbstractDatabaseMetaDataCapability implements DatabaseMeta /** * With caching enabled - see {@link #isCacheResults()} - * + * * @param connection * @param namesLookup - see {@link NamesLookup} * @see #AbstractDatabaseMetaDataCapability(Connection, UnaryOperator, boolean) */ - public AbstractDatabaseMetaDataCapability(Connection connection, UnaryOperator namesLookup) { + public AbstractDatabaseMetaDataCapability(Connection connection, + UnaryOperator namesLookup) { this(connection, namesLookup, true); } /** * @param connection - * @param namesLookup - see {@link NamesLookup} + * @param namesLookup - see {@link NamesLookup} * @param cacheResults - whether the results should be cached for later lookups * @see #AbstractDatabaseMetaDataCapability(Connection, UnaryOperator) */ - public AbstractDatabaseMetaDataCapability(Connection connection, UnaryOperator namesLookup, + public AbstractDatabaseMetaDataCapability(Connection connection, + UnaryOperator namesLookup, boolean cacheResults) { this.connection = connection; this.namesLookup = namesLookup; @@ -81,31 +81,32 @@ public final boolean exists(Named named) { named.setAliasLookup(getNamesLookup().apply(named.getAlias())); switch (named.getNamedObject()) { - case table: - return cache(named, this::tableExists); - case column: - return cache(named, this::columnExists); - case schema: - return cache(named, this::schemaExists); - case index: - return cache(named, this::indexExists); - case database: - return cache(named, this::databaseExists); - case constraint: - case uniqueConstraint: - return cache(named, this::constraintExists); - case view: - return cache(named, this::viewExists); - case procedure: - return cache(named, this::procedureExists); - case user: - return cache(named, this::userExists); - case role: - return cache(named, this::roleExists); - default: + case table: + return cache(named, this::tableExists); + case column: + return cache(named, this::columnExists); + case schema: + return cache(named, this::schemaExists); + case index: + return cache(named, this::indexExists); + case database: + return cache(named, this::databaseExists); + case constraint: + case uniqueConstraint: + return cache(named, this::constraintExists); + case view: + return cache(named, this::viewExists); + case procedure: + return cache(named, this::procedureExists); + case user: + return cache(named, this::userExists); + case role: + return cache(named, this::roleExists); + default: } throw new UnsupportedOperationException( - named.getFqn() + ": evaluation of " + named.getNamedObject() + "-name not implemented."); + named.getFqn() + ": evaluation of " + named.getNamedObject() + + "-name not implemented."); } protected boolean cache(Named named, BiPredicate, Named> fn) { @@ -159,7 +160,8 @@ protected boolean tableExists(Map results, Named name) { protected UnsupportedOperationException unsupported(Named name) { return new UnsupportedOperationException( - name.getFqn() + ": evaluation of " + name.getNamedObject() + "-name not supported."); + name.getFqn() + ": evaluation of " + name.getNamedObject() + + "-name not supported."); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/metadata/DatabaseException.java b/src/main/java/net/sf/jsqlparser/util/validation/metadata/DatabaseException.java index cbe872042..9a7ff15f3 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/metadata/DatabaseException.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/metadata/DatabaseException.java @@ -10,10 +10,12 @@ package net.sf.jsqlparser.util.validation.metadata; import java.sql.SQLException; + import net.sf.jsqlparser.util.validation.ValidationException; /** * database-errors wrapping a {@link SQLException} or PersistenceException + * * @author gitmotte */ public class DatabaseException extends ValidationException { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidation.java b/src/main/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidation.java index 3d919d62f..b9e8ff8b2 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidation.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidation.java @@ -11,6 +11,7 @@ import java.sql.SQLException; import java.util.function.Consumer; + import net.sf.jsqlparser.util.validation.UnexpectedValidationException; import net.sf.jsqlparser.util.validation.ValidationCapability; import net.sf.jsqlparser.util.validation.ValidationContext; @@ -37,7 +38,8 @@ default void validate(ValidationContext context, Consumer e } catch (ValidationException ve) { errorConsumer.accept(ve); } catch (UnsupportedOperationException uoe) { - errorConsumer.accept(new ValidationException("This Operation " + named.toString() + " is not supported yet.", uoe)); + errorConsumer.accept(new ValidationException( + "This Operation " + named.toString() + " is not supported yet.", uoe)); } catch (Exception e) { errorConsumer.accept(getUnexpectedErrorMessage(named, e)); } @@ -45,15 +47,11 @@ default void validate(ValidationContext context, Consumer e /** * @param named - * @return true, if the object exists, false - * otherwise. - * @throws ValidationException - on specific errors like - * {@link DatabaseException} on - * database-errors wrapping a - * {@link SQLException} or - * PersistenceException - * @throws UnsupportedOperationException - if testing of given - * {@link NamedObject} is not supported. + * @return true, if the object exists, false otherwise. + * @throws ValidationException - on specific errors like {@link DatabaseException} on + * database-errors wrapping a {@link SQLException} or PersistenceException + * @throws UnsupportedOperationException - if testing of given {@link NamedObject} is not + * supported. */ boolean exists(Named named); @@ -63,7 +61,8 @@ default void validate(ValidationContext context, Consumer e * @return a new {@link ValidationException} */ default ValidationException getErrorMessage(Named named, boolean checkForExists) { - return toError(String.format("%s does %sexist.", named.getFqn(), checkForExists ? "not " : "")); + return toError( + String.format("%s does %sexist.", named.getFqn(), checkForExists ? "not " : "")); } /** @@ -73,7 +72,9 @@ default ValidationException getErrorMessage(Named named, boolean checkForExists) */ default ValidationException getUnexpectedErrorMessage(Named named, Exception cause) { return new UnexpectedValidationException( - named.getFqn() + ": cannot validate " + named.getNamedObject() + "-name. detail: " + cause.getMessage(), cause); + named.getFqn() + ": cannot validate " + named.getNamedObject() + "-name. detail: " + + cause.getMessage(), + cause); } @Override diff --git a/src/main/java/net/sf/jsqlparser/util/validation/metadata/JdbcDatabaseMetaDataCapability.java b/src/main/java/net/sf/jsqlparser/util/validation/metadata/JdbcDatabaseMetaDataCapability.java index b40d2296c..a3d5102b8 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/metadata/JdbcDatabaseMetaDataCapability.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/metadata/JdbcDatabaseMetaDataCapability.java @@ -24,34 +24,36 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; + import net.sf.jsqlparser.util.validation.UnexpectedValidationException; import net.sf.jsqlparser.util.validation.ValidationException; /** - * Validates against schema by jdbc-metadata in a very basic way with simple - * caching and comparing names by {@link String#equalsIgnoreCase(String)} + * Validates against schema by jdbc-metadata in a very basic way with simple caching and comparing + * names by {@link String#equalsIgnoreCase(String)} * * @author gitmotte - * */ public class JdbcDatabaseMetaDataCapability extends AbstractDatabaseMetaDataCapability { private static final String VIEW = "VIEW"; private static final String TABLE = "TABLE"; private static final String COLUMN = "COLUMN"; - private static final Logger LOG = Logger.getLogger(JdbcDatabaseMetaDataCapability.class.getName()); + private static final Logger LOG = + Logger.getLogger(JdbcDatabaseMetaDataCapability.class.getName()); /** * @param connection * @param namesLookup - see {@link NamesLookup} */ - public JdbcDatabaseMetaDataCapability(Connection connection, UnaryOperator namesLookup) { + public JdbcDatabaseMetaDataCapability(Connection connection, + UnaryOperator namesLookup) { super(connection, namesLookup); } /** * @param connection - * @param namesLookup - see {@link NamesLookup} + * @param namesLookup - see {@link NamesLookup} * @param cacheResults - whether the results should be cached for later lookups */ public JdbcDatabaseMetaDataCapability(Connection connection, UnaryOperator namesLookup, @@ -61,7 +63,8 @@ public JdbcDatabaseMetaDataCapability(Connection connection, UnaryOperator results, Named named) throws ValidationException { + protected boolean columnExists(Map results, Named named) + throws ValidationException { String[] names = splitAndValidateMinMax(COLUMN, named.getFqnLookup(), 1, 4); String columnName = names[names.length - 1]; @@ -70,7 +73,8 @@ protected boolean columnExists(Map results, Named named) throws : named.getParents(); int lastIndexOf = named.getFqnLookup().lastIndexOf("."); - String fqnParent = lastIndexOf != -1 ? named.getFqnLookup().substring(0, lastIndexOf) : null; + String fqnParent = + lastIndexOf != -1 ? named.getFqnLookup().substring(0, lastIndexOf) : null; // try to match parents in results Predicate predicate = null; @@ -101,7 +105,8 @@ protected boolean columnExists(Map results, Named named) throws throw createDatabaseException(fqn, COLUMN, e); } } else if (LOG.isLoggable(Level.FINE)) { - LOG.fine(String.format("%s does not exists, cannot evaluate COLUMN from %s", fqn, named.getFqn())); + LOG.fine(String.format("%s does not exists, cannot evaluate COLUMN from %s", fqn, + named.getFqn())); } } return false; @@ -113,12 +118,14 @@ private boolean existsFromItem(Map results, String fqn) { } @Override - protected boolean viewExists(Map results, Named named) throws ValidationException { + protected boolean viewExists(Map results, Named named) + throws ValidationException { return jdbcMetadataTables(named, VIEW); } @Override - protected boolean tableExists(Map results, Named named) throws ValidationException { + protected boolean tableExists(Map results, Named named) + throws ValidationException { return jdbcMetadataTables(named, TABLE); } @@ -142,8 +149,9 @@ protected boolean jdbcMetadataTables(Named named, String type) throws Validation List tables = new ArrayList<>(); - try (ResultSet rs = connection.getMetaData().getTables(catalog, schemaPattern, tableNamePattern, - new String[] { type })) { + try (ResultSet rs = + connection.getMetaData().getTables(catalog, schemaPattern, tableNamePattern, + new String[] {type})) { while (rs.next()) { String tableCat = rs.getString("TABLE_CAT"); String tableSchem = rs.getString("TABLE_SCHEM"); @@ -156,10 +164,10 @@ protected boolean jdbcMetadataTables(Named named, String type) throws Validation tables.add(String.join(".", tableCat, tableSchem, tableName)); } } else { - tables.add(String.join(".", tableSchem, tableName)); + tables.add(String.join(".", tableSchem, tableName)); } } - } else { + } else { tables.add(tableName); } } @@ -184,7 +192,8 @@ private String[] splitAndValidateMinMax(String type, String fqn, int min, int ma String[] names = fqn.split("\\."); if (names.length < min || names.length > max) { throw new UnexpectedValidationException(String.format( - "%s path-elements count needs to be between %s and %s for %s", fqn, min, max, type)); + "%s path-elements count needs to be between %s and %s for %s", fqn, min, max, + type)); } return names; } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/metadata/MetadataContext.java b/src/main/java/net/sf/jsqlparser/util/validation/metadata/MetadataContext.java index 10c0d8047..38ea0b37d 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/metadata/MetadataContext.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/metadata/MetadataContext.java @@ -17,8 +17,7 @@ public enum MetadataContext implements ContextKey { */ named, /** - * true, check for existence, - * false, check for non-existence + * true, check for existence, false, check for non-existence */ exists } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/metadata/Named.java b/src/main/java/net/sf/jsqlparser/util/validation/metadata/Named.java index bd7597d53..2957df99d 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/metadata/Named.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/metadata/Named.java @@ -1,128 +1,127 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2020 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.util.validation.metadata; - -import java.util.List; -import java.util.Objects; - -public class Named { - - private final NamedObject namedObject; - private final String fqn; - private String alias; - private List parents; - - private String fqnLookup; - private String aliasLookup; - - public Named(NamedObject namedObject, String fqn) { - Objects.requireNonNull(namedObject, "named object must not be null"); - Objects.requireNonNull(fqn, "fully qualified name must not be null"); - this.namedObject = namedObject; - this.fqn = fqn; - } - - public String getFqn() { - return fqn; - } - - public String getAlias() { - return alias; - } - - public Named setAlias(String alias) { - this.alias = alias; - return this; - } - - public NamedObject getNamedObject() { - return namedObject; - } - - public List getParents() { - return parents; - } - - public Named setParents(List parents) { - this.parents = parents; - return this; - } - - public Named setFqnLookup(String fqnLookup) { - this.fqnLookup = fqnLookup; - return this; - } - - public Named setAliasLookup(String aliasLookup) { - this.aliasLookup = aliasLookup; - return this; - } - - /** - * @return the fqn transformed for catalog-lookup (uppercase/lowercase/.. - * depends on database) - */ - public String getFqnLookup() { - return fqnLookup; - } - - /** - * @return the alias transformed for catalog-lookup (uppercase/lowercase/.. - * depends on database) - */ - public String getAliasLookup() { - return aliasLookup; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((alias == null) ? 0 : alias.hashCode()); - result = prime * result + fqn.hashCode(); - result = prime * result + namedObject.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Named other = (Named) obj; - if (alias == null) { - if (other.alias != null) { - return false; - } - } else if (!alias.equals(other.alias)) { - return false; - } - if (!fqn.equals(other.fqn)) { - return false; - } - if (namedObject != other.namedObject) { - return false; - } - return true; - } - - @Override - public String toString() { - return "Named [namedObject=" + namedObject + ", fqn=" + fqn + ", alias=" + alias + ", parents=" + parents + "]"; - } - - -} +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.util.validation.metadata; + +import java.util.List; +import java.util.Objects; + +public class Named { + + private final NamedObject namedObject; + private final String fqn; + private String alias; + private List parents; + + private String fqnLookup; + private String aliasLookup; + + public Named(NamedObject namedObject, String fqn) { + Objects.requireNonNull(namedObject, "named object must not be null"); + Objects.requireNonNull(fqn, "fully qualified name must not be null"); + this.namedObject = namedObject; + this.fqn = fqn; + } + + public String getFqn() { + return fqn; + } + + public String getAlias() { + return alias; + } + + public Named setAlias(String alias) { + this.alias = alias; + return this; + } + + public NamedObject getNamedObject() { + return namedObject; + } + + public List getParents() { + return parents; + } + + public Named setParents(List parents) { + this.parents = parents; + return this; + } + + /** + * @return the fqn transformed for catalog-lookup (uppercase/lowercase/.. depends on database) + */ + public String getFqnLookup() { + return fqnLookup; + } + + public Named setFqnLookup(String fqnLookup) { + this.fqnLookup = fqnLookup; + return this; + } + + /** + * @return the alias transformed for catalog-lookup (uppercase/lowercase/.. depends on database) + */ + public String getAliasLookup() { + return aliasLookup; + } + + public Named setAliasLookup(String aliasLookup) { + this.aliasLookup = aliasLookup; + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((alias == null) ? 0 : alias.hashCode()); + result = prime * result + fqn.hashCode(); + result = prime * result + namedObject.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Named other = (Named) obj; + if (alias == null) { + if (other.alias != null) { + return false; + } + } else if (!alias.equals(other.alias)) { + return false; + } + if (!fqn.equals(other.fqn)) { + return false; + } + if (namedObject != other.namedObject) { + return false; + } + return true; + } + + @Override + public String toString() { + return "Named [namedObject=" + namedObject + ", fqn=" + fqn + ", alias=" + alias + + ", parents=" + parents + "]"; + } + + +} diff --git a/src/main/java/net/sf/jsqlparser/util/validation/metadata/NamedObject.java b/src/main/java/net/sf/jsqlparser/util/validation/metadata/NamedObject.java index ee97a4573..742f183ff 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/metadata/NamedObject.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/metadata/NamedObject.java @@ -27,32 +27,18 @@ public enum NamedObject { */ view, /** - * a name constisting of min 2 (the table-reference) and max. 4 identifiers, - * i.e. [catalog].[schema].[table].[columnName] + * a name constisting of min 2 (the table-reference) and max. 4 identifiers, i.e. + * [catalog].[schema].[table].[columnName] */ - column, - index, - constraint, - uniqueConstraint, + column, index, constraint, uniqueConstraint, /** * a name constisting of max. 3 identifiers, i.e. [catalog].[schema].[sequence] */ - sequence, - synonym, - procedure, - user, - role, - trigger, - alias; - - public boolean equalsIgnoreCase(String name) { - return name().equalsIgnoreCase(name); - } + sequence, synonym, procedure, user, role, trigger, alias; /** * @param name - * @return null, if not found, otherwise the - * {@link NamedObject} + * @return null, if not found, otherwise the {@link NamedObject} */ public static NamedObject forName(String name) { for (NamedObject o : values()) { @@ -62,4 +48,8 @@ public static NamedObject forName(String name) { } return null; } + + public boolean equalsIgnoreCase(String name) { + return name().equalsIgnoreCase(name); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/metadata/NamesLookup.java b/src/main/java/net/sf/jsqlparser/util/validation/metadata/NamesLookup.java index 6ff98158e..46c2aae03 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/metadata/NamesLookup.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/metadata/NamesLookup.java @@ -13,11 +13,11 @@ import java.util.function.UnaryOperator; /** - * A strategy for transformation of database-names before lookup in - * database-catalog-metadata + * A strategy for transformation of database-names before lookup in database-catalog-metadata */ public enum NamesLookup implements UnaryOperator { - UPPERCASE(String::toUpperCase), LOWERCASE(String::toLowerCase), NO_TRANSFORMATION(UnaryOperator.identity()); + UPPERCASE(String::toUpperCase), LOWERCASE(String::toLowerCase), NO_TRANSFORMATION( + UnaryOperator.identity()); private Function strategy; @@ -29,4 +29,4 @@ public enum NamesLookup implements UnaryOperator { public String apply(String name) { return name == null ? null : strategy.apply(name); } -} \ No newline at end of file +} diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/AbstractValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/AbstractValidator.java index 5eefdd1e4..9e810ca82 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/AbstractValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/AbstractValidator.java @@ -45,12 +45,10 @@ */ public abstract class AbstractValidator implements Validator { - private ValidationContext context = new ValidationContext(); - - private Map> errors = new HashMap<>(); - - private Map>, AbstractValidator> validatorForwards = + private final Map> errors = new HashMap<>(); + private final Map>, AbstractValidator> validatorForwards = new HashMap<>(); + private ValidationContext context = new ValidationContext(); public > T getValidator(Class type) { return type.cast(validatorForwards.computeIfAbsent(type, this::newObject)); @@ -132,16 +130,16 @@ protected > void validateOptionalList(List elementL } protected void validateOptionalExpression(Expression expression) { - validateOptional(expression, e -> e.accept(getValidator(ExpressionValidator.class))); + validateOptional(expression, e -> e.accept(getValidator(ExpressionValidator.class), null)); } protected void validateOptionalExpression(Expression expression, ExpressionValidator v) { - validateOptional(expression, e -> e.accept(v)); + validateOptional(expression, e -> e.accept(v, null)); } protected void validateOptionalExpressions(List expressions) { validateOptionalList(expressions, () -> getValidator(ExpressionValidator.class), - (o, v) -> o.accept(v)); + (o, v) -> o.accept(v, null)); } protected void validateOptionalFromItems(FromItem... fromItems) { @@ -155,15 +153,15 @@ protected void validateOptionalFromItems(List fromItems) { protected void validateOptionalOrderByElements(List orderByElements) { validateOptionalList(orderByElements, () -> getValidator(OrderByValidator.class), - (o, v) -> o.accept(v)); + (o, v) -> o.accept(v, null)); } protected void validateOptionalFromItem(FromItem fromItem) { - validateOptional(fromItem, i -> i.accept(getValidator(SelectValidator.class))); + validateOptional(fromItem, i -> i.accept(getValidator(SelectValidator.class), null)); } protected void validateOptionalFromItem(FromItem fromItem, SelectValidator v) { - validateOptional(fromItem, i -> i.accept(v)); + validateOptional(fromItem, i -> i.accept(v, null)); } /** diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterSessionValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterSessionValidator.java index 35b7f7477..1f45828ae 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterSessionValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterSessionValidator.java @@ -17,6 +17,6 @@ public class AlterSessionValidator extends AbstractValidator { @Override public void validate(AlterSession statement) { - //@todo: implement this method + // @todo: implement this method } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterValidator.java index abdfdb69c..4db652b96 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterValidator.java @@ -9,6 +9,8 @@ */ package net.sf.jsqlparser.util.validation.validator; +import static java.util.stream.Collectors.toList; + import java.util.EnumSet; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.statement.alter.Alter; @@ -41,13 +43,16 @@ public void validate(Alter alter, AlterExpression e) { validateOptionalColumnName(c, e.getColumnName()); if (e.getColumnDropNotNullList() != null) { - validateOptionalColumnNames(c, ValidationUtil.map(e.getColumnDropNotNullList(), ColumnDropNotNull::getColumnName)); + validateOptionalColumnNames(c, ValidationUtil.map(e.getColumnDropNotNullList(), + ColumnDropNotNull::getColumnName)); } if (e.getColDataTypeList() != null) { - boolean validateForExist = !EnumSet.of(AlterOperation.ADD).contains(e.getOperation()); + boolean validateForExist = + !EnumSet.of(AlterOperation.ADD).contains(e.getOperation()); validateOptionalColumnNames(c, - ValidationUtil.map(e.getColDataTypeList(), ColumnDataType::getColumnName), validateForExist, + ValidationUtil.map(e.getColDataTypeList(), ColumnDataType::getColumnName), + validateForExist, NamedObject.table); } @@ -70,12 +75,16 @@ public void validate(Alter alter, AlterExpression e) { if (e.getIndex() != null) { validateName(c, NamedObject.index, e.getIndex().getName()); if (e.getIndex().getColumns() != null) { - validateOptionalColumnNames(c, e.getIndex().getColumnsNames(), NamedObject.index); + validateOptionalColumnNames(c, + e.getIndex().getColumns().stream() + .filter(cp -> !cp.isExpression()) + .map(cp -> cp.getColumnName()) + .collect(toList()), + NamedObject.index); } } } } - } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterViewValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterViewValidator.java index fe1868485..fd875b181 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterViewValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/AlterViewValidator.java @@ -11,6 +11,7 @@ import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.statement.create.view.AlterView; +import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.util.validation.ValidationCapability; import net.sf.jsqlparser.util.validation.metadata.NamedObject; @@ -27,7 +28,8 @@ public void validate(AlterView alterView) { validateName(c, NamedObject.view, alterView.getView().getFullyQualifiedName()); validateOptionalColumnNames(c, alterView.getColumnNames()); } - alterView.getSelect().accept(getValidator(SelectValidator.class)); + alterView.getSelect().accept((SelectVisitor) getValidator(SelectValidator.class), + null); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java index 82864b7ff..ac5de0c19 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/AnalyzeValidator.java @@ -14,7 +14,7 @@ import net.sf.jsqlparser.util.validation.ValidationCapability; import net.sf.jsqlparser.util.validation.metadata.NamedObject; -public class AnalyzeValidator extends AbstractValidator{ +public class AnalyzeValidator extends AbstractValidator { @Override public void validate(Analyze analyze) { for (ValidationCapability c : getCapabilities()) { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidator.java index 0a0860197..d61378497 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidator.java @@ -9,11 +9,13 @@ */ package net.sf.jsqlparser.util.validation.validator; +import static java.util.stream.Collectors.toList; + import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.statement.create.index.CreateIndex; import net.sf.jsqlparser.statement.create.table.Index; -import net.sf.jsqlparser.util.validation.metadata.NamedObject; import net.sf.jsqlparser.util.validation.ValidationCapability; +import net.sf.jsqlparser.util.validation.metadata.NamedObject; /** * @author gitmotte @@ -27,7 +29,14 @@ public void validate(CreateIndex createIndex) { validateFeature(c, Feature.createIndex); validateName(c, NamedObject.table, createIndex.getTable().getFullyQualifiedName()); validateName(c, NamedObject.index, index.getName(), false); - validateOptionalColumnNames(c, index.getColumnsNames(), NamedObject.table); + if (index.getColumns() != null) { + validateOptionalColumnNames(c, + index.getColumns().stream() + .filter(cp -> !cp.isExpression()) + .map(Index.ColumnParams::getColumnName) + .collect(toList()), + NamedObject.table); + } } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateSequenceValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateSequenceValidator.java index 213549937..f2b95d897 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateSequenceValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateSequenceValidator.java @@ -1,30 +1,31 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2020 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.util.validation.validator; - -import net.sf.jsqlparser.parser.feature.Feature; -import net.sf.jsqlparser.statement.create.sequence.CreateSequence; -import net.sf.jsqlparser.util.validation.ValidationCapability; -import net.sf.jsqlparser.util.validation.metadata.NamedObject; - -/** - * @author gitmotte - */ -public class CreateSequenceValidator extends AbstractValidator { - - - @Override - public void validate(CreateSequence statement) { - for (ValidationCapability c : getCapabilities()) { - validateFeature(Feature.createSequence); - validateName(c, NamedObject.sequence, statement.getSequence().getFullyQualifiedName(), false); - } - } -} +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.util.validation.validator; + +import net.sf.jsqlparser.parser.feature.Feature; +import net.sf.jsqlparser.statement.create.sequence.CreateSequence; +import net.sf.jsqlparser.util.validation.ValidationCapability; +import net.sf.jsqlparser.util.validation.metadata.NamedObject; + +/** + * @author gitmotte + */ +public class CreateSequenceValidator extends AbstractValidator { + + + @Override + public void validate(CreateSequence statement) { + for (ValidationCapability c : getCapabilities()) { + validateFeature(Feature.createSequence); + validateName(c, NamedObject.sequence, statement.getSequence().getFullyQualifiedName(), + false); + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateSynonymValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateSynonymValidator.java index f60226464..eb0f9d5c2 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateSynonymValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateSynonymValidator.java @@ -1,8 +1,8 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2020 JSQLParser + * Copyright (C) 2004 - 2024 JSQLParser * %% * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% @@ -23,7 +23,8 @@ public class CreateSynonymValidator extends AbstractValidator { public void validate(CreateSynonym statement) { for (ValidationCapability c : getCapabilities()) { validateFeature(Feature.createSynonym); - validateName(c, NamedObject.synonym, statement.getSynonym().getFullyQualifiedName(), false); + validateName(c, NamedObject.synonym, statement.getSynonym().getFullyQualifiedName(), + false); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateTableValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateTableValidator.java index 57d85bd7d..e4b7a3c83 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateTableValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateTableValidator.java @@ -26,17 +26,21 @@ public void validate(CreateTable createTable) { for (ValidationCapability c : getCapabilities()) { validateFeature(c, Feature.createTable); validateFeature(c, createTable.isUnlogged(), Feature.createTableUnlogged); - validateOptionalFeature(c, createTable.getCreateOptionsStrings(), Feature.createTableCreateOptionStrings); - validateOptionalFeature(c, createTable.getTableOptionsStrings(), Feature.createTableTableOptionStrings); + validateOptionalFeature(c, createTable.getCreateOptionsStrings(), + Feature.createTableCreateOptionStrings); + validateOptionalFeature(c, createTable.getTableOptionsStrings(), + Feature.createTableTableOptionStrings); validateFeature(c, createTable.isIfNotExists(), Feature.createTableIfNotExists); - validateOptionalFeature(c, createTable.getRowMovement(), Feature.createTableRowMovement); + validateOptionalFeature(c, createTable.getRowMovement(), + Feature.createTableRowMovement); validateOptionalFeature(c, createTable.getSelect(), Feature.createTableFromSelect); - if (isNotEmpty(createTable.getIndexes()) ) { + if (isNotEmpty(createTable.getIndexes())) { for (Index i : createTable.getIndexes()) { validateName(c, NamedObject.index, i.getName()); } } - validateName(c, NamedObject.table, createTable.getTable().getFullyQualifiedName(), false); + validateName(c, NamedObject.table, createTable.getTable().getFullyQualifiedName(), + false); } if (createTable.getSelect() != null) { diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidator.java index e2910ada3..12c406f2c 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidator.java @@ -14,6 +14,7 @@ import net.sf.jsqlparser.statement.create.view.ForceOption; import net.sf.jsqlparser.statement.create.view.TemporaryOption; import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.util.validation.ValidationCapability; import net.sf.jsqlparser.util.validation.metadata.NamedObject; @@ -38,7 +39,7 @@ public void validate(CreateView createView) { } SelectValidator v = getValidator(SelectValidator.class); Select select = createView.getSelect(); - select.accept(v); + select.accept((SelectVisitor) v, null); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/DeleteValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/DeleteValidator.java index 3de5343c4..19588e3b7 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/DeleteValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/DeleteValidator.java @@ -33,10 +33,10 @@ public void validate(Delete delete) { } SelectValidator v = getValidator(SelectValidator.class); - delete.getTable().accept(v); + delete.getTable().accept(v, null); if (isNotEmpty(delete.getTables())) { - delete.getTables().forEach(t -> t.accept(v)); + delete.getTables().forEach(t -> t.accept(v, null)); } validateOptionalExpression(delete.getWhere()); @@ -49,7 +49,7 @@ public void validate(Delete delete) { } if (delete.getReturningClause() != null) { - delete.getReturningClause().forEach(c -> c.accept(v)); + delete.getReturningClause().forEach(c -> c.accept(v, null)); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/DropValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/DropValidator.java index 3a6a0b454..04ea1cf8f 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/DropValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/DropValidator.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.util.validation.validator; import java.util.Arrays; + import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.statement.drop.Drop; import net.sf.jsqlparser.util.validation.ValidationCapability; @@ -36,7 +37,8 @@ public void validate(Drop drop) { Feature.dropTableIfExists); validateFeature(c, drop.isIfExists() && NamedObject.index.equalsIgnoreCase(type), Feature.dropIndexIfExists); - validateFeature(c, drop.isIfExists() && NamedObject.view.equalsIgnoreCase(type), Feature.dropViewIfExists); + validateFeature(c, drop.isIfExists() && NamedObject.view.equalsIgnoreCase(type), + Feature.dropViewIfExists); validateFeature(c, drop.isIfExists() && NamedObject.schema.equalsIgnoreCase(type), Feature.dropSchemaIfExists); validateFeature(c, drop.isIfExists() && NamedObject.sequence.equalsIgnoreCase(type), diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java index 0fc2d32dc..f017cc979 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java @@ -15,11 +15,14 @@ import net.sf.jsqlparser.expression.ArrayConstructor; import net.sf.jsqlparser.expression.ArrayExpression; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.BooleanValue; import net.sf.jsqlparser.expression.CaseExpression; import net.sf.jsqlparser.expression.CastExpression; import net.sf.jsqlparser.expression.CollateExpression; +import net.sf.jsqlparser.expression.ConnectByPriorOperator; import net.sf.jsqlparser.expression.ConnectByRootOperator; import net.sf.jsqlparser.expression.DateTimeLiteralExpression; +import net.sf.jsqlparser.expression.DateUnitExpression; import net.sf.jsqlparser.expression.DateValue; import net.sf.jsqlparser.expression.DoubleValue; import net.sf.jsqlparser.expression.Expression; @@ -27,15 +30,20 @@ import net.sf.jsqlparser.expression.ExtractExpression; import net.sf.jsqlparser.expression.Function; import net.sf.jsqlparser.expression.HexValue; +import net.sf.jsqlparser.expression.HighExpression; import net.sf.jsqlparser.expression.IntervalExpression; +import net.sf.jsqlparser.expression.Inverse; import net.sf.jsqlparser.expression.JdbcNamedParameter; import net.sf.jsqlparser.expression.JdbcParameter; import net.sf.jsqlparser.expression.JsonAggregateFunction; import net.sf.jsqlparser.expression.JsonExpression; import net.sf.jsqlparser.expression.JsonFunction; +import net.sf.jsqlparser.expression.JsonTableFunction; import net.sf.jsqlparser.expression.KeepExpression; +import net.sf.jsqlparser.expression.KeyExpression; import net.sf.jsqlparser.expression.LambdaExpression; import net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.LowExpression; import net.sf.jsqlparser.expression.MySQLGroupConcat; import net.sf.jsqlparser.expression.NextValExpression; import net.sf.jsqlparser.expression.NotExpression; @@ -45,6 +53,7 @@ import net.sf.jsqlparser.expression.OracleHint; import net.sf.jsqlparser.expression.OracleNamedFunctionParameter; import net.sf.jsqlparser.expression.OverlapsCondition; +import net.sf.jsqlparser.expression.PostgresNamedFunctionParameter; import net.sf.jsqlparser.expression.RangeExpression; import net.sf.jsqlparser.expression.RowConstructor; import net.sf.jsqlparser.expression.RowGetExpression; @@ -82,6 +91,7 @@ import net.sf.jsqlparser.expression.operators.relational.Between; import net.sf.jsqlparser.expression.operators.relational.ContainedBy; import net.sf.jsqlparser.expression.operators.relational.Contains; +import net.sf.jsqlparser.expression.operators.relational.CosineSimilarity; import net.sf.jsqlparser.expression.operators.relational.DoubleAnd; import net.sf.jsqlparser.expression.operators.relational.EqualsTo; import net.sf.jsqlparser.expression.operators.relational.ExcludesExpression; @@ -96,6 +106,7 @@ import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression; import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression; import net.sf.jsqlparser.expression.operators.relational.IsNullExpression; +import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression; import net.sf.jsqlparser.expression.operators.relational.JsonOperator; import net.sf.jsqlparser.expression.operators.relational.LikeExpression; import net.sf.jsqlparser.expression.operators.relational.Matches; @@ -104,6 +115,8 @@ import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals; import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo; import net.sf.jsqlparser.expression.operators.relational.OldOracleJoinBinaryExpression; +import net.sf.jsqlparser.expression.operators.relational.Plus; +import net.sf.jsqlparser.expression.operators.relational.PriorTo; import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator; import net.sf.jsqlparser.expression.operators.relational.SimilarToExpression; import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax; @@ -111,9 +124,12 @@ import net.sf.jsqlparser.expression.operators.relational.TSQLRightJoin; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; +import net.sf.jsqlparser.statement.select.FunctionAllColumns; import net.sf.jsqlparser.statement.select.ParenthesedSelect; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.util.validation.ValidationCapability; @@ -124,73 +140,85 @@ */ @SuppressWarnings({"PMD.CyclomaticComplexity"}) public class ExpressionValidator extends AbstractValidator - implements ExpressionVisitor { + implements ExpressionVisitor { @Override - public void visit(Addition addition) { + public Void visit(Addition addition, S context) { visitBinaryExpression(addition, " + "); + return null; } @Override - public void visit(AndExpression andExpression) { + public Void visit(AndExpression andExpression, S context) { visitBinaryExpression(andExpression, andExpression.isUseOperator() ? " && " : " AND "); + return null; } @Override - public void visit(Between between) { - between.getLeftExpression().accept(this); - between.getBetweenExpressionStart().accept(this); - between.getBetweenExpressionEnd().accept(this); + public Void visit(Between between, S context) { + between.getLeftExpression().accept(this, context); + between.getBetweenExpressionStart().accept(this, context); + between.getBetweenExpressionEnd().accept(this, context); + return null; } @Override - public void visit(OverlapsCondition overlapsCondition) { + public Void visit(OverlapsCondition overlapsCondition, S context) { validateOptionalExpressionList(overlapsCondition.getLeft()); validateOptionalExpressionList(overlapsCondition.getRight()); + return null; } @Override - public void visit(EqualsTo equalsTo) { - visitOldOracleJoinBinaryExpression(equalsTo, " = "); + public Void visit(EqualsTo equalsTo, S context) { + validateOldOracleJoinBinaryExpression(equalsTo, " = ", context); + return null; } @Override - public void visit(Division division) { + public Void visit(Division division, S context) { visitBinaryExpression(division, " / "); + return null; } @Override - public void visit(IntegerDivision division) { + public Void visit(IntegerDivision division, S context) { visitBinaryExpression(division, " DIV "); + return null; } @Override - public void visit(DoubleValue doubleValue) { + public Void visit(DoubleValue doubleValue, S context) { // nothing to validate + return null; } @Override - public void visit(HexValue hexValue) { + public Void visit(HexValue hexValue, S context) { // nothing to validate + return null; } @Override - public void visit(NotExpression notExpr) { - notExpr.getExpression().accept(this); + public Void visit(NotExpression notExpr, S context) { + notExpr.getExpression().accept(this, context); + return null; } @Override - public void visit(BitwiseRightShift expr) { + public Void visit(BitwiseRightShift expr, S context) { visitBinaryExpression(expr, " >> "); + return null; } @Override - public void visit(BitwiseLeftShift expr) { + public Void visit(BitwiseLeftShift expr, S context) { visitBinaryExpression(expr, " << "); + return null; } - public void visitOldOracleJoinBinaryExpression(OldOracleJoinBinaryExpression expression, - String operator) { + public void validateOldOracleJoinBinaryExpression(OldOracleJoinBinaryExpression expression, + String operator, S context) { for (ValidationCapability c : getCapabilities()) { validateOptionalExpression(expression.getLeftExpression(), this); if (expression.getOldOracleJoinSyntax() != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN) { @@ -205,18 +233,20 @@ public void visitOldOracleJoinBinaryExpression(OldOracleJoinBinaryExpression exp } @Override - public void visit(GreaterThan greaterThan) { - visitOldOracleJoinBinaryExpression(greaterThan, " > "); + public Void visit(GreaterThan greaterThan, S context) { + validateOldOracleJoinBinaryExpression(greaterThan, " > ", context); + return null; } @Override - public void visit(GreaterThanEquals greaterThanEquals) { - visitOldOracleJoinBinaryExpression(greaterThanEquals, " >= "); + public Void visit(GreaterThanEquals greaterThanEquals, S context) { + validateOldOracleJoinBinaryExpression(greaterThanEquals, " >= ", context); + return null; } @Override - public void visit(InExpression inExpression) { + public Void visit(InExpression inExpression, S context) { for (ValidationCapability c : getCapabilities()) { validateOptionalExpression(inExpression.getLeftExpression(), this); if (inExpression @@ -225,155 +255,296 @@ public void visit(InExpression inExpression) { } } validateOptionalExpression(inExpression.getRightExpression(), this); + return null; } @Override - public void visit(IncludesExpression includesExpression) { + public Void visit(IncludesExpression includesExpression, S context) { validateOptionalExpression(includesExpression.getLeftExpression(), this); validateOptionalExpression(includesExpression.getRightExpression(), this); + return null; } @Override - public void visit(ExcludesExpression excludesExpression) { + public Void visit(ExcludesExpression excludesExpression, S context) { validateOptionalExpression(excludesExpression.getLeftExpression(), this); validateOptionalExpression(excludesExpression.getRightExpression(), this); + return null; } @Override - public void visit(FullTextSearch fullTextSearch) { + public Void visit(FullTextSearch fullTextSearch, S context) { validateOptionalExpressions(fullTextSearch.getMatchColumns()); + validateOptionalExpression(fullTextSearch.getAgainstValue(), this); + return null; } @Override - public void visit(SignedExpression signedExpression) { - signedExpression.getExpression().accept(this); + public Void visit(SignedExpression signedExpression, S context) { + signedExpression.getExpression().accept(this, context); + return null; } @Override - public void visit(IsNullExpression isNullExpression) { - isNullExpression.getLeftExpression().accept(this); + public Void visit(IsNullExpression isNullExpression, S context) { + isNullExpression.getLeftExpression().accept(this, context); + return null; } @Override - public void visit(IsBooleanExpression isBooleanExpression) { - isBooleanExpression.getLeftExpression().accept(this); + public Void visit(IsBooleanExpression isBooleanExpression, S context) { + isBooleanExpression.getLeftExpression().accept(this, context); + return null; } @Override - public void visit(JdbcParameter jdbcParameter) { + public Void visit(IsUnknownExpression isUnknownExpression, S context) { + isUnknownExpression.getLeftExpression().accept(this, context); + return null; + } + + @Override + public Void visit(JdbcParameter jdbcParameter, S context) { validateFeature(Feature.jdbcParameter); + return null; } + public void visit(PlainSelect plainSelect) { + visit(plainSelect, null); // Call the parametrized visit method with null context + } + + public void visit(Addition addition) { + visit(addition, null); // Call the parametrized visit method with null context + } + + public void visit(AndExpression andExpression) { + visit(andExpression, null); // Call the parametrized visit method with null context + } + + public void visit(Between between) { + visit(between, null); // Call the parametrized visit method with null context + } + + public void visit(OverlapsCondition overlapsCondition) { + visit(overlapsCondition, null); // Call the parametrized visit method with null context + } + + public void visit(EqualsTo equalsTo) { + visit(equalsTo, null); // Call the parametrized visit method with null context + } + + public void visit(Division division) { + visit(division, null); // Call the parametrized visit method with null context + } + + public void visit(IntegerDivision division) { + visit(division, null); // Call the parametrized visit method with null context + } + + public void visit(DoubleValue doubleValue) { + visit(doubleValue, null); // Call the parametrized visit method with null context + } + + public void visit(HexValue hexValue) { + visit(hexValue, null); // Call the parametrized visit method with null context + } + + public void visit(NotExpression notExpr) { + visit(notExpr, null); // Call the parametrized visit method with null context + } + + public void visit(BitwiseRightShift expr) { + visit(expr, null); // Call the parametrized visit method with null context + } + + public void visit(BitwiseLeftShift expr) { + visit(expr, null); // Call the parametrized visit method with null context + } + + public void visit(GreaterThan greaterThan) { + visit(greaterThan, null); // Call the parametrized visit method with null context + } + + public void visit(GreaterThanEquals greaterThanEquals) { + visit(greaterThanEquals, null); // Call the parametrized visit method with null context + } + + public void visit(InExpression inExpression) { + visit(inExpression, null); // Call the parametrized visit method with null context + } + + public void visit(IncludesExpression includesExpression) { + visit(includesExpression, null); // Call the parametrized visit method with null context + } + + public void visit(ExcludesExpression excludesExpression) { + visit(excludesExpression, null); // Call the parametrized visit method with null context + } + + public void visit(FullTextSearch fullTextSearch) { + visit(fullTextSearch, null); // Call the parametrized visit method with null context + } + + public void visit(SignedExpression signedExpression) { + visit(signedExpression, null); // Call the parametrized visit method with null context + } + + public void visit(IsNullExpression isNullExpression) { + visit(isNullExpression, null); // Call the parametrized visit method with null context + } + + public void visit(IsBooleanExpression isBooleanExpression) { + visit(isBooleanExpression, null); // Call the parametrized visit method with null context + } + + public void visit(IsUnknownExpression isUnknownExpression) { + visit(isUnknownExpression, null); // Call the parametrized visit method with null context + } + + public void visit(JdbcParameter jdbcParameter) { + visit(jdbcParameter, null); // Call the parametrized visit method with null context + } + + @Override - public void visit(LikeExpression likeExpression) { + public Void visit(LikeExpression likeExpression, S context) { validateFeature(Feature.exprLike); visitBinaryExpression(likeExpression, (likeExpression.isNot() ? " NOT" : "") + (likeExpression.isCaseInsensitive() ? " ILIKE " : " LIKE ")); + return null; } @Override - public void visit(ExistsExpression existsExpression) { - existsExpression.getRightExpression().accept(this); + public Void visit(ExistsExpression existsExpression, S context) { + existsExpression.getRightExpression().accept(this, context); + return null; } @Override - public void visit(MemberOfExpression memberOfExpression) { - memberOfExpression.getLeftExpression().accept(this); - memberOfExpression.getRightExpression().accept(this); + public Void visit(MemberOfExpression memberOfExpression, S context) { + memberOfExpression.getLeftExpression().accept(this, context); + memberOfExpression.getRightExpression().accept(this, context); + return null; } @Override - public void visit(LongValue longValue) { + public Void visit(LongValue longValue, S context) { // nothing to validate + return null; } @Override - public void visit(MinorThan minorThan) { - visitOldOracleJoinBinaryExpression(minorThan, " < "); + public Void visit(MinorThan minorThan, S context) { + validateOldOracleJoinBinaryExpression(minorThan, " < ", context); + return null; } @Override - public void visit(MinorThanEquals minorThanEquals) { - visitOldOracleJoinBinaryExpression(minorThanEquals, " <= "); + public Void visit(MinorThanEquals minorThanEquals, S context) { + validateOldOracleJoinBinaryExpression(minorThanEquals, " <= ", context); + return null; } @Override - public void visit(Multiplication multiplication) { + public Void visit(Multiplication multiplication, S context) { visitBinaryExpression(multiplication, " * "); + return null; } @Override - public void visit(NotEqualsTo notEqualsTo) { - visitOldOracleJoinBinaryExpression(notEqualsTo, - " " + notEqualsTo.getStringExpression() + " "); + public Void visit(NotEqualsTo notEqualsTo, S context) { + validateOldOracleJoinBinaryExpression(notEqualsTo, + " " + notEqualsTo.getStringExpression() + " ", context); + return null; } @Override - public void visit(DoubleAnd doubleAnd) { + public Void visit(DoubleAnd doubleAnd, S context) { + return null; } @Override - public void visit(Contains contains) { + public Void visit(Contains contains, S context) { + return null; } @Override - public void visit(ContainedBy containedBy) { + public Void visit(ContainedBy containedBy, S context) { + return null; } @Override - public void visit(NullValue nullValue) { + public Void visit(NullValue nullValue, S context) { // nothing to validate + return null; } @Override - public void visit(OrExpression orExpression) { + public Void visit(OrExpression orExpression, S context) { visitBinaryExpression(orExpression, " OR "); + return null; } @Override - public void visit(XorExpression xorExpression) { + public Void visit(XorExpression xorExpression, S context) { visitBinaryExpression(xorExpression, " XOR "); + return null; } @Override - public void visit(StringValue stringValue) { + public Void visit(StringValue stringValue, S context) { // nothing to validate + return null; } @Override - public void visit(Subtraction subtraction) { + public Void visit(BooleanValue booleanValue, S context) { + // nothing to validate + return null; + } + + @Override + public Void visit(Subtraction subtraction, S context) { visitBinaryExpression(subtraction, " - "); + return null; } protected void visitBinaryExpression(BinaryExpression binaryExpression, String operator) { - binaryExpression.getLeftExpression().accept(this); - binaryExpression.getRightExpression().accept(this); + binaryExpression.getLeftExpression().accept(this, null); + binaryExpression.getRightExpression().accept(this, null); } @Override - public void visit(ParenthesedSelect selectBody) { + public Void visit(ParenthesedSelect selectBody, S context) { validateOptionalFromItem(selectBody); + return null; } @Override - public void visit(Column tableColumn) { + public Void visit(Column tableColumn, S context) { + if (tableColumn + .getOldOracleJoinSyntax() != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN) { + validateFeature(Feature.oracleOldJoinSyntax); + } validateName(NamedObject.column, tableColumn.getFullyQualifiedName()); + return null; } @Override - public void visit(Function function) { + public Void visit(Function function, S context) { validateFeature(Feature.function); validateOptionalExpressionList(function.getNamedParameters()); validateOptionalExpressionList(function.getParameters()); + validateOptionalExpressionList(function.getChainedParameters()); Object attribute = function.getAttribute(); if (attribute instanceof Expression) { @@ -382,86 +553,197 @@ public void visit(Function function) { validateOptionalExpression(function.getKeep(), this); validateOptionalOrderByElements(function.getOrderByElements()); + return null; } @Override - public void visit(DateValue dateValue) { + public Void visit(DateValue dateValue, S context) { // nothing to validate + return null; } @Override - public void visit(TimestampValue timestampValue) { + public Void visit(TimestampValue timestampValue, S context) { // nothing to validate + return null; } @Override - public void visit(TimeValue timeValue) { + public Void visit(TimeValue timeValue, S context) { // nothing to validate + return null; } @Override - public void visit(CaseExpression caseExpression) { + public Void visit(CaseExpression caseExpression, S context) { Expression switchExp = caseExpression.getSwitchExpression(); if (switchExp != null) { - switchExp.accept(this); + switchExp.accept(this, context); } - caseExpression.getWhenClauses().forEach(wc -> wc.accept(this)); + caseExpression.getWhenClauses().forEach(wc -> wc.accept(this, context)); Expression elseExp = caseExpression.getElseExpression(); if (elseExp != null) { - elseExp.accept(this); + elseExp.accept(this, context); } + return null; + } + + public void visit(LikeExpression likeExpression) { + visit(likeExpression, null); + } + + public void visit(ExistsExpression existsExpression) { + visit(existsExpression, null); + } + + public void visit(MemberOfExpression memberOfExpression) { + visit(memberOfExpression, null); + } + + public void visit(LongValue longValue) { + visit(longValue, null); + } + + public void visit(MinorThan minorThan) { + visit(minorThan, null); + } + + public void visit(MinorThanEquals minorThanEquals) { + visit(minorThanEquals, null); + } + + public void visit(Multiplication multiplication) { + visit(multiplication, null); + } + + public void visit(NotEqualsTo notEqualsTo) { + visit(notEqualsTo, null); + } + + public void visit(DoubleAnd doubleAnd) { + visit(doubleAnd, null); + } + + public void visit(Contains contains) { + visit(contains, null); + } + + public void visit(ContainedBy containedBy) { + visit(containedBy, null); + } + + public void visit(NullValue nullValue) { + visit(nullValue, null); + } + + public void visit(OrExpression orExpression) { + visit(orExpression, null); } + public void visit(XorExpression xorExpression) { + visit(xorExpression, null); + } + + public void visit(StringValue stringValue) { + visit(stringValue, null); + } + + public void visit(BooleanValue booleanValue) { + visit(booleanValue, null); + } + + public void visit(Subtraction subtraction) { + visit(subtraction, null); + } + + public void visit(ParenthesedSelect selectBody) { + visit(selectBody, null); + } + + public void visit(Column tableColumn) { + visit(tableColumn, null); + } + + public void visit(Function function) { + visit(function, null); + } + + public void visit(DateValue dateValue) { + visit(dateValue, null); + } + + public void visit(TimestampValue timestampValue) { + visit(timestampValue, null); + } + + public void visit(TimeValue timeValue) { + visit(timeValue, null); + } + + public void visit(CaseExpression caseExpression) { + visit(caseExpression, null); + } + + @Override - public void visit(WhenClause whenClause) { - whenClause.getWhenExpression().accept(this); - whenClause.getThenExpression().accept(this); + public Void visit(WhenClause whenClause, S context) { + whenClause.getWhenExpression().accept(this, context); + whenClause.getThenExpression().accept(this, context); + return null; } @Override - public void visit(AnyComparisonExpression anyComparisonExpression) { - anyComparisonExpression.getSelect().accept(this); + public Void visit(AnyComparisonExpression anyComparisonExpression, S context) { + anyComparisonExpression.getSelect().accept(this, context); + return null; } @Override - public void visit(Concat concat) { + public Void visit(Concat concat, S context) { visitBinaryExpression(concat, " || "); + return null; } @Override - public void visit(Matches matches) { - visitOldOracleJoinBinaryExpression(matches, " @@ "); + public Void visit(Matches matches, S context) { + validateOldOracleJoinBinaryExpression(matches, " @@ ", context); + return null; } @Override - public void visit(BitwiseAnd bitwiseAnd) { + public Void visit(BitwiseAnd bitwiseAnd, S context) { visitBinaryExpression(bitwiseAnd, " & "); + return null; } @Override - public void visit(BitwiseOr bitwiseOr) { + public Void visit(BitwiseOr bitwiseOr, S context) { visitBinaryExpression(bitwiseOr, " | "); + return null; } @Override - public void visit(BitwiseXor bitwiseXor) { + public Void visit(BitwiseXor bitwiseXor, S context) { visitBinaryExpression(bitwiseXor, " ^ "); + return null; } @Override - public void visit(CastExpression cast) { - cast.getLeftExpression().accept(this); + public Void visit(CastExpression cast, S context) { + cast.getLeftExpression().accept(this, context); + return null; } @Override - public void visit(Modulo modulo) { + public Void visit(Modulo modulo, S context) { visitBinaryExpression(modulo, " % "); + return null; } @Override - public void visit(AnalyticExpression aexpr) { + public Void visit(AnalyticExpression aexpr, S context) { validateOptionalExpression(aexpr.getExpression(), this); validateOptionalExpression(aexpr.getOffset(), this); validateOptionalExpression(aexpr.getDefaultValue(), this); @@ -478,6 +760,7 @@ public void visit(AnalyticExpression aexpr) { } } validateOptionalExpression(aexpr.getFilterExpression()); + return null; } private void validateOptionalWindowOffset(WindowOffset offset) { @@ -487,250 +770,588 @@ private void validateOptionalWindowOffset(WindowOffset offset) { } @Override - public void visit(ExtractExpression eexpr) { - eexpr.getExpression().accept(this); + public Void visit(ExtractExpression eexpr, S context) { + eexpr.getExpression().accept(this, context); + return null; } @Override - public void visit(IntervalExpression iexpr) { + public Void visit(IntervalExpression iexpr, S context) { validateOptionalExpression(iexpr.getExpression()); + return null; } @Override - public void visit(JdbcNamedParameter jdbcNamedParameter) { + public Void visit(JdbcNamedParameter jdbcNamedParameter, S context) { validateFeature(Feature.jdbcNamedParameter); + return null; } @Override - public void visit(OracleHierarchicalExpression oexpr) { + public Void visit(OracleHierarchicalExpression oexpr, S context) { validateFeature(Feature.oracleHierarchicalExpression); + return null; } @Override - public void visit(RegExpMatchOperator rexpr) { + public Void visit(RegExpMatchOperator rexpr, S context) { visitBinaryExpression(rexpr, " " + rexpr.getStringExpression() + " "); + return null; } @Override - public void visit(JsonExpression jsonExpr) { + public Void visit(JsonExpression jsonExpr, S context) { validateOptionalExpression(jsonExpr.getExpression()); + return null; } @Override - public void visit(JsonOperator jsonExpr) { + public Void visit(JsonOperator jsonExpr, S context) { visitBinaryExpression(jsonExpr, " " + jsonExpr.getStringExpression() + " "); + return null; } @Override - public void visit(UserVariable var) { + public Void visit(UserVariable var, S context) { // nothing to validate + return null; } @Override - public void visit(NumericBind bind) { + public Void visit(NumericBind bind, S context) { // nothing to validate + return null; } @Override - public void visit(KeepExpression aexpr) { + public Void visit(KeepExpression aexpr, S context) { validateOptionalOrderByElements(aexpr.getOrderByElements()); + return null; } @Override - public void visit(MySQLGroupConcat groupConcat) { + public Void visit(MySQLGroupConcat groupConcat, S context) { validateOptionalExpressionList(groupConcat.getExpressionList()); validateOptionalOrderByElements(groupConcat.getOrderByElements()); + return null; } private void validateOptionalExpressionList(ExpressionList expressionList) { if (expressionList != null) { for (Expression expression : expressionList) { - expression.accept(this); + expression.accept(this, null); } } } + public void visit(WhenClause whenClause) { + visit(whenClause, null); + } + + public void visit(AnyComparisonExpression anyComparisonExpression) { + visit(anyComparisonExpression, null); + } + + public void visit(Concat concat) { + visit(concat, null); + } + + public void visit(Matches matches) { + visit(matches, null); + } + + public void visit(BitwiseAnd bitwiseAnd) { + visit(bitwiseAnd, null); + } + + public void visit(BitwiseOr bitwiseOr) { + visit(bitwiseOr, null); + } + + public void visit(BitwiseXor bitwiseXor) { + visit(bitwiseXor, null); + } + + public void visit(CastExpression cast) { + visit(cast, null); + } + + public void visit(Modulo modulo) { + visit(modulo, null); + } + + public void visit(AnalyticExpression aexpr) { + visit(aexpr, null); + } + + public void visit(ExtractExpression eexpr) { + visit(eexpr, null); + } + + public void visit(IntervalExpression iexpr) { + visit(iexpr, null); + } + + public void visit(JdbcNamedParameter jdbcNamedParameter) { + visit(jdbcNamedParameter, null); + } + + public void visit(OracleHierarchicalExpression oexpr) { + visit(oexpr, null); + } + + public void visit(RegExpMatchOperator rexpr) { + visit(rexpr, null); + } + + public void visit(JsonExpression jsonExpr) { + visit(jsonExpr, null); + } + + public void visit(JsonOperator jsonExpr) { + visit(jsonExpr, null); + } + + public void visit(UserVariable var) { + visit(var, null); + } + + public void visit(NumericBind bind) { + visit(bind, null); + } + + public void visit(KeepExpression aexpr) { + visit(aexpr, null); + } + + public void visit(MySQLGroupConcat groupConcat) { + visit(groupConcat, null); + } + @Override - public void visit(ExpressionList expressionList) { + public Void visit(ExpressionList expressionList, S context) { validateOptionalExpressionList(expressionList); + return null; } @Override - public void visit(RowConstructor rowConstructor) { + public Void visit(RowConstructor rowConstructor, S context) { validateOptionalExpressionList(rowConstructor); + return null; } @Override - public void visit(RowGetExpression rowGetExpression) { - rowGetExpression.getExpression().accept(this); + public Void visit(RowGetExpression rowGetExpression, S context) { + rowGetExpression.getExpression().accept(this, context); + return null; } @Override - public void visit(OracleHint hint) { + public Void visit(OracleHint hint, S context) { // nothing to validate + return null; } @Override - public void visit(TimeKeyExpression timeKeyExpression) { + public Void visit(TimeKeyExpression timeKeyExpression, S context) { // nothing to validate + return null; } @Override - public void visit(DateTimeLiteralExpression literal) { + public Void visit(DateTimeLiteralExpression literal, S context) { // nothing to validate + return null; } @Override - public void visit(NextValExpression nextVal) { + public Void visit(NextValExpression nextVal, S context) { validateName(NamedObject.sequence, nextVal.getName()); + return null; } @Override - public void visit(CollateExpression col) { + public Void visit(CollateExpression col, S context) { validateOptionalExpression(col.getLeftExpression()); + return null; } @Override - public void visit(SimilarToExpression expr) { + public Void visit(SimilarToExpression expr, S context) { validateFeature(Feature.exprSimilarTo); visitBinaryExpression(expr, (expr.isNot() ? " NOT" : "") + " SIMILAR TO "); + return null; } @Override - public void visit(ArrayExpression array) { - array.getObjExpression().accept(this); + public Void visit(ArrayExpression array, S context) { + array.getObjExpression().accept(this, context); if (array.getIndexExpression() != null) { - array.getIndexExpression().accept(this); + array.getIndexExpression().accept(this, context); } if (array.getStartIndexExpression() != null) { - array.getStartIndexExpression().accept(this); + array.getStartIndexExpression().accept(this, context); } if (array.getStopIndexExpression() != null) { - array.getStopIndexExpression().accept(this); + array.getStopIndexExpression().accept(this, context); } + return null; } @Override - public void visit(ArrayConstructor aThis) { + public Void visit(ArrayConstructor aThis, S context) { for (Expression expression : aThis.getExpressions()) { - expression.accept(this); + expression.accept(this, context); } + return null; } @Override public void validate(Expression expression) { - expression.accept(this); + expression.accept(this, null); } @Override - public void visit(VariableAssignment a) { + public Void visit(VariableAssignment a, S context) { validateOptionalExpression(a.getExpression()); if (a.getVariable() != null) { - a.getVariable().accept(this); + a.getVariable().accept(this, context); } + return null; } @Override - public void visit(TimezoneExpression a) { + public Void visit(TimezoneExpression a, S context) { validateOptionalExpression(a.getLeftExpression()); + return null; } @Override - public void visit(XMLSerializeExpr xml) { - // TODO this feature seams very close to a jsqlparser-user usecase + public Void visit(XMLSerializeExpr xml, S context) { + return null; } @Override - public void visit(JsonAggregateFunction expression) { + public Void visit(JsonAggregateFunction expression, S context) { // no idea what this is good for + return null; } @Override - public void visit(JsonFunction expression) { + public Void visit(JsonFunction expression, S context) { // no idea what this is good for + return null; } @Override - public void visit(ConnectByRootOperator connectByRootOperator) { - connectByRootOperator.getColumn().accept(this); + public Void visit(JsonTableFunction expression, S context) { + for (Expression jsonExpression : expression.getAllExpressions()) { + validateOptionalExpression(jsonExpression, this); + } + return null; } @Override - public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) { - oracleNamedFunctionParameter.getExpression().accept(this); + public Void visit(ConnectByRootOperator connectByRootOperator, S context) { + connectByRootOperator.getColumn().accept(this, context); + return null; } @Override - public void visit(AllColumns allColumns) {} + public Void visit(ConnectByPriorOperator connectByPriorOperator, S context) { + connectByPriorOperator.getColumn().accept(this, context); + return null; + } @Override - public void visit(AllTableColumns allTableColumns) {} + public Void visit(KeyExpression keyExpression, S context) { + keyExpression.getExpression().accept(this, context); + return null; + } @Override - public void visit(AllValue allValue) { + public Void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context) { + oracleNamedFunctionParameter.getExpression().accept(this, context); + return null; + } + @Override + public Void visit(PostgresNamedFunctionParameter postgresNamedFunctionParameter, + S context) { + postgresNamedFunctionParameter.getExpression().accept(this, context); + return null; } @Override - public void visit(IsDistinctExpression isDistinctExpression) { - isDistinctExpression.getLeftExpression().accept(this); - isDistinctExpression.getRightExpression().accept(this); + public Void visit(AllColumns allColumns, S context) { + return null; } @Override - public void visit(GeometryDistance geometryDistance) { - visitOldOracleJoinBinaryExpression(geometryDistance, " <-> "); + public Void visit(AllTableColumns allTableColumns, S context) { + return null; } @Override - public void visit(Select selectBody) { + public Void visit(FunctionAllColumns functionColumns, S context) { + return null; + } + @Override + public Void visit(AllValue allValue, S context) { + return null; } @Override - public void visit(TranscodingFunction transcodingFunction) { - transcodingFunction.getExpression().accept(this); + public Void visit(IsDistinctExpression isDistinctExpression, S context) { + isDistinctExpression.getLeftExpression().accept(this, context); + isDistinctExpression.getRightExpression().accept(this, context); + return null; } @Override - public void visit(TrimFunction trimFunction) { + public Void visit(GeometryDistance geometryDistance, S context) { + validateOldOracleJoinBinaryExpression(geometryDistance, " <-> ", context); + return null; + } + + @Override + public Void visit(Select select, S context) { + return null; + } + + @Override + public Void visit(TranscodingFunction transcodingFunction, S context) { + transcodingFunction.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(TrimFunction trimFunction, S context) { if (trimFunction.getExpression() != null) { - trimFunction.getExpression().accept(this); + trimFunction.getExpression().accept(this, context); } if (trimFunction.getFromExpression() != null) { - trimFunction.getFromExpression().accept(this); + trimFunction.getFromExpression().accept(this, context); } + return null; } @Override - public void visit(RangeExpression rangeExpression) { - rangeExpression.getStartExpression().accept(this); - rangeExpression.getEndExpression().accept(this); + public Void visit(RangeExpression rangeExpression, S context) { + rangeExpression.getStartExpression().accept(this, context); + rangeExpression.getEndExpression().accept(this, context); + return null; } @Override - public void visit(TSQLLeftJoin tsqlLeftJoin) { - tsqlLeftJoin.getLeftExpression().accept(this); - tsqlLeftJoin.getRightExpression().accept(this); + public Void visit(TSQLLeftJoin tsqlLeftJoin, S context) { + tsqlLeftJoin.getLeftExpression().accept(this, context); + tsqlLeftJoin.getRightExpression().accept(this, context); + return null; } @Override - public void visit(TSQLRightJoin tsqlRightJoin) { - tsqlRightJoin.getLeftExpression().accept(this); - tsqlRightJoin.getRightExpression().accept(this); + public Void visit(TSQLRightJoin tsqlRightJoin, S context) { + tsqlRightJoin.getLeftExpression().accept(this, context); + tsqlRightJoin.getRightExpression().accept(this, context); + return null; } @Override - public void visit(StructType structType) { + public Void visit(StructType structType, S context) { if (structType.getArguments() != null) { for (SelectItem selectItem : structType.getArguments()) { - selectItem.getExpression().accept(this); + selectItem.getExpression().accept(this, context); } } + return null; } @Override + public Void visit(LambdaExpression lambdaExpression, S context) { + lambdaExpression.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(HighExpression highExpression, S context) { + highExpression.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(LowExpression lowExpression, S context) { + lowExpression.getExpression().accept(this, context); + return null; + } + + @Override + public Void visit(Plus plus, S context) { + visitBinaryExpression(plus, " PLUS "); + return null; + } + + @Override + public Void visit(PriorTo priorTo, S context) { + visitBinaryExpression(priorTo, " PLUS "); + return null; + } + + @Override + public Void visit(Inverse inverse, S context) { + inverse.getExpression().accept(this, context); + return null; + } + + public void visit(TimeKeyExpression timeKeyExpression) { + visit(timeKeyExpression, null); + } + + public void visit(DateTimeLiteralExpression literal) { + visit(literal, null); + } + + public void visit(NextValExpression nextVal) { + visit(nextVal, null); + } + + public void visit(CollateExpression col) { + visit(col, null); + } + + public void visit(SimilarToExpression expr) { + visit(expr, null); + } + + public void visit(ArrayExpression array) { + visit(array, null); + } + + public void visit(ArrayConstructor aThis) { + visit(aThis, null); + } + + + public void visit(VariableAssignment a) { + visit(a, null); + } + + public void visit(TimezoneExpression a) { + visit(a, null); + } + + public void visit(XMLSerializeExpr xml) { + visit(xml, null); + } + + public void visit(JsonAggregateFunction expression) { + visit(expression, null); + } + + public void visit(JsonFunction expression) { + visit(expression, null); + } + + public void visit(ConnectByRootOperator connectByRootOperator) { + visit(connectByRootOperator, null); + } + + public void visit(KeyExpression keyExpression) { + visit(keyExpression, null); + } + + public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) { + visit(oracleNamedFunctionParameter, null); + } + + public void visit(AllColumns allColumns) { + visit(allColumns, null); + } + + public void visit(AllTableColumns allTableColumns) { + visit(allTableColumns, null); + } + + public void visit(AllValue allValue) { + visit(allValue, null); + } + + public void visit(IsDistinctExpression isDistinctExpression) { + visit(isDistinctExpression, null); + } + + public void visit(GeometryDistance geometryDistance) { + visit(geometryDistance, null); + } + + public void visit(Select select) { + visit(select, null); + } + + public void visit(TranscodingFunction transcodingFunction) { + visit(transcodingFunction, null); + } + + public void visit(TrimFunction trimFunction) { + visit(trimFunction, null); + } + + public void visit(RangeExpression rangeExpression) { + visit(rangeExpression, null); + } + + public void visit(TSQLLeftJoin tsqlLeftJoin) { + visit(tsqlLeftJoin, null); + } + + public void visit(TSQLRightJoin tsqlRightJoin) { + visit(tsqlRightJoin, null); + } + + public void visit(StructType structType) { + visit(structType, null); + } + public void visit(LambdaExpression lambdaExpression) { - lambdaExpression.getExpression().accept(this); + visit(lambdaExpression, null); } + + public void visit(HighExpression highExpression) { + visit(highExpression, null); + } + + public void visit(LowExpression lowExpression) { + visit(lowExpression, null); + } + + public void visit(Plus plus) { + visit(plus, null); + } + + public void visit(PriorTo priorTo) { + visit(priorTo, null); + } + + public void visit(Inverse inverse) { + visit(inverse, null); + } + + @Override + public Void visit(CosineSimilarity cosineSimilarity, S context) { + cosineSimilarity.getLeftExpression().accept(this, context); + cosineSimilarity.getRightExpression().accept(this, context); + return null; + } + + @Override + public Void visit(FromQuery fromQuery, S context) { + return null; + } + + @Override + public Void visit(DateUnitExpression dateUnitExpression, S context) { + return null; + } + } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/GroupByValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/GroupByValidator.java index 215b5b514..ee2d7155f 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/GroupByValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/GroupByValidator.java @@ -19,15 +19,16 @@ /** * @author gitmotte */ -public class GroupByValidator extends AbstractValidator implements GroupByVisitor { +public class GroupByValidator extends AbstractValidator + implements GroupByVisitor { @Override public void validate(GroupByElement groupBy) { - groupBy.accept(this); + groupBy.accept(this, null); } @Override - public void visit(GroupByElement groupBy) { + public Void visit(GroupByElement groupBy, S context) { for (ValidationCapability c : getCapabilities()) { validateFeature(c, Feature.selectGroupBy); if (isNotEmpty(groupBy.getGroupingSets())) { @@ -46,6 +47,7 @@ public void visit(GroupByElement groupBy) { } } } + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/InsertValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/InsertValidator.java index be09f314c..99f6ad3ea 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/InsertValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/InsertValidator.java @@ -11,6 +11,8 @@ import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.insert.OracleMultiInsertBranch; +import net.sf.jsqlparser.statement.insert.OracleMultiInsertClause; import net.sf.jsqlparser.statement.select.Values; import net.sf.jsqlparser.statement.update.UpdateSet; import net.sf.jsqlparser.util.validation.ValidationCapability; @@ -41,11 +43,32 @@ public void validate(Insert insert) { Feature.insertReturningExpressionList); } - validateOptionalFromItem(insert.getTable()); - validateOptionalExpressions(insert.getColumns()); + if (insert.isOracleMultiInsert() && insert.getOracleMultiInsertBranches() != null) { + ExpressionValidator v = getValidator(ExpressionValidator.class); + for (OracleMultiInsertBranch branch : insert.getOracleMultiInsertBranches()) { + if (branch.getWhenExpression() != null) { + branch.getWhenExpression().accept(v, null); + } + if (branch.getClauses() == null) { + continue; + } + for (OracleMultiInsertClause clause : branch.getClauses()) { + validateOptionalFromItem(clause.getTable()); + validateOptionalExpressions(clause.getColumns()); + if (clause.getSelect() instanceof Values) { + clause.getSelect().accept(getValidator(StatementValidator.class), null); + validateOptionalExpressions( + clause.getSelect().as(Values.class).getExpressions()); + } + } + } + } else { + validateOptionalFromItem(insert.getTable()); + validateOptionalExpressions(insert.getColumns()); + } if (insert.getSelect() instanceof Values) { - insert.getSelect().accept(getValidator(StatementValidator.class)); + insert.getSelect().accept(getValidator(StatementValidator.class), null); validateOptionalExpressions(insert.getValues().getExpressions()); } @@ -55,8 +78,8 @@ public void validate(Insert insert) { // validateModelCondition (insert.getSetColumns().size() != // insert.getSetExpressionList().size(), "model-error"); for (UpdateSet updateSet : insert.getSetUpdateSets()) { - updateSet.getColumns().forEach(c -> c.accept(v)); - updateSet.getValues().forEach(c -> c.accept(v)); + updateSet.getColumns().forEach(c -> c.accept(v, null)); + updateSet.getValues().forEach(c -> c.accept(v, null)); } } @@ -66,14 +89,14 @@ public void validate(Insert insert) { // validateModelCondition (insert.getSetColumns().size() != // insert.getSetExpressionList().size(), "model-error"); for (UpdateSet updateSet : insert.getDuplicateUpdateSets()) { - updateSet.getColumns().forEach(c -> c.accept(v)); - updateSet.getValues().forEach(c -> c.accept(v)); + updateSet.getColumns().forEach(c -> c.accept(v, null)); + updateSet.getValues().forEach(c -> c.accept(v, null)); } } if (insert.getReturningClause() != null) { SelectValidator v = getValidator(SelectValidator.class); - insert.getReturningClause().forEach(c -> c.accept(v)); + insert.getReturningClause().forEach(c -> c.accept(v, null)); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/MergeValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/MergeValidator.java index e9e0765cc..e82ebc91d 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/MergeValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/MergeValidator.java @@ -17,7 +17,8 @@ /** * @author gitmotte */ -public class MergeValidator extends AbstractValidator implements MergeOperationVisitor { +public class MergeValidator extends AbstractValidator + implements MergeOperationVisitor { @Override @@ -27,18 +28,23 @@ public void validate(Merge merge) { } validateOptionalExpression(merge.getOnCondition()); if (merge.getOperations() != null) { - merge.getOperations().forEach(operation -> operation.accept(this)); + merge.getOperations().forEach(operation -> operation.accept(this, null)); } validateOptionalFromItems(merge.getFromItem()); } @Override - public void visit(MergeDelete mergeDelete) { + public Void visit(MergeDelete mergeDelete, S context) { validateOptionalExpression(mergeDelete.getAndPredicate()); + return null; + } + + public void visit(MergeDelete mergeDelete) { + visit(mergeDelete, null); } @Override - public void visit(MergeUpdate mergeUpdate) { + public Void visit(MergeUpdate mergeUpdate, S context) { validateOptionalExpression(mergeUpdate.getAndPredicate()); for (UpdateSet updateSet : mergeUpdate.getUpdateSets()) { validateOptionalExpressions(updateSet.getColumns()); @@ -46,12 +52,23 @@ public void visit(MergeUpdate mergeUpdate) { } validateOptionalExpression(mergeUpdate.getDeleteWhereCondition()); validateOptionalExpression(mergeUpdate.getWhereCondition()); + return null; + } + + public void visit(MergeUpdate mergeUpdate) { + visit(mergeUpdate, null); } @Override - public void visit(MergeInsert mergeInsert) { + public Void visit(MergeInsert mergeInsert, S context) { validateOptionalExpression(mergeInsert.getAndPredicate()); validateOptionalExpressions(mergeInsert.getColumns()); validateOptionalExpressions(mergeInsert.getValues()); + + return null; + } + + public void visit(MergeInsert mergeInsert) { + visit(mergeInsert, null); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/OrderByValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/OrderByValidator.java index 20a5c780d..858702dda 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/OrderByValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/OrderByValidator.java @@ -1,36 +1,42 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2020 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.util.validation.validator; - -import net.sf.jsqlparser.parser.feature.Feature; -import net.sf.jsqlparser.statement.select.OrderByElement; -import net.sf.jsqlparser.statement.select.OrderByVisitor; -import net.sf.jsqlparser.util.validation.ValidationCapability; - -/** - * @author gitmotte - */ -public class OrderByValidator extends AbstractValidator implements OrderByVisitor { - - @Override - public void validate(OrderByElement element) { - element.accept(this); - } - - @Override - public void visit(OrderByElement orderBy) { - for (ValidationCapability c : getCapabilities()) { - validateFeature(c, Feature.orderBy); - validateOptionalFeature(c, orderBy.getNullOrdering(), Feature.orderByNullOrdering); - } - getValidator(ExpressionValidator.class).validate(orderBy.getExpression()); - } +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.util.validation.validator; -} +import net.sf.jsqlparser.parser.feature.Feature; +import net.sf.jsqlparser.statement.select.OrderByElement; +import net.sf.jsqlparser.statement.select.OrderByVisitor; +import net.sf.jsqlparser.util.validation.ValidationCapability; + +/** + * @author gitmotte + */ +public class OrderByValidator extends AbstractValidator + implements OrderByVisitor { + + @Override + public void validate(OrderByElement element) { + element.accept(this, null); + } + + @Override + public Void visit(OrderByElement orderBy, S context) { + for (ValidationCapability c : getCapabilities()) { + validateFeature(c, Feature.orderBy); + validateOptionalFeature(c, orderBy.getNullOrdering(), Feature.orderByNullOrdering); + } + getValidator(ExpressionValidator.class).validate(orderBy.getExpression()); + return null; + } + + public void visit(OrderByElement orderBy) { + visit(orderBy, null); + } + +} diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java index 97fcd08a3..5cab04030 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java @@ -15,6 +15,8 @@ import net.sf.jsqlparser.expression.SQLServerHints; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.imprt.Import; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.ExceptOp; import net.sf.jsqlparser.statement.select.Fetch; import net.sf.jsqlparser.statement.select.ForMode; @@ -23,6 +25,7 @@ import net.sf.jsqlparser.statement.select.Join; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.MinusOp; +import net.sf.jsqlparser.statement.select.MySqlSelectIntoClause; import net.sf.jsqlparser.statement.select.Offset; import net.sf.jsqlparser.statement.select.ParenthesedFromItem; import net.sf.jsqlparser.statement.select.ParenthesedSelect; @@ -47,15 +50,16 @@ /** * @author gitmotte */ -public class SelectValidator extends AbstractValidator - implements SelectVisitor, SelectItemVisitor, FromItemVisitor, PivotVisitor { +public class SelectValidator extends AbstractValidator> + implements SelectVisitor, SelectItemVisitor, FromItemVisitor, + PivotVisitor { @SuppressWarnings({"PMD.CyclomaticComplexity"}) @Override - public void visit(PlainSelect plainSelect) { + public Void visit(PlainSelect plainSelect, S context) { if (isNotEmpty(plainSelect.getWithItemsList())) { plainSelect.getWithItemsList() - .forEach(withItem -> withItem.accept((SelectVisitor) this)); + .forEach(withItem -> withItem.accept((SelectVisitor) this, context)); } for (ValidationCapability c : getCapabilities()) { @@ -97,6 +101,11 @@ public void visit(PlainSelect plainSelect) { validateOptionalFeature(c, plainSelect.getForUpdateTable(), Feature.selectForUpdateOfTable); + if (plainSelect.getForUpdateTables() != null) { + plainSelect.getForUpdateTables() + .forEach(t -> validateOptionalFeature(c, t, + Feature.selectForUpdateOfTable)); + } validateOptionalFeature(c, plainSelect.getWait(), Feature.selectForUpdateWait); validateFeature(c, plainSelect.isNoWait(), Feature.selectForUpdateNoWait); validateFeature(c, plainSelect.isSkipLocked(), Feature.selectForUpdateSkipLocked); @@ -111,13 +120,18 @@ public void visit(PlainSelect plainSelect) { validateOptionalJoins(plainSelect.getJoins()); // to correctly recognize aliased tables - validateOptionalList(plainSelect.getSelectItems(), () -> this, (e, v) -> e.accept(v)); + // @todo: fix this properly, I don't understand functional syntax + // validateOptionalList(plainSelect.getSelectItems(), () -> this, SelectItem::accept, + // context); + validateOptionalExpression(plainSelect.getPreWhere()); validateOptionalExpression(plainSelect.getWhere()); validateOptionalExpression(plainSelect.getOracleHierarchical()); + validateOptional(plainSelect.getMySqlSelectIntoClause(), + this::validateMySqlSelectIntoClause); if (plainSelect.getGroupBy() != null) { - plainSelect.getGroupBy().accept(getValidator(GroupByValidator.class)); + plainSelect.getGroupBy().accept(getValidator(GroupByValidator.class), context); } validateOptionalExpression(plainSelect.getHaving()); @@ -135,30 +149,45 @@ public void visit(PlainSelect plainSelect) { validateFetch(plainSelect.getFetch()); } + validateOptional(plainSelect.getPivot(), p -> p.accept(this, context)); + + return null; + } + + private void validateMySqlSelectIntoClause(MySqlSelectIntoClause mySqlSelectIntoClause) { + validateOptionalExpression(mySqlSelectIntoClause.getFileName()); + validateOptionalExpression(mySqlSelectIntoClause.getFieldsTerminatedBy()); + validateOptionalExpression(mySqlSelectIntoClause.getFieldsEnclosedBy()); + validateOptionalExpression(mySqlSelectIntoClause.getFieldsEscapedBy()); + validateOptionalExpression(mySqlSelectIntoClause.getLinesStartingBy()); + validateOptionalExpression(mySqlSelectIntoClause.getLinesTerminatedBy()); } @Override - public void visit(SelectItem selectExpressionItem) { - selectExpressionItem.getExpression().accept(getValidator(ExpressionValidator.class)); + public Void visit(SelectItem selectExpressionItem, S context) { + selectExpressionItem.getExpression().accept(getValidator(ExpressionValidator.class), + context); + return null; } @Override - public void visit(ParenthesedSelect selectBody) { + public Void visit(ParenthesedSelect selectBody, S context) { if (isNotEmpty(selectBody.getWithItemsList())) { selectBody.getWithItemsList() - .forEach(withItem -> withItem.accept((SelectVisitor) this)); + .forEach(withItem -> withItem.accept((SelectVisitor) this, context)); } - selectBody.getSelect().accept(this); - validateOptional(selectBody.getPivot(), p -> p.accept(this)); + selectBody.getSelect().accept((SelectVisitor) this, context); + validateOptional(selectBody.getPivot(), p -> p.accept(this, context)); + return null; } @Override - public void visit(Table table) { + public Void visit(Table table, S context) { validateNameWithAlias(NamedObject.table, table.getFullyQualifiedName(), ValidationUtil.getAlias(table.getAlias())); - validateOptional(table.getPivot(), p -> p.accept(this)); - validateOptional(table.getUnPivot(), up -> up.accept(this)); + validateOptional(table.getPivot(), p -> p.accept(this, context)); + validateOptional(table.getUnPivot(), up -> up.accept(this, context)); MySQLIndexHint indexHint = table.getIndexHint(); if (indexHint != null && isNotEmpty(indexHint.getIndexNames())) { @@ -168,33 +197,37 @@ public void visit(Table table) { if (sqlServerHints != null) { validateName(NamedObject.index, sqlServerHints.getIndexName()); } + return null; } @Override - public void visit(Pivot pivot) { + public Void visit(Pivot pivot, S context) { validateFeature(Feature.pivot); validateOptionalExpressions(pivot.getForColumns()); + return null; } @Override - public void visit(UnPivot unpivot) { + public Void visit(UnPivot unpivot, S context) { validateFeature(Feature.unpivot); validateOptionalExpressions(unpivot.getUnPivotForClause()); validateOptionalExpressions(unpivot.getUnPivotClause()); + return null; } @Override - public void visit(PivotXml pivot) { + public Void visit(PivotXml pivot, S context) { validateFeature(Feature.pivotXml); validateOptionalExpressions(pivot.getForColumns()); if (isNotEmpty(pivot.getFunctionItems())) { ExpressionValidator v = getValidator(ExpressionValidator.class); - pivot.getFunctionItems().forEach(f -> f.getExpression().accept(v)); + pivot.getFunctionItems().forEach(f -> f.getExpression().accept(v, context)); } if (pivot.getInSelect() != null) { - pivot.getInSelect().accept(this); + pivot.getInSelect().accept((SelectVisitor) this, context); } + return null; } public void validateOffset(Offset offset) { @@ -249,10 +282,10 @@ public void validateOptionalJoin(Join join) { } @Override - public void visit(SetOperationList setOperation) { + public Void visit(SetOperationList setOperation, S context) { if (isNotEmpty(setOperation.getWithItemsList())) { setOperation.getWithItemsList() - .forEach(withItem -> withItem.accept((SelectVisitor) this)); + .forEach(withItem -> withItem.accept((SelectVisitor) this, context)); } for (ValidationCapability c : getCapabilities()) { validateFeature(c, Feature.setOperation); @@ -271,7 +304,7 @@ public void visit(SetOperationList setOperation) { } if (isNotEmpty(setOperation.getSelects())) { - setOperation.getSelects().forEach(s -> s.accept(this)); + setOperation.getSelects().forEach(s -> s.accept((SelectVisitor) this, context)); } validateOptionalOrderByElements(setOperation.getOrderByElements()); @@ -287,58 +320,140 @@ public void visit(SetOperationList setOperation) { if (setOperation.getFetch() != null) { validateFetch(setOperation.getFetch()); } + return null; } @Override - public void visit(WithItem withItem) { + public Void visit(WithItem withItem, S context) { for (ValidationCapability c : getCapabilities()) { validateFeature(c, Feature.withItem); validateFeature(c, withItem.isRecursive(), Feature.withItemRecursive); } if (isNotEmpty(withItem.getWithItemList())) { - withItem.getWithItemList().forEach(wi -> wi.accept(this)); + withItem.getWithItemList().forEach(wi -> wi.accept(this, context)); } - withItem.getSelect().accept(this); + withItem.getSelect().accept((SelectVisitor) this, context); + return null; } @Override - public void visit(LateralSubSelect lateralSubSelect) { + public Void visit(LateralSubSelect lateralSubSelect, S context) { if (isNotEmpty(lateralSubSelect.getWithItemsList())) { lateralSubSelect.getWithItemsList() - .forEach(withItem -> withItem.accept((SelectVisitor) this)); + .forEach(withItem -> withItem.accept((SelectVisitor) this, context)); } validateFeature(Feature.lateralSubSelect); - validateOptional(lateralSubSelect.getPivot(), p -> p.accept(this)); - validateOptional(lateralSubSelect.getUnPivot(), up -> up.accept(this)); - validateOptional(lateralSubSelect.getSelect(), e -> e.accept(this)); + validateOptional(lateralSubSelect.getPivot(), p -> p.accept(this, context)); + validateOptional(lateralSubSelect.getUnPivot(), up -> up.accept(this, context)); + validateOptional(lateralSubSelect.getSelect(), + e -> e.accept((SelectVisitor) this, context)); + return null; } @Override - public void visit(TableStatement tableStatement) { + public Void visit(TableStatement tableStatement, S context) { getValidator(TableStatementValidator.class).validate(tableStatement); + return null; } @Override - public void visit(TableFunction tableFunction) { + public Void visit(TableFunction tableFunction, S context) { validateFeature(Feature.tableFunction); - validateOptional(tableFunction.getPivot(), p -> p.accept(this)); - validateOptional(tableFunction.getUnPivot(), up -> up.accept(this)); + validateOptional(tableFunction.getPivot(), p -> p.accept(this, context)); + validateOptional(tableFunction.getUnPivot(), up -> up.accept(this, context)); + return null; } @Override - public void visit(ParenthesedFromItem parenthesis) { - validateOptional(parenthesis.getFromItem(), e -> e.accept(this)); + public Void visit(ParenthesedFromItem parenthesis, S context) { + validateOptional(parenthesis.getFromItem(), e -> e.accept(this, context)); + return null; } @Override - public void visit(Values values) { + public Void visit(Values values, S context) { getValidator(ValuesStatementValidator.class).validate(values); + return null; + } + + @Override + public Void visit(Import imprt, S context) { + // TODO: not yet implemented + return null; } @Override - public void validate(SelectItem statement) { - statement.accept(this); + public void validate(SelectItem statement) { + statement.accept(this, null); + } + + public void visit(PlainSelect plainSelect) { + visit(plainSelect, null); } + + public void visit(SelectItem selectExpressionItem) { + visit(selectExpressionItem, null); + } + + public void visit(ParenthesedSelect selectBody) { + visit(selectBody, null); + } + + public void visit(Table table) { + visit(table, null); + } + + public void visit(Pivot pivot) { + visit(pivot, null); + } + + public void visit(UnPivot unpivot) { + visit(unpivot, null); + } + + public void visit(PivotXml pivot) { + visit(pivot, null); + } + + public void visit(SetOperationList setOperation) { + visit(setOperation, null); + } + + public void visit(WithItem withItem) { + visit(withItem, null); + } + + public void visit(LateralSubSelect lateralSubSelect) { + visit(lateralSubSelect, null); + } + + public void visit(TableStatement tableStatement) { + visit(tableStatement, null); + } + + @Override + public Void visit(FromQuery fromQuery, S context) { + return null; + } + + public void visit(TableFunction tableFunction) { + visit(tableFunction, null); + } + + public void visit(ParenthesedFromItem parenthesis) { + visit(parenthesis, null); + } + + public void visit(Values values) { + visit(values, null); + } + + public void visit(Import imprt) { + visit(imprt, null); + } + + + } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/ShowIndexStatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/ShowIndexStatementValidator.java index 624ee3828..8a35faffb 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/ShowIndexStatementValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/ShowIndexStatementValidator.java @@ -14,9 +14,8 @@ import net.sf.jsqlparser.util.validation.metadata.NamedObject; /** -* -* @author Jayant Kumar Yadav -*/ + * @author Jayant Kumar Yadav + */ public class ShowIndexStatementValidator extends AbstractValidator { @@ -24,4 +23,4 @@ public class ShowIndexStatementValidator extends AbstractValidator implements StatementVisitor { - +public class StatementValidator extends AbstractValidator + implements StatementVisitor { @Override - public void visit(CreateIndex createIndex) { + public Void visit(CreateIndex createIndex, S context) { getValidator(CreateIndexValidator.class).validate(createIndex); + return null; } @Override - public void visit(CreateTable createTable) { + public Void visit(CreateTable createTable, S context) { getValidator(CreateTableValidator.class).validate(createTable); + return null; } @Override - public void visit(CreateView createView) { + public Void visit(CreateView createView, S context) { getValidator(CreateViewValidator.class).validate(createView); + return null; } @Override - public void visit(AlterView alterView) { + public Void visit(AlterView alterView, S context) { getValidator(AlterViewValidator.class).validate(alterView); + return null; } @Override - public void visit(RefreshMaterializedViewStatement materializedView) { + public Void visit(RefreshMaterializedViewStatement materializedView, S context) { getValidator(RefreshMaterializedViewStatementValidator.class).validate(materializedView); + return null; } @Override - public void visit(Delete delete) { + public Void visit(Delete delete, S context) { getValidator(DeleteValidator.class).validate(delete); + return null; } @Override - public void visit(Drop drop) { + public Void visit(ParenthesedDelete delete, S context) { + return visit(delete.getDelete(), context); + } + + @Override + public Void visit(SessionStatement sessionStatement, S context) { + return null; + } + + + @Override + public Void visit(Drop drop, S context) { getValidator(DropValidator.class).validate(drop); + return null; } @Override - public void visit(Insert insert) { + public Void visit(Insert insert, S context) { getValidator(InsertValidator.class).validate(insert); + return null; } @Override - public void visit(Select select) { + public Void visit(ParenthesedInsert insert, S context) { + return visit(insert.getInsert(), context); + } + + @Override + public Void visit(Select select, S context) { validateFeature(Feature.select); SelectValidator selectValidator = getValidator(SelectValidator.class); - select.accept(selectValidator); + select.accept((SelectVisitor) selectValidator, null); + return null; } @Override - public void visit(Truncate truncate) { + public Void visit(Truncate truncate, S context) { validateFeature(Feature.truncate); validateOptionalFromItem(truncate.getTable()); + return null; } @Override - public void visit(Update update) { + public Void visit(Update update, S context) { getValidator(UpdateValidator.class).validate(update); + return null; } @Override - public void visit(Alter alter) { + public Void visit(ParenthesedUpdate update, S context) { + return visit(update.getUpdate(), context); + } + + @Override + public Void visit(Alter alter, S context) { getValidator(AlterValidator.class).validate(alter); + return null; } @Override - public void visit(Statements stmts) { - stmts.getStatements().forEach(s -> s.accept(this)); + public Void visit(Statements statements, S context) { + statements.forEach(s -> s.accept(this, context)); + return null; } @Override - public void visit(Execute execute) { + public Void visit(Execute execute, S context) { getValidator(ExecuteValidator.class).validate(execute); + return null; } @Override - public void visit(SetStatement set) { + public Void visit(SetStatement set, S context) { getValidator(SetStatementValidator.class).validate(set); + return null; } @Override - public void visit(ResetStatement reset) { + public Void visit(ResetStatement reset, S context) { getValidator(ResetStatementValidator.class).validate(reset); + return null; } @Override - public void visit(Merge merge) { + public Void visit(Merge merge, S context) { getValidator(MergeValidator.class).validate(merge); + return null; } @Override - public void visit(Commit commit) { + public Void visit(Commit commit, S context) { validateFeature(Feature.commit); + return null; } @Override - public void visit(Upsert upsert) { + public Void visit(Upsert upsert, S context) { getValidator(UpsertValidator.class).validate(upsert); + return null; } @Override - public void visit(UseStatement use) { + public Void visit(UseStatement use, S context) { getValidator(UseStatementValidator.class).validate(use); + return null; } @Override - public void visit(ShowStatement show) { - getValidator(ShowStatementValidator.class).validate(show); + public Void visit(ShowStatement showStatement, S context) { + getValidator(ShowStatementValidator.class).validate(showStatement); + return null; } @Override - public void visit(ShowColumnsStatement show) { + public Void visit(ShowColumnsStatement show, S context) { getValidator(ShowColumnsStatementValidator.class).validate(show); + return null; } @Override - public void visit(ShowIndexStatement show) { + public Void visit(ShowIndexStatement show, S context) { getValidator(ShowIndexStatementValidator.class).validate(show); + return null; } @Override - public void visit(ShowTablesStatement showTables) { + public Void visit(ShowTablesStatement showTables, S context) { getValidator(ShowTablesStatementValidator.class).validate(showTables); + return null; } @Override - public void visit(Block block) { + public Void visit(Block block, S context) { validateFeature(Feature.block); - block.getStatements().accept(this); + block.getStatements().accept(this, context); + return null; } @Override - public void visit(Comment comment) { + public Void visit(Comment comment, S context) { for (ValidationCapability c : getCapabilities()) { validateFeature(c, Feature.comment); validateOptionalFeature(c, comment.getTable(), Feature.commentOnTable); validateOptionalFeature(c, comment.getColumn(), Feature.commentOnColumn); validateOptionalFeature(c, comment.getView(), Feature.commentOnView); } + return null; } @Override - public void visit(DescribeStatement describe) { + public Void visit(DescribeStatement describe, S context) { validateFeature(Feature.describe); validateFeature(Feature.desc); validateOptionalFromItem(describe.getTable()); + return null; } @Override - public void visit(ExplainStatement explain) { + public Void visit(ExplainStatement explainStatement, S context) { validateFeature(Feature.explain); - if (explain.getStatement() != null) { - explain.getStatement().accept(this); + if (explainStatement.getStatement() != null) { + explainStatement.getStatement().accept(this, context); } + return null; } @Override - public void visit(DeclareStatement declare) { - getValidator(DeclareStatementValidator.class).validate(declare); + public Void visit(DeclareStatement declareStatement, S context) { + getValidator(DeclareStatementValidator.class).validate(declareStatement); + return null; } @Override - public void visit(Grant grant) { + public Void visit(Grant grant, S context) { getValidator(GrantValidator.class).validate(grant); + return null; } @Override - public void visit(CreateSchema aThis) { + public Void visit(CreateSchema aThis, S context) { validateFeatureAndName(Feature.createSchema, NamedObject.schema, aThis.getSchemaName()); - aThis.getStatements().forEach(s -> s.accept(this)); + aThis.getStatements().forEach(s -> s.accept(this, context)); + return null; } @Override - public void visit(CreateSequence createSequence) { + public Void visit(CreateSequence createSequence, S context) { getValidator(CreateSequenceValidator.class).validate(createSequence); + return null; } @Override - public void visit(AlterSequence alterSequence) { + public Void visit(AlterSequence alterSequence, S context) { getValidator(AlterSequenceValidator.class).validate(alterSequence); + return null; } @Override - public void visit(CreateFunctionalStatement createFunctionalStatement) { + public Void visit(CreateFunctionalStatement createFunctionalStatement, S context) { validateFeature(Feature.functionalStatement); if (createFunctionalStatement instanceof CreateFunction) { validateFeature(Feature.createFunction); } else if (createFunctionalStatement instanceof CreateProcedure) { validateFeature(Feature.createProcedure); } + return null; } @Override public void validate(Statement statement) { - statement.accept(this); + statement.accept(this, null); } @Override - public void visit(CreateSynonym createSynonym) { + public Void visit(CreateSynonym createSynonym, S context) { getValidator(CreateSynonymValidator.class).validate(createSynonym); + return null; } @Override - public void visit(Analyze analyze) { + public Void visit(Analyze analyze, S context) { getValidator(AnalyzeValidator.class).validate(analyze); + return null; } @Override - public void visit(SavepointStatement savepointStatement) { + public Void visit(SavepointStatement savepointStatement, S context) { // TODO: not yet implemented + return null; } @Override - public void visit(RollbackStatement rollbackStatement) { + public Void visit(RollbackStatement rollbackStatement, S context) { // TODO: not yet implemented + return null; } @Override - public void visit(AlterSession alterSession) { + public Void visit(AlterSession alterSession, S context) { // TODO: not yet implemented + return null; } @Override - public void visit(IfElseStatement ifElseStatement) { - ifElseStatement.getIfStatement().accept(this); + public Void visit(IfElseStatement ifElseStatement, S context) { + ifElseStatement.getIfStatement().accept(this, context); if (ifElseStatement.getElseStatement() != null) { - ifElseStatement.getElseStatement().accept(this); + ifElseStatement.getElseStatement().accept(this, context); } + return null; } - public void visit(RenameTableStatement renameTableStatement) { + public Void visit(RenameTableStatement renameTableStatement, S context) { // TODO: not yet implemented + return null; } @Override - public void visit(PurgeStatement purgeStatement) { + public Void visit(PurgeStatement purgeStatement, S context) { // TODO: not yet implemented + return null; } @Override - public void visit(AlterSystemStatement alterSystemStatement) { + public Void visit(AlterSystemStatement alterSystemStatement, S context) { // TODO: not yet implemented + return null; } @Override + public Void visit(UnsupportedStatement unsupportedStatement, S context) { + + return null; + } + + @Override + public Void visit(Import imprt, S context) { + // TODO: not yet implemented + return null; + } + + @Override + public Void visit(Export export, S context) { + // TODO: not yet implemented + return null; + } + + @Override + public Void visit(LockStatement lock, S context) { + // TODO: not yet implemented + return null; + } + + public void visit(CreateIndex createIndex) { + visit(createIndex, null); + } + + public void visit(CreateTable createTable) { + visit(createTable, null); + } + + public void visit(CreateView createView) { + visit(createView, null); + } + + public void visit(AlterView alterView) { + visit(alterView, null); + } + + public void visit(RefreshMaterializedViewStatement materializedView) { + visit(materializedView, null); + } + + public void visit(Delete delete) { + visit(delete, null); + } + + public void visit(Drop drop) { + visit(drop, null); + } + + public void visit(Insert insert) { + visit(insert, null); + } + + public void visit(Select select) { + visit(select, null); + } + + public void visit(Truncate truncate) { + visit(truncate, null); + } + + public void visit(Update update) { + visit(update, null); + } + + public void visit(Alter alter) { + visit(alter, null); + } + + public void visit(Statements statements) { + visit(statements, null); + } + + public void visit(Execute execute) { + visit(execute, null); + } + + public void visit(SetStatement set) { + visit(set, null); + } + + public void visit(ResetStatement reset) { + visit(reset, null); + } + + public void visit(Merge merge) { + visit(merge, null); + } + + public void visit(Commit commit) { + visit(commit, null); + } + + public void visit(Upsert upsert) { + visit(upsert, null); + } + + public void visit(UseStatement use) { + visit(use, null); + } + + public void visit(ShowStatement showStatement) { + visit(showStatement, null); + } + + public void visit(ShowColumnsStatement show) { + visit(show, null); + } + + public void visit(ShowIndexStatement show) { + visit(show, null); + } + + public void visit(ShowTablesStatement showTables) { + visit(showTables, null); + } + + public void visit(Block block) { + visit(block, null); + } + + public void visit(Comment comment) { + visit(comment, null); + } + + public void visit(DescribeStatement describe) { + visit(describe, null); + } + + public void visit(ExplainStatement explainStatement) { + visit(explainStatement, null); + } + + public void visit(DeclareStatement declareStatement) { + visit(declareStatement, null); + } + + public void visit(Grant grant) { + visit(grant, null); + } + + public void visit(CreateSchema aThis) { + visit(aThis, null); + } + + public void visit(CreateSequence createSequence) { + visit(createSequence, null); + } + + public void visit(AlterSequence alterSequence) { + visit(alterSequence, null); + } + + public void visit(CreateFunctionalStatement createFunctionalStatement) { + visit(createFunctionalStatement, null); + } + + public void visit(CreateSynonym createSynonym) { + visit(createSynonym, null); + } + + public void visit(Analyze analyze) { + visit(analyze, null); + } + + public void visit(SavepointStatement savepointStatement) { + visit(savepointStatement, null); + } + + public void visit(RollbackStatement rollbackStatement) { + visit(rollbackStatement, null); + } + + public void visit(AlterSession alterSession) { + visit(alterSession, null); + } + + public void visit(IfElseStatement ifElseStatement) { + visit(ifElseStatement, null); + } + + public void visit(RenameTableStatement renameTableStatement) { + visit(renameTableStatement, null); + } + + public void visit(PurgeStatement purgeStatement) { + visit(purgeStatement, null); + } + + public void visit(AlterSystemStatement alterSystemStatement) { + visit(alterSystemStatement, null); + } + public void visit(UnsupportedStatement unsupportedStatement) { + visit(unsupportedStatement, null); + } + + public void visit(Import imprt) { + visit(imprt, null); + } + + public void visit(Export export) { + visit(export, null); + } + + @Override + public Void visit(CreatePolicy createPolicy, S context) { + // TODO: not yet implemented + return null; + } + public void visit(CreatePolicy createPolicy) { + visit(createPolicy, null); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/UpdateValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/UpdateValidator.java index 735725126..058b6aa9f 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/UpdateValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/UpdateValidator.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.util.validation.validator; import net.sf.jsqlparser.parser.feature.Feature; +import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.util.validation.ValidationCapability; @@ -40,7 +41,7 @@ public void validate(Update update) { if (update.isUseSelect()) { validateOptionalExpressions(update.getColumns()); validateOptional(update.getSelect(), - e -> e.accept(getValidator(SelectValidator.class))); + e -> e.accept((SelectVisitor) getValidator(SelectValidator.class), null)); } else { validateOptionalExpressions(update.getColumns()); validateOptionalExpressions(update.getExpressions()); @@ -61,7 +62,7 @@ public void validate(Update update) { if (update.getReturningClause() != null) { SelectValidator v = getValidator(SelectValidator.class); - update.getReturningClause().forEach(c -> c.accept(v)); + update.getReturningClause().forEach(c -> c.accept(v, null)); } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/UpsertValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/UpsertValidator.java index 21e9ebeeb..585cf7132 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/UpsertValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/UpsertValidator.java @@ -11,6 +11,7 @@ import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.update.UpdateSet; import net.sf.jsqlparser.statement.upsert.Upsert; import net.sf.jsqlparser.util.validation.ValidationCapability; @@ -35,7 +36,7 @@ public void validate(Upsert upsert) { private void validateOptionalSelect(Select select) { if (select != null) { SelectValidator v = getValidator(SelectValidator.class); - select.accept(v); + select.accept((SelectVisitor) v, null); } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index d53f51ebc..9d3946191 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -18,7 +18,7 @@ options { // FORCE_LA_CHECK = true; UNICODE_INPUT = true; JAVA_TEMPLATE_TYPE = "modern"; - JDK_VERSION = "1.8"; +// JDK_VERSION = "1.8"; TOKEN_EXTENDS = "BaseToken"; COMMON_TOKEN_ACTION = true; NODE_DEFAULT_VOID = true; @@ -26,6 +26,7 @@ options { VISITOR = true; GRAMMAR_ENCODING = "UTF-8"; KEEP_LINE_COLUMN = true; +// USER_CHAR_STREAM = false; } PARSER_BEGIN(CCJSqlParser) @@ -48,6 +49,7 @@ import net.sf.jsqlparser.statement.alter.sequence.*; import net.sf.jsqlparser.statement.comment.*; import net.sf.jsqlparser.statement.create.function.*; import net.sf.jsqlparser.statement.create.index.*; +import net.sf.jsqlparser.statement.create.policy.*; import net.sf.jsqlparser.statement.create.procedure.*; import net.sf.jsqlparser.statement.create.schema.*; import net.sf.jsqlparser.statement.create.synonym.*; @@ -58,6 +60,7 @@ import net.sf.jsqlparser.statement.delete.*; import net.sf.jsqlparser.statement.drop.*; import net.sf.jsqlparser.statement.insert.*; import net.sf.jsqlparser.statement.execute.*; +import net.sf.jsqlparser.statement.piped.*; import net.sf.jsqlparser.statement.select.*; import net.sf.jsqlparser.statement.refresh.*; import net.sf.jsqlparser.statement.show.*; @@ -66,8 +69,12 @@ import net.sf.jsqlparser.statement.update.*; import net.sf.jsqlparser.statement.upsert.*; import net.sf.jsqlparser.statement.merge.*; import net.sf.jsqlparser.statement.grant.*; +import net.sf.jsqlparser.statement.imprt.*; +import net.sf.jsqlparser.statement.export.*; +import net.sf.jsqlparser.statement.lock.*; import java.util.*; import java.util.AbstractMap.SimpleEntry; +import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; import java.util.logging.Level; import java.util.logging.Logger; @@ -94,7 +101,7 @@ public class CCJSqlParser extends AbstractJSqlParser { return this; } - private void linkAST(ASTNodeAccess access, SimpleNode node) { + private void linkAST(ASTNodeAccess access, Node node) { access.setASTNode(node); node.jjtSetValue(access); } @@ -121,6 +128,553 @@ public class CCJSqlParser extends AbstractJSqlParser { return delimiters; } } + + private static void appendWhitespaceFromTokenGap(StringBuilder buffer, Token prev, Token curr) { + if (prev == null) return; + + int lineDiff = curr.beginLine - prev.endLine; + if (lineDiff > 0) { + for (int i = 0; i < lineDiff; i++) buffer.append('\n'); + for (int i = 1; i < curr.beginColumn; i++) buffer.append(' '); + } else { + int spaceCount = curr.beginColumn - prev.endColumn - 1; + for (int i = 0; i < spaceCount; i++) buffer.append(' '); + } + } + + private static void appendTokenImageAndTrackDelimiter(StringBuilder buffer, Deque windowQueue, + int delimiterLength, String image, String tag) { + for (char ch : image.toCharArray()) { + buffer.append(ch); + windowQueue.addLast(ch); + if (windowQueue.size() > delimiterLength) { + windowQueue.removeFirst(); + } + } + } + + private static boolean endsWithDelimiter(Deque windowQueue, String delimiter) { + if (windowQueue.size() != delimiter.length()) return false; + + int i = 0; + for (char ch : windowQueue) { + if (ch != delimiter.charAt(i++)) return false; + } + return true; + } + + + /** + * Checks whether the given token can start the operator in a RegularCondition + * (comparison operators, JSON operators, regex operators, geometry distance, etc.) + * + * Used to avoid expensive syntactic lookaheads like LOOKAHEAD(RegularCondition()). + * By the time this is called, lower-precedence operators like "-" (subtraction) + * and "||" (concatenation) have already been consumed by SimpleExpression, + * so seeing them here means they are comparison-level operators. + */ + + protected boolean isComparisonOperatorAhead() { + try { + Token token = getToken(1); + if (token.image.equals("(") && getToken(2).image.equals("+")) { + // Oracle (+) — only route to RegularConditionRHS if a real + // comparison operator follows after "(" "+" ")" + return isComparisonOperator(getToken(4)); + } + return isComparisonOperator(token); + } catch (Exception e) { + return false; + } + } + + protected static boolean isComparisonOperator(Token token) { + if (token.image == null || token.image.isEmpty()) { + return false; + } + switch (token.image.charAt(0)) { + case '>': // >, >= + case '=': // =, =* but not => Oracle/PostgreSQL named parameter syntax + return !token.image.equals("=>"); + case '~': // ~, ~* + return true; + case '<': // <, <=, <>, <@, <->, <#>, <=>, <& + return true; + case '*': return token.image.equals("*="); + case '!': return token.image.startsWith("!~") || token.image.startsWith("!="); + case '@': return token.image.equals("@@") || token.image.equals("@>"); + case '?': return true; // ?, ?|, ?& + case '-': return true; // -, -# + case '|': return token.image.equals("||"); + case '^': return token.image.startsWith("^="); + case '&': return token.image.equals("&&") || token.image.equals("&>"); + default: return false; + } + } + + protected boolean isParenthesedSelectAhead() { + if (getToken(1).kind != OPENING_BRACKET) { + return false; + } + int nextKind = getToken(2).kind; + return nextKind == K_SELECT + || nextKind == K_WITH + || nextKind == K_VALUES + || nextKind == K_FROM; + } + + /** + * Tokens that have dedicated branches in PrimaryExpression AFTER the Function branch. + * If isFunctionAhead() returns true for these, Function() would consume them and fail. + */ + private boolean isNonFunctionKeyword(Token t) { + switch (t.kind) { + case K_CONNECT_BY_ROOT: // CONNECT_BY_ROOT (expr) + case K_PRIOR: // PRIOR expr + case K_STRUCT: // STRUCT(...) + return true; + default: + return false; + } + } + + /** + * Scans ahead through a dotted identifier chain and checks if '(' follows. + * Distinguishes function calls like func(), schema.func(), a.b.c.func() + * from column references like col, schema.col, a.b.c.col. + * + * Replaces LOOKAHEAD(16) on Function() with a targeted O(chain-length) check. + */ + protected boolean isFunctionAhead() { + int i = 1; + Token t = getToken(i); + + // JDBC escape function: {fn ...} — must check for FN keyword + if (t.image.equals("{")) { + return getToken(2).kind == K_FN; + } + + // Optional APPROXIMATE keyword + if (t.kind == K_APPROXIMATE) { + i++; + t = getToken(i); + } + + // Exclude tokens that have their own dedicated branches + // after Function() in PrimaryExpression + if (isNonFunctionKeyword(t)) { + return false; + } + + // First token must not be a literal, bracket, or EOF + if (t.kind == S_LONG || t.kind == S_DOUBLE || t.kind == S_HEX + || t.kind == S_CHAR_LITERAL || t.kind == OPENING_BRACKET + || t.kind == CLOSING_BRACKET || t.kind == EOF) { + return false; + } + i++; + + // Walk through dotted name chain + while (true) { + t = getToken(i); + if (t.image.equals(".") || t.image.equals("..") + || t.image.equals("...") || t.image.equals(":")) { + i++; // skip delimiter + i++; // skip next name part + } else { + break; + } + } + + // Must be followed by ( + if (getToken(i).kind != OPENING_BRACKET) { + return false; + } + + // Exclude Oracle join syntax: column(+) + if (getToken(i + 1).image.equals("+") + && getToken(i + 2).kind == CLOSING_BRACKET) { + return false; + } + + return true; + } + + private boolean isKeywordArgumentAhead() { + Token t = getToken(1); + if (t.kind == EOF || t.image.equals(")")) return false; + if (t.image.isEmpty() || !Character.isLetter(t.image.charAt(0))) return false; + // S_QUOTED_IDENTIFIER is not a valid keyword arg name. + // S_IDENTIFIER and DATA_TYPE ARE allowed — after ExpressionList has + // consumed all comma-separated arguments, a remaining identifier or + // type keyword before ')' is a keyword argument name (e.g. + // PREDICTION(expr COST MODEL USING cols), + // XMLTABLE(... COLUMNS "col" VARCHAR2(6) PATH '...')). + if (t.kind == S_QUOTED_IDENTIFIER) return false; + switch (t.kind) { + case S_LONG: case S_DOUBLE: case S_HEX: case S_CHAR_LITERAL: + case K_DISTINCT: case K_ALL: case K_UNIQUE: case K_TABLE: + case K_ORDER: case K_ON: case K_HAVING: case K_IGNORE: case K_RESPECT: + case K_SELECT: case K_FROM: case K_WHERE: case K_GROUP: case K_LIMIT: + case K_UNION: case K_EXCEPT: case K_INTERSECT: case K_MINUS: + case K_JOIN: case K_INNER: case K_LEFT: case K_RIGHT: case K_FULL: case K_CROSS: + case K_INTO: case K_SET: case K_FETCH: case K_OFFSET: + case K_OVER: case K_WITHIN: case K_FILTER: case K_WITH: case K_WITHOUT: + case K_AND: case K_OR: case K_NOT: case K_IN: case K_BETWEEN: case K_LIKE: + case K_IS: case K_EXISTS: case K_AS: + case K_CASE: case K_WHEN: case K_THEN: case K_ELSE: case K_END: + case K_NULL: case K_TRUE: case K_FALSE: + case K_RETURNING: + return false; + } + Token t2 = getToken(2); + if (t2.kind == EOF || t2.image.equals(")")) return false; + return true; + } + + /** + * Scans ahead through a dotted identifier chain and checks if '*' follows. + * Identifies table.* patterns for AllTableColumns. + */ + protected boolean isAllTableColumnsAhead() { + int i = 1; + Token t = getToken(i); + + // Must start with a name-like token + if (t.kind == S_LONG || t.kind == S_DOUBLE || t.kind == S_HEX + || t.kind == S_CHAR_LITERAL || t.kind == OPENING_BRACKET + || t.kind == CLOSING_BRACKET || t.kind == EOF) { + return false; + } + i++; + + // Walk through dotted name chain + while (true) { + t = getToken(i); + if (t.image.equals(".") || t.image.equals("..") + || t.image.equals("...")) { + i++; // skip delimiter + i++; // skip next part (could be "*") + } else { + break; + } + } + + // It's AllTableColumns if the chain ended on "*" + // i.e., the last name part we skipped over was "*" + // Back up: the last token consumed was at (i-1) + return getToken(i - 1).image.equals("*"); + } + + /** + * Follower-based disambiguation for reserved keywords in ambiguous + * positions (implicit alias, clause boundary, after parenthesised + * expression, etc.). + * + * Checks the candidate keyword ({@code getToken(1)}) and its follower + * ({@code getToken(2)}) to decide whether the keyword is being used as + * an identifier or as SQL syntax. Returns {@code true} only for + * keywords that provably don't collide with clause syntax in the + * current follower context. + */ + private boolean isReservedKeywordSafeByFollower() { + Token next2 = getToken(2); + + // If followed by . or = the keyword is a name part / property key + if (next2.image != null + && (next2.image.equals(".") || next2.image.equals("="))) { + return true; + } + + int kind = getToken(1).kind; + int nextKind = next2.kind; + + switch (kind) { + // Safe as implicit identifiers (no clause collision) + case K_TABLES: case K_OPTIMIZE: case K_PROCEDURE: case K_PUBLIC: + case K_CASEWHEN: case K_IIF: + return true; + + // Safe when the follower doesn't form a clause + case K_GROUP: return nextKind != K_BY; + case K_ORDER: return nextKind != K_BY && nextKind != K_SIBLINGS; + case K_CONNECT: return nextKind != K_BY; + case K_START: return nextKind != K_WITH; + case K_LEFT: return nextKind != K_JOIN && nextKind != K_OUTER + && nextKind != K_SEMI; + case K_RIGHT: return nextKind != K_JOIN && nextKind != K_OUTER + && nextKind != K_SEMI; + case K_ALL: return nextKind != K_JOIN; + case K_ANY: return nextKind != OPENING_BRACKET; + case K_SOME: return nextKind != OPENING_BRACKET; + case K_IN: return nextKind != OPENING_BRACKET; + case K_IF: return nextKind != OPENING_BRACKET; + case K_GROUPING: return nextKind != OPENING_BRACKET; + case K_DEFAULT: return nextKind != K_VALUES; + case K_CREATE: return nextKind != K_TABLE && nextKind != K_VIEW + && nextKind != K_INDEX; + case K_INTERVAL: return nextKind != S_LONG && nextKind != S_DOUBLE + && nextKind != S_CHAR_LITERAL; + case K_TOP: return nextKind != S_LONG && nextKind != S_DOUBLE + && nextKind != OPENING_BRACKET; + case K_NEXTVAL: return nextKind != K_VALUE; + + // IGNORE: blocks NULLS (IGNORE NULLS), FROM (DELETE IGNORE FROM), + // INDEX (IGNORE INDEX hint) + case K_IGNORE: return nextKind != K_NULLS && nextKind != K_FROM + && nextKind != K_INDEX; + + // GLOBAL: blocks IN (GLOBAL IN), TEMPORARY, JOIN (GLOBAL JOIN) + case K_GLOBAL: return nextKind != K_IN && nextKind != K_TEMPORARY + && nextKind != K_JOIN; + + // Structural keywords — never safe as implicit identifiers + case K_SET: case K_ON: case K_QUALIFY: + case K_LIMIT: case K_OFFSET: + return false; + + // VALUE/VALUES: safe as alias when not starting VALUES(...) + case K_VALUE: case K_VALUES: + return nextKind != OPENING_BRACKET && nextKind != S_IDENTIFIER + && nextKind != S_QUOTED_IDENTIFIER && nextKind != S_CHAR_LITERAL; + + default: + return false; + } + } + + /** + * Determines whether a reserved keyword token can be treated as an unquoted + * identifier in the current parser position. + * + * Called from the semantic LOOKAHEAD inside {@code RelObjectName()}. + * Uses the previous token to detect name positions (after structural + * keywords, delimiters, AS), the follower token (after . or =), and + * falls back to conservative follower-based disambiguation. + */ + private boolean isReservedKeywordAsIdentifier() { + Token prev = getToken(0); + + // Guard: at the very start of parsing (e.g. parseExpression()), + // prev may be null or have null image. This is always a name / + // expression position, so accept any keyword. + if (prev == null || prev.image == null) { + return true; + } + + // ── 1. After AS: explicit alias — accept any keyword ────────── + if (prev.kind == K_AS) { + return true; + } + + // ── 2. After delimiters and operators: expression position ───── + // With K_FROM/K_SELECT/K_CURRENT removed from RelObjectName's + // token list, accepting all remaining keywords after these + // delimiters and operators is safe. + if (!prev.image.isEmpty()) { + switch (prev.image.charAt(0)) { + // Structural delimiters + case '.': case ',': case ':': case '(': case '=': + // Comparison and arithmetic operators + case '>': case '<': case '!': case '^': + case '+': case '-': case '*': case '/': case '%': + case '~': case '|': case '&': case '?': + return true; + } + } + + // ── 3. If followed by . or = the keyword is a name/property key ── + Token next2 = getToken(2); + if (next2.image != null + && (next2.image.equals(".") || next2.image.equals("="))) { + return true; + } + + // ── 4. After TRULY STRUCTURAL keywords that can NEVER be ────── + // consumed as identifiers (i.e. they are never in our own + // keyword-as-identifier set). After these, any keyword is + // safe as an identifier. + // + // Keywords that CAN be identifiers (LEFT, LIMIT, IGNORE, + // etc.) are NOT listed here because they may appear as + // getToken(0) after being consumed as identifiers or + // modifiers, which is NOT a name position. + switch (prev.kind) { + // Boolean / conditional operators + case K_AND: case K_OR: case K_NOT: case K_XOR: + + // Clause keywords + case K_SELECT: case K_FROM: case K_WHERE: case K_HAVING: + case K_INTO: case K_USING: case K_SET: case K_ON: + case K_FETCH: case K_FOR: case K_WITH: + + // Comparison / expression operators + case K_BETWEEN: case K_LIKE: case K_ILIKE: case K_IS: + + // Join keywords + case K_JOIN: case K_INNER: case K_OUTER: case K_FULL: + case K_CROSS: case K_NATURAL: case K_STRAIGHT: case K_SEMI: + case K_LATERAL: + + // CASE/WHEN expression structure + case K_WHEN: case K_ELSE: + + // Non-reserved keywords that structurally introduce expression + // positions (GROUP BY expr, ORDER BY expr, CASE WHEN x THEN expr) + case K_BY: case K_THEN: + + // Modifiers + case K_DISTINCT: case K_DISTINCTROW: + + // Set operators + case K_UNION: case K_EXCEPT: case K_INTERSECT: case K_MINUS: + + // DDL / utility keywords (never identifiers) + case K_FOREIGN: case K_CONSTRAINT: case K_UNIQUE: case K_CHECK: + case K_FORCE: + case K_RETURNING: case K_OUTPUT: case K_IMPORT: + case K_PIVOT: case K_UNPIVOT: + case K_PRIOR: case K_WINDOW: case K_ONLY: + case K_PREFERRING: case K_PREWHERE: + case K_RETURNS: case K_EXISTS: + case K_QUALIFY: case K_CURRENT: + return true; + } + + // ── 5. Conservative default: fall back to follower check ────── + return isReservedKeywordSafeByFollower(); + } + + /** + * Checks whether the next token(s) can plausibly start an {@code Alias}. + * + * Used as a semantic LOOKAHEAD guard at alias call-sites. Unlike + * {@link #isReservedKeywordAsIdentifier()}, this method does NOT use + * the structural-keyword whitelist (step 4), because an alias always + * follows an expression — never a structural keyword in isolation. + * Instead it goes directly to follower-based disambiguation for + * reserved keywords. + */ + private boolean isAliasAhead() { + Token t = getToken(1); + int kind = t.kind; + + // AS always starts an alias + if (kind == K_AS) return true; + + // String-literal alias: SELECT col 'myAlias' + if (kind == S_CHAR_LITERAL) return true; + + // Base identifier tokens + if (kind == S_IDENTIFIER || kind == S_QUOTED_IDENTIFIER + || kind == DATA_TYPE || kind == K_DATETIMELITERAL + || kind == K_DATE_LITERAL) { + return true; + } + + // Non-reserved keywords + if (kind >= MIN_NON_RESERVED_WORD && kind <= MAX_NON_RESERVED_WORD) { + return true; + } + + // For reserved keywords in alias position, skip the structural- + // keyword whitelist and go directly to follower disambiguation. + // Only check keywords that are actually in RelObjectName's token + // alternatives — don't fire for brackets, operators, literals, etc. + switch (kind) { + case K_ALL: case K_ANY: case K_CASEWHEN: case K_CONNECT: + case K_CREATE: case K_DEFAULT: + case K_GLOBAL: case K_GROUP: case K_GROUPING: case K_IF: + case K_IIF: case K_IGNORE: case K_IN: case K_INTERVAL: + case K_LEFT: case K_LIMIT: case K_NEXTVAL: case K_OFFSET: + case K_ON: case K_OPTIMIZE: case K_ORDER: case K_PROCEDURE: + case K_PUBLIC: case K_QUALIFY: case K_RIGHT: + case K_SET: case K_SOME: case K_START: case K_TABLES: + case K_TOP: case K_VALUE: case K_VALUES: + return isReservedKeywordSafeByFollower(); + default: + return false; + } + } + + /** + * Lightweight lookahead for SpecialStringFunctionWithNamedParameters: + * scans forward from the current position (just past the opening '(') + * looking for FROM, IN, or PLACING at bracket nesting depth 0. + * + * This replaces an expensive syntactic LOOKAHEAD(NamedExpressionListExprFirst()) + * that caused exponential backtracking with deeply nested expressions. + */ + protected boolean isNamedExprListAhead() { + int depth = 0; + for (int i = 1; ; i++) { + Token t = getToken(i); + if (t.kind == EOF) { + return false; + } + if (t.kind == OPENING_BRACKET) { + depth++; + } else if (t.kind == CLOSING_BRACKET) { + if (depth == 0) { + return false; + } + depth--; + } else if (depth == 0) { + if (t.kind == K_FROM || t.kind == K_IN || t.kind == K_PLACING) { + return true; + } + if (t.image.equals(",")) { + return false; + } + } + } + } + + /** + * Checks if the next token can start a condition suffix + * (comparison, IN, BETWEEN, LIKE, IS NULL, etc.) + * + * Used as the entry guard for the entire optional condition-suffix block + * in Condition(), eliminating choice conflicts. + */ + protected boolean isConditionSuffixAhead() { + if (isComparisonOperatorAhead()) { + return true; + } + Token t = getToken(1); + switch (t.kind) { + // Each suffix's start token: + case K_OVERLAPS: // OVERLAPS + case K_IN: // IN + case K_GLOBAL: // GLOBAL ... IN + case K_EXCLUDES: // EXCLUDES (...) + case K_INCLUDES: // INCLUDES (...) + case K_BETWEEN: // BETWEEN + case K_MEMBER: // MEMBER OF + case K_IS: // IS [NOT] NULL / TRUE / FALSE / UNKNOWN / DISTINCT + case K_ISNULL: // ISNULL + case K_NOTNULL: // NOTNULL + case K_LIKE: // LIKE + case K_ILIKE: // ILIKE + case K_RLIKE: // RLIKE + case K_REGEXP_LIKE: // REGEXP_LIKE + case K_REGEXP: // REGEXP + case K_SIMILAR_TO: // SIMILAR TO (in LikeExpression) + case K_SIMILAR: // SIMILAR TO (in SimilarToExpression) + case K_MATCH_ANY: // MATCH_ANY + case K_MATCH_ALL: // MATCH_ALL + case K_MATCH_PHRASE: // MATCH_PHRASE + case K_MATCH_PHRASE_PREFIX: // MATCH_PHRASE_PREFIX + case K_MATCH_REGEXP: // MATCH_REGEXP + case K_NOT: // NOT IN / NOT BETWEEN / NOT LIKE / NOT ISNULL / NOT SIMILAR + return true; + // Oracle (+) before IN: col(+) IN (...) + case OPENING_BRACKET: + return getToken(2).image.equals("+"); + default: + return false; + } + } } PARSER_END(CCJSqlParser) @@ -128,6 +682,51 @@ PARSER_END(CCJSqlParser) TOKEN_MGR_DECLS : { public FeatureConfiguration configuration = new FeatureConfiguration(); + // Nesting depth for block comments: /* /* ... */ */ + int commentNesting = 0; + // Stores the comment image up to and including the outermost */ + String storedCommentImage = null; + + // Identify the index of the quoting/escaping tokens + public int charLiteralIndex = -1; + public int squaredBracketOpenIndex = -1; + { + for (int i=0;i") ) { + charLiteralIndex = i; + break; + } + } + for (int i=0;i= 0; i--) { + if (s.charAt(i) == '\\' && s.charAt(i + 1) == '\'' && s.charAt(i + 2) == '\'') { + return i; + } + } + return -1; + } + public void CommonTokenAction(Token t) { t.absoluteBegin = getCurrentTokenAbsolutePosition(); @@ -140,6 +739,40 @@ TOKEN_MGR_DECLS : { return ((SimpleCharStream)input_stream).getAbsoluteTokenBegin(); return -1; } + + private static boolean endsWithDelimiter(Deque windowQueue, String delimiter) { + if (windowQueue.size() != delimiter.length()) { + return false; + } + + int i = 0; + for (char ch : windowQueue) { + if (ch != delimiter.charAt(i++)) { + return false; + } + } + return true; + } + + public void consumeDollarQuotedString(String closingQuote) { + Deque windowQueue = new ArrayDeque(); + int delimiterLength = closingQuote.length(); + + try { + while (true) { + char ch = input_stream.readChar(); + windowQueue.addLast(ch); + if (windowQueue.size() > delimiterLength) { + windowQueue.removeFirst(); + } + if (endsWithDelimiter(windowQueue, closingQuote)) { + return; + } + } + } catch (java.io.IOException e) { + reportError(Math.max(closingQuote.length(), input_stream.GetImage().length())); + } + } } SKIP: @@ -147,373 +780,515 @@ SKIP: } -// http://www.h2database.com/html/advanced.html#keywords +// Sentinel: start of non-reserved keyword range (for O(1) identifier checks) +SKIP: +{ + +} + +/** + * Non-reserved SQL keywords usable as unquoted identifiers. + * Tokens are declared inline to get consecutive kind values between + * MIN_NON_RESERVED_WORD and MAX_NON_RESERVED_WORD sentinels. + */ +String NonReservedWord() : +{ Token tk = null; } +{ + ( + tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + | tk= + ) + { return tk.image; } +} + +// Sentinel: end of non-reserved keyword range +SKIP: +{ + +} -TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ +TOKEN: /* Reserved SQL Keywords and structural tokens */ { - -| -| -| -| -| -| -| + +| +| | -| -| | | -| -| -| -| | -| -| -| -| -| -| -| | -| -| -| | -| -| -| -| -| -| -| -| -| | /* H2 casewhen function */ -| -| -| -| | -| -| -| -| -| -| | -| -| -| | | | -| -| -| | | +| | -| -| -| -| | | -| | -| -| -| -| -| -| -| | -| -| -| -| -| -| -| -| -| +| | -| -| -| -| -| -| +| +| | /* Salesforce SOQL */ -| -| | -| -| -| -| +| +| | -| -| +| | -| | -| -| | | | -| | | -| -| | -| | | -| -| | -| -| -| -| | | | | +| | -| | /* Salesforce SOQL */ -| -| -| | +| | -| -| -| | | | -| | -| | -| -| -| -| -| -| -| -| -| -| | -| | | | -| -| -| -| -| -| -| -| -| -| -| -| -| -| | -| -| -| | -| -| -| -| | -| -| -| -| -| | -| -| -| | -| -| -| -| | | | -| | | "> +| | | -| -| | -| -| -| -| -| | -| -| -| +| +| | | | -| | -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| -| +| | | -| -| -| -| -| -| | -| -| -| -| +| | | -| -| -| | -| -| -| -| -| -| -| -| +| | | -| -| -| -| -| -| -| -| | | -| -| -| -| -| -| -| -| -| | | -| | -| -| -| | | | -| +| | -| -| -| | -| | | | | -| -| -| -| | | -| -| -| -| -| +| | | | | -| -| -| -| -| -| | | -| -| -| -| -| -| -| -| - +| | | | | @@ -528,9 +1303,11 @@ TOKEN : /* Statement Separators */ TOKEN : /* Operators */ { " ()* "="> +| "> | )* "="> | )* ">"> | )* "="> +| )* "="> | )* "|"> | | "> @@ -553,7 +1330,8 @@ TOKEN : /* Data Types */ | <#TYPE_BIT: "BISTRING"> | <#TYPE_BLOB: "BLOB" | "BYTEA" | | "VARBINARY" | > - | <#TYPE_BOOLEAN: "BOOLEAN" | "BOOL" > + | <#TYPE_BOOLEAN: | "BOOL" > + | <#TYPE_CLOB: "CLOB"> | <#TYPE_ENUM: "ENUM" > | <#TYPE_MAP: "MAP" > | <#TYPE_DECIMAL: "DECIMAL" | "NUMBER" | "NUMERIC" > @@ -569,7 +1347,7 @@ TOKEN : /* Data Types */ | <#TYPE_UHUGEINT: "UHUGEINT" > | <#TYPE_REAL: "REAL" | "FLOAT4" | "FLOAT"> | <#TYPE_DOUBLE: "DOUBLE" | "PRECISION" | "FLOAT8" | "FLOAT64"> - | <#TYPE_VARCHAR: "NVARCHAR" | "VARCHAR" | "NCHAR" | | "BPCHAR" | "STRING" | "TEXT" | | "VARYING"> + | <#TYPE_VARCHAR: "NVARCHAR" | "VARCHAR" | "NCHAR" | | "BPCHAR" | "TEXT" | "STRING" | | "VARYING"> | <#TYPE_TIME: "TIMETZ" > | <#TYPE_TIMESTAMP: "TIMESTAMP_NS" | "TIMESTAMP_MS" | "TIMESTAMP_S" > @@ -593,18 +1371,65 @@ TOKEN : /* Numeric Constants */ SPECIAL_TOKEN: { < LINE_COMMENT: ("--" | "//") (~["\r","\n"])*> -| < MULTI_LINE_COMMENT: "/*" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/"> +} + +// Nested block comments: /* ... /* ... */ ... */ +// +// Uses a nesting counter (commentNesting in TOKEN_MGR_DECLS) and +// lexer states DEFAULT -> IN_BLOCK_COMMENT -> BLOCK_COMMENT_END. +// +// The */ rule has NO `: STATE` suffix — this is critical because +// JavaCC's `: STATE` always overrides SwitchTo(). Without it, +// SwitchTo(BLOCK_COMMENT_END) only fires when nesting reaches 0. +// +// In BLOCK_COMMENT_END, we match one real char with ~[], then +// backup(1) to put it back. This avoids the empty-string-at-EOF +// problem while cleanly emitting the accumulated comment image. +MORE: +{ + "/*" { commentNesting = 0; } : IN_BLOCK_COMMENT +} + + MORE: +{ + "/*" { commentNesting++; } +| "*/" { + if (commentNesting > 0) { + commentNesting--; + } else { + storedCommentImage = image.toString(); + SwitchTo(BLOCK_COMMENT_END); + } + } +| < ~[] > +} + + SPECIAL_TOKEN: +{ + { + input_stream.backup(1); + matchedToken.image = storedCommentImage; + } : DEFAULT } TOKEN: { | - ()*> + + { + consumeDollarQuotedString(matchedToken.image); + matchedToken.image = input_stream.GetImage(); + matchedToken.kind = charLiteralIndex; + } +| + ()*) | "$" | ("$" ()*)> | <#LETTER: - | | [ "$" , "#", "_" ] // Not SQL:2016 compliant! + | | [ "#", "_" ] // Not SQL:2016 compliant! > +| <#PART_LETTER_NO_DOLLAR: | | [ "#", "_" , "@" ] > | <#PART_LETTER: | | [ "$" , "#", "_" , "@" ] > +| ()? > // Unicode characters and categories are defined here: https://www.unicode.org/Public/UNIDATA/UnicodeData.txt // SQL:2016 states: @@ -651,38 +1476,70 @@ TOKEN: // which contains the , then we will need to // 1) break the at close it with a "'" // 2) continue tokenizing after that with a new or any other Token - if ( !configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\'") ) { - matchedToken.image = image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; - for (int i=0;i") ) { - matchedToken.kind = i; - } - } - input_stream.backup(image.length() - matchedToken.image.length() ); - } else if ( configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter) && matchedToken.image.contains("\\''") ) { - matchedToken.image = image.substring( 0, image.lastIndexOf("\\'") + 3); - for (int i=0;i") ) { - matchedToken.kind = i; + boolean allowEscape = configuration.getAsBoolean(Feature.allowBackslashEscapeCharacter); + String img = matchedToken.image; + int pos; + if (!allowEscape) { + pos = indexOfSequence(img, "\\'"); + if (pos > 0) { + matchedToken.image = "'" + image.substring( 0, image.indexOf("\\'") + 1 ) + "'"; + // `charLiteralIndex` defined in TokenManagerDeclaration above + matchedToken.kind = charLiteralIndex; + input_stream.backup(image.length() + 1 - matchedToken.image.length()); + } + } else { + pos = lastIndexOfSequence(img, "\\''"); + if (pos > 0) { + matchedToken.image = "'" + image.substring( 0, image.lastIndexOf("\\'") + 3); + // `charLiteralIndex` defined in TokenManagerDeclaration above + matchedToken.kind = charLiteralIndex; + input_stream.backup(image.length() + 1 - matchedToken.image.length() ); + } } - } - input_stream.backup(image.length() - matchedToken.image.length() ); - } } -| < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | "$$" (~["$"])* "$$" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > +| < S_QUOTED_IDENTIFIER: "\"" ( "\"\"" | ~["\n","\r","\""])* "\"" | ("`" (~["\n","\r","`"])+ "`") | ( "[" (~["\n","\r","]"])* "]" ) > { - if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) && matchedToken.image.charAt(0) == '[' ) { + if ( !configuration.getAsBoolean(Feature.allowSquareBracketQuotation) + && matchedToken.image.charAt(0) == '[' ) { + matchedToken.image = "["; - for (int i=0;i: Standard unquoted SQL identifier + * - : Quoted identifier (e.g., `identifier` or "identifier") + * - , , , , , : Specific keywords treated as identifiers + * + * @return Token representing the identifier or keyword used as identifier + */ +Token KeywordOrIdentifier(): +{ + Token tk; +} +{ + ( + tk = + | tk = + | tk = + | tk = + | tk = + | tk = + | tk = + | tk = + ) + { return tk; } +} Statement Statement() #Statement: { @@ -719,7 +1576,7 @@ Statement Statement() #Statement: ( | ) ) | - LOOKAHEAD( { getAsBoolean(Feature.allowUnsupportedStatements) } ) stm = UnsupportedStatement() + LOOKAHEAD( { stm==null && getAsBoolean(Feature.allowUnsupportedStatements) } ) stm = UnsupportedStatement() } catch (ParseException ex) { if ( getAsBoolean(Feature.allowUnsupportedStatements) ) { stm = new UnsupportedStatement( stm.toString(), error_skipto(ST_SEMICOLON) ); @@ -742,7 +1599,7 @@ Statement Statement() #Statement: Statement SingleStatement() : { Statement stm = null; - List with = null; + List> with = null; } { ( @@ -751,13 +1608,13 @@ Statement SingleStatement() : ( stm = SelectWithWithItems( with ) | - stm = Insert( with ) + stm = InsertWithWithItems( with ) | - stm = Update( with ) + stm = UpdateWithWithItems( with ) | - stm = Delete( with ) + stm = DeleteWithWithItems( with ) | - stm = Merge( with) + stm = Merge( with ) ) ) | @@ -809,6 +1666,12 @@ Statement SingleStatement() : stm = Grant() | stm = PurgeStatement() + | + stm = SessionStatement() + | + stm = LockStatement() + | + LOOKAHEAD({ Dialect.EXASOL.name().equals(getAsString(Feature.dialect)) }) ( stm = Import() | stm = Export() ) ) { return stm; } } @@ -912,7 +1775,7 @@ Statements Statements() #Statements: { ) - ( + ( LOOKAHEAD(2) ( )* try { ( @@ -974,7 +1837,7 @@ Statements Statements() #Statements: { JAVACODE List error_skipto(int kind) { ArrayList tokenImages = new ArrayList(); - ParseException e = generateParseException(); + ParseException e = generateParseException("test"); Token t; do { t = getNextToken(); @@ -985,3396 +1848,5723 @@ List error_skipto(int kind) { return tokenImages; } -DeclareStatement Declare(): { - UserVariable userVariable; - ColDataType colDataType; - Expression defaultExpr = null; - DeclareStatement stmt = new DeclareStatement(); - String typeName; - String columnName; - ColumnDefinition colDef; +LockStatement LockStatement(): { + Table table; + boolean noWait = false; + LockMode lockMode; + Token waitSecondsToken = null; + Long waitSeconds = null; } { - userVariable = UserVariable() - ( - LOOKAHEAD(2) ( - "(" colDef = ColumnDefinition() - { - stmt.withUserVariable(userVariable) - .withDeclareType(DeclareType.TABLE) - .addColumnDefinition(colDef); - } - ("," colDef = ColumnDefinition() { stmt.addColumnDefinition(colDef); })* ")" - ) - | - typeName = RelObjectName() - { - stmt.withUserVariable(userVariable) - .withDeclareType(DeclareType.AS) - .withTypeName(typeName); - } - | - (colDataType = ColDataType() ["=" defaultExpr = Expression()] - { - stmt.withDeclareType(DeclareType.TYPE) - .addType(userVariable, colDataType, defaultExpr); - } - ("," userVariable = UserVariable() colDataType = ColDataType() { defaultExpr = null; } - ["=" defaultExpr = Expression()] { stmt.addType(userVariable, colDataType, defaultExpr); } )* - ) - ) - { - return stmt; - } + table = Table() + ( + LOOKAHEAD(2) ( { lockMode = LockMode.RowShare; } ) | + ( { lockMode = LockMode.RowExclusive; } ) | + LOOKAHEAD(2) ( { lockMode = LockMode.ShareRowExclusive; } ) | + LOOKAHEAD(2) ( { lockMode = LockMode.ShareUpdate; } ) | + ( { lockMode = LockMode.Share; } ) | + ( { lockMode = LockMode.Exclusive; } ) + ) + + [ { noWait = true; } | waitSecondsToken = { waitSeconds = Long.valueOf(waitSecondsToken.image); } ] + + { + return new LockStatement(table, lockMode, noWait, waitSeconds); + } } +LikeClause LikeClause(): { + LikeClause likeClause = new LikeClause(); + Table table; + List> columnsList; +} { + + table = Table() { likeClause.setTable(table); } + [ "(" columnsList = ColumnSelectItemsList() ")" { likeClause.setColumnsList(columnsList); }] + [ + LOOKAHEAD(2) + ( + { likeClause.setIncludingDefaults(true); } + | { likeClause.setExcludingDefaults(true); } + ) + + ] -SetStatement Set(): { - String namePart; - Object name; - ExpressionList expList; - boolean useEqual = false; - SetStatement set; - Expression exp = null; - Token tk = null; - String effectParameter = null; -} -{ - - [LOOKAHEAD(3) (tk = | tk = ) {effectParameter = tk.image; } ] - ( + [ LOOKAHEAD(2) - { name = "Time Zone"; useEqual=false; } - | ( - name = UserVariable() ["=" { useEqual=true; } ] + { likeClause.setIncludingIdentity(true); } + | { likeClause.setExcludingIdentity(true); } ) - | + + ] + + [ + LOOKAHEAD(2) ( - name = IdentifierChain() - ["=" { useEqual=true; } ] + { likeClause.setIncludingComments(true); } + | { likeClause.setExcludingComments(true); } ) - ) - exp=Expression() + + ] + { - expList = new ExpressionList(); - expList.add(exp); - set = new SetStatement(name, expList) - .withUseEqual(useEqual) - .withEffectParameter(effectParameter); + return likeClause; } +} +Export Export() #Export: { + Export export = new Export(); + Table table; + ParenthesedExpressionList columns; + ParenthesedSelect select; + ExportIntoItem exportIntoItem; +} { + ( - { useEqual=false; } - "," - (LOOKAHEAD(3) - ( - ( LOOKAHEAD(2) - { name = "Time Zone"; useEqual=false; } - | - (name = RelObjectNameExt() ["=" { useEqual=true; } ]) - ) - exp=Expression() - { - expList = new ExpressionList(); - expList.add(exp); - set.add(name, expList, useEqual); - } - ) - | - exp=Expression() { expList.add(exp); } - ) - )* - { return set; } -} + table = Table() { export.setTable(table); } + [ columns = ParenthesedColumnList() { export.setColumns(columns); } ] + | select = ParenthesedSelect() { export.setSelect(select); } + ) -ResetStatement Reset(): { - String name; - ResetStatement reset; - Token all; + + exportIntoItem = ExportIntoItem() { export.setExportIntoItem(exportIntoItem); } + + { + return export; + } } -{ - ( LOOKAHEAD(2) {name = "Time Zone"; } | name = RelObjectName() | all = {name = all.image; } ) - { reset = new ResetStatement(name); return reset; } + +Import Import() #Import: { + Import impt = new Import(); + Table table; + ParenthesedExpressionList columns; + List importColumns; + ImportFromItem fromItem; +} { + + [ + + ( + table = Table() { impt.setTable(table); } + [ columns = ParenthesedColumnList() { impt.setColumns(columns); } ] + | importColumns = ImportColumns() { impt.setImportColumns(importColumns); } + ) + ] + + + fromItem = ImportFromItem() { impt.setFromItem(fromItem); } + + { + return impt; + } } -RenameTableStatement RenameTableStatement(): { - RenameTableStatement renameTableStatement; - Table oldName; - Table newName; - boolean usingTableKeyword=false; - boolean usesIfExistsKeyword=false; - String waitDirective = ""; - Token token; +Import SubImport() #SubImport: { + Import impt = new Import(); + List importColumns; + ImportFromItem fromItem; +} { + "(" + + [ importColumns = ImportColumns() { impt.setImportColumns(importColumns); } ] + + + fromItem = ImportFromItem() { impt.setFromItem(fromItem); } + ")" + + { + return impt; + } } -{ - - [ LOOKAHEAD(2) { usingTableKeyword = true; } ] - [ LOOKAHEAD(2) { usesIfExistsKeyword = true; } ] - oldName = Table() - [ ( - token= { waitDirective = "WAIT " + token.image; } - | - { waitDirective = "NOWAIT"; } - ) ] - - newName = Table() + +List ImportColumns(): { + ImportColumn importColumn; + List importColumns = new ArrayList(); +} { + "(" + ( + importColumn = ColumnDefinition() + | importColumn = LikeClause() + ) + { importColumns.add(importColumn); } + + ( + "," + ( + importColumn = ColumnDefinition() + | importColumn = LikeClause() + ) + { importColumns.add(importColumn); } + )* + ")" { - renameTableStatement = new RenameTableStatement(oldName, newName, usingTableKeyword, usesIfExistsKeyword, waitDirective); + return importColumns; } +} +ExportIntoItem ExportIntoItem(): { + ExportIntoItem exportIntoItem; + ErrorClause errorClause; +} { ( - "," - oldName = Table() - - newName = Table() - { - renameTableStatement.addTableNames(oldName, newName); - } - )* + exportIntoItem = DBMSDestination() + | exportIntoItem = FileDestination() + | exportIntoItem = ScriptSourceDestination() + ) + [ LOOKAHEAD(2) errorClause = ErrorClause() { exportIntoItem.setErrorClause(errorClause); } ] { - return renameTableStatement; + return exportIntoItem; } } -PurgeStatement PurgeStatement(): { - PurgeStatement purgeStatement = null; - Table table; - Index index; - Token tableSpaceToken; - Token userToken = null; -} -{ - +ImportFromItem ImportFromItem(): { + ImportFromItem importFromItem; + ErrorClause errorClause; +} { ( - table=Table() { purgeStatement = new PurgeStatement(table); } - | - index=Index() { purgeStatement = new PurgeStatement(index); } - | - { purgeStatement = new PurgeStatement(PurgeObjectType.RECYCLEBIN); } - | - { purgeStatement = new PurgeStatement(PurgeObjectType.DBA_RECYCLEBIN); } - | - tableSpaceToken= [ userToken= ] { - purgeStatement = new PurgeStatement( - PurgeObjectType.TABLESPACE - , tableSpaceToken.image - , userToken!=null ? userToken.image : null); - } + importFromItem = DBMSSource() + | importFromItem = FileSource() + | importFromItem = ScriptSourceDestination() ) + [ LOOKAHEAD(2) errorClause = ErrorClause() { importFromItem.setErrorClause(errorClause); } ] { - return purgeStatement; + return importFromItem; } } -DescribeStatement Describe(): { +DBMSDestination DBMSDestination() #DBMSDestination: { + DBMSDestination dbmsDestination = new DBMSDestination(); + DBMSType dbmsType; + ConnectionDefinition connectionDefinition; Table table; - DescribeStatement stmt = new DescribeStatement(); - Token tk = null; + ExpressionList columns; + StringValue statement; + List dbmsTableDestinationOptions; } { - (tk= | tk=) - table = Table() { stmt.setDescribeType(tk.image).setTable(table); } + dbmsType = DBMSType() { dbmsDestination.setDestinationType(dbmsType); } + + connectionDefinition = ConnectionDefinition() { dbmsDestination.setConnectionDefinition(connectionDefinition); } + + ( + LOOKAHEAD(3) + table = Table() { dbmsDestination.setTable(table); } + [ LOOKAHEAD(2) columns = ParenthesedColumnList() { dbmsDestination.setColumns(columns); } ] + [ LOOKAHEAD(2) dbmsTableDestinationOptions = DBMSTableDestinationOptionList() { dbmsDestination.setDBMSTableDestinationOptions(dbmsTableDestinationOptions); } ] + | statement = ImportExportStatement() { dbmsDestination.setStatement(statement); } + ) + { - return stmt; + return dbmsDestination; } } -ExplainStatement Explain(): { - Select select; - Table table = null; - List options = null; - ExplainStatement es = new ExplainStatement(); +DBMSTableDestinationOption DBMSTableDestinationOption(): { + DBMSTableDestinationOption dbmsTableDestinationOption; + + Token token; + Token token2; + Token token3; } { - ( - LOOKAHEAD(3)( - options=ExplainStatementOptions() - select = Select( ) - { - es.setStatement(select); - if (options != null && !options.isEmpty()) { - for(ExplainStatement.Option o : options) { - es.addOption(o); - } - } - } - ) - | ( - table=Table( ) { es.setTable(table); } - ) - + token = + | token = + ) { dbmsTableDestinationOption = new DBMSTableDestinationOption(token.image); } + | token = token2 = token3 = { dbmsTableDestinationOption = new DBMSTableDestinationOption(token.image + " " + token2.image, new StringValue(token3.image)); } ) - { return es; } -} -/** - * Postgres supports TRUE,ON,1,FALSE,OFF,0 as values - */ -String ExplainOptionBoolean(): -{ - Token tk = null; -} -{ - // intentionally not supporting 0,1 at the moment - [( tk= | tk= | tk= | tk= )] // optional - { - return tk != null ? tk.image : null; - } + { + return dbmsTableDestinationOption; + } } -/** - * The output format, which can be TEXT, XML, JSON, or YAML - */ -String ExplainFormatOption(): -{ - Token tk = null; -} -{ - // TODO support Text - [( tk= | tk= | tk= )] // optional - { - return tk != null ? tk.image : null; - } +List DBMSTableDestinationOptionList(): { + List dbmsTableDestinationOptions = new ArrayList(); + DBMSTableDestinationOption dbmsTableDestinationOption; +} { + ( LOOKAHEAD(2) dbmsTableDestinationOption = DBMSTableDestinationOption() { dbmsTableDestinationOptions.add(dbmsTableDestinationOption); } )+ + { + return dbmsTableDestinationOptions; + } } -/** - * Options for explain, see https://www.postgresql.org/docs/9.1/sql-explain.html - */ -List ExplainStatementOptions(): -{ - List options = new ArrayList(); - ExplainStatement.Option option = null; - Token token = null; - String value = null; -} -{ - ( - ( value=ExplainOptionBoolean() - { - option = new ExplainStatement.Option(ExplainStatement.OptionType.ANALYZE); - option.setValue(value); - options.add(option); - } - ) - | - ( value=ExplainOptionBoolean() - { - option = new ExplainStatement.Option(ExplainStatement.OptionType.BUFFERS); - option.setValue(value); - options.add(option); - } - ) - | - ( value=ExplainOptionBoolean() - { - option = new ExplainStatement.Option(ExplainStatement.OptionType.COSTS); - option.setValue(value); - options.add(option); - } - ) - | - ( value=ExplainOptionBoolean() - { - option = new ExplainStatement.Option(ExplainStatement.OptionType.VERBOSE); - option.setValue(value); - options.add(option); - } - ) - | - ( value=ExplainFormatOption() - { - option = new ExplainStatement.Option(ExplainStatement.OptionType.FORMAT); - option.setValue(value); - options.add(option); - } +DBMSSource DBMSSource() #DBMSSource: { + DBMSSource dbmsSource = new DBMSSource(); + DBMSType dbmsType; + ConnectionDefinition connectionDefinition; + Table table; + ExpressionList columns; + List statements; +} { + dbmsType = DBMSType() { dbmsSource.setSourceType(dbmsType); } + + connectionDefinition = ConnectionDefinition() { dbmsSource.setConnectionDefinition(connectionDefinition); } + + ( + table = Table() { dbmsSource.setTable(table); } + [ LOOKAHEAD(2) columns = ParenthesedColumnList() { dbmsSource.setColumns(columns); } ] + | statements = ImportExportStatementsList() { dbmsSource.setStatements(statements); } ) - )* //zero or many times those productions - { - return options; - } + { + return dbmsSource; + } } -UseStatement Use(): { - String name; - boolean hasSchemaKeyword = false; +DBMSType DBMSType(): { + DBMSType dbmsType; + Token tk1; + Token tk2 = null; +} { + ( + tk1= + | tk1= + | tk1= + [ "=" tk2=] + ) { dbmsType = new DBMSType(tk1.image, tk2 == null ? null : tk2.image); } + { + return dbmsType; + } } -{ - [ LOOKAHEAD(2) { hasSchemaKeyword = true; } ] name = RelObjectNameExt() + +FileType FileType(): { + FileType fileType; + Token tk; +} { + ( + tk= + | tk= + ) { fileType = new FileType(tk.image); } { - return new UseStatement(name, hasSchemaKeyword); + return fileType; } } -Statement Show(): -{ - Statement statement; - List captureRest; +StringValue ImportExportStatement() #ImportExportStatement: { + StringValue statement; +} { + token = + { + statement = new StringValue(token.image); + linkAST(statement, jjtThis); + return statement; + } } -{ - - ( - LOOKAHEAD(2) statement = ShowColumns() - | - LOOKAHEAD(2) statement = ShowIndex() - | - LOOKAHEAD(2) statement = ShowTables() - | - // any of the RDBMS specific SHOW syntax - captureRest = captureRest() - { - if (captureRest.size()==1) { - statement = new ShowStatement(captureRest.get(0)); - } else { - statement = new UnsupportedStatement("SHOW", captureRest); - } - } - ) + +List ImportExportStatementsList(): { + List statements = new ArrayList(); + StringValue statement; +} { + ( statement = ImportExportStatement() { statements.add(statement); } )+ + { - return statement; + return statements; } } -ShowColumnsStatement ShowColumns(): { - String tableName; -} -{ - tableName = RelObjectNameExt() +StringValue File() #File: { + Token token; +} { + token = { - return new ShowColumnsStatement(tableName); + StringValue file = new StringValue(token.image); + linkAST(file, jjtThis); + return file; } } -ShowIndexStatement ShowIndex(): { - String tableName; -} -{ - tableName = RelObjectNameExt() +List FileList(): { + List files = new ArrayList(); + StringValue file; +} { + ( file = File() { files.add(file); } )+ { - return new ShowIndexStatement(tableName); + return files; } } -Statement RefreshMaterializedView(): { - Table view = null; - boolean concurrently = false; - RefreshMode refreshMode = null; - List captureRest; -} -{ - - [ LOOKAHEAD(2) { concurrently = true; } ] - view = Table() - [ - { refreshMode = RefreshMode.WITH_DATA; } - [ - { refreshMode = RefreshMode.WITH_NO_DATA; } - ] - - ] - captureRest = captureRest() +ConnectionFileDefinition ConnectionFileDefinition(): { + ConnectionDefinition connectionDefinition = null; + List files; +} { + connectionDefinition = ConnectionOrCloudConnectionDefinition() + files = FileList() { - if (concurrently && refreshMode == RefreshMode.WITH_NO_DATA) { - return new UnsupportedStatement("REFRESH", captureRest); - } else { - return new RefreshMaterializedViewStatement(view, concurrently, refreshMode); - } + return new ConnectionFileDefinition(connectionDefinition, files); } } -// https://dev.mysql.com/doc/refman/8.0/en/show-tables.html -ShowTablesStatement ShowTables(): { - ShowTablesStatement showTablesStatement; - EnumSet modifiers = EnumSet.noneOf(ShowTablesStatement.Modifiers.class); - ShowTablesStatement.SelectionMode selectionMode = null; - String dbName = null; - Expression likeExpression = null; - Expression whereCondition = null; + +List ConnectionFileDefinitionList(): { + List connectionFileDefinitions = new ArrayList(); + ConnectionFileDefinition connectionFileDefinition; +} { + ( LOOKAHEAD(2) connectionFileDefinition = ConnectionFileDefinition() { connectionFileDefinitions.add(connectionFileDefinition); } )+ + { + return connectionFileDefinitions; + } } -{ - [ { modifiers.add(ShowTablesStatement.Modifiers.EXTENDED); } ] - [ { modifiers.add(ShowTablesStatement.Modifiers.FULL); } ] - - [ + +CSVColumn CSVDestinationColumn(): { + CSVColumn csvColumn; + + Token token; + Token token2; +} { ( - {selectionMode = ShowTablesStatement.SelectionMode.FROM; } - | { selectionMode = ShowTablesStatement.SelectionMode.IN; } + LOOKAHEAD(2) + token= ".." token2= { csvColumn = new CSVColumn(Long.valueOf(token.image), Long.valueOf(token2.image)); } + | token= { csvColumn = new CSVColumn(Long.valueOf(token.image)); } + [ "=" token = { csvColumn.setFormat(new StringValue(token.image)); }] + [ + + "=" + ( + token= + | token= + | token= + ) + { csvColumn.setDelimit(token.image); } + ] ) - dbName = RelObjectNameExt() - ] - [ ( likeExpression = SimpleExpression() | whereCondition = Expression()) ] - { - showTablesStatement = new ShowTablesStatement(); - showTablesStatement.setModifiers(modifiers); - showTablesStatement.setSelectionMode(selectionMode); - showTablesStatement.setDbName(dbName); - showTablesStatement.setLikeExpression(likeExpression); - showTablesStatement.setWhereCondition(whereCondition); - return showTablesStatement; - } + { + return csvColumn; + } } -Values Values(): { - ExpressionList expressions; +List CSVDestinationColumnList(): { + List csvColumns = new ArrayList(); + CSVColumn csvColumn; } { - ( | ) - expressions = ExpressionList() - + csvColumn = CSVDestinationColumn() { csvColumns.add(csvColumn); } + ( "," csvColumn = CSVDestinationColumn() { csvColumns.add(csvColumn); } )* { - return new Values(expressions); + return csvColumns; } } -ReturningClause ReturningClause(): -{ - Token keyword; - List> selectItems; - Object dataItem; - List dataItems = null; -} -{ - ( keyword= | keyword= ) - selectItems = SelectItemsList() - - [ - - ( dataItem = Table() | dataItem = UserVariable() ) - { dataItems = new ArrayList(); dataItems.add(dataItem); } - - ( - "," - ( dataItem = Table() | dataItem = UserVariable() ) { dataItems.add(dataItem); } - )* - ] +CSVColumn CSVSourceColumn(): { + CSVColumn csvColumn; + Token token; + Token token2; +} { + ( + LOOKAHEAD(2) + token= ".." token2= { csvColumn = new CSVColumn(Long.valueOf(token.image), Long.valueOf(token2.image)); } + | token= { csvColumn = new CSVColumn(Long.valueOf(token.image)); } + [ "=" token = { csvColumn.setFormat(new StringValue(token.image)); }] + ) { - return new ReturningClause(keyword.image, selectItems, dataItems); + return csvColumn; } } -Update Update( List with ): -{ - Update update = new Update(); - Table table = null; - List startJoins = null; +List CSVSourceColumnList(): { + List csvColumns = new ArrayList(); + CSVColumn csvColumn; +} { + csvColumn = CSVSourceColumn() { csvColumns.add(csvColumn); } + ( "," csvColumn = CSVSourceColumn() { csvColumns.add(csvColumn); } )* + { + return csvColumns; + } +} - List updateSets; - Expression where = null; - FromItem fromItem = null; - List joins = null; - Limit limit = null; - List orderByElements; - boolean useColumnsBrackets = false; - ReturningClause returningClause; - Token tk = null; - UpdateModifierPriority modifierPriority = null; - boolean modifierIgnore = false; +FBVColumn FBVDestinationColumn(): { + FBVColumn fbvColumn; - OutputClause outputClause = null; + Token token; + Token token2; +} { + ( + token= "=" token2= { fbvColumn = new FBVColumn(token.image, new LongValue(token2.image)); } + | ( token= | token= ) "=" token2= { fbvColumn = new FBVColumn(token.image, new StringValue(token2.image)); } + | token= "=" ( token2= | token2= ) { fbvColumn = new FBVColumn(token.image, token2.image); } + ) + { + return fbvColumn; + } } -{ - { update.setOracleHint(getOracleHint()); } - [ LOOKAHEAD(2) { modifierPriority = UpdateModifierPriority.LOW_PRIORITY; }] - [ LOOKAHEAD(2) { modifierIgnore = true; }] - table=TableWithAliasAndMysqlIndexHint() [ startJoins=JoinsList() ] - updateSets = UpdateSets() { update.setUpdateSets(updateSets); } - [ outputClause = OutputClause() {update.setOutputClause(outputClause); } ] - - [ - fromItem=FromItem() - [ LOOKAHEAD(2) joins=JoinsList() ] ] +List FBVDestinationColumnList(): { + List fbvColumns = new ArrayList(); + FBVColumn fbvColumn; + boolean precedesComma; +} { + fbvColumn = FBVDestinationColumn() { fbvColumns.add(fbvColumn); } + ( + { precedesComma = false; } + ["," { precedesComma = true; }] + fbvColumn = FBVDestinationColumn() { fbvColumn.setPrecedesComma(precedesComma); fbvColumns.add(fbvColumn); } + )* + { + return fbvColumns; + } +} - [ where=WhereClause() { update.setWhere(where); } ] +FBVColumn FBVSourceColumn(): { + FBVColumn fbvColumn; - [ orderByElements = OrderByElements() { update.setOrderByElements(orderByElements); } ] - [ limit = PlainLimit() { update.setLimit(limit); } ] - [ returningClause = ReturningClause() { update.setReturningClause(returningClause); } ] + Token token; + Token token2; +} { + ( + ( token= | token= ) "=" token2= { fbvColumn = new FBVColumn(token.image, new LongValue(token2.image)); } + | ( token= | token= ) "=" token2= { fbvColumn = new FBVColumn(token.image, new StringValue(token2.image)); } + | token= "=" ( token2= | token2= ) { fbvColumn = new FBVColumn(token.image, token2.image); } + ) + { + return fbvColumn; + } +} +List FBVSourceColumnList(): { + List fbvColumns = new ArrayList(); + FBVColumn fbvColumn; + boolean precedesComma; +} { + fbvColumn = FBVSourceColumn() { fbvColumns.add(fbvColumn); } + ( + { precedesComma = false; } + ["," { precedesComma = true; }] + fbvColumn = FBVSourceColumn() { fbvColumn.setPrecedesComma(precedesComma); fbvColumns.add(fbvColumn); } + )* { - return update.withWithItemsList(with) - .withTable(table) - .withStartJoins(startJoins) - .withFromItem(fromItem) - .withJoins(joins) - .withModifierPriority(modifierPriority) - .withModifierIgnore(modifierIgnore); + return fbvColumns; } } -List UpdateSets(): -{ - ArrayList updateSets = new ArrayList(); - UpdateSet updateSet; - Column tableColumn; - Expression valueExpression; +FileOption FileDestinationOption(): { + FileOption fileOption; - ExpressionList columns; - ExpressionListvalues; -} -{ + Token token; + Token token2; + Token token3; +} { ( - ( - tableColumn=Column() "=" valueExpression=Expression() - { updateSets.add( new UpdateSet (tableColumn, valueExpression)); } - ) - | - ( - { updateSet = new UpdateSet(); updateSets.add(updateSet); } - columns = ParenthesedExpressionList() { updateSet.setColumns(columns); } - "=" - ( - LOOKAHEAD(3) valueExpression = ParenthesedSelect() { updateSet.setValues( new ExpressionList(valueExpression)); } - | - values = ParenthesedExpressionList() { updateSet.setValues(values); } - ) + ( token= | token= ) { fileOption = new FileOption(token.image); } + | token= token2= token3= { fileOption = new FileOption(token.image + " " + token2.image + " " + token3.image); } + | ( token= | token= | token= ) "=" token2= { fileOption = new FileOption(token.image, new StringValue(token2.image)); } + | ( + token= token2= "=" token3= + | token= ( token2= | token2= ) "=" token3= ) + { fileOption = new FileOption(token.image + " " + token2.image, new StringValue(token3.image)); } + | token= "=" ( token2= | token2= | token2= ) { fileOption = new FileOption(token.image, token2.image); } ) + { + return fileOption; + } +} + +List FileDestinationOptionList(): { + List fileOptions = new ArrayList(); + FileOption fileOption; +} { + ( LOOKAHEAD(2) fileOption = FileDestinationOption() { fileOptions.add(fileOption); } )+ + { + return fileOptions; + } +} + +FileOption FileSourceOption(): { + FileOption fileOption; + Token token; + Token token2; + Token token3; +} { ( - "," - ( - tableColumn=Column() "=" valueExpression=Expression() - { updateSets.add( new UpdateSet (tableColumn, valueExpression)); } + ( token= | token= | token= ) { fileOption = new FileOption(token.image); } + | ( + ( token= | token= ) "=" token2= { fileOption = new FileOption(token.image, new StringValue(token2.image)); } + | token= "=" token2= { fileOption = new FileOption(token.image, new LongValue(token2.image)); } ) - | + | LOOKAHEAD(2) ( - { updateSet = new UpdateSet(); updateSets.add(updateSet); } - columns = ParenthesedExpressionList() { updateSet.setColumns(columns); } - "=" - ( - LOOKAHEAD(3) valueExpression = ParenthesedSelect() { updateSet.setValues( new ExpressionList(valueExpression)); } - | - values = ParenthesedExpressionList() { updateSet.setValues(values); } - ) + token= token2= "=" token3= + | token= ( token2= | token2= ) "=" token3= ) - )* - + { fileOption = new FileOption(token.image + " " + token2.image, new StringValue(token3.image)); } + | token= token2= "=" token3= + { fileOption = new FileOption(token.image + " " + token2.image, new LongValue(token3.image)); } + ) { - return updateSets; + return fileOption; } } -Insert Insert( List with ): -{ - Insert insert = new Insert(); - Table table = null; - Column tableColumn = null; - ExpressionList columns = new ExpressionList(); - Expression exp = null; - ReturningClause returningClause; - Select select = null; - boolean useDuplicate = false; - Token tk = null; - InsertModifierPriority modifierPriority = null; - boolean modifierIgnore = false; +List FileSourceOptionList(): { + List fileOptions = new ArrayList(); + FileOption fileOption; +} { + ( LOOKAHEAD(2) fileOption = FileSourceOption() { fileOptions.add(fileOption); } )+ + { + return fileOptions; + } +} - List updateSets; - List duplicateUpdateSets; +FileDestination FileDestination() #FileDestination: { + FileDestination fileDestination = new FileDestination(); + FileType fileType; + List connectionFileDefinitions; + List files; + List csvColumns; + List fbvColumns; + List fileOptions; + CertificateVerification certificateVerification; +} { + ( + fileType = FileType() { fileDestination.setDestinationType(fileType); } + connectionFileDefinitions = ConnectionFileDefinitionList() { fileDestination.setConnectionFileDefinitions(connectionFileDefinitions); } + | { fileDestination.setLocal(true); } + [ { fileDestination.setSecure(true); }] - String name = null; - boolean useAs = false; - OutputClause outputClause = null; + fileType = FileType() { fileDestination.setDestinationType(fileType); } + files = FileList() + { + connectionFileDefinitions = new ArrayList(); + connectionFileDefinitions.add(new ConnectionFileDefinition(files)); + } + ) + { fileDestination.setConnectionFileDefinitions(connectionFileDefinitions); } - InsertConflictTarget conflictTarget = null; - InsertConflictAction conflictAction = null; -} -{ - { insert.setOracleHint(getOracleHint()); } + [ + LOOKAHEAD(2) + "(" + ( + csvColumns = CSVDestinationColumnList() { fileDestination.setCSVColumns(csvColumns); } + | fbvColumns = FBVDestinationColumnList() { fileDestination.setFBVColumns(fbvColumns); } + ) + ")" + ] - [ - LOOKAHEAD(2) (tk = | tk = | tk = ) - { - if (tk!=null) - modifierPriority = InsertModifierPriority.from(tk.image); - } - ] - [ LOOKAHEAD(2) { modifierIgnore = true; }] - [ LOOKAHEAD(2) ] table=Table() + [ LOOKAHEAD(2) fileOptions = FileDestinationOptionList() { fileDestination.setFileOptions(fileOptions); } ] - [ LOOKAHEAD(2) [ { useAs = true; } ] name=RelObjectNameWithoutValue() { table.setAlias(new Alias(name,useAs)); }] + [ LOOKAHEAD(2) certificateVerification = CertificateVerification() { fileDestination.setCertificateVerification(certificateVerification); } ] - [LOOKAHEAD(2) "(" columns=ColumnList() ")" ] + { + return fileDestination; + } +} - [ outputClause = OutputClause() { insert.setOutputClause(outputClause); } ] +FileSource FileSource() #FileSource: { + FileSource fileSource = new FileSource(); + FileType fileType; + List connectionFileDefinitions; + List files; + List csvColumns; + List fbvColumns; + List fileOptions; + CertificateVerification certificateVerification; +} { + ( + fileType = FileType() { fileSource.setSourceType(fileType); } + connectionFileDefinitions = ConnectionFileDefinitionList() { fileSource.setConnectionFileDefinitions(connectionFileDefinitions); } + | { fileSource.setLocal(true); } + [ { fileSource.setSecure(true); }] - ( + fileType = FileType() { fileSource.setSourceType(fileType); } + files = FileList() + { + connectionFileDefinitions = new ArrayList(); + connectionFileDefinitions.add(new ConnectionFileDefinition(files)); + } + ) + { fileSource.setConnectionFileDefinitions(connectionFileDefinitions); } + + [ + LOOKAHEAD(2) + "(" ( - updateSets = UpdateSets() { insert.withSetUpdateSets(updateSets); } + csvColumns = CSVSourceColumnList() { fileSource.setCSVColumns(csvColumns); } + | fbvColumns = FBVSourceColumnList() { fileSource.setFBVColumns(fbvColumns); } ) - | - select = Select() - ) + ")" + ] - [ LOOKAHEAD(2) - duplicateUpdateSets = UpdateSets() { insert.withDuplicateUpdateSets(duplicateUpdateSets); } - ] + [ LOOKAHEAD(2) fileOptions = FileSourceOptionList() { fileSource.setFileOptions(fileOptions); } ] - [ - - [ conflictTarget = InsertConflictTarget() ] - conflictAction = InsertConflictAction() { insert.withConflictTarget(conflictTarget).setConflictAction(conflictAction); } - ] + [ LOOKAHEAD(2) certificateVerification = CertificateVerification() { fileSource.setCertificateVerification(certificateVerification); } ] - [ returningClause = ReturningClause() { insert.setReturningClause(returningClause); } ] + { + return fileSource; + } +} +CertificateVerification CertificateVerification(): { + CertificateVerification certificateVerification = new CertificateVerification(); + Token token; +} { + ( + ( + { certificateVerification.setIgnoreCertificate(true); } + | { certificateVerification.setVerifyCertificate(true); } + ) + + [ + LOOKAHEAD(2) + + token = { certificateVerification.setPublicKey(new StringValue(token.image)); } + ] + | + token = { certificateVerification.setPublicKey(new StringValue(token.image)); } + ) { - if (!columns.isEmpty()) { - insert.setColumns(columns); - } - return insert.withWithItemsList(with) - .withSelect(select) - .withTable(table) - .withModifierPriority(modifierPriority) - .withModifierIgnore(modifierIgnore); + return certificateVerification; } } -InsertConflictTarget InsertConflictTarget(): -{ - String indexColumnName; - ArrayList indexColumnNames = new ArrayList(); - Expression indexExpression = null; - Expression whereExpression = null; - String constraintName = null ; -} -{ - ( - ( - "(" - indexColumnName = RelObjectNameExt2() { indexColumnNames.add(indexColumnName); } - ( "," indexColumnName = RelObjectNameExt2() { indexColumnNames.add(indexColumnName); } )* -// | -// ( -// "(" indexExpression = Expression() ")" -// ) +ScriptSourceDestination ScriptSourceDestination(): { + ScriptSourceDestination scriptSourceDestination = new ScriptSourceDestination(); + ConnectionDefinition connectionDefinition; + Table script; + String property; + StringValue value; - ")" - [ whereExpression = WhereClause() ] - ) - | + Token token; +} { + + script = Table() { scriptSourceDestination.setScript(script); } + + [ LOOKAHEAD(2) connectionDefinition = ConnectionDefinition() { scriptSourceDestination.setConnectionDefinition(connectionDefinition); } ] + + [ + LOOKAHEAD(2) + { + List properties = new ArrayList(); + List values = new ArrayList(); + scriptSourceDestination.setProperties(properties); + scriptSourceDestination.setValues(values); + } + + ( - constraintName = RelObjectNameExt2() - ) - ) + LOOKAHEAD(2) + property = RelObjectName() "=" token = { value = new StringValue(token.image); } + { + properties.add(property); + values.add(value); + } + )+ + ] - { return new InsertConflictTarget(indexColumnNames, indexExpression, whereExpression, constraintName); } + { + return scriptSourceDestination; + } } -InsertConflictAction InsertConflictAction(): -{ - InsertConflictAction conflictAction; - Expression whereExpression = null; - List updateSets; +UserIdentification UserIdentification(): { + UserIdentification userIdentification = new UserIdentification(); + Token token; +} { + + token= { userIdentification.setUser(new StringValue(token.image)); } + + token= { userIdentification.setPassword(new StringValue(token.image)); } + + { + return userIdentification; + } } -{ - ( - LOOKAHEAD(2) ( - { conflictAction = new InsertConflictAction( ConflictActionType.DO_NOTHING ); } - ) - | - ( - { conflictAction = new InsertConflictAction( ConflictActionType.DO_UPDATE ); } - updateSets = UpdateSets() { conflictAction.setUpdateSets(updateSets); } - [ whereExpression = WhereClause() ] - ) - ) - { return conflictAction - .withWhereExpression(whereExpression); } +ConnectionDefinition ConnectionDefinition(): { + ConnectionDefinition connectionDefinition = new ConnectionDefinition(); + String connectionObjectName; + UserIdentification userIdentification; + CertificateVerification certificateVerification; + + Token token; +} { + + ( + connectionObjectName = RelObjectName() { connectionDefinition.setConnectionObjectName(connectionObjectName); } + | token= { connectionDefinition.setConnectionDefinition(new StringValue(token.image)); } + ) + + [ LOOKAHEAD(2) userIdentification = UserIdentification() { connectionDefinition.setUserIdentification(userIdentification); } ] + + [ LOOKAHEAD(2) certificateVerification = CertificateVerification() { connectionDefinition.setCertificateVerification(certificateVerification); } ] + + { + return connectionDefinition; + } } -OutputClause OutputClause(): -{ - List> selectItemList = null; - UserVariable tableVariable = null; - Table outputTable = null; - List columnList = null; +ConnectionDefinition CloudConnectionDefinition(): { + CloudConnectionDefinition connectionDefinition = new CloudConnectionDefinition(); + String connectionObjectName; + UserIdentification userIdentification; + + Token token; + Token token2; +} { + + ( + token = { connectionDefinition.setStorage(token.image); } + | token = token2 = { connectionDefinition.setStorage(token.image + " " + token2.image); } + ) + + ( + connectionObjectName = RelObjectName() { connectionDefinition.setConnectionObjectName(connectionObjectName); } + | token = { connectionDefinition.setConnectionDefinition(new StringValue(token.image)); } + ) + + [ userIdentification = UserIdentification() { connectionDefinition.setUserIdentification(userIdentification); } ] + + { + return connectionDefinition; + } } -{ - - selectItemList = SelectItemsList() - [ - ( - tableVariable = UserVariable() - | - outputTable = Table() - ) - [ - LOOKAHEAD(2) columnList = ColumnsNamesList() - ] - ] +ConnectionDefinition ConnectionOrCloudConnectionDefinition(): { + ConnectionDefinition connectionDefinition; +} { + ( + LOOKAHEAD(2) connectionDefinition = CloudConnectionDefinition() + | connectionDefinition = ConnectionDefinition() + ) { - return new OutputClause(selectItemList, tableVariable, outputTable, columnList); + return connectionDefinition; } } -Upsert Upsert(): -{ - Upsert upsert = new Upsert(); - Table table = null; - ExpressionList columns; - List updateSets; +ErrorClause ErrorClause(): { + ErrorClause errorClause = new ErrorClause(); + ErrorDestination errorDestination; + Expression expression; + RejectClause rejectClause; - Select select = null; - List duplicateUpdateSets; - Token tk = null; -} -{ + Token token; +} { ( - { upsert.setUpsertType(UpsertType.UPSERT); } - | - { upsert.setUpsertType(UpsertType.REPLACE); } - | - ( - { upsert.setUpsertType(UpsertType.INSERT_OR_REPLACE); } - ) - ) - [ LOOKAHEAD(2) { upsert.setUsingInto(true); } ] + + errorDestination = ErrorDestination() { errorClause.setErrorDestination(errorDestination); } + [ + LOOKAHEAD(2) + "(" + expression = Expression() { errorClause.setExpression(expression); } + ")" + ] + [ + LOOKAHEAD(2) + ( + { errorClause.setReplace(true); } + | { errorClause.setTruncate(true); } + ) + ] + [ LOOKAHEAD(2) rejectClause = RejectClause() { errorClause.setRejectClause(rejectClause); } ] + | rejectClause = RejectClause() { errorClause.setRejectClause(rejectClause); } + ) - table=Table() { upsert.setTable(table); } + { + return errorClause; + } +} - [ LOOKAHEAD(2) columns = ParenthesedColumnList() { upsert.setColumns(columns); } ] +RejectClause RejectClause(): { + RejectClause rejectClause = new RejectClause(); +} { + ( - ( - - updateSets = UpdateSets() { upsert.setUpdateSets(updateSets); } - ) - | - ( - select = Select() { upsert.setSelect(select); } - ) + token= { rejectClause.setLimit(new LongValue(token.image)); } + | ) - [ - - duplicateUpdateSets = UpdateSets() { upsert.setDuplicateUpdateSets(duplicateUpdateSets); } - ] + [ LOOKAHEAD(2) { rejectClause.setErrors(true); } ] { - return upsert; + return rejectClause; } } -Delete Delete( List with ): -{ - Delete delete = new Delete(); - Table table = null; - List
tables = new ArrayList
(); - Table usingTable = null; - List
usingList = new ArrayList
(); - List joins = null; - Expression where = null; - Limit limit = null; - List orderByElements; - boolean hasFrom = false; - Token tk = null; - DeleteModifierPriority modifierPriority = null; - boolean modifierIgnore = false; - boolean modifierQuick = false; +ErrorDestination ErrorDestination(): { + ErrorDestination errorDestination; +} { + ( + LOOKAHEAD(2) errorDestination = CSVFileDestination() + | errorDestination = Table() + ) - ReturningClause returningClause; - OutputClause outputClause; + { + return errorDestination; + } } -{ - { delete.setOracleHint(getOracleHint()); } - [ LOOKAHEAD(2) { modifierPriority = DeleteModifierPriority.LOW_PRIORITY; }] - [ LOOKAHEAD(2) { modifierQuick = true; }] - [ LOOKAHEAD(2) { modifierIgnore = true; }] - [LOOKAHEAD(4) (table=TableWithAlias() { tables.add(table); } - ("," table=TableWithAlias() { tables.add(table); } )* - [ outputClause = OutputClause() {delete.setOutputClause(outputClause); } ] - | ) { hasFrom = true; }] - [ LOOKAHEAD(3) table=TableWithAlias() [ LOOKAHEAD(2) joins=JoinsList() ] ] - [ usingTable=TableWithAlias() { usingList.add(usingTable); } - ("," usingTable=TableWithAlias() { usingList.add(usingTable); } )*] - [where=WhereClause() { delete.setWhere(where); } ] - [orderByElements = OrderByElements() { delete.setOrderByElements(orderByElements); } ] - [limit=PlainLimit() {delete.setLimit(limit); } ] +CSVFileDestination CSVFileDestination(): { + CSVFileDestination csvFileDestination = new CSVFileDestination(); + ConnectionDefinition connectionDefinition; + StringValue file; +} { + ( + + connectionDefinition = ConnectionOrCloudConnectionDefinition() { csvFileDestination.setConnectionDefinition(connectionDefinition); } + | { csvFileDestination.setLocal(true); } + [ { csvFileDestination.setSecure(true); } ] + + ) + + file = File() { csvFileDestination.setFile(file); } - [ returningClause = ReturningClause() { delete.setReturningClause(returningClause); } ] { - if (joins != null && joins.size() > 0) { - delete.setJoins(joins); - } - return delete.withWithItemsList(with) - .withTables(tables) - .withTable(table) - .withHasFrom(hasFrom) - .withUsingList(usingList) - .withModifierPriority(modifierPriority) - .withModifierIgnore(modifierIgnore) - .withModifierQuick(modifierQuick); + return csvFileDestination; } } -Statement Merge( List with ) : { - Merge merge = new Merge(); - Table table; - FromItem fromItem; - Expression condition; - List operations; - OutputClause outputClause; +DeclareStatement Declare(): { + UserVariable userVariable; + ColDataType colDataType; + Expression defaultExpr = null; + DeclareStatement stmt = new DeclareStatement(); + String typeName; + String columnName; + ColumnDefinition colDef; +} { + userVariable = UserVariable() + ( + LOOKAHEAD(2) ( + "(" colDef = ColumnDefinition() + { + stmt.withUserVariable(userVariable) + .withDeclareType(DeclareType.TABLE) + .addColumnDefinition(colDef); + } + ("," colDef = ColumnDefinition() { stmt.addColumnDefinition(colDef); })* ")" + ) + | + typeName = RelObjectName() + { + stmt.withUserVariable(userVariable) + .withDeclareType(DeclareType.AS) + .withTypeName(typeName); + } + | + (colDataType = ColDataType() ["=" defaultExpr = Expression()] + { + stmt.withDeclareType(DeclareType.TYPE) + .addType(userVariable, colDataType, defaultExpr); + } + ("," userVariable = UserVariable() colDataType = ColDataType() { defaultExpr = null; } + ["=" defaultExpr = Expression()] { stmt.addType(userVariable, colDataType, defaultExpr); } )* + ) + ) + { + return stmt; + } } + +SessionStatement SessionStatement(): { - { merge.setOracleHint(getOracleHint()); } table=TableWithAlias() { merge.setTable(table); } - fromItem = FromItem() { merge.setFromItem(fromItem); } - condition = Expression() { merge.setOnCondition(condition); } + SessionStatement sessionsStatement; + Token actionToken; + Token idToken = null; + String id = null; +} +{ + ( | ) + ( + actionToken = + | + actionToken = + | + actionToken = + | + actionToken = + | + actionToken = + ) - operations = MergeOperations() { merge.setOperations(operations); } + [ + ( + idToken = + | + idToken = + | + idToken = + | + idToken = + ) { id = idToken.image; } - [ outputClause = OutputClause() { merge.setOutputClause(outputClause); } ] + ( + "." + ( + idToken = + | + idToken = + | + idToken = + | + idToken = + ) { id += "." + idToken.image; } + )? + ] + { + sessionsStatement = id!=null + ? new SessionStatement(actionToken.image, id) + : new SessionStatement(actionToken.image); + } - { return merge.withWithItemsList(with); } + // options + [ + LOOKAHEAD(2) + ( idToken = | idToken = ) + "=" + ( actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = ) + { sessionsStatement.putOption(idToken.image, actionToken.image ); } + + ( + "," + ( idToken = | idToken = ) + "=" + ( actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = | actionToken = ) + { sessionsStatement.putOption(idToken.image, actionToken.image ); } + )* + ] + + { + //linkAST(sessionsStatement,jjtThis); + return sessionsStatement; + } } -List MergeOperations() : { - List operationsList = new ArrayList(); - MergeOperation operation; +SetStatement Set(): { + String namePart; + Object name; + ExpressionList expList; + boolean useEqual = false; + SetStatement set; + Expression exp = null; + Token tk = null; + String effectParameter = null; } { + + [LOOKAHEAD(3) (tk = | tk = ) {effectParameter = tk.image; } ] ( - LOOKAHEAD(2) operation = MergeWhenMatched() { operationsList.add(operation); } + LOOKAHEAD(2) + { name = "Time Zone"; useEqual=false; } | - operation = MergeWhenNotMatched() { operationsList.add(operation); } - )* - { return operationsList; } -} + ( + name = UserVariable() ["=" { useEqual=true; } ] + ) + | + ( + name = IdentifierChain() + ["=" { useEqual=true; } ] + ) + ) + exp=Expression() + { + expList = new ExpressionList(); + expList.add(exp); + set = new SetStatement(name, expList) + .withUseEqual(useEqual) + .withEffectParameter(effectParameter); + } -MergeOperation MergeWhenMatched() : { - Expression predicate = null; - MergeOperation operation; -} -{ - - [ predicate = Expression() ] - ( - operation = MergeDeleteClause(predicate) | operation = MergeUpdateClause(predicate) - ) - { return operation; } + { useEqual=false; } + "," + (LOOKAHEAD(3) + ( + ( LOOKAHEAD(2) + { name = "Time Zone"; useEqual=false; } + | + (name = RelObjectName() ["=" { useEqual=true; } ]) + ) + exp=Expression() + { + expList = new ExpressionList(); + expList.add(exp); + set.add(name, expList, useEqual); + } + ) + | + exp=Expression() { expList.add(exp); } + ) + )* + { return set; } } -MergeOperation MergeDeleteClause(Expression predicate) : { - MergeDelete md = new MergeDelete().withAndPredicate(predicate); +ResetStatement Reset(): { + String name; + ResetStatement reset; + Token all; } { - { return md; } + ( LOOKAHEAD(2) {name = "Time Zone"; } | name = RelObjectName() | all = {name = all.image; } ) + { reset = new ResetStatement(name); return reset; } } -MergeOperation MergeUpdateClause(Expression predicate) : { - MergeUpdate mu = new MergeUpdate().withAndPredicate(predicate); - List updateSets; - Expression condition; +RenameTableStatement RenameTableStatement(): { + RenameTableStatement renameTableStatement; + Table oldName; + Table newName; + boolean usingTableKeyword=false; + boolean usesIfExistsKeyword=false; + String waitDirective = ""; + Token token; } { - updateSets = UpdateSets() { mu.setUpdateSets(updateSets); } - [ condition = Expression() { mu.setWhereCondition(condition); }] - [ LOOKAHEAD(2) condition = Expression() { mu.setDeleteWhereCondition(condition); } ] - { return mu; } -} + + [ LOOKAHEAD(2) { usingTableKeyword = true; } ] + [ LOOKAHEAD(2) { usesIfExistsKeyword = true; } ] + oldName = Table() + [ ( + token= { waitDirective = "WAIT " + token.image; } + | + { waitDirective = "NOWAIT"; } + ) ] + + newName = Table() -MergeOperation MergeWhenNotMatched() : { - MergeInsert mi = new MergeInsert(); - Expression predicate; - ExpressionList columns; - ExpressionList expList; - Expression condition; -} -{ - - [ predicate = Expression() { mi.setAndPredicate(predicate); } ] - - - [ "(" columns = ColumnList() ")" - { - mi.setColumns( new ParenthesedExpressionList(columns) ); - } - ] - "(" expList = SimpleExpressionList() ")" + { + renameTableStatement = new RenameTableStatement(oldName, newName, usingTableKeyword, usesIfExistsKeyword, waitDirective); + } + + ( + "," + oldName = Table() + + newName = Table() { - mi.setValues( new ParenthesedExpressionList(expList) ); + renameTableStatement.addTableNames(oldName, newName); } + )* - [ condition = Expression() { mi.setWhereCondition(condition); }] - - { return mi; } + { + return renameTableStatement; + } } -ObjectNames RelObjectNames() : { - String token = null; - Token delimiter = null; - List data = new ArrayList(); - List delimiters = new ArrayList(); -} { - token = RelObjectNameExt() { data.add(token); } - ( - LOOKAHEAD (2) ( delimiter = "." | delimiter = ":" ) { delimiters.add(delimiter.image); } (( delimiter = "." | delimiter = ":" ) { data.add(null); delimiters.add(delimiter.image); })* - token = RelObjectNameExt2() { data.add(token); } - ) * - - { return new ObjectNames(data, delimiters); } +PurgeStatement PurgeStatement(): { + PurgeStatement purgeStatement = null; + Table table; + Index index; + Token tableSpaceToken; + Token userToken = null; } - -// See: http://technet.microsoft.com/en-us/library/ms187879%28v=sql.105%29.aspx - -Column Column() #Column : { - ObjectNames data = null; - ArrayConstructor arrayConstructor = null; - Token tk = null; -} -{ - data = RelObjectNames() - [ LOOKAHEAD(2) tk= ] - // @todo: we better should return a SEQUENCE instead of a COLUMN - [ "." { data.getNames().add("nextval"); } ] + + ( + table=Table() { purgeStatement = new PurgeStatement(table); } + | + index=Index() { purgeStatement = new PurgeStatement(index); } + | + { purgeStatement = new PurgeStatement(PurgeObjectType.RECYCLEBIN); } + | + { purgeStatement = new PurgeStatement(PurgeObjectType.DBA_RECYCLEBIN); } + | + tableSpaceToken= [ userToken= ] { + purgeStatement = new PurgeStatement( + PurgeObjectType.TABLESPACE + , tableSpaceToken.image + , userToken!=null ? userToken.image : null); + } + ) - [ LOOKAHEAD(2) arrayConstructor = ArrayConstructor(false) ] { - Column col = new Column(data.getNames(), data.getDelimiters()); - if (tk != null) { col.withCommentText(tk.image); } - if (arrayConstructor!=null) { - col.setArrayConstructor(arrayConstructor); - } - linkAST(col,jjtThis); - return col; + return purgeStatement; } } -/* -The following tokens are allowed as Names for Schema, Table, Column and Aliases -*/ - -// Generated Code! Please do not edit manually. -// Instead: -// 1) define the ALL_RESERVED_KEYWORDS in the PARSER DECLARATION above (line 157 ff) -// 2) run the Gradle Task :JSQLParser:updateKeywords, which would update/replace the content of this method -String RelObjectNameWithoutValue() : -{ Token tk = null; } -{ - ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="COSTS" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DDL" | tk="DECLARE" | tk="DEFAULT" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="END" | tk="ESCAPE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FALSE" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GUARD" | tk="HASH" | tk="HISTORY" | tk="HOPPING" | tk="INCLUDE" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="ISNULL" | tk="JSON" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="LAST" | tk="LEADING" | tk="LINK" | tk="LOCAL" | tk="LOCKED" | tk="LOG" | tk="LOOP" | tk="MATCH" | tk="MATCHED" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="OVER" | tk="OVERLAPS" | tk="PARALLEL" | tk="PARENT" | tk="PARTITION" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PRECEDING" | tk="PRECISION" | tk="PRIMARY" | tk="PRIOR" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGISTER" | tk="REMOTE" | tk="RENAME" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="STORED" | tk="STRING" | tk="STRUCT" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TO" | tk="TRIGGER" | tk="TRUE" | tk="TRUNCATE" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VERBOSE" | tk="VIEW" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) - { return tk.image; } -} - -/* -These tokens can be used as names for Schema and Tables and Columns -BUT NOT for Aliases (without quoting) -*/ -String RelObjectName() : -{ Token tk = null; String result = null; } -{ - (result = RelObjectNameWithoutValue() - | tk= | tk= | tk= | tk= | tk= | tk= - | tk= | tk= | tk= | tk= | tk= - | tk= - ) - - { return tk!=null ? tk.image : result; } +DescribeStatement Describe(): { + Table table; + DescribeStatement stmt = new DescribeStatement(); + Token tk = null; +} { + (tk= | tk=) + table = Table() { stmt.setDescribeType(tk.image).setTable(table); } + { + return stmt; + } } -String RelObjectNameWithoutStart() : -{ Token tk = null; String result = null; } +ExplainStatement Explain(): { - (result = RelObjectNameWithoutValue() | tk= | tk= | tk= - | tk= ) - - { return tk!=null ? tk.image : result; } -} - -/* -Extended version of object names. - -These tokens can be used as names for Schema and Tables and Columns -BUT NOT for Aliases (without quoting) - -*/ -String RelObjectNameExt(): -{ Token tk = null; - String result=null; + Token tk; + Statement statement; + List> with = null; + Table table; + List options; + ExplainStatement es; } { - ( result=RelObjectName() | tk= | tk= | tk= | tk= | tk= | tk= - | tk= | tk= | tk= | tk= - | tk= | tk= | tk= - | tk= | tk= | tk= | tk= - | tk= - | tk= + ( tk= | tk = ) + ( + LOOKAHEAD(3)( + options= ExplainStatementOptions() + ( + [ LOOKAHEAD(2) with=WithList() ] + ( + statement = SelectWithWithItems( with ) + | statement = InsertWithWithItems( with ) + | statement = UpdateWithWithItems( with ) + | statement = DeleteWithWithItems( with ) + | statement = Merge( with ) + ) + ) + { + es = new ExplainStatement(tk.image, statement, options); + } ) - { return tk!=null ? tk.image : result; } -} - -/* -Extended usage of object names - part 2. Using within multipart names as following parts. - -These tokens can be used as names for Tables and Columns -BUT NOT for Schema or Aliases (without quoting) - -*/ -String RelObjectNameExt2(): -{ Token tk = null; - String result=null; -} -{ - ( result=RelObjectNameExt() | tk= | tk= | tk= ) - { return tk!=null ? tk.image : result; } -} - -Table Table() #TableName : -{ - //String serverName = null, databaseName = null, schemaName = null, tableName = null; - ObjectNames data = null; -} -{ - data = RelObjectNames() - + | + ( + table=Table( ) { es = new ExplainStatement(tk.image, table); } + ) + ) { - Table table = new Table(data.getNames()); - linkAST(table,jjtThis); - return table; + return es; } } -Table TableWithAlias(): +/** + * Postgres supports TRUE,ON,1,FALSE,OFF,0 as values + */ +String ExplainOptionBoolean(): { - Table table = null; - Alias alias = null; + Token tk = null; } { - table=Table() - [ LOOKAHEAD(2) alias=Alias() { table.setAlias(alias); }] - { return table; } + // intentionally not supporting 0,1 at the moment + [( tk= | tk= | tk= | tk= )] // optional + { + return tk != null ? tk.image : null; + } } -Table TableWithAliasAndMysqlIndexHint(): +/** + * The output format, which can be TEXT, XML, JSON, or YAML + */ +String ExplainFormatOption(): { - Table table = null; - Alias alias = null; - MySQLIndexHint indexHint = null; + Token tk = null; } { - table=Table() - [ LOOKAHEAD(2) alias=Alias() { table.setAlias(alias); } ] - [ LOOKAHEAD(2) indexHint=MySQLIndexHint() { table.setHint(indexHint); } ] - { return table; } + // TODO support Text + [( tk= | tk= | tk= )] // optional + { + return tk != null ? tk.image : null; + } } -Number Number(): +/** + * Options for explain, see https://www.postgresql.org/docs/9.1/sql-explain.html + */ +List ExplainStatementOptions(): { - Token token; - Number number; + List options = new ArrayList(); + ExplainStatement.Option option = null; + Token token = null; + String value = null; } { + ( + ( value=ExplainOptionBoolean() + { + option = new ExplainStatement.Option(ExplainStatement.OptionType.ANALYZE); + option.setValue(value); + options.add(option); + } + ) + | + ( value=ExplainOptionBoolean() + { + option = new ExplainStatement.Option(ExplainStatement.OptionType.BUFFERS); + option.setValue(value); + options.add(option); + } + ) + | + ( value=ExplainOptionBoolean() + { + option = new ExplainStatement.Option(ExplainStatement.OptionType.COSTS); + option.setValue(value); + options.add(option); + } + ) + | + ( value=ExplainOptionBoolean() + { + option = new ExplainStatement.Option(ExplainStatement.OptionType.VERBOSE); + option.setValue(value); + options.add(option); + } + ) + | + ( value=ExplainFormatOption() + { + option = new ExplainStatement.Option(ExplainStatement.OptionType.FORMAT); + option.setValue(value); + options.add(option); + } + ) + | ( - token = { number = Double.valueOf(token.image); } - | - token = { number = Long.valueOf(token.image); } + { option = new ExplainStatement.Option(ExplainStatement.OptionType.PLAN); } + [ { option = new ExplainStatement.Option(ExplainStatement.OptionType.PLAN_FOR); } ] + + value=ExplainFormatOption() + { + option.setValue(value); + options.add(option); + } ) + )* //zero or many times those productions + { + return options; + } +} +UseStatement Use(): { + String name; + boolean hasSchemaKeyword = false; +} +{ + [ LOOKAHEAD(2) { hasSchemaKeyword = true; } ] name = RelObjectName() { - return number; + return new UseStatement(name, hasSchemaKeyword); } } -SampleClause SampleClause(): +Statement Show(): { - Token token; - SampleClause sampleClause; - String keyword; - String method=null; - Number percentageArgument; - Number repeatArgument=null; - Number seedArgument=null; + Statement statement; + List captureRest; } { + ( - ( - // Oracle - token= { keyword = token.image; } - [ token= { method = token.image; } ] - ) + LOOKAHEAD(2) statement = ShowColumns() | - ( - // SQL:2016 compliant - token = { keyword = token.image; } - ( token = | token = ) { method = token.image; } - ) + LOOKAHEAD(2) statement = ShowIndex() + | + LOOKAHEAD(2) statement = ShowTables() + | + // any of the RDBMS specific SHOW syntax + captureRest = captureRest() + { + if (captureRest.size()==1) { + statement = new ShowStatement(captureRest.get(0)); + } else { + statement = new UnsupportedStatement("SHOW", captureRest); + } + } ) - - "(" percentageArgument = Number() ")" - - [ LOOKAHEAD(2) "(" repeatArgument = Number() ")" ] - - [ LOOKAHEAD(2) "(" seedArgument = Number() ")" ] - { - return new SampleClause(keyword, method, percentageArgument, repeatArgument, seedArgument); + return statement; } } -Select SelectWithWithItems( List withItems): -{ - Select select; +ShowColumnsStatement ShowColumns(): { + String tableName; } { - select = Select() { select.setWithItemsList( withItems ); - return select; -} + tableName = RelObjectName() + { + return new ShowColumnsStatement(tableName); + } } -Select Select() #Select: +ShowIndexStatement ShowIndex(): { + String tableName; +} { - Select select = null; - List with = null; - List orderByElements = null; - Limit limit = null; - Offset offset = null; - Fetch fetch = null; - WithIsolation withIsolation = null; + tableName = RelObjectName() + { + return new ShowIndexStatement(tableName); + } +} + +Statement RefreshMaterializedView(): { + Table view = null; + boolean concurrently = false; + RefreshMode refreshMode = null; + List captureRest; } { - [ with=WithList() ] - ( - LOOKAHEAD(3) select = PlainSelect() - | - LOOKAHEAD(3) select = Values() + + [ LOOKAHEAD(2) { concurrently = true; } ] + view = Table() + [ + { refreshMode = RefreshMode.WITH_DATA; } + [ + { refreshMode = RefreshMode.WITH_NO_DATA; } + ] + + ] + captureRest = captureRest() + { + if (concurrently && refreshMode == RefreshMode.WITH_NO_DATA) { + return new UnsupportedStatement("REFRESH", captureRest); + } else { + return new RefreshMaterializedViewStatement(view, concurrently, refreshMode); + } + } +} +// https://dev.mysql.com/doc/refman/8.0/en/show-tables.html +ShowTablesStatement ShowTables(): { + ShowTablesStatement showTablesStatement; + EnumSet modifiers = EnumSet.noneOf(ShowTablesStatement.Modifiers.class); + ShowTablesStatement.SelectionMode selectionMode = null; + String dbName = null; + Expression likeExpression = null; + Expression whereCondition = null; +} +{ + [ { modifiers.add(ShowTablesStatement.Modifiers.EXTENDED); } ] + [ { modifiers.add(ShowTablesStatement.Modifiers.FULL); } ] + + [ + LOOKAHEAD(2) ( + { selectionMode = ShowTablesStatement.SelectionMode.FROM; } | - LOOKAHEAD(3) select = ParenthesedSelect() + { selectionMode = ShowTablesStatement.SelectionMode.IN; } ) - [ LOOKAHEAD(2) select = SetOperationList(select) ] - - [ LOOKAHEAD( ) orderByElements = OrderByElements() { select.setOrderByElements(orderByElements); } ] + dbName = RelObjectName() + ] + [ ( likeExpression = SimpleExpression() | whereCondition = Expression()) ] + { + showTablesStatement = new ShowTablesStatement(); + showTablesStatement.setModifiers(modifiers); + showTablesStatement.setSelectionMode(selectionMode); + showTablesStatement.setDbName(dbName); + showTablesStatement.setLikeExpression(likeExpression); + showTablesStatement.setWhereCondition(whereCondition); + return showTablesStatement; + } +} - [ LOOKAHEAD() limit=LimitWithOffset() {select.setLimit(limit);} ] - [ LOOKAHEAD() offset = Offset() { select.setOffset(offset);} ] - [ LOOKAHEAD() fetch = Fetch() { select.setFetch(fetch);} ] - [ LOOKAHEAD( ) withIsolation = WithIsolation() { select.setIsolation(withIsolation);} ] +Values Values(): { + ExpressionList expressions; +} { + ( | ) + expressions = ExpressionList() { - linkAST(select, jjtThis); - return select.withWithItemsList(with); + return new Values(expressions); } } -TableStatement TableStatement(): -{ - Table table = null; - List orderByElements = null; - Limit limit = null; - Offset offset = null; - TableStatement tableStatement = new TableStatement(); -}{ - - table = Table() - { tableStatement.setTable(table); } - [ LOOKAHEAD( ) orderByElements = OrderByElements() { tableStatement.setOrderByElements(orderByElements); } ] - [ LOOKAHEAD() limit=LimitWithOffset() { tableStatement.setLimit(limit);} ] - [ LOOKAHEAD() offset = Offset() { tableStatement.setOffset(offset);} ] - { return tableStatement; } - /* Support operationList */ -} - -ParenthesedSelect ParenthesedSelect() #ParenthesedSelect: +ReturningClause ReturningClause(): { - ParenthesedSelect parenthesedSelect = new ParenthesedSelect(); - Select select; + Token keyword; + List outputAliases = null; + List> selectItems; + Object dataItem; + List dataItems = null; } { - "(" - select = Select() - ")" + ( keyword= | keyword= ) + [ LOOKAHEAD(2) outputAliases = ReturningOutputAliasList() ] + selectItems = SelectItemsList() + + [ + + ( dataItem = Table() | dataItem = UserVariable() ) + { dataItems = new ArrayList(); dataItems.add(dataItem); } + + ( + "," + ( dataItem = Table() | dataItem = UserVariable() ) { dataItems.add(dataItem); } + )* + ] + { - linkAST(parenthesedSelect,jjtThis); - return parenthesedSelect.withSelect(select); + return new ReturningClause(keyword.image, selectItems, outputAliases, dataItems); } } -LateralView LateralView() #LateralView: +ReturningReferenceType ReturningReferenceKind(): { - boolean useOuter = false; - Function generatorFunction = null; - String tableName = null; - String columnName = null; - Alias tableAlias = null; - Alias columnAlias = null; + String refName; + ReturningReferenceType refType; } { - [ { useOuter=true; } ] - generatorFunction = Function() - [ LOOKAHEAD(2) - tableName=RelObjectNameWithoutStart() - { - tableAlias = new Alias(tableName, false); - } - ] - columnName = RelObjectNameWithoutStart() + refName = RelObjectName() { - columnAlias = new Alias(columnName, true); - return new LateralView( - useOuter - , generatorFunction - , tableAlias - , columnAlias - ); + refType = ReturningReferenceType.from(refName); + if (refType == ReturningReferenceType.OLD) { + return ReturningReferenceType.OLD; + } else if (refType == ReturningReferenceType.NEW) { + return ReturningReferenceType.NEW; + } + throw new ParseException("Expected OLD or NEW but found: " + refName); } } -ForClause ForClause() #ForClause: +ReturningOutputAlias ReturningOutputAliasDefinition(): { - Token token = null; - ForClause forClause = new ForClause(); + ReturningReferenceType refType; + String aliasName; } { - - ( - token = - | - token = - ( - ( - ( [ LOOKAHEAD(2) "(" ")" ] | ) - ( - LOOKAHEAD(2) "," - ( - - | - | [ LOOKAHEAD(2) "(" ")" ] - | - | [ LOOKAHEAD(2) "(" ")" ] - | [ LOOKAHEAD(2) ( | ) ] - ) - )* - ) - | - ( - - ( - LOOKAHEAD(2) "," - ( - - | - | [ LOOKAHEAD(2) "(" ")" ] - | - ) - )* - ) - | - ( - [ LOOKAHEAD(2) "(" ")" ] - ( - LOOKAHEAD(2) "," - ( - - | - | [ LOOKAHEAD(2) "(" ")" ] - | [ LOOKAHEAD(2) ( | ) ] - ) - )* - ) - ) - | - ( - token = ( | ) - ( - LOOKAHEAD(2) "," - ( - [ LOOKAHEAD(2) "(" ")" ] - | - | - ) - )* - ) - ) + refType = ReturningReferenceKind() + + aliasName = RelObjectName() { - forClause.setForOption(token.image); - linkAST(forClause,jjtThis); - return forClause; + return new ReturningOutputAlias(refType, aliasName); } } - -List LateralViews(): +List ReturningOutputAliasList(): { - ArrayList lateralViews = new ArrayList(); - LateralView lateralView = null; + List outputAliases = new ArrayList(); + ReturningOutputAlias outputAlias; } { - lateralView = LateralView() { lateralViews.add(lateralView); } - ( lateralView = LateralView() { lateralViews.add(lateralView); } )* - + "(" + outputAlias = ReturningOutputAliasDefinition() { outputAliases.add(outputAlias); } + ( + "," + outputAlias = ReturningOutputAliasDefinition() { outputAliases.add(outputAlias); } + )* + ")" { - return lateralViews; + return outputAliases; } } -LateralSubSelect LateralSubSelect() #LateralSubSelect: +Update UpdateWithWithItems( List> withItems ): { - LateralSubSelect lateralSubSelect = new LateralSubSelect();; - Select select; + Update update; } { - "(" select = Select() ")" { lateralSubSelect.withSelect(select).setPrefix("LATERAL"); } - { - linkAST(lateralSubSelect,jjtThis); - return lateralSubSelect; - } + update = Update() { update.setWithItemsList( withItems ); + return update; +} } -PlainSelect PlainSelect() #PlainSelect: +Update Update(): { - PlainSelect plainSelect = new PlainSelect(); - List> selectItems = null; + Update update = new Update(); + Table table = null; + List startJoins = null; + List> with = null; + List updateSets; + Expression where = null; + PreferringClause preferringClause = null; FromItem fromItem = null; - List lateralViews = null; List joins = null; - List> distinctOn = null; - Expression where = null; - ForClause forClause = null; - List orderByElements; - GroupByElement groupBy = null; - Expression having = null; - Expression qualify; - Limit limitBy = null; Limit limit = null; - Offset offset = null; - Fetch fetch = null; - WithIsolation withIsolation = null; - OptimizeFor optimize = null; - Top top = null; - Skip skip = null; - First first = null; - OracleHierarchicalExpression oracleHierarchicalQueryClause = null; - List
intoTables = null; - Table updateTable = null; - Wait wait = null; - boolean mySqlSqlCalcFoundRows = false; - Token token; - KSQLWindow ksqlWindow = null; - boolean noWait = false; - String windowName = null; - WindowDefinition winDef; - Table intoTempTable = null; + List orderByElements; + boolean useColumnsBrackets = false; + ReturningClause returningClause; + Token tk = null; + UpdateModifierPriority modifierPriority = null; + boolean modifierIgnore = false; + + OutputClause outputClause = null; } { - - - [ { plainSelect.setMySqlHintStraightJoin(true); } ] - - { plainSelect.setOracleHint(getOracleHint()); } - - [ LOOKAHEAD(2) skip = Skip() { plainSelect.setSkip(skip); } ] - - [ LOOKAHEAD(2) first = First() { plainSelect.setFirst(first); } ] - - // Redshift allows TOP before DISTINCT - // https://docs.aws.amazon.com/redshift/latest/dg/r_SELECT_list.html - // @Todo: reflect the order when de-parsing - [ LOOKAHEAD(2) top = Top() { plainSelect.setTop(top); } ] - - [ LOOKAHEAD(2) - ( - - | - ( - { Distinct distinct = new Distinct(); plainSelect.setDistinct(distinct); } - [ LOOKAHEAD(2) "ON" "(" distinctOn=SelectItemsList() { plainSelect.getDistinct().setOnSelectItems(distinctOn); } ")" ] - ) - | - { Distinct distinct = new Distinct(true); plainSelect.setDistinct(distinct); } - | - { plainSelect.setMySqlSqlCalcFoundRows(true); } - | - { plainSelect.setMySqlSqlCacheFlag(MySqlSqlCacheFlags.SQL_NO_CACHE); } - | - { plainSelect.setMySqlSqlCacheFlag(MySqlSqlCacheFlags.SQL_CACHE); } - ) - ] + { update.setOracleHint(getOracleHint()); } + [ LOOKAHEAD(2) { modifierPriority = UpdateModifierPriority.LOW_PRIORITY; }] + [ LOOKAHEAD(2) { modifierIgnore = true; }] + table=TableWithAliasAndMysqlIndexHint() [ startJoins=JoinsList() ] + updateSets = UpdateSets() { update.setUpdateSets(updateSets); } - [ LOOKAHEAD(2) top = Top() { plainSelect.setTop(top); } ] + [ outputClause = OutputClause() {update.setOutputClause(outputClause); } ] - selectItems=SelectItemsList() + [ LOOKAHEAD(2) + fromItem=FromItem() + [ LOOKAHEAD(2) joins=JoinsList() ] ] - [ LOOKAHEAD(2) intoTables = IntoClause() { plainSelect.setIntoTables(intoTables); } ] - [ LOOKAHEAD(2) fromItem=FromItem() - [ lateralViews=LateralViews() ] - [ LOOKAHEAD(2) joins=JoinsList() ] - ] - [ LOOKAHEAD(3) { plainSelect.setUsingOnly(true); } fromItem=FromItem() - [ lateralViews=LateralViews() ] - [ LOOKAHEAD(2) joins=JoinsList() ] - ] + [ where=WhereClause() { update.setWhere(where); } ] + [ preferringClause=PreferringClause() { update.setPreferringClause(preferringClause); } ] - // Clickhouse FINAL as shown at https://clickhouse.com/docs/en/operations/settings/settings#final - [ LOOKAHEAD(2) { plainSelect.setUsingFinal(true); } ] + [ orderByElements = OrderByElements() { update.setOrderByElements(orderByElements); } ] + [ limit = PlainLimit() { update.setLimit(limit); } ] + [ returningClause = ReturningClause() { update.setReturningClause(returningClause); } ] - [ LOOKAHEAD(2) ksqlWindow=KSQLWindowClause() { plainSelect.setKsqlWindow(ksqlWindow); } ] - [ LOOKAHEAD(2) where=WhereClause() { plainSelect.setWhere(where); }] - [ LOOKAHEAD(2) oracleHierarchicalQueryClause=OracleHierarchicalQueryClause() { plainSelect.setOracleHierarchical(oracleHierarchicalQueryClause); } ] - // Oracle supports "HAVING" before "GROUP BY", we will simply parse that but won't pay special attention to the order - [ LOOKAHEAD(2) having=Having() { plainSelect.setHaving(having); }] - [ LOOKAHEAD(2) groupBy=GroupByColumnReferences() { plainSelect.setGroupByElement(groupBy); }] - [ LOOKAHEAD(2) having=Having() { plainSelect.setHaving(having); }] - [ LOOKAHEAD(2) qualify=Qualify() {plainSelect.setQualify(qualify); }] - [ LOOKAHEAD(2) forClause = ForClause() {plainSelect.setForClause(forClause);} ] - [ LOOKAHEAD( ) orderByElements = OrderByElements() { plainSelect.setOracleSiblings(true); plainSelect.setOrderByElements(orderByElements); } ] - [ LOOKAHEAD(2) - windowName = RelObjectName() winDef = windowDefinition() { List winDefs = new ArrayList(); winDefs.add(winDef.withWindowName(windowName)); } - ( LOOKAHEAD(2) "," windowName = RelObjectName() winDef = windowDefinition() { winDefs.add(winDef.withWindowName(windowName)); } )* - { plainSelect.setWindowDefinitions(winDefs); } - ] - [ LOOKAHEAD( ) orderByElements = OrderByElements() { plainSelect.setOrderByElements(orderByElements); } ] - [ LOOKAHEAD(2) { plainSelect.setEmitChanges(true); } ] - [ LOOKAHEAD(LimitBy()) limit = LimitBy() { plainSelect.setLimitBy(limit); } ] - [ LOOKAHEAD() limit = LimitWithOffset() { plainSelect.setLimit(limit); } ] - [ LOOKAHEAD() offset = Offset() { plainSelect.setOffset(offset); } ] - [ LOOKAHEAD(, { limit==null }) limit = LimitWithOffset() { plainSelect.setLimit(limit); } ] - [ LOOKAHEAD() fetch = Fetch() { plainSelect.setFetch(fetch); } ] - [ LOOKAHEAD( ) withIsolation = WithIsolation() { plainSelect.setIsolation(withIsolation); } ] - [ LOOKAHEAD(2) - - ( - { plainSelect.setForMode(ForMode.UPDATE); } - | { plainSelect.setForMode(ForMode.SHARE); } - | ( { plainSelect.setForMode(ForMode.NO_KEY_UPDATE); }) - | ( { plainSelect.setForMode(ForMode.KEY_SHARE); }) - ) - [ LOOKAHEAD(2) updateTable = Table() { plainSelect.setForUpdateTable(updateTable); } ] - [ LOOKAHEAD() wait = Wait() { plainSelect.setWait(wait); } ] - [ LOOKAHEAD(2) ( { plainSelect.setNoWait(true); } - | { plainSelect.setSkipLocked(true); }) ] - ] - [ LOOKAHEAD() optimize = OptimizeFor() { plainSelect.setOptimizeFor(optimize); } ] - [ LOOKAHEAD(3) intoTempTable = Table() { plainSelect.setIntoTempTable(intoTempTable);} ] - [ LOOKAHEAD(3) { plainSelect.setUseWithNoLog(true); } ] { - plainSelect.setSelectItems(selectItems); - plainSelect.setFromItem(fromItem); - if ( lateralViews!=null && lateralViews.size()>0 ) { - plainSelect.setLateralViews( lateralViews ); - } - if ( joins!=null && joins.size()>0 ) { - plainSelect.setJoins( joins ); - } - linkAST(plainSelect,jjtThis); - return plainSelect; + return update.withWithItemsList(with) + .withTable(table) + .withStartJoins(startJoins) + .withFromItem(fromItem) + .withJoins(joins) + .withModifierPriority(modifierPriority) + .withModifierIgnore(modifierIgnore); } } -Select SetOperationList(Select select) #SetOperationList: { - SetOperationList list = new SetOperationList(); - List orderByElements = null; - Limit limit = null; - Offset offset = null; - Fetch fetch = null; - WithIsolation withIsolation = null; - List(); - List operations = new ArrayList(); -} +List UpdateSets(): { + ArrayList updateSets = new ArrayList(); + UpdateSet updateSet; + Column tableColumn; + Expression valueExpression; - { - selects.add(select); - } - - ( LOOKAHEAD(2) ( + ExpressionList columns; + ExpressionListvalues; +} +{ + ( + ( + tableColumn=Column() "=" valueExpression=Expression() + { updateSets.add( new UpdateSet (tableColumn, valueExpression)); } + ) + | + ( + { updateSet = new UpdateSet(); updateSets.add(updateSet); } + columns = ParenthesedExpressionList() { updateSet.setColumns(columns); } + "=" ( - { UnionOp union = new UnionOp(); linkAST(union,jjtThis); operations.add(union); } - [ { union.setAll(true); } | { union.setDistinct(true); } ] + LOOKAHEAD(3) valueExpression = ParenthesedSelect() { updateSet.setValues( new ExpressionList(valueExpression)); } + | + values = ParenthesedExpressionList() { updateSet.setValues(values); } ) - | - { operations.add(new IntersectOp()); } - | - { operations.add(new MinusOp()); } - | - { operations.add(new ExceptOp()); } ) + ) - ( - select = PlainSelect() - | - select = Values() + ( + LOOKAHEAD(2) ( + "," + tableColumn=Column() "=" valueExpression=Expression() + { updateSets.add( new UpdateSet (tableColumn, valueExpression)); } | - select = ParenthesedSelect() + ( + { updateSet = new UpdateSet(); updateSets.add(updateSet); } + columns = ParenthesedExpressionList() { updateSet.setColumns(columns); } + "=" + ( + LOOKAHEAD(3) valueExpression = ParenthesedSelect() { updateSet.setValues( new ExpressionList(valueExpression)); } + | + values = ParenthesedExpressionList() { updateSet.setValues(values); } + ) + ) ) - { - selects.add(select); - } - )+ - - [ LOOKAHEAD(2) orderByElements=OrderByElements() {list.setOrderByElements(orderByElements);} ] - [ LOOKAHEAD() limit = LimitWithOffset() { list.setLimit(limit); } ] - [ LOOKAHEAD() offset = Offset() { list.setOffset(offset); } ] - [ LOOKAHEAD(, { limit==null }) limit = LimitWithOffset() { list.setLimit(limit); } ] - [ LOOKAHEAD() fetch = Fetch() { list.setFetch(fetch); } ] - [ LOOKAHEAD( ) withIsolation = WithIsolation() { list.setIsolation(withIsolation); } ] + )* { - if ( selects.get(selects.size()-1) instanceof PlainSelect ) { - PlainSelect ps = (PlainSelect)selects.get(selects.size()-1); - if (ps.getOrderByElements() != null) { - list.setOrderByElements(ps.getOrderByElements()); - list.setLimit(ps.getLimit()); - list.setOffset(ps.getOffset()); - ps.setOrderByElements(null); - ps.setLimit(null); - ps.setOffset(null); - } - if (ps.getFetch() != null) { - list.setFetch(ps.getFetch()); - ps.setFetch(null); - } - if (ps.getIsolation() != null) { - list.setIsolation(ps.getIsolation()); - ps.setIsolation(null); - } - } - list.setBracketsOpsAndSelects(selects,operations); - return list; + return updateSets; } } -List WithList(): +List Partitions(): { - List withItemsList = new ArrayList(); - WithItem with = null; + List partitions = new ArrayList(); + Column tableColumn; + Expression valueExpression = null; } { - with=WithItem() { withItemsList.add(with); } ("," with=WithItem() { withItemsList.add(with); } )* + ( + ( + tableColumn=Column() [ "=" valueExpression=Expression() ] + { partitions.add( new Partition (tableColumn, valueExpression)); } + ) + ) - { return withItemsList; } + ( + LOOKAHEAD(2) ( + "," + tableColumn=Column() [ "=" valueExpression=Expression() ] + { partitions.add( new Partition (tableColumn, valueExpression)); } + ) + )* + + { + return partitions; + } } -WithItem WithItem() #WithItem: +Insert InsertWithWithItems( List> withItems ): { - WithItem withItem = new WithItem(); - String name; - List> selectItems; - Select select; + Insert insert; } { - [ LOOKAHEAD(2) { withItem.setRecursive(true); } ] - name=RelObjectName() { withItem.setAlias( new Alias( name, false)); } - [ "(" selectItems=SelectItemsList() ")" { withItem.setWithItemList(selectItems); } ] - select = ParenthesedSelect() { withItem.setSelect(select); } - { - return withItem; - } + insert = Insert() { insert.setWithItemsList( withItems ); + return insert; } - -List> SelectItemsList(): -{ - List> selectItemsList = null; - SelectItem selectItem = null; } + +Insert Insert(): { - selectItem=SelectItem() { selectItemsList = new ArrayList>(); selectItemsList.add(selectItem); } - ( - LOOKAHEAD(2) "," selectItem=SelectItem() - { - selectItemsList.add(selectItem); - } - )* + Insert insert = new Insert(); + Table table = null; + List> with = null; + Column tableColumn = null; + ExpressionList columns = new ExpressionList(); + List partitions = new ArrayList(); + Expression exp = null; + ReturningClause returningClause; + Select select = null; + Token tk = null; + InsertModifierPriority modifierPriority = null; + boolean modifierIgnore = false; - { return selectItemsList; } -} + List updateSets; + List duplicateUpdateSets; + + String name = null; + boolean useAs = false; + boolean useSet = false; + Alias rowAlias = null; + OutputClause outputClause = null; + InsertConflictTarget conflictTarget = null; + InsertConflictAction conflictAction = null; -SelectItem SelectItem() #SelectItem: + InsertDuplicateAction duplicateAction = null; + Token multiInsertToken = null; + List oracleMultiInsertBranches = new ArrayList(); + OracleMultiInsertClause oracleMultiInsertClause = null; + OracleMultiInsertBranch oracleMultiInsertBranch = null; +} { - Expression expression; - Alias alias = null; -} -{ - // @fixme: Oracle's SEQUENCE.nextval is parsed as COLUMN with a name part nextval - // @todo: parse a proper SEQUENCE instead of a COLUMN + { insert.setOracleHint(getOracleHint()); } + + [ + LOOKAHEAD(2) (tk = | tk = | tk = ) + { + if (tk!=null) + modifierPriority = InsertModifierPriority.from(tk.image); + } + ] + [ LOOKAHEAD(2) { modifierIgnore = true; }] ( - expression = AllColumns() - | - LOOKAHEAD(AllTableColumns()) expression = AllTableColumns() - | - LOOKAHEAD( 3 ) expression = XorExpression() - | - LOOKAHEAD( 3 ) expression = ConcatExpression() + LOOKAHEAD(2, ( | ) ( | )) + ( + (multiInsertToken = | multiInsertToken = ) { + insert.setOracleMultiInsert(true); + insert.setOracleMultiInsertFirst(multiInsertToken.kind == K_FIRST); + } + ( + { + oracleMultiInsertBranch = new OracleMultiInsertBranch(); + } + oracleMultiInsertClause = OracleMultiInsertClause() { + oracleMultiInsertBranch.addClause(oracleMultiInsertClause); + table = oracleMultiInsertClause.getTable(); + } + ( + oracleMultiInsertClause = OracleMultiInsertClause() { + oracleMultiInsertBranch.addClause(oracleMultiInsertClause); + } + )* + { + oracleMultiInsertBranches.add(oracleMultiInsertBranch); + } + | + ( + ( + oracleMultiInsertBranch = OracleMultiInsertWhenBranch() { + if (table == null && !oracleMultiInsertBranch.getClauses().isEmpty()) { + table = oracleMultiInsertBranch.getClauses().get(0).getTable(); + } + oracleMultiInsertBranches.add(oracleMultiInsertBranch); + } + )+ + [ + oracleMultiInsertBranch = OracleMultiInsertElseBranch() { + if (table == null && !oracleMultiInsertBranch.getClauses().isEmpty()) { + table = oracleMultiInsertBranch.getClauses().get(0).getTable(); + } + oracleMultiInsertBranches.add(oracleMultiInsertBranch); + } + ] + ) + ) + select = Select() { + insert.setOracleMultiInsertBranches(oracleMultiInsertBranches); + } + ) | - expression=Expression() + ( + [ LOOKAHEAD(2) ( + { insert.setOverwrite(true); insert.setTableKeyword(true); } + | [ LOOKAHEAD(2) { insert.setTableKeyword(true); }] + ) + ] table=Table() + [ LOOKAHEAD(2) "(" partitions=Partitions() ")" ] + + [ LOOKAHEAD({ isAliasAhead() }) [ { useAs = true; } ] name=RelObjectName() { table.setAlias(new Alias(name,useAs)); }] + + [ LOOKAHEAD(2) "(" columns=ColumnList() ")" ] + + [ LOOKAHEAD(2) { insert.setOverriding(true); } ] + + [ outputClause = OutputClause() { insert.setOutputClause(outputClause); } ] + + ( + { insert.setOnlyDefaultValues(true); } + | + ( + updateSets = UpdateSets() { insert.withSetUpdateSets(updateSets); useSet = true; } + ) + | + select = Select() + ) + + [ LOOKAHEAD({ isAliasAhead() && (select instanceof Values || useSet) }) rowAlias = Alias() { + if (select instanceof Values) { + select.setAlias(rowAlias); + } else { + insert.setRowAlias(rowAlias); + } + } ] + + [ LOOKAHEAD(2) + duplicateAction = InsertDuplicateAction() { insert.setDuplicateAction(duplicateAction); } + ] + + [ + + [ conflictTarget = InsertConflictTarget() ] + conflictAction = InsertConflictAction() { insert.withConflictTarget(conflictTarget).setConflictAction(conflictAction); } + ] + + [ returningClause = ReturningClause() { insert.setReturningClause(returningClause); } ] + ) ) - [ LOOKAHEAD(2) alias=Alias() ] + { - SelectItem selectItem = new SelectItem(expression, alias); - linkAST(selectItem,jjtThis); - return selectItem; + if (!columns.isEmpty()) { + insert.setColumns(columns); + } + if (!partitions.isEmpty()) { + insert.setPartitions(partitions); + } + return insert.withWithItemsList(with) + .withSelect(select) + .withTable(table) + .withModifierPriority(modifierPriority) + .withModifierIgnore(modifierIgnore); } } -AllColumns AllColumns(): +OracleMultiInsertClause OracleMultiInsertClause(): { - ParenthesedExpressionList exceptColumns = null; - List> replaceExpressions = null; + OracleMultiInsertClause clause = new OracleMultiInsertClause(); + Table clauseTable = null; + ExpressionList clauseColumns = new ExpressionList(); + Select clauseSelect = null; } { - "*" - [ LOOKAHEAD(2) exceptColumns = ParenthesedColumnList() ] - [ LOOKAHEAD(2) "(" replaceExpressions = SelectItemsList() ")" ] - + clauseTable=Table() + [ LOOKAHEAD(2) "(" clauseColumns=ColumnList() ")" ] + clauseSelect = Select() { - return new AllColumns(exceptColumns, replaceExpressions); + if (!clauseColumns.isEmpty()) { + clause.setColumns(clauseColumns); + } + return clause.withTable(clauseTable).withSelect(clauseSelect); } } -AllTableColumns AllTableColumns(): +OracleMultiInsertBranch OracleMultiInsertWhenBranch(): { - Table table = null; - AllColumns allColumns; + Expression whenExpression = null; + List clauses = null; } { - table=Table() "." allColumns=AllColumns() + whenExpression = Expression() + clauses = OracleMultiInsertClauseList() { - return new AllTableColumns(table, allColumns); + return new OracleMultiInsertBranch() + .withWhenExpression(whenExpression) + .withClauses(clauses); } +} +OracleMultiInsertBranch OracleMultiInsertElseBranch(): +{ + List clauses = null; +} +{ + + clauses = OracleMultiInsertClauseList() + { + return new OracleMultiInsertBranch() + .withElseClause(true) + .withClauses(clauses); + } } -Alias Alias(): -{ String name = ""; - Token token = null; - boolean useAs = false; - Alias alias; - String colname; - ColDataType colDataType = null; +List OracleMultiInsertClauseList(): +{ + List clauses = new ArrayList(); + OracleMultiInsertClause clause = null; } { + clause = OracleMultiInsertClause() { + clauses.add(clause); + } ( - LOOKAHEAD(3) ( - // Aliases with Columns: - // SELECT fun(x) AS (a,b,c) - // SELECT fun(x) AS T(a,b,c) - - [ LOOKAHEAD(2) name=RelObjectNameWithoutStart() ] - { alias = new Alias(name, true ); } + clause = OracleMultiInsertClause() { + clauses.add(clause); + } + )* + { + return clauses; + } +} - "(" { List list = new ArrayList(); } - colname = RelObjectName() [ colDataType = ColDataType() ] { list.add(new Alias.AliasColumn(colname, colDataType)); } - ( - "," { colDataType=null; } colname = RelObjectName() [ colDataType = ColDataType()] { list.add(new Alias.AliasColumn(colname, colDataType)); } - )* - ")" { alias.setAliasColumns(list); } +InsertConflictTarget InsertConflictTarget(): +{ + String indexColumnName; + ArrayList indexColumnNames = new ArrayList(); + Expression indexExpression = null; + Expression whereExpression = null; + String constraintName = null ; +} +{ + ( + ( + "(" + indexColumnName = RelObjectNameExt() { indexColumnNames.add(indexColumnName); } + ( "," indexColumnName = RelObjectNameExt() { indexColumnNames.add(indexColumnName); } )* +// | +// ( +// "(" indexExpression = Expression() ")" +// ) + ")" + [ whereExpression = WhereClause() ] ) | ( - // Aliases without Columns: - // SELECT fun(x) AS T - // SELECT fun(x) T - - [ { useAs = true; } ] - ( name=RelObjectNameWithoutStart() | token= { name=token.image; } ) - { alias = new Alias(name,useAs); } - - /* Should not be allowed/needed - We can bring this back only if people complain - - [ LOOKAHEAD(2) "(" { List list = new ArrayList(); } - colname = RelObjectName() [ colDataType = ColDataType() ] { list.add(new Alias.AliasColumn(colname, colDataType)); } - ("," { colDataType=null; } colname = RelObjectName() [ colDataType = ColDataType()] { list.add(new Alias.AliasColumn(colname, colDataType)); } )* - ")" { alias.setAliasColumns(list); } ] - - */ + constraintName = RelObjectNameExt() ) ) - { return alias; } + + { return new InsertConflictTarget(indexColumnNames, indexExpression, whereExpression, constraintName); } } -void SQLServerHint(SQLServerHints hints) : { - String str; +InsertConflictAction InsertConflictAction(): +{ + InsertConflictAction conflictAction; + Expression whereExpression = null; + List updateSets; } { - "(" str = RelObjectName() ")" { hints.setIndexName(str); } + ( + LOOKAHEAD(2) ( + { conflictAction = new InsertConflictAction( ConflictActionType.DO_NOTHING ); } + ) | - { hints.withNoLock(); } -} + ( + { conflictAction = new InsertConflictAction( ConflictActionType.DO_UPDATE ); } + updateSets = UpdateSets() { conflictAction.setUpdateSets(updateSets); } + [ whereExpression = WhereClause() ] + ) + ) -SQLServerHints SQLServerHints() : { - SQLServerHints hints = new SQLServerHints(); -} -{ - "(" - SQLServerHint(hints) ("," SQLServerHint(hints) )* - ")" - { return hints; } + { return conflictAction + .withWhereExpression(whereExpression); } } -MySQLIndexHint MySQLIndexHint(): +InsertDuplicateAction InsertDuplicateAction(): { - Token actionToken = null; - Token indexToken = null; - String indexName = null; - List indexNameList = new ArrayList(); + InsertDuplicateAction duplicateAction; + Expression whereExpression = null; + List updateSets; } { - ( - actionToken = - | actionToken = - | actionToken = - | actionToken = - ) - - ( - indexToken = - | indexToken = - ) + ( + LOOKAHEAD(2) ( + { duplicateAction = new InsertDuplicateAction( ConflictActionType.NOTHING ); } + ) + | + ( + { duplicateAction = new InsertDuplicateAction( ConflictActionType.DO_UPDATE ); } + updateSets = UpdateSets() { duplicateAction.setUpdateSets(updateSets); } + [ whereExpression = WhereClause() ] + ) + ) - "(" - indexName = RelObjectNameWithoutValue() { indexNameList.add(indexName); } - ("," indexName= RelObjectNameWithoutValue() { indexNameList.add(indexName); })* - ")" - { - return new MySQLIndexHint(actionToken.image, indexToken.image, indexNameList); - } + { return duplicateAction + .withWhereExpression(whereExpression); } } -SelectItem FunctionItem(): + +OutputClause OutputClause(): { - Alias alias = null; - Function function; + List> selectItemList = null; + UserVariable tableVariable = null; + Table outputTable = null; + List columnList = null; } { - function=Function() - [ alias=Alias() ] - { return new SelectItem(function, alias); } + + selectItemList = SelectItemsList() + [ + ( + tableVariable = UserVariable() + | + outputTable = Table() + ) + [ + LOOKAHEAD(2) columnList = ColumnsNamesList() + ] + ] + + { + return new OutputClause(selectItemList, tableVariable, outputTable, columnList); + } } -ExpressionList PivotForColumns(): +Upsert Upsert(): { + Upsert upsert = new Upsert(); + Table table = null; ExpressionList columns; - Column column; + List updateSets; + + Select select = null; + List duplicateUpdateSets; + InsertDuplicateAction duplicateAction = null; + Token tk = null; } { ( - columns = ParenthesedColumnList() + { upsert.setUpsertType(UpsertType.UPSERT); } | - column = Column() { columns = new ExpressionList(column); } - ) - { return columns; } + { upsert.setUpsertType(UpsertType.REPLACE); } + | + ( + { upsert.setUpsertType(UpsertType.INSERT_OR_REPLACE); } + ) + ) + [ LOOKAHEAD(2) { upsert.setUsingInto(true); } ] + + table=Table() { upsert.setTable(table); } + + [ LOOKAHEAD(2) columns = ParenthesedColumnList() { upsert.setColumns(columns); } ] + ( + ( + + updateSets = UpdateSets() { upsert.setUpdateSets(updateSets); } + ) + | + ( + select = Select() { upsert.setSelect(select); } + ) + ) + + [ + + duplicateAction = InsertDuplicateAction() { upsert.setDuplicateAction(duplicateAction); } + ] + + { + return upsert; + } } -List> PivotFunctionItems(): +Delete DeleteWithWithItems( List> withItems ): { - List> functionItems = new ArrayList>(); - SelectItem item; + Delete delete; } { - item = FunctionItem() {functionItems.add(item);} - ( "," item = FunctionItem() {functionItems.add(item);} )* - { return functionItems; } + delete = Delete() { delete.setWithItemsList( withItems ); + return delete; +} } -SelectItem ExpressionListItem(): +Delete Delete(): { - ExpressionList expressionList; - Alias alias = null; + Delete delete = new Delete(); + Table table = null; + List
tables = new ArrayList
(); + List> with = null; + FromItem usingFromItem = null; + List usingFromItemList = new ArrayList(); + List joins = null; + Expression where = null; + PreferringClause preferringClause = null; + Limit limit = null; + List orderByElements; + boolean hasFrom = false; + Token tk = null; + DeleteModifierPriority modifierPriority = null; + boolean modifierIgnore = false; + boolean modifierQuick = false; + + ReturningClause returningClause; + OutputClause outputClause; } { - expressionList=ParenthesedExpressionList() - [ alias=Alias() ] - { return new SelectItem(expressionList, alias); } + { delete.setOracleHint(getOracleHint()); } + [ LOOKAHEAD(2) { modifierPriority = DeleteModifierPriority.LOW_PRIORITY; }] + [ LOOKAHEAD(2) { modifierQuick = true; }] + [ LOOKAHEAD(2) { modifierIgnore = true; }] + [LOOKAHEAD(4) (table=TableWithAlias() { tables.add(table); } + ("," table=TableWithAlias() { tables.add(table); } )* + [ outputClause = OutputClause() {delete.setOutputClause(outputClause); } ] + | ) { hasFrom = true; }] + + [ LOOKAHEAD(3) table=TableWithAlias() [ LOOKAHEAD(2) joins=JoinsList() ] ] + [ usingFromItem=FromItem() { usingFromItemList.add(usingFromItem); } + ("," usingFromItem=FromItem() { usingFromItemList.add(usingFromItem); } )*] + [where=WhereClause() { delete.setWhere(where); } ] + [preferringClause=PreferringClause() { delete.setPreferringClause(preferringClause);} ] + [orderByElements = OrderByElements() { delete.setOrderByElements(orderByElements); } ] + [limit=PlainLimit() {delete.setLimit(limit); } ] + + [ returningClause = ReturningClause() { delete.setReturningClause(returningClause); } ] + { + if (joins != null && joins.size() > 0) { + delete.setJoins(joins); + } + return delete.withWithItemsList(with) + .withTables(tables) + .withTable(table) + .withHasFrom(hasFrom) + .withUsingFromItemList(usingFromItemList) + .withModifierPriority(modifierPriority) + .withModifierIgnore(modifierIgnore) + .withModifierQuick(modifierQuick); + } } -List> PivotMultiInItems(): -{ - List> retval = new ArrayList>(); - SelectItem item; +Statement Merge( List> with ) : { + Merge merge = new Merge(); + Table table; + FromItem fromItem; + Expression condition; + List operations; + OutputClause outputClause; } { - item = ExpressionListItem() {retval.add(item);} - ("," item = ExpressionListItem() {retval.add(item);} )* - { return retval; } + { merge.setOracleHint(getOracleHint()); } table=TableWithAlias() { merge.setTable(table); } + fromItem = FromItem() { merge.setFromItem(fromItem); } + condition = Expression() { merge.setOnCondition(condition); } + + operations = MergeOperations() { merge.setOperations(operations); } + + [ outputClause = OutputClause() { merge.setOutputClause(outputClause); } ] + + { return merge.withWithItemsList(with); } } -Pivot Pivot(): -{ - Pivot retval = new Pivot(); - List> functionItems; - ExpressionList forColumns; - List> singleInItems = null; - List> multiInItems = null; - Alias alias = null; +List MergeOperations() : { + List operationsList = new ArrayList(); + MergeOperation operation; } { - "(" functionItems = PivotFunctionItems() - forColumns = PivotForColumns() - "(" - (LOOKAHEAD(3) singleInItems = SelectItemsList() - | multiInItems = PivotMultiInItems() ) - ")" - ")" - [ LOOKAHEAD(2) alias = Alias() ] - { - retval.setFunctionItems(functionItems); - retval.setForColumns(forColumns); - retval.setSingleInItems(singleInItems); - retval.setMultiInItems(multiInItems); - retval.setAlias(alias); - return retval; - } + ( + LOOKAHEAD(2) operation = MergeWhenMatched() { operationsList.add(operation); } + | + operation = MergeWhenNotMatched() { operationsList.add(operation); } + )* + { return operationsList; } } -PivotXml PivotXml(): -{ - PivotXml retval = new PivotXml(); - List> functionItems; - ExpressionList forColumns; - List> singleInItems = null; - List> multiInItems = null; - Select inSelect = null; +MergeOperation MergeWhenMatched() : { + Expression predicate = null; + MergeOperation operation; } { - "(" functionItems = PivotFunctionItems() - forColumns = PivotForColumns() - "(" + + [ predicate = Expression() ] + ( - LOOKAHEAD(2) { retval.setInAny(true); } | - LOOKAHEAD(1) inSelect = Select() | - LOOKAHEAD(2) singleInItems =SelectItemsList() | - multiInItems = PivotMultiInItems() + operation = MergeDeleteClause(predicate) | operation = MergeUpdateClause(predicate) ) - ")" - ")" - { - retval.setFunctionItems(functionItems); - retval.setForColumns(forColumns); - retval.setSingleInItems(singleInItems); - retval.setMultiInItems(multiInItems); - retval.setInSelect(inSelect); - return retval; - } + { return operation; } } -UnPivot UnPivot(): -{ - UnPivot retval = new UnPivot(); - ExpressionList unpivotClause; - ExpressionList unpivotForClause; - List> unpivotInClause; - Alias alias = null; +MergeOperation MergeDeleteClause(Expression predicate) : { + MergeDelete md = new MergeDelete().withAndPredicate(predicate); } { - - [ ( { retval.setIncludeNulls(true); } - | { retval.setIncludeNulls(false); } ) ] - "(" unpivotClause = PivotForColumns() - unpivotForClause = PivotForColumns() - "(" - unpivotInClause = SelectItemsList() - ")" - ")" - [ LOOKAHEAD(2) alias = Alias() ] - { - retval.setUnPivotClause(unpivotClause); - retval.setUnPivotForClause(unpivotForClause); - retval.setUnPivotInClause(unpivotInClause); - retval.setAlias(alias); - return retval; - } + { return md; } } -List
IntoClause(): -{ - List
tables = new ArrayList
(); - Table table; +MergeOperation MergeUpdateClause(Expression predicate) : { + MergeUpdate mu = new MergeUpdate().withAndPredicate(predicate); + List updateSets; + Expression condition; } { - table=Table() { tables.add(table); } ( LOOKAHEAD(2) "," table=Table() { tables.add(table); } )* - { - return tables; - } + updateSets = UpdateSets() { mu.setUpdateSets(updateSets); } + [ condition = Expression() { mu.setWhereCondition(condition); }] + [ LOOKAHEAD(2) condition = Expression() { mu.setDeleteWhereCondition(condition); } ] + { return mu; } } -FromItem ParenthesedFromItem(): -{ - ParenthesedFromItem ParenthesedFromItem = new ParenthesedFromItem(); - FromItem fromItem; - List joins = null; +MergeOperation MergeWhenNotMatched() : { + MergeInsert mi = new MergeInsert(); + Expression predicate; + ExpressionList columns; + ExpressionList expList; + Expression condition; } { - "(" - fromItem = FromItem() - [ joins=JoinsList() ] - ")" + + [ predicate = Expression() { mi.setAndPredicate(predicate); } ] + + + [ "(" columns = ColumnList() ")" + { + mi.setColumns( new ParenthesedExpressionList(columns) ); + } + ] + "(" expList = SimpleExpressionList() ")" + { + mi.setValues( new ParenthesedExpressionList(expList) ); + } - { - return ParenthesedFromItem.withFromItem(fromItem).withJoins(joins); - } -} + [ condition = Expression() { mi.setWhereCondition(condition); }] -FromItem FromItem() #FromItem: -{ - FromItem fromItem = null; - FromItem fromItem2 = null; - SampleClause sampleClause; - Pivot pivot = null; - UnPivot unpivot = null; - Alias alias = null; - MySQLIndexHint indexHint = null; - SQLServerHints sqlServerHints = null; - Select select; + { return mi; } } -{ - ( - LOOKAHEAD(3) fromItem = Values() - | - LOOKAHEAD( TableFunction() ) fromItem=TableFunction() - | - LOOKAHEAD(3) fromItem=Table() - | - LOOKAHEAD( ParenthesedFromItem() ) fromItem = ParenthesedFromItem() - | - LOOKAHEAD(3) ( - fromItem=ParenthesedSelect() - [ LOOKAHEAD(2) pivot=Pivot() { fromItem.setPivot(pivot); } ] - [ LOOKAHEAD(2) unpivot=UnPivot() { fromItem.setUnPivot(unpivot); } ] + +// table names seem to allow ":" delimiters, e.g. for Informix see #1134 +ObjectNames RelObjectNames() : { + String token = null; + Token delimiter = null; + List data = new ArrayList(); + List delimiters = new ArrayList(); +} { + token = RelObjectName() { data.add(token); } + ( + LOOKAHEAD (2) ( + ( delimiter = "..." { delimiters.add("."); data.add(null); delimiters.add("."); data.add(null); delimiters.add("."); } ) + | + ( delimiter = ".." { delimiters.add("."); data.add(null); delimiters.add("."); } ) + | + ( ( delimiter = "." | delimiter = ":" ) { delimiters.add(delimiter.image); } ) ) - | - fromItem=LateralSubSelect() - ) - [ LOOKAHEAD(2) alias=Alias() { fromItem.setAlias(alias); } ] - [ LOOKAHEAD(2) sampleClause = SampleClause() { ((Table) fromItem).setSampleClause(sampleClause); } ] - [ LOOKAHEAD(2) unpivot=UnPivot() { fromItem.setUnPivot(unpivot); } ] - [ LOOKAHEAD(2) ( LOOKAHEAD(2) pivot=PivotXml() | pivot=Pivot() ) { fromItem.setPivot(pivot); } ] - [ - LOOKAHEAD(2) - ( - indexHint = MySQLIndexHint() { - if (fromItem instanceof Table) - ((Table) fromItem).setHint(indexHint); - } + token = RelObjectNameExt() { data.add(token); } + ) * + + { return new ObjectNames(data, delimiters); } +} + +// column names do not allow ":" delimeters as those represent JSON `GET` operators +ObjectNames ColumnIdentifier() : { + String token = null; + Token delimiter = null; + List data = new ArrayList(); + List delimiters = new ArrayList(); +} { + token = RelObjectName() { data.add(token); } + ( + LOOKAHEAD (2) ( + ( delimiter = "..." { delimiters.add("."); data.add(null); delimiters.add("."); data.add(null); delimiters.add("."); } ) | - sqlServerHints = SQLServerHints() { - if (fromItem instanceof Table) - ((Table) fromItem).setSqlServerHints(sqlServerHints); - } + ( delimiter = ".." { delimiters.add("."); data.add(null); delimiters.add("."); } ) + | + ( delimiter = "." { delimiters.add(delimiter.image); } ) ) - ] + + token = RelObjectNameExt() { data.add(token); } + ) * + + { return new ObjectNames(data, delimiters); } +} + +// See: http://technet.microsoft.com/en-us/library/ms187879%28v=sql.105%29.aspx +Column Column() #Column : +{ + ObjectNames data = null; + ArrayConstructor arrayConstructor = null; + Token tk = null; +} +{ + data = ColumnIdentifier() + [ LOOKAHEAD(2) tk= ] + // @todo: we better should return a SEQUENCE instead of a COLUMN + [ LOOKAHEAD(2) "." { data.getNames().add("nextval"); } ] + + [ LOOKAHEAD(2) arrayConstructor = ArrayConstructor(false) ] { - linkAST(fromItem,jjtThis); - return fromItem; + Column col = new Column(data.getNames(), data.getDelimiters()); + if (tk != null) { col.withCommentText(tk.image); } + if (arrayConstructor!=null) { + col.setArrayConstructor(arrayConstructor); + } + linkAST(col,jjtThis); + return col; } } -List JoinsList(): +/* + * Unified identifier production for SQL object names. + * + * Accepts base identifier tokens (S_IDENTIFIER, S_QUOTED_IDENTIFIER, DATA_TYPE, + * date literals), any non-reserved keyword, and — guarded by the semantic + * check isReservedKeywordAsIdentifier() — reserved keywords that can serve as + * unquoted identifiers in the current parser position. + * + * NOTE: K_FROM, K_SELECT, and K_CURRENT are deliberately NOT included here + * to avoid FIRST-set pollution in JavaCC's choice resolution. They are only + * valid as identifiers in dotted-name continuations (after '.'), named + * parameters (after ':'), index columns, constraint names, and similar + * restricted contexts. Those call sites add the three tokens inline. + */ +String RelObjectName() : +{ Token tk = null; String result = null; } { - List joinsList = new ArrayList(); - Join join = null; + ( + /* ── Base identifier tokens ─────────────────────────────────────── */ + tk= + | tk= + | tk= + | tk= + | tk= + + /* ── Non-reserved keywords (range-guarded) ──────────────────────── */ + | LOOKAHEAD({ getToken(1).kind >= MIN_NON_RESERVED_WORD + && getToken(1).kind <= MAX_NON_RESERVED_WORD }) + result = NonReservedWord() + + /* ── Reserved keywords usable as identifiers (context-guarded) ─── */ + | LOOKAHEAD({ isReservedKeywordAsIdentifier() }) + ( tk= | tk= | tk= | tk= + | tk= | tk= + | tk= | tk= | tk= | tk= + | tk= | tk= | tk= | tk= + | tk= | tk= | tk= | tk= + | tk= | tk= | tk= | tk= + | tk= | tk= | tk= + | tk= | tk= | tk= | tk= + | tk= | tk= | tk= ) + ) + { return result != null ? result : tk.image; } } + +/* + * Extended version of RelObjectName that additionally accepts FROM, SELECT, + * and CURRENT as unquoted identifiers. + * + * These three tokens are kept OUT of RelObjectName() to avoid polluting + * JavaCC's FIRST-set computation (which would cause choice conflicts in + * expression parsing, subselect detection, etc.). + * + * Used only in specific contexts where the old grammar's RelObjectNameExt2 + * was called: dotted-name continuations, index/constraint names, type names, + * named-parameter identifier chains, and join table references. + */ +String RelObjectNameExt() : +{ Token tk = null; String result = null; } { - ( LOOKAHEAD(2) join=JoinerExpression() { joinsList.add(join); } )+ + ( result = RelObjectName() | tk= | tk= | tk= ) + { return tk != null ? tk.image : result; } +} + +Table Table() #TableName : +{ + //String serverName = null, databaseName = null, schemaName = null, tableName = null; + ObjectNames data = null; + Token fileNameToken = null; + Table table; + String timeTravelStr = null; +} +{ + ( + data = RelObjectNames() [ LOOKAHEAD(2) timeTravelStr = TimeTravelBeforeAlias() ] + { + table = new Table(data.getNames()); + table.setTimeTravel(timeTravelStr); + } + | + fileNameToken = + { + // don't split name parts + table = new Table(fileNameToken.image, false); + } + ) + { - return joinsList; + linkAST(table,jjtThis); + return table; } } -JoinHint JoinHint(): +Table TableWithAlias(): +{ + Table table = null; + Alias alias = null; +} +{ + table=Table() + [ LOOKAHEAD({ isAliasAhead() }) alias=Alias() { table.setAlias(alias); }] + { return table; } +} + +Table TableWithAliasAndMysqlIndexHint(): +{ + Table table = null; + Alias alias = null; + MySQLIndexHint indexHint = null; +} +{ + table=Table() + [ LOOKAHEAD({ isAliasAhead() }) alias=Alias() { table.setAlias(alias); } ] + [ LOOKAHEAD(2) indexHint=MySQLIndexHint() { table.setHint(indexHint); } ] + { return table; } +} + +Number Number(): { Token token; + Number number; } { ( - token = - | - token = - | - token = + token = { number = Double.valueOf(token.image); } | - token = + token = { number = Long.valueOf(token.image); } ) + { - return new JoinHint(token.image); + return number; } } -Join JoinerExpression() #JoinerExpression: +SampleClause SampleClause(): { - Join join = new Join(); - FromItem right = null; - Expression onExpression = null; - Column tableColumn; - List columns = null; - KSQLJoinWindow joinWindow = null; - JoinHint joinHint = null; + Token token; + SampleClause sampleClause; + String keyword; + String method=null; + Number percentageArgument; + String percentageUnit = null; + boolean argumentInBrackets = true; + Number offsetArgument = null; + Number repeatArgument=null; + Number seedArgument=null; } { - [ { join.setGlobal(true); } ] - [ { join.setNatural(true); } ] - - [ + ( ( - { join.setLeft(true); } [ { join.setSemi(true); } | { join.setOuter(true); } ] - | - ( - { join.setRight(true); } - | - { join.setFull(true); } - ) [ { join.setOuter(true); } ] - | - { join.setInner(true); } + // Oracle + token= { keyword = token.image; } + [ token= { method = token.image; } ] ) | - { join.setCross(true); } + ( + // SQL:2016 compliant + token = { keyword = token.image; } + ( token = | token = ) { method = token.image; } + ) | - { join.setOuter(true); } - ] + ( + // Duck DB + { keyword = "USING SAMPLE"; } + ( token = | token = ) { method = token.image; } + ) + ) ( - ( [ joinHint=JoinHint() {join.setJoinHint(joinHint); } ] ) - | - "," { join.setSimple(true); } ( { join.setOuter(true); } )? - | - { join.setStraight(true); } + "(" percentageArgument = Number() + [ + "%" { percentageUnit="%"; } + | + { percentageUnit="PERCENT"; } + | + { percentageUnit="ROWS"; } + ] + ")" + + [ LOOKAHEAD(2) "(" repeatArgument = Number() ")" ] + + [ LOOKAHEAD(2) "(" seedArgument = Number() ")" ] | - {join.setApply(true); } + percentageArgument = Number() { argumentInBrackets = false; } + [ LOOKAHEAD(2) offsetArgument = Number() ] ) - right=FromItem() - - [ - LOOKAHEAD(2) ( - [ "(" joinWindow = JoinWindow() ")" {join.setJoinWindow(joinWindow);} ] - ( onExpression=Expression() { join.addOnExpression(onExpression); } - ( LOOKAHEAD(2) onExpression=Expression() { join.addOnExpression(onExpression); } )* - ) - | - ( - "(" tableColumn=Column() { columns = new ArrayList(); columns.add(tableColumn); } - ( "," tableColumn=Column() { columns.add(tableColumn); } ) * - ")" { join.setUsingColumns(columns); } - ) - ) - ] { - linkAST(join,jjtThis); - join.setFromItem(right); - return join; + sampleClause = new SampleClause(keyword, method, percentageArgument, percentageUnit, repeatArgument, seedArgument); + sampleClause.setArgumentInBrackets(argumentInBrackets); + sampleClause.setOffsetArgument(offsetArgument); + return sampleClause; } - } -KSQLJoinWindow JoinWindow(): +Select SelectWithWithItems( List> withItems): { - KSQLJoinWindow retval = new KSQLJoinWindow(); - boolean beforeAfter; - Token beforeDurationToken = null; - Token beforeTimeUnitToken = null; - Token afterDurationToken = null; - Token afterTimeUnitToken = null; + Select select; } { - beforeDurationToken= (beforeTimeUnitToken= | beforeTimeUnitToken=) - [ "," afterDurationToken= (afterTimeUnitToken= | afterTimeUnitToken=) ] - { - if (afterDurationToken == null) { - retval.setDuration(Long.parseLong(beforeDurationToken.image)); - retval.setTimeUnit(KSQLWindow.TimeUnit.from(beforeTimeUnitToken.image)); - retval.setBeforeAfterWindow(false); - return retval; - } - retval.setBeforeDuration(Long.parseLong(beforeDurationToken.image)); - retval.setBeforeTimeUnit(KSQLWindow.TimeUnit.from(beforeTimeUnitToken.image)); - retval.setAfterDuration(Long.parseLong(afterDurationToken.image)); - retval.setAfterTimeUnit(KSQLWindow.TimeUnit.from(afterTimeUnitToken.image)); - retval.setBeforeAfterWindow(true); - return retval; - } + select = Select() { select.setWithItemsList( withItems ); + return select; +} } -KSQLWindow KSQLWindowClause(): +Select Select() #Select: { - KSQLWindow retval = null; - Token sizeDurationToken = null; - Token sizeTimeUnitToken = null; - Token advanceDurationToken = null; - Token advanceTimeUnitToken = null; + Select select = null; + List> with = null; + List orderByElements = null; + Limit limit = null; + Offset offset = null; + Fetch fetch = null; + WithIsolation withIsolation = null; + Alias alias = null; } { - - { - retval=new KSQLWindow(); - retval.setHoppingWindow(false); - retval.setSessionWindow(false); - retval.setTumblingWindow(false); - } + + [ with=WithList() ] ( - "(" - sizeDurationToken= sizeTimeUnitToken= "," - advanceDurationToken= advanceTimeUnitToken= ")" - { - retval.setHoppingWindow(true); - } | - "(" sizeDurationToken= sizeTimeUnitToken= ")" - { - retval.setSessionWindow(true); - } | - "(" sizeDurationToken= sizeTimeUnitToken= ")" - { - retval.setTumblingWindow(true); - } + LOOKAHEAD(3) select = FromQuery() + | + ( + ( + LOOKAHEAD(3) select = PlainSelect() + | + LOOKAHEAD(3) select = Values() + | + LOOKAHEAD(3) select = ParenthesedSelect() [ LOOKAHEAD({ isAliasAhead() }) alias = Alias() {select.setAlias(alias);} ] + ) + [ LOOKAHEAD(2) select = FromQueryFromSelect(select) ] + [ LOOKAHEAD(2) select = SetOperationList(select) ] + + [ LOOKAHEAD( ) orderByElements = OrderByElements() { select.setOrderByElements(orderByElements); } ] + + [ LOOKAHEAD() limit=LimitWithOffset() {select.setLimit(limit);} ] + [ LOOKAHEAD() offset = Offset() { select.setOffset(offset);} ] + [ LOOKAHEAD() fetch = Fetch() { select.setFetch(fetch);} ] + [ LOOKAHEAD( ) withIsolation = WithIsolation() { select.setIsolation(withIsolation);} ] + ) ) { - retval.setSizeDuration(Long.parseLong(sizeDurationToken.image)); - retval.setSizeTimeUnit(KSQLWindow.TimeUnit.from(sizeTimeUnitToken.image)); - if (advanceDurationToken != null) { - retval.setAdvanceDuration(Long.parseLong(advanceDurationToken.image)); - retval.setAdvanceTimeUnit(KSQLWindow.TimeUnit.from(advanceTimeUnitToken.image)); - } - return retval; + linkAST(select, jjtThis); + return select.withWithItemsList(with); } } -Expression WhereClause(): +FromQuery FromQuery() #FromQuery: { - Expression retval = null; + FromQuery fromQuery; + FromItem fromItem; + List lateralViews = null; + List joins = null; + PipeOperator pipeOperator; } { - retval=Expression() - { return retval; } + fromItem = FromItem() { fromQuery = new FromQuery(fromItem); } + [ LOOKAHEAD(2) lateralViews=LateralViews() { fromQuery.setLateralViews(lateralViews); } ] + [ LOOKAHEAD(2) joins=JoinsList() { fromQuery.setJoins(joins); } ] + ( + LOOKAHEAD(2) "|>" pipeOperator = PipeOperator() { fromQuery.add(pipeOperator); } + )* + + { + return fromQuery; + } } -OracleHierarchicalExpression OracleHierarchicalQueryClause(): +FromQuery FromQueryFromSelect(Select select): { - OracleHierarchicalExpression result = new OracleHierarchicalExpression(); - Expression expr; + FromQuery fromQuery; + FromItem fromItem; + PipeOperator pipeOperator; } { + "|>" pipeOperator = PipeOperator() + { + fromQuery = new FromQuery(select, false); + fromQuery.add(pipeOperator); + } ( - ( - expr=AndExpression() {result.setStartExpression(expr);} - [ { result.setNoCycle(true); } ] expr=AndExpression() - { - result.setConnectExpression(expr); - } - ) - | - ( - [ { result.setNoCycle(true); } ] expr=AndExpression() - { - result.setConnectExpression(expr); - result.setConnectFirst(true); - } - [ LOOKAHEAD(2) expr=AndExpression() {result.setStartExpression(expr);} ] - ) - ) + LOOKAHEAD(2) "|>" pipeOperator = PipeOperator() + { fromQuery.add(pipeOperator); } + )* + { - return result; + return fromQuery; } } -GroupByElement GroupByColumnReferences(): +PipeOperator PipeOperator() #PipeOperator: { - Expression columnReference; - GroupByElement groupBy = new GroupByElement(); - Expression expr; - ExpressionList list; - Token token; + PipeOperator operator; } { - ( - LOOKAHEAD(2) ( - - "(" - list = GroupingSet() { groupBy.addGroupingSet(list); } - ( LOOKAHEAD(2) "," list = GroupingSet() { groupBy.addGroupingSet(list); })* - ")" - ) + // SELECT covers also EXTEND, WINDOW and RENAME + operator = SelectPipeOperator() | - ( - list = ExpressionList() { groupBy.setGroupByExpressions(list); } - ( - LOOKAHEAD(2) - "(" - list = GroupingSet() { groupBy.addGroupingSet(list); } - ( LOOKAHEAD(2) "," list = GroupingSet() { groupBy.addGroupingSet(list); })* - ")" - )? - [ LOOKAHEAD(2) { groupBy.setMysqlWithRollup(true); } ] - ) + operator = SetPipeOperator() + | + operator = DropPipeOperator() + | + LOOKAHEAD(2) operator = AsPipeOperator() + | + operator = WherePipeOperator() + | + operator = LimitPipeOperator() + | + LOOKAHEAD(2) operator = AggregatePipeOperator() + | + operator = OrderByPipeOperator() + | + // covers UNION, INTERSET, EXCEPT + operator = SetOperationPipeOperator() + | + operator = JoinPipeOperator() + | + operator = CallPipeOperator() + | + operator = TableSamplePipeOperator() + | + operator = PivotPipeOperator() + | + operator = UnPivotPipeOperator() ) { - return groupBy; + return operator; } } -ExpressionList GroupingSet(): +SelectPipeOperator SelectPipeOperator(): { - ExpressionList list; - Expression expression; + Token operatorKeyToken; + Token modifierToken = null; + SelectPipeOperator selectPipeOperator; + SelectItem selectItem; } { ( - LOOKAHEAD(2) list = ParenthesedExpressionList() + ( operatorKeyToken = [ LOOKAHEAD(2) ( modifierToken= | modifierToken= ) ] ) + | + operatorKeyToken = + | + operatorKeyToken = | - expression = SimpleExpression() { list = new ExpressionList(expression); } + operatorKeyToken = ) + selectItem = SelectItem() + { selectPipeOperator = new SelectPipeOperator(operatorKeyToken.image, selectItem, modifierToken !=null ? modifierToken.image : null); } + + ( LOOKAHEAD(2) "," selectItem = SelectItem() { selectPipeOperator.add(selectItem); } )* + { - return list; + return selectPipeOperator; } } -Expression Having(): +WherePipeOperator WherePipeOperator(): { - Expression having = null; + WherePipeOperator wherePipeOperator; + Expression expression; } { - having=Expression() + expression = Expression() { - return having; + wherePipeOperator = new WherePipeOperator(expression); + return wherePipeOperator; } } -Expression Qualify(): +String OrderSuffix(): { - Expression qualify = null; + Token token =null; + String orderSuffix = null; } { - qualify=Expression() + ( token = | token = ) { orderSuffix = token.image; } + [ LOOKAHEAD(2) ( token = | token = ) { orderSuffix += " NULLS " + token.image; } ] + { - return qualify; + return orderSuffix; } } -List OrderByElements(): +AggregatePipeOperator AggregatePipeOperator(): { - List orderByList = new ArrayList(); - OrderByElement orderByElement = null; + AggregatePipeOperator aggregatePipeOperator; + SelectItem selectItem; + Token token =null; + String orderSuffix = null; } { - [ ] orderByElement=OrderByElement() { orderByList.add(orderByElement); } - ( LOOKAHEAD(2) "," orderByElement=OrderByElement() { orderByList.add(orderByElement); } )* + + selectItem = SelectItem() [ LOOKAHEAD(2) orderSuffix = OrderSuffix() ] + { aggregatePipeOperator = new AggregatePipeOperator(selectItem, orderSuffix); orderSuffix=null; } + + ( LOOKAHEAD(2) "," selectItem = SelectItem() [ LOOKAHEAD(2) orderSuffix = OrderSuffix() ] + { aggregatePipeOperator.add(selectItem, orderSuffix); orderSuffix=null; } )* + + [ + LOOKAHEAD(2) [ { aggregatePipeOperator.setShorthandOrdering(true); } ] + selectItem = SelectItem() [ LOOKAHEAD(2) orderSuffix = OrderSuffix() ] + { aggregatePipeOperator.addGroupItem(selectItem, orderSuffix); orderSuffix=null; } + + ( + LOOKAHEAD(2) "," selectItem = SelectItem() [ LOOKAHEAD(2) orderSuffix = OrderSuffix() ] + { aggregatePipeOperator.addGroupItem(selectItem, orderSuffix); orderSuffix=null; } + )* + ] + { - return orderByList; + return aggregatePipeOperator; } } -OrderByElement OrderByElement(): +OrderByPipeOperator OrderByPipeOperator(): { - OrderByElement orderByElement = new OrderByElement(); - Expression columnReference = null; + OrderByPipeOperator orderByPipeOperator; + List orderByElements; } { - columnReference = Expression() - [ LOOKAHEAD(2) ( | ( { orderByElement.setAsc(false); } )) { orderByElement.setAscDescPresent(true); } ] - [ LOOKAHEAD(2) - [ LOOKAHEAD(2) ( - { orderByElement.setNullOrdering(OrderByElement.NullOrdering.NULLS_FIRST); } - | - { orderByElement.setNullOrdering(OrderByElement.NullOrdering.NULLS_LAST); } - ) - ] - ] - [ LOOKAHEAD(2) { orderByElement.setMysqlWithRollup(true); } ] + orderByElements = OrderByElements() { - orderByElement.setExpression(columnReference); - return orderByElement; + orderByPipeOperator = new OrderByPipeOperator(orderByElements); + return orderByPipeOperator; } } -JdbcParameter JdbcParameter() : { - Token tk; - JdbcParameter retval; +AsPipeOperator AsPipeOperator(): +{ + AsPipeOperator asPipeOperator; + Alias alias; } { - ( tk="?" | tk= ) - { retval = new JdbcParameter(++jdbcParameterIndex, false, tk.image); } - - [ LOOKAHEAD(2) token = { retval.setUseFixedIndex(true); retval.setIndex(Integer.valueOf(token.image)); } ] - - { return retval; } + alias = Alias() + { + asPipeOperator = new AsPipeOperator( alias.withUseAs(true) ); + return asPipeOperator; + } } - -Limit LimitWithOffset() #LimitWithOffset: +JoinPipeOperator JoinPipeOperator(): { - Limit limit = new Limit(); - Expression rowCountExpression; - Expression offsetExpression; + JoinPipeOperator joinPipeOperator; + Join join; } { - ( - LOOKAHEAD( Expression() "," Expression()) ( - // mysql-> LIMIT offset,row_count - - offsetExpression=Expression() { limit.setOffset( offsetExpression ); } - "," - rowCountExpression=Expression() { limit.setRowCount( rowCountExpression ); } - ) - | - limit = PlainLimit() - ) + join = JoinerExpression() { - linkAST(limit,jjtThis); - return limit; + joinPipeOperator = new JoinPipeOperator(join); + return joinPipeOperator; } } -Limit PlainLimit() #PlainLimit: +SetPipeOperator SetPipeOperator(): { - Limit limit = new Limit(); - Expression rowCountExpression; + SetPipeOperator setPipeOperator; + List updateSets; } { - // mysql-postgresql-> LIMIT (row_count | ALL | NULL) - - ( - LOOKAHEAD(3) rowCountExpression = ParenthesedSelect() - | - rowCountExpression = Expression() - ) + updateSets = UpdateSets() { - limit.setRowCount(rowCountExpression); - linkAST(limit,jjtThis); - return limit; + setPipeOperator = new SetPipeOperator(updateSets); + return setPipeOperator; } } -/** - * Clickhouse LIMIT BY - * @see SELECT Query - */ -Limit LimitBy(): +DropPipeOperator DropPipeOperator(): { - Limit limit; - ExpressionList byExpressions; + DropPipeOperator dropPipeOperator; + ExpressionList columns; } { - limit = LimitWithOffset() - byExpressions = ExpressionList() + columns = ColumnList() { - limit.setByExpressions(byExpressions); - return limit; + dropPipeOperator = new DropPipeOperator(columns); + return dropPipeOperator; } } -Offset Offset(): +LimitPipeOperator LimitPipeOperator(): { - Offset offset = new Offset(); - Expression offsetExpression; + LimitPipeOperator limitPipeOperator; + Expression expression; } { - ( - // postgresql-> OFFSET offset - // sqlserver-oracle-> OFFSET offset (ROW | ROWS) - - offsetExpression=Expression() { offset.setOffset( offsetExpression ); } - - [ LOOKAHEAD(2) ( { offset.setOffsetParam("ROWS"); } | { offset.setOffsetParam("ROW"); })] + expression = Expression() { limitPipeOperator = new LimitPipeOperator(expression); } + [ LOOKAHEAD(2) expression = Expression() { limitPipeOperator.setOffsetExpression(expression); } ] - ) { - return offset; + return limitPipeOperator; } } -Fetch Fetch(): +// see https://manticore-projects.com/SQL2016Parser/syntax_snapshot.html#corresponding-spec +String SetOperationModifier(): { - Fetch fetch = new Fetch(); - Token token = null; - Expression expression; - List fetchParameters = new ArrayList(); + Token tk; + String modifier = ""; + String identifier; } { ( - LOOKAHEAD(3) ( - ( { fetch.setFetchParamFirst(true); } | ) - ( - { fetch.addFetchParameter("ROWS"); } - | - { fetch.addFetchParameter("ROW"); } - ) - ( - { fetch.addFetchParameter("ONLY"); } - | - { fetch.addFetchParameter("WITH TIES"); } - ) + LOOKAHEAD(2) ( + [ ( tk= | tk="DISTINCT") { modifier+=tk.image; } ] + { modifier+= " BY NAME"; } + [ + "MATCHING" { modifier+= " MATCHING"; } + "(" + identifier = RelObjectName() { modifier+="(" + identifier; } + ("," identifier = RelObjectName() { modifier+=", " + identifier; })* + ")" { modifier+=")"; } + ] ) | ( - ( { fetch.setFetchParamFirst(true); } | ) + [ { modifier+= " STRICT"; } ] + { modifier+= " CORRESPONDING"; } + [ (tk= | tk="DISTINCT") { modifier+=tk.image; } ] + [ + { modifier+= " BY"; }[ (tk= | tk="DISTINCT") { modifier+=tk.image; } ] + "(" + identifier = RelObjectName() { modifier+="(" + identifier; } + ("," identifier = RelObjectName() { modifier+=", " + identifier;})* + ")" { modifier+=")"; } + ] + ) + | + ( tk= | tk= ) { modifier+=tk.image; } + ) + { + return modifier; + } +} - // Expression is optional according to https://www.h2database.com/html/commands.html#select - expression = Expression() { fetch.setExpression(expression); } - [ { fetch.addFetchParameter("PERCENT"); } ] - ( - ( - { fetch.addFetchParameter("ROWS"); } - | - { fetch.addFetchParameter("ROW"); } - ) - - ( - { fetch.addFetchParameter("ONLY"); } - | - { fetch.addFetchParameter("WITH TIES"); } - ) - ) +SetOperationPipeOperator SetOperationPipeOperator(): +{ + SetOperationPipeOperator setOperationPipeOperator = null; + SetOperationType setOperationType; + String modifier = null; + ParenthesedSelect select; +} +{ + ( + ( + [ modifier=SetOperationModifier() ] { setOperationType = SetOperationType.UNION; } + select = ParenthesedSelect() { setOperationPipeOperator = new SetOperationPipeOperator(select, setOperationType, modifier); } + ) + | + ( + [ modifier=SetOperationModifier() ] { setOperationType = SetOperationType.INTERSECT; } + select = ParenthesedSelect() { setOperationPipeOperator = new SetOperationPipeOperator(select, setOperationType, modifier); } + ) + | + ( + [ modifier=SetOperationModifier() ] { setOperationType = SetOperationType.EXCEPT; } + select = ParenthesedSelect() { setOperationPipeOperator = new SetOperationPipeOperator(select, setOperationType, modifier); } ) ) + + ( + LOOKAHEAD(2) "," select = ParenthesedSelect() { setOperationPipeOperator.add(select); } + )* + { - return fetch; + return setOperationPipeOperator; } } -WithIsolation WithIsolation(): +CallPipeOperator CallPipeOperator(): { - WithIsolation withIsolation = new WithIsolation(); - Token token = null; - JdbcParameter jdbc; + TableFunction tableFunction; + Alias alias=null; } { - ( - //with (ur | cs | rs | rr) - - token= { withIsolation.setIsolation(token.image); } + tableFunction = TableFunction() [ LOOKAHEAD({ isAliasAhead() }) alias = Alias() ] - ) { - return withIsolation; + return new CallPipeOperator(tableFunction, alias); } } -OptimizeFor OptimizeFor(): + +TableSamplePipeOperator TableSamplePipeOperator(): { Token token; - LongValue value; } { - token= + "(" ( token= | token= ) ")" { - value = new LongValue(token.image); - return new OptimizeFor(value.getValue()); + return new TableSamplePipeOperator( token.image ); } } -// according to http://technet.microsoft.com/en-us/library/ms189463.aspx -Top Top() #Top: +PivotPipeOperator PivotPipeOperator(): { - Top top = new Top(); - Token token = null; - Expression expr = null; - JdbcParameter jdbc = null; + Function aggregateExpression; + Column inputColumn; + List> pivotColumns; + Alias alias = null; } { - - ( - token= { top.setExpression(new LongValue(token.image)); } - | - jdbc = JdbcParameter() { top.setExpression(jdbc); } - | - ":" { top.setExpression(new JdbcNamedParameter()); } - [ LOOKAHEAD(2) token = { ((JdbcNamedParameter)top.getExpression()).setName(token.image); } ] - | - "(" - expr=AdditiveExpression() - { - top.setExpression(expr); - top.setParenthesis(true); - } - ")" - ) - [ LOOKAHEAD(2) { top.setPercentage(true); } ] - [ LOOKAHEAD(2) { top.setWithTies(true); } ] + "(" aggregateExpression=Function() + inputColumn=Column() + "(" pivotColumns = SelectItemsList() ")" + ")" + [ LOOKAHEAD({ isAliasAhead() }) alias = Alias() ] { - linkAST(top,jjtThis); - return top; + return new PivotPipeOperator(aggregateExpression, inputColumn, pivotColumns, alias); } } -// according to http://www-01.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.sqls.doc/ids_sqs_0156.htm -Skip Skip(): +UnPivotPipeOperator UnPivotPipeOperator(): { - Skip skip = new Skip(); - Token token = null; - JdbcParameter jdbc; + Column valuesColumn; + Column nameColumn; + List> pivotColumns; + Alias alias = null; } { - - ( - token= { skip.setRowCount(Long.parseLong(token.image)); } - | token= { skip.setVariable(token.image); } - | jdbc = JdbcParameter() { skip.setJdbcParameter(jdbc); } - /* "?" { skip.setJdbcParameter(new JdbcParameter(++jdbcParameterIndex, false)); } [ LOOKAHEAD(2) token = { skip.getJdbcParameter().setUseFixedIndex(true); skip.getJdbcParameter().setIndex(Integer.valueOf(token.image)); } ] */ - ) + "(" valuesColumn=Column() + nameColumn=Column() + "(" pivotColumns = SelectItemsList() ")" + ")" + [ LOOKAHEAD({ isAliasAhead() }) alias = Alias() ] { - return skip; + return new UnPivotPipeOperator(valuesColumn, nameColumn, pivotColumns, alias); } } -JAVACODE -OracleHint getOracleHint() { - OracleHint hint = null; - Token tok = getToken(1); - // Retrieve first comment (if any) prior next token - if (tok.specialToken != null) { - tok = tok.specialToken; - while (tok.specialToken != null) tok = tok.specialToken; - // Check if it matches Hint pattern? - if (OracleHint.isHintMatch(tok.image)) { - hint = new OracleHint(); - hint.setComment(tok.image); - } - } - return hint; +TableStatement TableStatement(): +{ + Table table = null; + List orderByElements = null; + Limit limit = null; + Offset offset = null; + TableStatement tableStatement = new TableStatement(); +}{ + + table = Table() + { tableStatement.setTable(table); } + [ LOOKAHEAD( ) orderByElements = OrderByElements() { tableStatement.setOrderByElements(orderByElements); } ] + [ LOOKAHEAD() limit = LimitWithOffset() { tableStatement.setLimit(limit);} ] + [ LOOKAHEAD() offset = Offset() { tableStatement.setOffset(offset);} ] + { return tableStatement; } + /* Support operationList */ } -First First(): +ParenthesedSelect ParenthesedSelect() #ParenthesedSelect: { - First first = new First(); - Token token = null; - JdbcParameter jdbc; + ParenthesedSelect parenthesedSelect = new ParenthesedSelect(); + Select select; } { - ( - { first.setKeyword(First.Keyword.FIRST); } - | - { first.setKeyword(First.Keyword.LIMIT); } - ) - ( - token= { first.setRowCount(Long.parseLong(token.image)); } - | - token= { first.setVariable(token.image); } - | - jdbc = JdbcParameter() { first.setJdbcParameter(jdbc); } - ) + "(" + select = Select() + ")" { - return first; + linkAST(parenthesedSelect,jjtThis); + return parenthesedSelect.withSelect(select); } } - -Expression Expression() #Expression : +ParenthesedInsert ParenthesedInsert() #ParenthesedInsert: { - Expression retval = null; + ParenthesedInsert parenthesedInsert = new ParenthesedInsert(); + Insert insert; } { - retval=XorExpression() - - { return retval; } + "(" + insert = Insert() + ")" + { + return parenthesedInsert.withInsert(insert); + } } -Expression XorExpression(): +ParenthesedUpdate ParenthesedUpdate() #ParenthesedUpdate: { - Expression left, right, result; + ParenthesedUpdate parenthesedUpdate = new ParenthesedUpdate(); + Update update; } { - left=OrExpression() { result = left; } - ( LOOKAHEAD(2) - - right=OrExpression() - { - result = new XorExpression(left, right); - left = result; - } - )* - { - return result; - } + "(" + update = Update() + ")" + { + return parenthesedUpdate.withUpdate(update); + } } -Expression OrExpression(): +ParenthesedDelete ParenthesedDelete() #ParenthesedDelete: { - Expression left, right, result; + ParenthesedDelete parenthesedDelete = new ParenthesedDelete(); + Delete delete; } { - left=AndExpression() { result = left; } - ( LOOKAHEAD(2) - - right=AndExpression() - { - result = new OrExpression(left, right); - left = result; - } - )* - { - return result; - } - + "(" + delete = Delete() + ")" + { + return parenthesedDelete.withDelete(delete); + } } -Expression AndExpression() : +LateralView LateralView() #LateralView: { - Expression left, right, result; - boolean not = false; - boolean exclamationMarkNot=false; + boolean useOuter = false; + Function generatorFunction = null; + String tableName = null; + String columnName = null; + Alias tableAlias = null; + Alias columnAlias = null; } { - ( - LOOKAHEAD(Condition(), {!interrupted}) - left=Condition() - | - [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] - "(" left=XorExpression() ")" {left = new ParenthesedExpressionList(left); if (not) { left = new NotExpression(left, exclamationMarkNot); not = false; } } - ) - { result = left; } - - ( LOOKAHEAD(2) - { boolean useOperator = false; } - ( | {useOperator=true;} ) - ( - LOOKAHEAD(Condition(), {!interrupted}) - right=Condition() - | - [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] - "(" right=XorExpression() ")" {right = new ParenthesedExpressionList(right); if (not) { right = new NotExpression(right, exclamationMarkNot); not = false; } } - ) + [ { useOuter=true; } ] + generatorFunction = Function() + [ LOOKAHEAD(2) + tableName=RelObjectName() { - result = new AndExpression(left, right); - ((AndExpression)result).setUseOperator(useOperator); - left = result; + tableAlias = new Alias(tableName, false); } - )* + ] + columnName = RelObjectName() { columnAlias = new Alias(columnName, true); } + + // Spark SQL supports multiple Alias Columns: https://spark.apache.org/docs/latest/sql-ref-syntax-qry-select-lateral-view.html + // we simulate this by setting the alias name to null and then just adding the columns + [ + LOOKAHEAD(2) "," { columnAlias.setName(null); columnAlias.addAliasColumns( columnName); } + columnName = RelObjectName() { columnAlias.addAliasColumns( columnName); } + ] { - return result; + return new LateralView( + useOuter + , generatorFunction + , tableAlias + , columnAlias + ); } } -Expression Condition(): +ForClause ForClause() #ForClause: { - Expression result; - Token token; - boolean not = false; - boolean exclamationMarkNot = false; + Token token = null; + ForClause forClause = new ForClause(); } { - [ LOOKAHEAD(2) ( { not=true; } | "!" { not=true; exclamationMarkNot=true; })] + ( - LOOKAHEAD(RegularCondition()) result=RegularCondition() - | result=SQLCondition() - ) - - { return not?new NotExpression(result, exclamationMarkNot):result; } -} - -Expression OverlapsCondition():{ - ExpressionList left = new ExpressionList(); - ExpressionList right = new ExpressionList(); -} -{ - //As per the sql2003 standard, we need at least two items in the list if there is not explicit ROW prefix - //More than two expression are allowed per the sql2003 grammar. - left = ParenthesedExpressionList() - - right = ParenthesedExpressionList() - - {return new OverlapsCondition(left, right);} -} - -Expression RegularCondition() #RegularCondition: -{ - Expression result = null; - Expression leftExpression; - Expression rightExpression; - int oracleJoin=EqualsTo.NO_ORACLE_JOIN; - int oraclePrior=EqualsTo.NO_ORACLE_PRIOR; - boolean binary = false; - boolean not = false; -} -{ - [ LOOKAHEAD(2) { oraclePrior = EqualsTo.ORACLE_PRIOR_START; }] - leftExpression=ComparisonItem() { result = leftExpression; } - - [ "(" "+" ")" { oracleJoin=EqualsTo.ORACLE_JOIN_RIGHT; } ] - - ( - LOOKAHEAD(2) - ">" { result = new GreaterThan(); } - | "<" { result = new MinorThan(); } - | "=" { result = new EqualsTo(); } - | token= { result = new GreaterThanEquals(token.image); } - | token= { result = new MinorThanEquals(token.image); } - | token= { result = new NotEqualsTo(token.image); } - | token= { result = new NotEqualsTo(token.image); } - | "*=" { result = new TSQLLeftJoin(); } - | "=*" { result = new TSQLRightJoin(); } - | token= { result = new DoubleAnd(); } - | token= { result = new Contains(); } - | token= { result = new ContainedBy(); } - | "@@" { result = new Matches(); } - | "~" { result = new RegExpMatchOperator(RegExpMatchOperatorType.MATCH_CASESENSITIVE); } - | "~*" { result = new RegExpMatchOperator(RegExpMatchOperatorType.MATCH_CASEINSENSITIVE); } - | "!~" { result = new RegExpMatchOperator(RegExpMatchOperatorType.NOT_MATCH_CASESENSITIVE); } - | "!~*" { result = new RegExpMatchOperator(RegExpMatchOperatorType.NOT_MATCH_CASEINSENSITIVE); } - - | "@>" { result = new JsonOperator("@>"); } - | "<@" { result = new JsonOperator("<@"); } - | "?" { result = new JsonOperator("?"); } - | "?|" { result = new JsonOperator("?|"); } - | "?&" { result = new JsonOperator("?&"); } - | { result = new JsonOperator("||"); } - | "-" { result = new JsonOperator("-"); } - | "-#" { result = new JsonOperator("-#"); } - | "<->" { result = new GeometryDistance("<->"); } - | "<#>" { result = new GeometryDistance("<#>"); } + token = + | + token = + ( + ( + ( [ LOOKAHEAD(2) "(" ")" ] | ) + ( + LOOKAHEAD(2) "," + ( + + | + | [ LOOKAHEAD(2) "(" ")" ] + | + | [ LOOKAHEAD(2) "(" ")" ] + | [ LOOKAHEAD(2) ( | ) ] + ) + )* + ) + | + ( + + ( + LOOKAHEAD(2) "," + ( + + | + | [ LOOKAHEAD(2) "(" ")" ] + | + ) + )* + ) + | + ( + [ LOOKAHEAD(2) "(" ")" ] + ( + LOOKAHEAD(2) "," + ( + + | + | [ LOOKAHEAD(2) "(" ")" ] + | [ LOOKAHEAD(2) ( | ) ] + ) + )* + ) + ) + | + ( + token = ( | ) + ( + LOOKAHEAD(2) "," + ( + [ LOOKAHEAD(2) "(" ")" ] + | + | + ) + )* + ) ) - - ( LOOKAHEAD(2) rightExpression=ComparisonItem() { oraclePrior = EqualsTo.ORACLE_PRIOR_END; } - | rightExpression=ComparisonItem() ) - - [ LOOKAHEAD(2) "(" "+" ")" { oracleJoin=EqualsTo.ORACLE_JOIN_LEFT; } ] - - { - BinaryExpression regCond = (BinaryExpression) result; - regCond.setLeftExpression(leftExpression); - regCond.setRightExpression(rightExpression); - - if (oracleJoin>0) - ((SupportsOldOracleJoinSyntax)result).setOldOracleJoinSyntax(oracleJoin); - - if (oraclePrior!=EqualsTo.NO_ORACLE_PRIOR) - ((SupportsOldOracleJoinSyntax)result).setOraclePriorPosition(oraclePrior); - } - { - linkAST(result,jjtThis); - return result; + forClause.setForOption(token.image); + linkAST(forClause,jjtThis); + return forClause; } } -Expression SQLCondition(): -{ - Expression result; - Expression left; -} -{ - ( - result=ExistsExpression() - | LOOKAHEAD(InExpression() , {!interrupted}) result=InExpression() - | LOOKAHEAD(OverlapsCondition(), {!interrupted}) result=OverlapsCondition() - | left = SimpleExpression() { result = left; } - [ - LOOKAHEAD(2) ( - ( - LOOKAHEAD(ExcludesExpression()) result=ExcludesExpression(left) - | - LOOKAHEAD(IncludesExpression()) result=IncludesExpression(left) - | - LOOKAHEAD(2) result=Between(left) - | - result = MemberOfExpression(left) - | - LOOKAHEAD(IsNullExpression()) result=IsNullExpression(left) - | - LOOKAHEAD(IsBooleanExpression()) result=IsBooleanExpression(left) - | - LOOKAHEAD(2) result=LikeExpression(left) - | - LOOKAHEAD(IsDistinctExpression()) result=IsDistinctExpression(left) - | - result=SimilarToExpression(left) - ) - ) - ] - ) - { return result; } -} -Expression InExpression() #InExpression : +List LateralViews(): { - Token token; - int oldOracleJoin = 0; - boolean usingNot = false; - boolean usingGlobal = false; - Expression leftExpression; - Expression rightExpression; + ArrayList lateralViews = new ArrayList(); + LateralView lateralView = null; } { - leftExpression=SimpleExpression() - [ "(" "+" ")" { oldOracleJoin=EqualsTo.ORACLE_JOIN_RIGHT; } ] + lateralView = LateralView() { lateralViews.add(lateralView); } + ( LOOKAHEAD(2) lateralView = LateralView() { lateralViews.add(lateralView); } )* - [ { usingGlobal=true; } ] - [ { usingNot=true; } ] - - ( - LOOKAHEAD(2) token= { rightExpression = new StringValue(token.image); } - | LOOKAHEAD(3) rightExpression = Function() - | LOOKAHEAD(ParenthesedSelect(), {!interrupted}) rightExpression = ParenthesedSelect() - | LOOKAHEAD(3) rightExpression = ParenthesedExpressionList() - | rightExpression = SimpleExpression() - ) { - InExpression inExpression = new InExpression(leftExpression, rightExpression) - .withOldOracleJoinSyntax(oldOracleJoin) - .withNot(usingNot) - .setGlobal(usingGlobal); - linkAST(inExpression,jjtThis); - return inExpression; + return lateralViews; } } -Expression IncludesExpression(Expression leftExpression) #IncludesExpression : +LateralSubSelect LateralSubSelect() #LateralSubSelect: { - Token token; - Expression rightExpression; + LateralSubSelect lateralSubSelect = new LateralSubSelect();; + Select select; } { - (rightExpression = ParenthesedExpressionList()) + "(" select = Select() ")" { lateralSubSelect.withSelect(select).setPrefix("LATERAL"); } { - IncludesExpression includesExpression = new IncludesExpression(leftExpression, rightExpression); - - linkAST(includesExpression,jjtThis); - return includesExpression; + linkAST(lateralSubSelect,jjtThis); + return lateralSubSelect; } } -Expression ExcludesExpression(Expression leftExpression) #ExcludesExpression : +PlainSelect PlainSelect() #PlainSelect: { + PlainSelect plainSelect = new PlainSelect(); + List> selectItems = null; + FromItem fromItem = null; + List lateralViews = null; + List joins = null; + List> distinctOn = null; + Expression preWhere = null; + Expression where = null; + ForClause forClause = null; + List orderByElements; + GroupByElement groupBy = null; + Expression having = null; + Expression qualify; + Limit limitBy = null; + Limit limit = null; + Offset offset = null; + Fetch fetch = null; + WithIsolation withIsolation = null; + OptimizeFor optimize = null; + Top top = null; + Skip skip = null; + First first = null; + OracleHierarchicalExpression oracleHierarchicalQueryClause = null; + PreferringClause preferringClause = null; + ExpressionList expressionList = null; + boolean partitionByBrackets = false; + List
intoTables = null; + MySqlSelectIntoClause mySqlSelectIntoClause = null; + Table updateTable = null; + List
updateTables = new ArrayList
(); + Wait wait = null; + boolean mySqlSqlCalcFoundRows = false; Token token; - Expression rightExpression; + KSQLWindow ksqlWindow = null; + boolean noWait = false; + String windowName = null; + WindowDefinition winDef; + Table intoTempTable = null; + List settings = null; + Distinct distinct; } { - (rightExpression = ParenthesedExpressionList()) - { - ExcludesExpression excludesExpression = new ExcludesExpression(leftExpression, rightExpression); + - linkAST(excludesExpression,jjtThis); - return excludesExpression; - } -} + [ { plainSelect.setMySqlHintStraightJoin(true); } ] -Expression Between(Expression leftExpression) : -{ - Between result = new Between(); - Expression betweenExpressionStart = null; - Expression betweenExpressionEnd = null; -} -{ - [ { result.setNot(true); }] - + { plainSelect.setOracleHint(getOracleHint()); } + + [ LOOKAHEAD(2) skip = Skip() { plainSelect.setSkip(skip); } ] + + [ LOOKAHEAD(2) first = First() { plainSelect.setFirst(first); } ] + + // Redshift allows TOP before DISTINCT + // https://docs.aws.amazon.com/redshift/latest/dg/r_SELECT_list.html + // @Todo: reflect the order when de-parsing + [ LOOKAHEAD(2) top = Top() { plainSelect.setTop(top); } ] + + [ LOOKAHEAD(2) ( - LOOKAHEAD( 3 ) betweenExpressionStart = ParenthesedSelect() - | - LOOKAHEAD( RegularCondition() ) betweenExpressionStart = RegularCondition() - | - betweenExpressionStart = SimpleExpression() + + | + ( + { distinct = new Distinct(); plainSelect.setDistinct(distinct); } + [ LOOKAHEAD(2) "ON" "(" distinctOn=SelectItemsList() { plainSelect.getDistinct().setOnSelectItems(distinctOn); } ")" ] + ) + | + { distinct = new Distinct(); distinct.setUseDistinctRow(true); plainSelect.setDistinct(distinct); } + | + { distinct = new Distinct(true); plainSelect.setDistinct(distinct); } + | + { plainSelect.setMySqlSqlCalcFoundRows(true); } + | + { plainSelect.setMySqlSqlCacheFlag(MySqlSqlCacheFlags.SQL_NO_CACHE); } + | + { plainSelect.setMySqlSqlCacheFlag(MySqlSqlCacheFlags.SQL_CACHE); } ) + ] - + [ + ( - LOOKAHEAD( 3 ) betweenExpressionEnd = ParenthesedSelect() - | - LOOKAHEAD( RegularCondition() ) betweenExpressionEnd = RegularCondition() + { plainSelect.setBigQuerySelectQualifier( PlainSelect.BigQuerySelectQualifier.AS_STRUCT ); } | - betweenExpressionEnd = SimpleExpression() + { plainSelect.setBigQuerySelectQualifier( PlainSelect.BigQuerySelectQualifier.AS_VALUE ); } ) + ] - { - result.setLeftExpression(leftExpression); - result.setBetweenExpressionStart(betweenExpressionStart); - result.setBetweenExpressionEnd(betweenExpressionEnd); - return result; + [ LOOKAHEAD(2) top = Top() { plainSelect.setTop(top); } ] + + selectItems=SelectItemsList() + + [ LOOKAHEAD( ( | )) + mySqlSelectIntoClause = MySqlSelectIntoClause(MySqlSelectIntoClause.Position.BEFORE_FROM) + { plainSelect.setMySqlSelectIntoClause(mySqlSelectIntoClause); } + ] + [ LOOKAHEAD() + intoTables = IntoClause() { plainSelect.setIntoTables(intoTables); } + ] + [ LOOKAHEAD(2) fromItem=FromItem() + [ LOOKAHEAD(2) lateralViews=LateralViews() ] + [ LOOKAHEAD(2) joins=JoinsList() ] + ] + [ LOOKAHEAD(3) { plainSelect.setUsingOnly(true); } fromItem=FromItem() + [ LOOKAHEAD(2) lateralViews=LateralViews() ] + [ LOOKAHEAD(2) joins=JoinsList() ] + ] + + // Clickhouse FINAL as shown at https://clickhouse.com/docs/en/operations/settings/settings#final + [ LOOKAHEAD(2) { plainSelect.setUsingFinal(true); } ] + + [ LOOKAHEAD(2) ksqlWindow=KSQLWindowClause() { plainSelect.setKsqlWindow(ksqlWindow); } ] + [ LOOKAHEAD(2) preWhere=PreWhereClause() { plainSelect.setPreWhere(preWhere); }] + [ LOOKAHEAD(2) where=WhereClause() { plainSelect.setWhere(where); }] + [ LOOKAHEAD(2) oracleHierarchicalQueryClause=OracleHierarchicalQueryClause() { plainSelect.setOracleHierarchical(oracleHierarchicalQueryClause); } ] + [ LOOKAHEAD(2) preferringClause=PreferringClause() { plainSelect.setPreferringClause(preferringClause); } + [LOOKAHEAD(2) + ( + LOOKAHEAD(2) expressionList=ComplexExpressionList() + | + "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" + ) + { + preferringClause.setPartitionExpressionList(expressionList, partitionByBrackets); + } + ] + ] + // Oracle supports "HAVING" before "GROUP BY", we will simply parse that but won't pay special attention to the order + [ LOOKAHEAD(2) having=Having() { plainSelect.setHaving(having); }] + [ LOOKAHEAD(2) groupBy=GroupByColumnReferences() { plainSelect.setGroupByElement(groupBy); }] + [ LOOKAHEAD(2) having=Having() { plainSelect.setHaving(having); }] + [ LOOKAHEAD(2) qualify=Qualify() {plainSelect.setQualify(qualify); }] + [ LOOKAHEAD( ) orderByElements = OrderByElements() { plainSelect.setOracleSiblings(true); plainSelect.setOrderByElements(orderByElements); } ] + [ LOOKAHEAD(2) + windowName = RelObjectName() winDef = windowDefinition() { List winDefs = new ArrayList(); winDefs.add(winDef.withWindowName(windowName)); } + ( LOOKAHEAD(2) "," windowName = RelObjectName() winDef = windowDefinition() { winDefs.add(winDef.withWindowName(windowName)); } )* + { plainSelect.setWindowDefinitions(winDefs); } + ] + [ LOOKAHEAD( ) orderByElements = OrderByElements() { plainSelect.setOrderByElements(orderByElements); } ] + [ LOOKAHEAD(2) forClause = ForClause() {plainSelect.setForClause(forClause);} ] + [ LOOKAHEAD(2) { plainSelect.setEmitChanges(true); } ] + [ LOOKAHEAD(7) limit = LimitBy() { plainSelect.setLimitBy(limit); } ] + [ LOOKAHEAD() limit = LimitWithOffset() { plainSelect.setLimit(limit); } ] + [ LOOKAHEAD() offset = Offset() { plainSelect.setOffset(offset); } ] + [ LOOKAHEAD(, { limit==null }) limit = LimitWithOffset() { plainSelect.setLimit(limit); } ] + [ LOOKAHEAD() fetch = Fetch() { plainSelect.setFetch(fetch); } ] + [ LOOKAHEAD( ) withIsolation = WithIsolation() { plainSelect.setIsolation(withIsolation); } ] + [ LOOKAHEAD(2) + + ( + { plainSelect.setForMode(ForMode.UPDATE); } + | { plainSelect.setForMode(ForMode.SHARE); } + | ( { plainSelect.setForMode(ForMode.NO_KEY_UPDATE); }) + | ( { plainSelect.setForMode(ForMode.KEY_SHARE); }) + | ( { plainSelect.setForMode(ForMode.READ_ONLY); }) + | ( { plainSelect.setForMode(ForMode.FETCH_ONLY); }) + ) + [ LOOKAHEAD(2) + updateTable = Table() { updateTables.add(updateTable); } + ( LOOKAHEAD(2) "," updateTable = Table() { updateTables.add(updateTable); } )* + { plainSelect.setForUpdateTables(updateTables); } + ] + [ LOOKAHEAD() wait = Wait() { plainSelect.setWait(wait); } ] + [ LOOKAHEAD(2) ( { plainSelect.setNoWait(true); } + | { plainSelect.setSkipLocked(true); }) ] + [ LOOKAHEAD( ) orderByElements = OrderByElements() + { plainSelect.setOrderByElements(orderByElements); plainSelect.setForUpdateBeforeOrderBy(true); } + ] + ] + [ LOOKAHEAD( ( | )) + mySqlSelectIntoClause = MySqlSelectIntoClause(MySqlSelectIntoClause.Position.TRAILING) + { plainSelect.setMySqlSelectIntoClause(mySqlSelectIntoClause); } + ] + [ LOOKAHEAD(2) settings = UpdateSets() { plainSelect.setSettings(settings); } ] + [ LOOKAHEAD() optimize = OptimizeFor() { plainSelect.setOptimizeFor(optimize); } ] + [ LOOKAHEAD(3) intoTempTable = Table() { plainSelect.setIntoTempTable(intoTempTable);} ] + [ LOOKAHEAD(3) { plainSelect.setUseWithNoLog(true); } ] + { + plainSelect.setSelectItems(selectItems); + plainSelect.setFromItem(fromItem); + if ( lateralViews!=null && lateralViews.size()>0 ) { + plainSelect.setLateralViews( lateralViews ); + } + if ( joins!=null && joins.size()>0 ) { + plainSelect.setJoins( joins ); + } + linkAST(plainSelect,jjtThis); + return plainSelect; } } -Expression LikeExpression(Expression leftExpression) #LikeExpression: -{ - LikeExpression result = new LikeExpression(); - Expression rightExpression = null; - Expression escape; - Token token; +Select SetOperationList(Select select) #SetOperationList: { + SetOperationList list = new SetOperationList(); + List orderByElements = null; + Limit limit = null; + Offset offset = null; + Fetch fetch = null; + WithIsolation withIsolation = null; + List(); + List operations = new ArrayList(); + String modifier = null; } { - [ { result.setNot(true); } ] - ( - token = - | token = - | token = - | token = - | token = - ) { result.setLikeKeyWord( LikeExpression.KeyWord.from(token.image)); } - [ LOOKAHEAD(2) {result.setUseBinary(true); } ] - rightExpression=SimpleExpression() - [ LOOKAHEAD(2) + + { + selects.add(select); + } + + ( LOOKAHEAD(2) { modifier = null; } ( + ( + [ modifier=SetOperationModifier() ] { UnionOp union = new UnionOp(modifier); linkAST(union,jjtThis); operations.add(union); } + + ) + | + ( + [ modifier=SetOperationModifier() ] { IntersectOp intersect = new IntersectOp(modifier); linkAST(intersect,jjtThis); operations.add(intersect); } + ) + | + ( + [ modifier=SetOperationModifier() ] { MinusOp minus = new MinusOp(modifier); linkAST(minus,jjtThis); operations.add(minus); } + ) + | + ( + [ modifier=SetOperationModifier() ] { ExceptOp except = new ExceptOp(modifier); linkAST(except,jjtThis); operations.add(except); } + ) + + ) + ( - LOOKAHEAD(2) token = { result.setEscape( new StringValue( token.image ) ); } + select = PlainSelect() | - escape=Expression() { result.setEscape(escape); } + select = Values() + | + select = ParenthesedSelect() ) - ] + { + selects.add(select); + } + )+ + + [ LOOKAHEAD(2) orderByElements=OrderByElements() {list.setOrderByElements(orderByElements);} ] + [ LOOKAHEAD() limit = LimitWithOffset() { list.setLimit(limit); } ] + [ LOOKAHEAD() offset = Offset() { list.setOffset(offset); } ] + [ LOOKAHEAD(, { limit==null }) limit = LimitWithOffset() { list.setLimit(limit); } ] + [ LOOKAHEAD() fetch = Fetch() { list.setFetch(fetch); } ] + [ LOOKAHEAD( ) withIsolation = WithIsolation() { list.setIsolation(withIsolation); } ] + { - result.setLeftExpression(leftExpression); - result.setRightExpression(rightExpression); - linkAST(result,jjtThis); - return result; + if ( selects.get(selects.size()-1) instanceof PlainSelect ) { + PlainSelect ps = (PlainSelect)selects.get(selects.size()-1); + if (ps.getOrderByElements() != null) { + list.setOrderByElements(ps.getOrderByElements()); + list.setLimit(ps.getLimit()); + list.setOffset(ps.getOffset()); + ps.setOrderByElements(null); + ps.setLimit(null); + ps.setOffset(null); + } + if (ps.getFetch() != null) { + list.setFetch(ps.getFetch()); + ps.setFetch(null); + } + if (ps.getIsolation() != null) { + list.setIsolation(ps.getIsolation()); + ps.setIsolation(null); + } + } + list.setBracketsOpsAndSelects(selects,operations); + return list; } } -Expression SimilarToExpression(Expression leftExpression) #SimilarToExpression: +List> WithList(): { - SimilarToExpression result = new SimilarToExpression(); - Expression rightExpression = null; + List> withItemsList = new ArrayList>(); + WithItem with = null; } { - [ { result.setNot(true); } ] - - rightExpression=SimpleExpression() - [ LOOKAHEAD(2) token= { result.setEscape((new StringValue(token.image)).getValue()); }] - { - result.setLeftExpression(leftExpression); - result.setRightExpression(rightExpression); - linkAST(result,jjtThis); - return result; - } + with=WithItem() { withItemsList.add(with); } + ( "," with=WithItem() { withItemsList.add(with); } )* + + { return withItemsList; } } -Expression IsDistinctExpression(Expression leftExpression) #IsDistinctExpression: +WithItem WithItem() #WithItem: { - IsDistinctExpression result = new IsDistinctExpression(); - Expression rightExpression = null; + boolean recursive = false; + boolean materialized = false; + boolean usingNot = false; + String name = null; + List> selectItems = null; + WithFunctionDeclaration withFunctionDeclaration = null; + ParenthesedStatement statement = null; + WithSearchClause withSearchClause = null; + WithItem withItem; } { - [ { result.setNot(true); } ] - rightExpression=SimpleExpression() - { - result.setLeftExpression(leftExpression); - result.setRightExpression(rightExpression); - linkAST(result,jjtThis); - return result; - } + ( + LOOKAHEAD(2) + withFunctionDeclaration = WithFunctionDeclaration() + { + withItem = new WithItem().withWithFunctionDeclaration(withFunctionDeclaration); + } + | + ( + [ LOOKAHEAD(2) { recursive = true; } ] + name=RelObjectName() + [ "(" selectItems=SelectItemsList() ")" ] + + [ LOOKAHEAD(2) [ { usingNot = true; } ] { materialized = true; } ] + ( + LOOKAHEAD(2) statement = ParenthesedSelect() + | + LOOKAHEAD(2) statement = ParenthesedInsert() + | + LOOKAHEAD(2) statement = ParenthesedUpdate() + | + LOOKAHEAD(2) statement = ParenthesedDelete() + ) + { + withItem = new WithItem(statement, new Alias(name, false)) + .withRecursive(recursive, usingNot, materialized) + .withWithItemList(selectItems); + } + ) + ) + [ withSearchClause = WithSearchClause() { withItem.setSearchClause(withSearchClause); } ] + { + return withItem; + } } -Expression IsNullExpression(Expression leftExpression): +WithSearchClause WithSearchClause() #WithSearchClause: { - IsNullExpression result = new IsNullExpression(); + Token orderingToken; + ExpressionList searchColumns = new ExpressionList(); + Column searchColumn = null; + String sequenceColumnName; } { - ( - [ { result.setNot(true); } ] { result.setUseIsNull(true); } - | { result.setUseIsNull(true); result.setUseNotNull(true); } - | [ { result.setNot(true); } ] - ) + + ( orderingToken= | orderingToken= ) + + + searchColumn = Column() { searchColumns.add(searchColumn); } + ( "," searchColumn = Column() { searchColumns.add(searchColumn); } )* + + sequenceColumnName = RelObjectName() { - result.setLeftExpression(leftExpression); - return result; + return new WithSearchClause( + "BREADTH".equalsIgnoreCase(orderingToken.image) + ? WithSearchClause.SearchOrder.BREADTH + : WithSearchClause.SearchOrder.DEPTH, + searchColumns, sequenceColumnName); } } -Expression IsBooleanExpression(Expression leftExpression): +WithFunctionDeclaration WithFunctionDeclaration() #WithFunctionDeclaration: { - IsBooleanExpression result = new IsBooleanExpression(); + String functionName; + List parameters = new ArrayList(); + String returnType; + Expression returnExpression; + WithFunctionParameter parameter; } { - ( - [ { result.setNot(true); } ] ( { result.setIsTrue(true); } | { result.setIsTrue(false); }) - ) - + functionName = RelObjectName() + "(" + [ parameter=WithFunctionParameter() { parameters.add(parameter); } + ( "," parameter=WithFunctionParameter() { parameters.add(parameter); } )* + ] + ")" + returnType = RelObjectName() + returnExpression = Expression() { - result.setLeftExpression(leftExpression); - return result; + return new WithFunctionDeclaration(functionName, parameters, returnType, returnExpression); } } -Expression ExistsExpression(): +WithFunctionParameter WithFunctionParameter() #WithFunctionParameter: { - ExistsExpression result = new ExistsExpression(); - Expression rightExpression = null; + String name; + String type = null; + String arrayType = null; } { - rightExpression=SimpleExpression() + name = RelObjectName() + ( + LOOKAHEAD(2) "<" arrayType = RelObjectName() ">" + | + type = RelObjectName() + ) { - result.setRightExpression(rightExpression); - return result; + if (arrayType != null) { + type = "ARRAY<" + arrayType + ">"; + } + return new WithFunctionParameter(name, type); } } -Expression MemberOfExpression(Expression leftExpression): +List> ColumnSelectItemsList(): { - MemberOfExpression result; - Expression rightExpression = null; + List> selectItemsList = null; + SelectItem selectItem = null; } { - rightExpression=Expression() - { - return new MemberOfExpression(leftExpression, rightExpression ); - } + selectItem=SelectItem() { selectItemsList = new ArrayList>(); selectItemsList.add(selectItem); } + ( + LOOKAHEAD(2) "," selectItem=SelectItem() + { + selectItemsList.add(selectItem); + } + )* + + { return selectItemsList; } } -ExpressionList ExpressionList() #ExpressionList: +List> SelectItemsList(): { - ExpressionList expressionList; + List> selectItemsList = null; + SelectItem selectItem = null; } { + selectItem=SelectItem() { selectItemsList = new ArrayList>(); selectItemsList.add(selectItem); } ( - LOOKAHEAD(3, { getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expressionList = ComplexExpressionList() - | - LOOKAHEAD(3) expressionList = SimpleExpressionList() - | - LOOKAHEAD(3) expressionList = ParenthesedExpressionList() - ) - { - // Avoid redundant ExpressionLists containing only one ParenthesedExpressionList - // return the Parenthesed Sub ExpressionList instead - // Same for ParenthesedExpressionList containing only 1 ExpressionList - - if ( expressionList.size() == 1 && expressionList.get(0) instanceof ExpressionList ) { - ExpressionList subList = (ExpressionList) expressionList.get(0); - if (expressionList instanceof ParenthesedExpressionList) { - if (subList instanceof ParenthesedExpressionList) { - return expressionList; - } else { - return new ParenthesedExpressionList(subList); - } - } else { - if (subList instanceof ParenthesedExpressionList) { - return new ParenthesedExpressionList(subList); - } else { - return subList; - } - } + LOOKAHEAD(2) "," selectItem=SelectItem() + { + selectItemsList.add(selectItem); } - return expressionList; - } + )* + + { return selectItemsList; } } -ParenthesedExpressionList ParenthesedExpressionList(): +FunctionAllColumns FunctionAllColumns() #FunctionAllColumns: { - ExpressionList expressions=new ExpressionList(); + Function function; } { - "(" - ( - LOOKAHEAD({ getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expressions = ComplexExpressionList() - | - expressions = SimpleExpressionList() - )? - ")" + "(" ( "(" )* function=Function() ")" ( ")" )* "." "*" { - return new ParenthesedExpressionList(expressions); + return new FunctionAllColumns(function); } } -ExpressionList SimpleExpressionList(): +SelectItem SelectItem() #SelectItem: { - ExpressionList expressions = new ExpressionList(); - Expression expr; + Expression expression; + Alias alias = null; } { - expr=SimpleExpression() { expressions.add(expr); } - ( LOOKAHEAD(2, {!interrupted} ) "," ( LOOKAHEAD(2) expr=LambdaExpression() | expr=SimpleExpression()) { expressions.add(expr); } )* + // @fixme: Oracle's SEQUENCE.nextval is parsed as COLUMN with a name part nextval + // @todo: parse a proper SEQUENCE instead of a COLUMN + ( + LOOKAHEAD( 3 ) expression = ConnectByPriorOperator() + | + LOOKAHEAD( 3 ) expression = XorExpression() + | + LOOKAHEAD( 3 ) expression = ConcatExpression() + | + expression=Expression() + ) + [ LOOKAHEAD({ isAliasAhead() }) alias=Alias() ] { - return expressions; + SelectItem selectItem = new SelectItem(expression, alias); + linkAST(selectItem,jjtThis); + return selectItem; } } - -ExpressionList ColumnList(): +/** + * Parses the AllColumns-Pattern '*'. + * + * If the allowAdditions is true, it parses additional Keywords. + */ +AllColumns AllColumns(boolean allowAdditions): { - ExpressionList expressions = new ExpressionList(); - Column expr; + ParenthesedExpressionList exceptColumns = null; + List> replaceExpressions = null; + String exceptKeyword=null; + Token tk; } { - expr=Column() { expressions.add(expr); } - ( LOOKAHEAD(2) "," expr=Column() { expressions.add(expr); } )* + "*" + // BigData allows EXCEPT, DuckDB allows EXCLUDE + [ LOOKAHEAD(2, { allowAdditions }) ( tk= | tk= ) exceptColumns = ParenthesedColumnList() { exceptKeyword=tk.image; } ] + // BigData allows REPLACE + [ LOOKAHEAD(2, { allowAdditions }) "(" replaceExpressions = SelectItemsList() ")" ] + { - return expressions; + return new AllColumns(exceptColumns, replaceExpressions, exceptKeyword); } } -ParenthesedExpressionList ParenthesedColumnList(): +/** + * Parses the AllTableColumns-Pattern 'table.*' + * + * If the allowAdditions is true, it parses additional Keywords. + */ +AllTableColumns AllTableColumns(boolean allowAdditions): { - ExpressionList expressions; + Table table = null; + AllColumns allColumns; } { - "(" expressions = ColumnList() ")" + table=Table() "." allColumns=AllColumns(allowAdditions) { - return new ParenthesedExpressionList(expressions); + return new AllTableColumns(table, allColumns); } + } -ExpressionList ComplexExpressionList(): -{ - ExpressionList expressions = new ExpressionList(); - Expression expr; +Alias Alias(): +{ String name = ""; + Token token = null; + boolean useAs = false; + Alias alias; + String colname; + ColDataType colDataType = null; } { ( - LOOKAHEAD(2) expr=OracleNamedFunctionParameter() - | expr=Expression() - ) - { - expressions.add(expr); - } + LOOKAHEAD(3) ( + // Aliases with AS and Columns, but optional identifier: + // SELECT fun(x) AS (a,b,c) + // SELECT fun(x) AS T(a,b,c) + + [ LOOKAHEAD(2) name=RelObjectName() ] + { alias = new Alias(name, true ); } - ( - LOOKAHEAD(2, {!interrupted}) "," + "(" { List list = new ArrayList(); } + colname = RelObjectName() [ colDataType = ColDataType() ] { list.add(new Alias.AliasColumn(colname, colDataType)); } + ( + "," { colDataType=null; } colname = RelObjectName() [ colDataType = ColDataType()] { list.add(new Alias.AliasColumn(colname, colDataType)); } + )* + ")" { alias.setAliasColumns(list); } + + ) + | ( - LOOKAHEAD(2) expr=OracleNamedFunctionParameter() - | LOOKAHEAD(2) expr=LambdaExpression() - | expr=Expression() - ) { expressions.add(expr); } - )* + // Aliases with identifier but optional AS and Columns: + // SELECT fun(x) AS T + // SELECT fun(x) T + // SELECT fun(x) T(a,b,c) - { - return expressions; - } + [ { useAs = true; } ] + ( name=RelObjectName() | token= { name=token.image; } ) + { alias = new Alias(name,useAs); } + + [ LOOKAHEAD(2) "(" { List list = new ArrayList(); } + colname = RelObjectName() [ colDataType = ColDataType() ] { list.add(new Alias.AliasColumn(colname, colDataType)); } + ("," { colDataType=null; } colname = RelObjectName() [ colDataType = ColDataType()] { list.add(new Alias.AliasColumn(colname, colDataType)); } )* + ")" { alias.setAliasColumns(list); } ] + + ) + ) + { return alias; } } -// @Todo: Refactor this with proper SQL:2016 functions according to https://manticore-projects.com/SQL2016Parser/syntax.html#character-value-function -// substring(expr1 from expr2) -// substring(expr1 from expr2 for expr3) -// trim(expr1 from expr2) <-- Superceded by TrimFunction() below -// position(expr1 in expr2) -// overlay(expr1 placing expr2 from expr3) -// overlay(expr1 placing expr2 from expr3 for expr4) -// expr1 has already been consumed -NamedExpressionList NamedExpressionListExprFirst(): +void SQLServerHint(SQLServerHints hints) : { + String str; +} { - NamedExpressionList retval = new NamedExpressionList(); - List expressions = new ArrayList(); - List names = new ArrayList(); - Expression expr1 = null; - Expression expr2 = null; - Expression expr3 = null; - Expression expr4 = null; - Token tk2 = null; - Token tk3 = null; - Token tk4 = null; + "(" str = RelObjectName() ")" { hints.setIndexName(str); } + | + { hints.withNoLock(); } +} + +SQLServerHints SQLServerHints() : { + SQLServerHints hints = new SQLServerHints(); } { - expr1=SimpleExpression() - (tk2=|tk2=|tk2=) + "(" + SQLServerHint(hints) ("," SQLServerHint(hints) )* + ")" + { return hints; } +} + +MySQLIndexHint MySQLIndexHint(): +{ + Token actionToken = null; + Token indexToken = null; + String indexName = null; + List indexNameList = new ArrayList(); +} +{ + ( + actionToken = + | actionToken = + | actionToken = + | actionToken = + ) + + ( + indexToken = + | indexToken = + ) + + "(" + indexName = RelObjectName() { indexNameList.add(indexName); } + ("," indexName= RelObjectName() { indexNameList.add(indexName); })* + ")" { - names.add(""); - expressions.add(expr1); - names.add(tk2.image); + return new MySQLIndexHint(actionToken.image, indexToken.image, indexNameList); } - ( - expr2=SimpleExpression() { expressions.add(expr2);} - ( - (tk3=|tk3=) - expr3=SimpleExpression() {names.add(tk3.image); expressions.add(expr3);} - ( - (tk4=) - expr4=SimpleExpression() {names.add(tk4.image); expressions.add(expr4);} - )? - )? - ) - - { - retval.setNames(names); - retval.setExpressions(expressions); - return retval; - } } -Expression ComparisonItem() : +SelectItem FunctionItem(): { - Expression retval = null; + Alias alias = null; + Function function; } { - ( - LOOKAHEAD( AnyComparisonExpression() ) retval=AnyComparisonExpression() - | LOOKAHEAD(3) retval=SimpleExpression() - | LOOKAHEAD(3) retval=ParenthesedExpressionList() - | LOOKAHEAD(3) retval=RowConstructor() - | retval=PrimaryExpression() - ) - - { - return retval; - } + function=Function() + [ LOOKAHEAD({ isAliasAhead() }) alias=Alias() ] + { return new SelectItem(function, alias); } } -Expression AnyComparisonExpression() : +ExpressionList PivotForColumns(): { - AnyType anyType; - Select select; + ExpressionList columns; + Column column; } { ( - ( - { anyType = AnyType.ANY; } - | { anyType = AnyType.SOME; } - | { anyType = AnyType.ALL; } - ) - - select = ParenthesedSelect() + columns = ParenthesedColumnList() + | + column = Column() { columns = new ExpressionList(column); } ) - { - return new AnyComparisonExpression(anyType, select); - } + { return columns; } } -Expression SimpleExpression(): +List> PivotFunctionItems(): { - Expression retval = null; - UserVariable user = null; - Token operation = null; + List> functionItems = new ArrayList>(); + SelectItem item; } { + item = FunctionItem() {functionItems.add(item);} + ( "," item = FunctionItem() {functionItems.add(item);} )* + { return functionItems; } +} - ( - [ LOOKAHEAD(UserVariable() ("=" | ":=") ) - user = UserVariable() - ( operation = "=" | operation = ":=" ) - ] +SelectItem> ExpressionListItem(): +{ + ExpressionList expressionList; + Alias alias = null; +} +{ + expressionList=ParenthesedExpressionList() + [ LOOKAHEAD({ isAliasAhead() }) alias=Alias() ] + { return new SelectItem>(expressionList, alias); } +} - ( - retval=ConcatExpression() - ) +List>> PivotMultiInItems(): +{ + List>> retval = new ArrayList>>(); + SelectItem> item; +} +{ + item = ExpressionListItem() {retval.add(item);} + ("," item = ExpressionListItem() {retval.add(item);} )* + { return retval; } +} + +Pivot Pivot(): +{ + Pivot retval = new Pivot(); + List> functionItems; + ExpressionList forColumns; + List> singleInItems = null; + List>> multiInItems = null; + Alias alias = null; +} +{ + "(" functionItems = PivotFunctionItems() + forColumns = PivotForColumns() + "(" + (LOOKAHEAD(3) singleInItems = SelectItemsList() + | multiInItems = PivotMultiInItems() ) + ")" + ")" + [ LOOKAHEAD({ isAliasAhead() }) alias = Alias() ] + { + retval.setFunctionItems(functionItems); + retval.setForColumns(forColumns); + retval.setSingleInItems(singleInItems); + retval.setMultiInItems(multiInItems); + retval.setAlias(alias); + return retval; + } +} + +PivotXml PivotXml(): +{ + PivotXml retval = new PivotXml(); + List> functionItems; + ExpressionList forColumns; + List> singleInItems = null; + List>> multiInItems = null; + Select inSelect = null; +} +{ + "(" functionItems = PivotFunctionItems() + forColumns = PivotForColumns() + "(" + ( + LOOKAHEAD(2) { retval.setInAny(true); } | + LOOKAHEAD(1) inSelect = Select() | + LOOKAHEAD(2) singleInItems =SelectItemsList() | + multiInItems = PivotMultiInItems() ) + ")" + ")" { - if (user != null) { - VariableAssignment assignment = new VariableAssignment(); - assignment.setVariable(user); - assignment.setOperation(operation.image); - assignment.setExpression(retval); - return assignment; - } else - return retval; + retval.setFunctionItems(functionItems); + retval.setForColumns(forColumns); + retval.setSingleInItems(singleInItems); + retval.setMultiInItems(multiInItems); + retval.setInSelect(inSelect); + return retval; } } -Expression ConcatExpression(): +UnPivot UnPivot(): { - Expression result = null; - Expression leftExpression = null; - Expression rightExpression = null; + UnPivot retval = new UnPivot(); + ExpressionList unpivotClause; + ExpressionList unpivotForClause; + List> unpivotInClause; + Alias alias = null; } { - leftExpression=BitwiseAndOr() { result = leftExpression; } - (LOOKAHEAD(3) - /* Oracle allows space between the bars. */ - rightExpression=BitwiseAndOr() - { - Concat binExp = new Concat(); - binExp.setLeftExpression(leftExpression); - binExp.setRightExpression(rightExpression); - result = binExp; - leftExpression = result; - } - )* + + [ ( { retval.setIncludeNulls(true); } + | { retval.setIncludeNulls(false); } ) ] + "(" unpivotClause = PivotForColumns() + unpivotForClause = PivotForColumns() + "(" + unpivotInClause = SelectItemsList() + ")" + ")" + [ LOOKAHEAD({ isAliasAhead() }) alias = Alias() ] + { + retval.setUnPivotClause(unpivotClause); + retval.setUnPivotForClause(unpivotForClause); + retval.setUnPivotInClause(unpivotInClause); + retval.setAlias(alias); + return retval; + } +} - { return result; } +List
IntoClause(): +{ + List
tables = new ArrayList
(); + Table table; +} +{ + table=Table() { tables.add(table); } ( LOOKAHEAD(2) "," table=Table() { tables.add(table); } )* + { + return tables; + } } -Expression BitwiseAndOr(): +MySqlSelectIntoClause MySqlSelectIntoClause(MySqlSelectIntoClause.Position position): { - Expression result = null; - Expression leftExpression = null; - Expression rightExpression = null; + MySqlSelectIntoClause intoClause = new MySqlSelectIntoClause().withPosition(position); + Token token; } { - leftExpression=AdditiveExpression() { result = leftExpression; } + ( - LOOKAHEAD(2) ( - "|" { result = new BitwiseOr(); } - | - "&" { result = new BitwiseAnd(); } - | - "<<" { result = new BitwiseLeftShift(); } - | - ">>" { result = new BitwiseRightShift(); } - ) - - rightExpression=AdditiveExpression() - - { - BinaryExpression binExp = (BinaryExpression) result; - binExp.setLeftExpression(leftExpression); - binExp.setRightExpression(rightExpression); - leftExpression = result; - } - )* - - { return result; } + { intoClause.setType(MySqlSelectIntoClause.Type.OUTFILE); } + token= { intoClause.setFileName(new StringValue(token.image)); } + MySqlSelectIntoOutfileTail(intoClause) + | + { intoClause.setType(MySqlSelectIntoClause.Type.DUMPFILE); } + token= { intoClause.setFileName(new StringValue(token.image)); } + ) + { + return intoClause; + } } -Expression AdditiveExpression(): +void MySqlSelectIntoOutfileTail(MySqlSelectIntoClause intoClause): { - Expression result = null; - Expression leftExpression = null; - Expression rightExpression = null; + Token token; } { - leftExpression=MultiplicativeExpression() { result = leftExpression; } - ( LOOKAHEAD(2) - ("+" { result = new Addition(); } - | "-" { result = new Subtraction(); } ) - - rightExpression=MultiplicativeExpression() - { - BinaryExpression binExp = (BinaryExpression) result; - binExp.setLeftExpression(leftExpression); - binExp.setRightExpression(rightExpression); - leftExpression = result; - } - )* - - { return result; } + ( + LOOKAHEAD( ) + + (token= | token=) + { intoClause.setCharacterSet(token.image); } + ( + LOOKAHEAD(( | )) + MySqlSelectIntoFieldsClause(intoClause) + [ LOOKAHEAD() MySqlSelectIntoLinesClause(intoClause) ] + | + LOOKAHEAD() + MySqlSelectIntoLinesClause(intoClause) + | + { } + ) + | + LOOKAHEAD(( | )) + MySqlSelectIntoFieldsClause(intoClause) + [ LOOKAHEAD() MySqlSelectIntoLinesClause(intoClause) ] + | + LOOKAHEAD() + MySqlSelectIntoLinesClause(intoClause) + | + { } + ) } -Expression MultiplicativeExpression(): +void MySqlSelectIntoFieldsClause(MySqlSelectIntoClause intoClause): { - Expression result = null; - Expression leftExpression = null; - Expression rightExpression = null; + Token token; } { ( - leftExpression=BitwiseXor() + { intoClause.setFieldsKeyword(MySqlSelectIntoClause.FieldsKeyword.FIELDS); } + | { intoClause.setFieldsKeyword(MySqlSelectIntoClause.FieldsKeyword.COLUMNS); } ) - { result = leftExpression; } ( - LOOKAHEAD(2) ("*" { result = new Multiplication(); } - | "/" { result = new Division(); } - | { result = new IntegerDivision(); } - | "%" { result = new Modulo(); } - ) - - rightExpression=BitwiseXor() - - { - BinaryExpression binExp = (BinaryExpression) result; - binExp.setLeftExpression(leftExpression); - binExp.setRightExpression(rightExpression); - leftExpression = result; - } - )* - { return result; } + LOOKAHEAD( ) + token= + { intoClause.setFieldsTerminatedBy(new StringValue(token.image)); } + ( + LOOKAHEAD(( | )) + [ { intoClause.setFieldsOptionallyEnclosed(true); } ] + token= + { intoClause.setFieldsEnclosedBy(new StringValue(token.image)); } + [ LOOKAHEAD( ) + token= + { intoClause.setFieldsEscapedBy(new StringValue(token.image)); } + ] + | + LOOKAHEAD( ) + token= + { intoClause.setFieldsEscapedBy(new StringValue(token.image)); } + | + { } + ) + | + LOOKAHEAD(( | )) + [ { intoClause.setFieldsOptionallyEnclosed(true); } ] + token= + { intoClause.setFieldsEnclosedBy(new StringValue(token.image)); } + [ LOOKAHEAD( ) + token= + { intoClause.setFieldsEscapedBy(new StringValue(token.image)); } + ] + | + LOOKAHEAD( ) + token= + { intoClause.setFieldsEscapedBy(new StringValue(token.image)); } + | + { } + ) } -Expression BitwiseXor(): +void MySqlSelectIntoLinesClause(MySqlSelectIntoClause intoClause): { - Expression result = null; - Expression leftExpression = null; - Expression rightExpression = null; + Token token; } { - leftExpression=PrimaryExpression() { result = leftExpression; } + ( - "^" - rightExpression=PrimaryExpression() - { - BitwiseXor binExp = new BitwiseXor(); - binExp.setLeftExpression(leftExpression); - binExp.setRightExpression(rightExpression); - result = binExp; - leftExpression = result; - } - )* + LOOKAHEAD( ) + token= + { intoClause.setLinesStartingBy(new StringValue(token.image)); } + [ LOOKAHEAD( ) + token= + { intoClause.setLinesTerminatedBy(new StringValue(token.image)); } + ] + | + LOOKAHEAD( ) + token= + { intoClause.setLinesTerminatedBy(new StringValue(token.image)); } + | + { } + ) +} - { return result; } +FromItem ParenthesedFromItem(): +{ + ParenthesedFromItem ParenthesedFromItem = new ParenthesedFromItem(); + FromItem fromItem; + List joins = null; } +{ + "(" + fromItem = FromItem() + [ joins=JoinsList() ] + ")" -Expression ArrayExpression(Expression obj): { - Expression expr; - Expression idxExpr = null; - Expression startExpr = null; - Expression stopExpr = null; -} { - "[" + { + return ParenthesedFromItem.withFromItem(fromItem).withJoins(joins); + } +} + +FromItem FromItem() #FromItem: +{ + FromItem fromItem = null; + FromItem fromItem2 = null; + SampleClause sampleClause; + Pivot pivot = null; + UnPivot unpivot = null; + Alias alias = null; + MySQLIndexHint indexHint = null; + SQLServerHints sqlServerHints = null; + Select select; + + String timeTravelStr = null; +} +{ + ( + LOOKAHEAD(3, { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) fromItem = Values() + | + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("JSON_TABLE") + && getToken(2).kind == OPENING_BRACKET + }) fromItem=TableFunction() + | + LOOKAHEAD({ + getToken(1).kind == K_LATERAL + && getToken(2).kind == S_IDENTIFIER + && getToken(2).image.equalsIgnoreCase("JSON_TABLE") + && getToken(3).kind == OPENING_BRACKET + }) fromItem=TableFunction() + | + LOOKAHEAD({ (isFunctionAhead() && getToken(1).kind != K_LATERAL) + || (getToken(1).kind == K_LATERAL && getToken(2).kind != OPENING_BRACKET) }) + fromItem=TableFunction() + | + LOOKAHEAD(3) fromItem=Table() + | + LOOKAHEAD(ParenthesedFromItem()) fromItem = ParenthesedFromItem() + | + LOOKAHEAD(3, { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) ( + fromItem=ParenthesedSelect() + [ LOOKAHEAD(2) pivot=Pivot() { fromItem.setPivot(pivot); } ] + [ LOOKAHEAD(2) unpivot=UnPivot() { fromItem.setUnPivot(unpivot); } ] + ) + | + fromItem=LateralSubSelect() + | + LOOKAHEAD(2, { Dialect.EXASOL.name().equals(getAsString(Feature.dialect)) }) fromItem=SubImport() { fromItem = new ParenthesedFromItem(fromItem); } + | + LOOKAHEAD({ getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) fromItem=Select() + ) + + [ LOOKAHEAD({ isAliasAhead() }) alias=Alias() { fromItem.setAlias(alias); } ] + [ + LOOKAHEAD(2, {fromItem instanceof Table }) timeTravelStr = TimeTravelAfterAlias() + { ((Table) fromItem).setTimeTravelStrAfterAlias(timeTravelStr); } + ] + [ LOOKAHEAD(2) sampleClause = SampleClause() { fromItem.setSampleClause(sampleClause); } ] + [ LOOKAHEAD(2) unpivot=UnPivot() { fromItem.setUnPivot(unpivot); } ] + [ LOOKAHEAD(2) ( LOOKAHEAD(2) pivot=PivotXml() | pivot=Pivot() ) { fromItem.setPivot(pivot); } ] + [ + LOOKAHEAD(2) + ( + indexHint = MySQLIndexHint() { + if (fromItem instanceof Table) + ((Table) fromItem).setHint(indexHint); + } + | + sqlServerHints = SQLServerHints() { + if (fromItem instanceof Table) + ((Table) fromItem).setSqlServerHints(sqlServerHints); + } + ) + ] + { + linkAST(fromItem,jjtThis); + return fromItem; + } +} + +List JoinsList(): +{ + List joinsList = new ArrayList(); + Join join = null; +} +{ + ( LOOKAHEAD(2) join=JoinerExpression() { joinsList.add(join); } )+ + { + return joinsList; + } +} + +JoinHint JoinHint(): +{ + Token token; +} +{ + ( + token = + | + token = + | + token = + | + token = + ) + { + return new JoinHint(token.image); + } +} + +Join JoinerExpression() #JoinerExpression: +{ + Join join = new Join(); + FromItem right = null; + Expression onExpression = null; + Column tableColumn; + List columns = null; + KSQLJoinWindow joinWindow = null; + JoinHint joinHint = null; +} +{ + [ { join.setGlobal(true); } ] + [ { join.setAny(true); } | { join.setAll(true); } ] + [ { join.setNatural(true); } ] + + [ + ( + { join.setLeft(true); } [ { join.setSemi(true); } | { join.setOuter(true); } | { join.setAny(true); } | { join.setAll(true); } ] + | + ( + { join.setRight(true); } + | + { join.setFull(true); } + ) [ { join.setOuter(true); } | { join.setAny(true); } | { join.setAll(true); } ] + | + { join.setInner(true); } + ) + | + { join.setCross(true); } + | + { join.setOuter(true); } + ] + + ( + ( + [ joinHint=JoinHint() {join.setJoinHint(joinHint); } ] + + [ { join.setFetch(true); } ] + ) + | + "," { join.setSimple(true); } ( { join.setOuter(true); } )? + | + { join.setStraight(true); } + | + {join.setApply(true); } + ) + + right=FromItem() + + [ + LOOKAHEAD(2) ( + [ "(" joinWindow = JoinWindow() ")" {join.setJoinWindow(joinWindow);} ] + ( onExpression=Expression() { join.addOnExpression(onExpression); } + ( LOOKAHEAD(2) onExpression=Expression() { join.addOnExpression(onExpression); } )* + ) + | + ( + "(" tableColumn=Column() { columns = new ArrayList(); columns.add(tableColumn); } + ( "," tableColumn=Column() { columns.add(tableColumn); } ) * + ")" { join.setUsingColumns(columns); } + ) + ) + ] + { + linkAST(join,jjtThis); + join.setFromItem(right); + return join; + } + +} + +KSQLJoinWindow JoinWindow(): +{ + KSQLJoinWindow retval = new KSQLJoinWindow(); + boolean beforeAfter; + Token beforeDurationToken = null; + Token beforeTimeUnitToken = null; + Token afterDurationToken = null; + Token afterTimeUnitToken = null; +} +{ + beforeDurationToken= (beforeTimeUnitToken= | beforeTimeUnitToken=) + [ "," afterDurationToken= (afterTimeUnitToken= | afterTimeUnitToken=) ] + { + if (afterDurationToken == null) { + retval.setDuration(Long.parseLong(beforeDurationToken.image)); + retval.setTimeUnit(KSQLWindow.TimeUnit.from(beforeTimeUnitToken.image)); + retval.setBeforeAfterWindow(false); + return retval; + } + retval.setBeforeDuration(Long.parseLong(beforeDurationToken.image)); + retval.setBeforeTimeUnit(KSQLWindow.TimeUnit.from(beforeTimeUnitToken.image)); + retval.setAfterDuration(Long.parseLong(afterDurationToken.image)); + retval.setAfterTimeUnit(KSQLWindow.TimeUnit.from(afterTimeUnitToken.image)); + retval.setBeforeAfterWindow(true); + return retval; + } +} + +KSQLWindow KSQLWindowClause(): +{ + KSQLWindow retval = null; + Token sizeDurationToken = null; + Token sizeTimeUnitToken = null; + Token advanceDurationToken = null; + Token advanceTimeUnitToken = null; +} +{ + + { + retval=new KSQLWindow(); + retval.setHoppingWindow(false); + retval.setSessionWindow(false); + retval.setTumblingWindow(false); + } + ( + "(" + sizeDurationToken= sizeTimeUnitToken= "," + advanceDurationToken= advanceTimeUnitToken= ")" + { + retval.setHoppingWindow(true); + } | + "(" sizeDurationToken= sizeTimeUnitToken= ")" + { + retval.setSessionWindow(true); + } | + "(" sizeDurationToken= sizeTimeUnitToken= ")" + { + retval.setTumblingWindow(true); + } + ) + { + retval.setSizeDuration(Long.parseLong(sizeDurationToken.image)); + retval.setSizeTimeUnit(KSQLWindow.TimeUnit.from(sizeTimeUnitToken.image)); + if (advanceDurationToken != null) { + retval.setAdvanceDuration(Long.parseLong(advanceDurationToken.image)); + retval.setAdvanceTimeUnit(KSQLWindow.TimeUnit.from(advanceTimeUnitToken.image)); + } + return retval; + } +} + +Expression WhereClause(): +{ + Expression retval = null; +} +{ + retval=Expression() + { return retval; } +} + +Expression PreWhereClause(): +{ + Expression retval = null; +} +{ + retval=Expression() + { return retval; } +} + +OracleHierarchicalExpression OracleHierarchicalQueryClause(): +{ + OracleHierarchicalExpression result = new OracleHierarchicalExpression(); + Expression expr; +} +{ + ( + ( + expr=XorExpression() {result.setStartExpression(expr);} + [ { result.setNoCycle(true); } ] expr=XorExpression() + { + result.setConnectExpression(expr); + } + ) + | + ( + [ { result.setNoCycle(true); } ] expr=XorExpression() + { + result.setConnectExpression(expr); + result.setConnectFirst(true); + } + [ LOOKAHEAD(2) expr=XorExpression() {result.setStartExpression(expr);} ] + ) + ) + { + return result; + } +} + +PreferringClause PreferringClause(): +{ + Expression result = null; +} +{ + + result=PreferenceTerm() + + { + PreferringClause preferring = new PreferringClause(result); + return preferring; + } +} + +Expression PreferenceTerm(): +{ + Expression retval = null; +} +{ + // recursively build preferenceterm inside Plus + // like Expression -> XorExpression -> OrExpression -> ... + + retval=Plus() + + { + return retval; + } +} + +Expression Plus(): +{ + Expression left, right, result; +} +{ + left=PriorTo() { result = left; } + ( + LOOKAHEAD(2) + + right=PriorTo() + { + result = new Plus(left, right); + left = result; + } + )* + { + return result; + } +} + +Expression PriorTo(): +{ + Expression left, right, result; +} +{ + ( + LOOKAHEAD(3) left=PreferenceTermTerminal() + | + "(" left=PreferenceTerm() ")" { left = new ParenthesedExpressionList(left); } + ) + { result = left; } + + ( + LOOKAHEAD(2) + ( + LOOKAHEAD(3) right=PreferenceTermTerminal() + | + "(" right=PreferenceTerm() ")" { left = new ParenthesedExpressionList(right); } + ) + { + result = new PriorTo(left, right); + left = result; + } + )* + { + return result; + } +} + +Expression PreferenceTermTerminal(): +{ + Expression retval; +} +{ + ( + LOOKAHEAD(2) retval=HighExpression() + | + LOOKAHEAD(2) retval=LowExpression() + | + LOOKAHEAD(2) retval=Inverse() + | + retval=Condition() + ) + + { + return retval; + } +} + +Expression HighExpression() #HighExpression: +{ + Expression result; +} +{ + + result=Expression() + + { + HighExpression high = new HighExpression(result); + linkAST(high,jjtThis); + return high; + } +} + +Expression LowExpression() #LowExpression: +{ + Expression result; +} +{ + + result=Expression() + + { + LowExpression low = new LowExpression(result); + linkAST(low,jjtThis); + return low; + } +} + +Expression Inverse() #Inverse: +{ + Expression result; +} +{ + + "(" result=PreferenceTerm() ")" + + { + Inverse inverse = new Inverse(result); + linkAST(inverse,jjtThis); + return inverse; + } +} + +GroupByElement GroupByColumnReferences(): +{ + Expression columnReference; + GroupByElement groupBy = new GroupByElement(); + Expression expr; + ExpressionList list; + Token token; +} +{ + + ( + LOOKAHEAD(2) ( + + "(" + list = GroupingSet() { groupBy.addGroupingSet(list); } + ( LOOKAHEAD(2) "," list = GroupingSet() { groupBy.addGroupingSet(list); })* + ")" + ) + | + ( + list = ExpressionList() { groupBy.setGroupByExpressions(list); } + ( + LOOKAHEAD(2) + "(" + list = GroupingSet() { groupBy.addGroupingSet(list); } + ( LOOKAHEAD(2) "," list = GroupingSet() { groupBy.addGroupingSet(list); })* + ")" + )? + [ LOOKAHEAD(2) { groupBy.setMysqlWithRollup(true); } ] + ) + ) + { + return groupBy; + } +} + +ExpressionList GroupingSet(): +{ + ExpressionList list; + Expression expression; +} +{ + ( + LOOKAHEAD(2) list = ParenthesedExpressionList() + | + expression = SimpleExpression() { list = new ExpressionList(expression); } + ) + { + return list; + } +} + +Expression Having(): +{ + Expression having = null; +} +{ + having=Expression() + { + return having; + } +} + +Expression Qualify(): +{ + Expression qualify = null; +} +{ + qualify=Expression() + { + return qualify; + } +} + +List OrderByElements(): +{ + List orderByList = new ArrayList(); + OrderByElement orderByElement = null; +} +{ + [ ] orderByElement=OrderByElement() { orderByList.add(orderByElement); } + ( LOOKAHEAD(2) "," orderByElement=OrderByElement() { orderByList.add(orderByElement); } )* + { + return orderByList; + } +} + +OrderByElement OrderByElement(): +{ + OrderByElement orderByElement = new OrderByElement(); + Expression columnReference = null; + Token collateToken = null; +} +{ + columnReference = Expression() + [ LOOKAHEAD() (collateToken= | collateToken=) { columnReference = new CollateExpression(columnReference, collateToken.image); } ] + [ LOOKAHEAD(2) ( | ( { orderByElement.setAsc(false); } )) { orderByElement.setAscDescPresent(true); } ] + [ LOOKAHEAD(2) + [ LOOKAHEAD(2) ( + { orderByElement.setNullOrdering(OrderByElement.NullOrdering.NULLS_FIRST); } + | + { orderByElement.setNullOrdering(OrderByElement.NullOrdering.NULLS_LAST); } + ) + ] + ] + [ LOOKAHEAD(2) { orderByElement.setMysqlWithRollup(true); } ] + { + orderByElement.setExpression(columnReference); + return orderByElement; + } +} + +JdbcParameter JdbcParameter() : { + Token tk; + JdbcParameter retval; +} +{ + ( tk="?" | tk= ) + { retval = new JdbcParameter(++jdbcParameterIndex, false, tk.image); } + + [ LOOKAHEAD(2) token = { retval.setUseFixedIndex(true); retval.setIndex(Integer.valueOf(token.image)); } ] + + { return retval; } +} + + +Limit LimitWithOffset() #LimitWithOffset: +{ + Limit limit = new Limit(); + Expression firstExpression; + Expression secondExpression; +} +{ + + ( + LOOKAHEAD(3) firstExpression = ParenthesedSelect() + | + firstExpression = Expression() + ) + ( + // MySQL: LIMIT offset, row_count + "," + secondExpression = Expression() + { + limit.setOffset(firstExpression); + limit.setRowCount(secondExpression); + } + | + // PostgreSQL: LIMIT row_count + { + limit.setRowCount(firstExpression); + } + ) + { + linkAST(limit, jjtThis); + return limit; + } +} + +Limit PlainLimit() #PlainLimit: +{ + Limit limit = new Limit(); + Expression rowCountExpression; +} +{ + // mysql-postgresql-> LIMIT (row_count | ALL | NULL) + + ( + LOOKAHEAD(3) rowCountExpression = ParenthesedSelect() + | + rowCountExpression = Expression() + ) + { + limit.setRowCount(rowCountExpression); + linkAST(limit,jjtThis); + return limit; + } +} + +/** + * Clickhouse LIMIT BY + * @see SELECT Query + */ +Limit LimitBy(): +{ + Limit limit; + ExpressionList byExpressions; +} +{ + limit = LimitWithOffset() + byExpressions = ExpressionList() + { + limit.setByExpressions(byExpressions); + return limit; + } +} + +Offset Offset(): +{ + Offset offset = new Offset(); + Expression offsetExpression; +} +{ + ( + // postgresql-> OFFSET offset + // sqlserver-oracle-> OFFSET offset (ROW | ROWS) + + offsetExpression=Expression() { offset.setOffset( offsetExpression ); } + + [ LOOKAHEAD(2) ( { offset.setOffsetParam("ROWS"); } | { offset.setOffsetParam("ROW"); })] + + ) + { + return offset; + } +} + +Fetch Fetch(): +{ + Fetch fetch = new Fetch(); + Token token = null; + Expression expression; + List fetchParameters = new ArrayList(); +} +{ + ( + LOOKAHEAD(3) ( + ( { fetch.setFetchParamFirst(true); } | ) + ( + { fetch.addFetchParameter("ROWS"); } + | + { fetch.addFetchParameter("ROW"); } + ) + ( + { fetch.addFetchParameter("ONLY"); } + | + { fetch.addFetchParameter("WITH TIES"); } + ) + ) + | + ( + ( { fetch.setFetchParamFirst(true); } | ) + + // Expression is optional according to https://www.h2database.com/html/commands.html#select + expression = Expression() { fetch.setExpression(expression); } + [ { fetch.addFetchParameter("PERCENT"); } ] + ( + ( + { fetch.addFetchParameter("ROWS"); } + | + { fetch.addFetchParameter("ROW"); } + ) + + ( + { fetch.addFetchParameter("ONLY"); } + | + { fetch.addFetchParameter("WITH TIES"); } + ) + ) + ) + ) + { + return fetch; + } +} + +WithIsolation WithIsolation(): +{ + WithIsolation withIsolation = new WithIsolation(); + Token token = null; + JdbcParameter jdbc; +} +{ + + token= + { withIsolation.setIsolation(token.image); + return withIsolation; + } +} + +OptimizeFor OptimizeFor(): +{ + Token token; + LongValue value; +} +{ + token= + { + value = new LongValue(token.image); + return new OptimizeFor(value.getValue()); + } +} + +// according to http://technet.microsoft.com/en-us/library/ms189463.aspx +Top Top() #Top: +{ + Top top = new Top(); + Token token = null; + Expression expr = null; + JdbcParameter jdbc = null; +} +{ + + ( + token= { top.setExpression(new LongValue(token.image)); } + | + jdbc = JdbcParameter() { top.setExpression(jdbc); } + | + ":" { top.setExpression(new JdbcNamedParameter()); } + [ LOOKAHEAD(2) token = { ((JdbcNamedParameter)top.getExpression()).setName(token.image); } ] + | + "(" + expr=AdditiveExpression() + { + top.setExpression(expr); + top.setParenthesis(true); + } + ")" + ) + [ LOOKAHEAD(2) { top.setPercentage(true); } ] + [ LOOKAHEAD(2) { top.setWithTies(true); } ] + { + linkAST(top,jjtThis); + return top; + } +} + +// according to http://www-01.ibm.com/support/knowledgecenter/SSGU8G_12.1.0/com.ibm.sqls.doc/ids_sqs_0156.htm +Skip Skip(): +{ + Skip skip = new Skip(); + Token token = null; + JdbcParameter jdbc; +} +{ + + ( + token= { skip.setRowCount(Long.parseLong(token.image)); } + | + token= { skip.setVariable(token.image); } + | + jdbc = JdbcParameter() { skip.setJdbcParameter(jdbc); } + ) + { + return skip; + } +} + +JAVACODE +OracleHint getOracleHint() { + OracleHint hint = null; + Token tok = getToken(1); + // Retrieve first comment (if any) prior next token + if (tok.specialToken != null) { + tok = tok.specialToken; + while (tok.specialToken != null) tok = tok.specialToken; + // Check if it matches Hint pattern? + if (OracleHint.isHintMatch(tok.image)) { + hint = new OracleHint(); + hint.setComment(tok.image); + } + } + return hint; +} + +First First(): +{ + First first = new First(); + Token token = null; + JdbcParameter jdbc; +} +{ + ( + { first.setKeyword(First.Keyword.FIRST); } + | + { first.setKeyword(First.Keyword.LIMIT); } + ) + ( + token= { first.setRowCount(Long.parseLong(token.image)); } + | + token= { first.setVariable(token.image); } + | + jdbc = JdbcParameter() { first.setJdbcParameter(jdbc); } + ) + { + return first; + } +} + + +Expression Expression() #Expression : +{ + Expression expression = null; +} +{ + expression=XorExpression() + { + linkAST(expression,jjtThis); + return expression; + } +} + +Expression XorExpression(): +{ + Expression left, right, result; +} +{ + left=OrExpression() { result = left; } + ( LOOKAHEAD(2) + + right=OrExpression() + { + result = new XorExpression(left, right); + left = result; + } + )* + { + return result; + } +} + +Expression OrExpression(): +{ + Expression left, right, result; +} +{ + left=AndExpression() { result = left; } + ( LOOKAHEAD(2) + + right=AndExpression() + { + result = new OrExpression(left, right); + left = result; + } + )* + { + return result; + } + +} + +Expression AndExpression() : +{ + Expression left, right, result; +} +{ + // ParenthesedExpressionList always delegates to ComplexExpressionList which + // uses full Expression(), so Condition() can handle ALL parenthesized content + // (including boolean operators like LIKE/IN/BETWEEN/IS inside parens). + // No speculative parsing or XorExpression fallback needed. + left=Condition() + { result = left; } + + ( LOOKAHEAD(2) + { boolean useOperator = false; } + ( | {useOperator=true;} ) + + right=Condition() + + { + result = new AndExpression(left, right); + ((AndExpression)result).setUseOperator(useOperator); + left = result; + } + )* + { + return result; + } +} + +Expression Condition(): +{ + Expression result; + Expression left; + boolean not = false; + boolean exclamationMarkNot = false; + int oraclePrior = EqualsTo.NO_ORACLE_PRIOR; + int oracleJoin = EqualsTo.NO_ORACLE_JOIN; +} +{ + [ LOOKAHEAD(2) ( { not=true; } | "!" { not=true; exclamationMarkNot=true; })] + ( + result=ExistsExpression() + | + [ LOOKAHEAD(2) { oraclePrior = EqualsTo.ORACLE_PRIOR_START; } ] + left=SimpleExpression() { result = left; } + + // Consume Oracle (+) once, before dispatching + [ + LOOKAHEAD("(" "+" ")") + "(" "+" ")" + { + oracleJoin = EqualsTo.ORACLE_JOIN_RIGHT; + if (left instanceof Column) { + ((Column) left).setOldOracleJoinSyntax(oracleJoin); + } + } + ] + + // Single guard: only enter if next token can start a condition suffix + [ + LOOKAHEAD({ isConditionSuffixAhead() }) + ( + LOOKAHEAD({ isComparisonOperatorAhead() }) + result = RegularConditionRHS(left, oracleJoin) + | LOOKAHEAD(2) result = OverlapsCondition(left) + | LOOKAHEAD(3) result=InExpression(left) + | LOOKAHEAD(3) result=ExcludesExpression(left) + | LOOKAHEAD(3) result=IncludesExpression(left) + | LOOKAHEAD(2) result=Between(left) + | LOOKAHEAD(2) result = MemberOfExpression(left) + | LOOKAHEAD(3) result=IsNullExpression(left) + | LOOKAHEAD(3) result=IsBooleanExpression(left) + | LOOKAHEAD(3) result=IsUnknownExpression(left) + | LOOKAHEAD(2) result=LikeExpression(left) + | LOOKAHEAD(3) result=IsDistinctExpression(left) + | result=SimilarToExpression(left) + ) + ] + ) + { + if (oraclePrior == EqualsTo.ORACLE_PRIOR_START + && result instanceof SupportsOldOracleJoinSyntax) { + ((SupportsOldOracleJoinSyntax) result).setOraclePriorPosition(oraclePrior); + } + return not ? new NotExpression(result, exclamationMarkNot) : result; + } +} + +Expression RegularConditionRHS(Expression leftExpression, int oracleJoinRight) #RegularCondition: +{ + Expression result = null; + Expression rightExpression; + int oracleJoin = EqualsTo.NO_ORACLE_JOIN; + int oraclePrior = EqualsTo.NO_ORACLE_PRIOR; + Token token; +} +{ + // Only consume (+) here if it wasn't already consumed by Condition + [ LOOKAHEAD("(" "+" ")") "(" "+" ")" { oracleJoin = EqualsTo.ORACLE_JOIN_RIGHT; } ] + + ( + LOOKAHEAD(2) + ">" { result = new GreaterThan(); } + | "<" { result = new MinorThan(); } + | "=" { result = new EqualsTo(); } + | token= { result = new GreaterThanEquals(token.image); } + | token= { result = new MinorThanEquals(token.image); } + | token= { result = new NotEqualsTo(token.image); } + | token= { result = new NotEqualsTo(token.image); } + | token= { result = new NotEqualsTo(token.image); } + | "*=" { result = new TSQLLeftJoin(); } + | "=*" { result = new TSQLRightJoin(); } + | token= { result = new DoubleAnd(); } + | token= { result = new Contains(); } + | token= { result = new ContainedBy(); } + | "@@" { result = new Matches(); } + | "~" { result = new RegExpMatchOperator(RegExpMatchOperatorType.MATCH_CASESENSITIVE); } + | "~*" { result = new RegExpMatchOperator(RegExpMatchOperatorType.MATCH_CASEINSENSITIVE); } + | "!~" { result = new RegExpMatchOperator(RegExpMatchOperatorType.NOT_MATCH_CASESENSITIVE); } + | "!~*" { result = new RegExpMatchOperator(RegExpMatchOperatorType.NOT_MATCH_CASEINSENSITIVE); } + | "@>" { result = new JsonOperator("@>"); } + | "<@" { result = new JsonOperator("<@"); } + | "?" { result = new JsonOperator("?"); } + | "?|" { result = new JsonOperator("?|"); } + | "?&" { result = new JsonOperator("?&"); } + | { result = new JsonOperator("||"); } + | "-" { result = new JsonOperator("-"); } + | "-#" { result = new JsonOperator("-#"); } + | "<->" { result = new GeometryDistance("<->"); } + | "<#>" { result = new GeometryDistance("<#>"); } + | { result = new CosineSimilarity(); } + ) + + ( LOOKAHEAD(2) rightExpression=ComparisonItem() { oraclePrior = EqualsTo.ORACLE_PRIOR_END; } + | rightExpression=ComparisonItem() ) + + [ LOOKAHEAD(2) "(" "+" ")" { oracleJoin = EqualsTo.ORACLE_JOIN_LEFT; } ] + + { + BinaryExpression regCond = (BinaryExpression) result; + regCond.setLeftExpression(leftExpression); + regCond.setRightExpression(rightExpression); + + if (oracleJoin > 0) + ((SupportsOldOracleJoinSyntax) result).setOldOracleJoinSyntax(oracleJoin); + + if (oraclePrior != EqualsTo.NO_ORACLE_PRIOR) + ((SupportsOldOracleJoinSyntax) result).setOraclePriorPosition(oraclePrior); + } + + { + linkAST(result, jjtThis); + return result; + } +} + +Expression OverlapsCondition(Expression leftExpression): +{ + ExpressionList right; +} +{ + + right = ParenthesedExpressionList() + { + ExpressionList left; + if (leftExpression instanceof ExpressionList) { + left = (ExpressionList) leftExpression; + } else { + left = new ExpressionList(leftExpression); + } + return new OverlapsCondition(left, right); + } +} + +Expression SQLCondition(): +{ + Expression result; + Expression left; +} +{ + ( + result=ExistsExpression() + | left = SimpleExpression() { result = left; } + [ + LOOKAHEAD(2) ( + LOOKAHEAD(2, ) result=OverlapsCondition(left) + | + LOOKAHEAD(3, {!interrupted}) result=InExpression(left) + | + LOOKAHEAD(3) result=ExcludesExpression(left) + | + LOOKAHEAD(3) result=IncludesExpression(left) + | + LOOKAHEAD(2) result=Between(left) + | + result = MemberOfExpression(left) + | + LOOKAHEAD(3) result=IsNullExpression(left) + | + LOOKAHEAD(3) result=IsBooleanExpression(left) + | + LOOKAHEAD(3) result=IsUnknownExpression(left) + | + LOOKAHEAD(2) result=LikeExpression(left) + | + LOOKAHEAD(3) result=IsDistinctExpression(left) + | + result=SimilarToExpression(left) + ) + ] + ) + { return result; } +} + +Expression InExpression(Expression leftExpression) #InExpression : +{ + Token token; + int oldOracleJoin = 0; + boolean usingNot = false; + boolean usingGlobal = false; + Expression rightExpression; +} +{ + [ "(" "+" ")" { oldOracleJoin=EqualsTo.ORACLE_JOIN_RIGHT; } ] + + [ { usingGlobal=true; } ] + [ { usingNot=true; } ] + + ( + LOOKAHEAD(2) token= { rightExpression = new StringValue(token.image); } + | + rightExpression = PrimaryExpression() + ) + { + InExpression inExpression = new InExpression(leftExpression, rightExpression) + .withOldOracleJoinSyntax(oldOracleJoin) + .withNot(usingNot) + .setGlobal(usingGlobal); + linkAST(inExpression,jjtThis); + return inExpression; + } +} + +Expression IncludesExpression(Expression leftExpression) #IncludesExpression : +{ + Token token; + Expression rightExpression; +} +{ + (rightExpression = ParenthesedExpressionList()) + { + IncludesExpression includesExpression = new IncludesExpression(leftExpression, rightExpression); + + linkAST(includesExpression,jjtThis); + return includesExpression; + } +} + +Expression ExcludesExpression(Expression leftExpression) #ExcludesExpression : +{ + Token token; + Expression rightExpression; +} +{ + (rightExpression = ParenthesedExpressionList()) + { + ExcludesExpression excludesExpression = new ExcludesExpression(leftExpression, rightExpression); + + linkAST(excludesExpression,jjtThis); + return excludesExpression; + } +} + +Expression Between(Expression leftExpression) : +{ + Between result = new Between(); + Expression betweenExpressionStart = null; + Expression betweenExpressionEnd = null; +} +{ + [ { result.setNot(true); }] + + [ + LOOKAHEAD(2) ( + { result.setUsingSymmetric(true); } + | + { result.setUsingAsymmetric(true); } + ) + ] + ( + LOOKAHEAD({ isParenthesedSelectAhead() }) betweenExpressionStart = ParenthesedSelect() + | + betweenExpressionStart = SimpleExpression() + [ + LOOKAHEAD({ isComparisonOperatorAhead() }) + betweenExpressionStart = RegularConditionRHS(betweenExpressionStart, EqualsTo.NO_ORACLE_JOIN) + ] + ) + + + ( + LOOKAHEAD({ isParenthesedSelectAhead() }) betweenExpressionEnd = ParenthesedSelect() + | + betweenExpressionEnd = SimpleExpression() + [ + LOOKAHEAD({ isComparisonOperatorAhead() }) + betweenExpressionEnd = RegularConditionRHS(betweenExpressionEnd, EqualsTo.NO_ORACLE_JOIN) + ] + ) + + { + result.setLeftExpression(leftExpression); + result.setBetweenExpressionStart(betweenExpressionStart); + result.setBetweenExpressionEnd(betweenExpressionEnd); + return result; + } +} + +Expression LikeExpression(Expression leftExpression) #LikeExpression: +{ + LikeExpression result = new LikeExpression(); + Expression rightExpression = null; + Expression escape; + Token token; +} +{ + [ { result.setNot(true); } ] + ( + token = + | token = + | token = + | token = + | token = + | token = + | token = + | token = + | token = + | token = + | token = + ) { result.setLikeKeyWord( LikeExpression.KeyWord.from(token.image)); } + [ LOOKAHEAD(2) {result.setUseBinary(true); } ] + rightExpression=SimpleExpression() + [ LOOKAHEAD(2) + ( + LOOKAHEAD(2) token = { result.setEscape( new StringValue( token.image ) ); } + | + escape=Expression() { result.setEscape(escape); } + ) + ] + { + result.setLeftExpression(leftExpression); + result.setRightExpression(rightExpression); + linkAST(result,jjtThis); + return result; + } +} + +Expression SimilarToExpression(Expression leftExpression) #SimilarToExpression: +{ + SimilarToExpression result = new SimilarToExpression(); + Expression rightExpression = null; +} +{ + [ { result.setNot(true); } ] + + rightExpression=SimpleExpression() + [ LOOKAHEAD(2) token= { result.setEscape((new StringValue(token.image)).getValue()); }] + { + result.setLeftExpression(leftExpression); + result.setRightExpression(rightExpression); + linkAST(result,jjtThis); + return result; + } +} + +Expression IsDistinctExpression(Expression leftExpression) #IsDistinctExpression: +{ + IsDistinctExpression result = new IsDistinctExpression(); + Expression rightExpression = null; +} +{ + [ { result.setNot(true); } ] + rightExpression=SimpleExpression() + { + result.setLeftExpression(leftExpression); + result.setRightExpression(rightExpression); + linkAST(result,jjtThis); + return result; + } +} + +Expression IsNullExpression(Expression leftExpression): +{ + IsNullExpression result = new IsNullExpression(); +} +{ + ( + [ { result.setNot(true); } ] { result.setUseIsNull(true); } + | { result.setUseIsNull(true); result.setUseNotNull(true); } + | [ { result.setNot(true); } ] + ) + { + result.setLeftExpression(leftExpression); + return result; + } +} + +Expression IsBooleanExpression(Expression leftExpression): +{ + IsBooleanExpression result = new IsBooleanExpression(); +} +{ + ( + [ { result.setNot(true); } ] ( { result.setIsTrue(true); } | { result.setIsTrue(false); }) + ) + + { + result.setLeftExpression(leftExpression); + return result; + } +} + +Expression IsUnknownExpression(Expression leftExpression): +{ + IsUnknownExpression result = new IsUnknownExpression(); +} +{ + ( + [ { result.setNot(true); } ] + ) + + { + result.setLeftExpression(leftExpression); + return result; + } +} + +Expression ExistsExpression(): +{ + ExistsExpression result = new ExistsExpression(); + Expression rightExpression = null; +} +{ + rightExpression=SimpleExpression() + { + result.setRightExpression(rightExpression); + return result; + } +} + +Expression MemberOfExpression(Expression leftExpression): +{ + MemberOfExpression result; + Expression rightExpression = null; +} +{ + rightExpression=Expression() + { + return new MemberOfExpression(leftExpression, rightExpression ); + } +} + +ExpressionList ExpressionList() #ExpressionList: +{ + ExpressionList expressionList; +} +{ + ( + LOOKAHEAD(3, { !interrupted }) expressionList = ComplexExpressionList() + | + LOOKAHEAD(3) expressionList = SimpleExpressionList() + | + LOOKAHEAD(3) expressionList = ParenthesedExpressionList() + ) + { + // Avoid redundant ExpressionLists containing only one ParenthesedExpressionList + // return the Parenthesed Sub ExpressionList instead + // Same for ParenthesedExpressionList containing only 1 ExpressionList + + if ( expressionList.size() == 1 && expressionList.get(0) instanceof ExpressionList ) { + ExpressionList subList = (ExpressionList) expressionList.get(0); + if (expressionList instanceof ParenthesedExpressionList) { + if (subList instanceof ParenthesedExpressionList) { + return expressionList; + } else { + return new ParenthesedExpressionList(subList); + } + } else { + if (subList instanceof ParenthesedExpressionList) { + return new ParenthesedExpressionList(subList); + } else { + return subList; + } + } + } + return expressionList; + } +} + +ParenthesedExpressionList ParenthesedExpressionList(): +{ + ExpressionList expressions=new ExpressionList(); +} +{ + "(" + ( + LOOKAHEAD({ !interrupted }) expressions = ComplexExpressionList() + | + expressions = SimpleExpressionList() + )? + ")" + { + return new ParenthesedExpressionList(expressions); + } +} + +ExpressionList SimpleExpressionList(): +{ + ExpressionList columns; + ExpressionList expressions = new ExpressionList(); + Expression expr; +} +{ + expr=SimpleExpression() { expressions.add(expr); } + ( + LOOKAHEAD(2, {!interrupted} ) "," + ( + LOOKAHEAD( 7 ) expr=LambdaExpression() + | + expr=SimpleExpression() + ) + { + expressions.add(expr); + } + )* + { + return expressions; + } +} + + +ExpressionList ColumnList(): +{ + ExpressionList expressions = new ExpressionList(); + Column expr; +} +{ + expr=Column() { expressions.add(expr); } + ( LOOKAHEAD(2) "," expr=Column() { expressions.add(expr); } )* + { + return expressions; + } +} + +ParenthesedExpressionList ParenthesedColumnList(): +{ + ExpressionList expressions; +} +{ + "(" expressions = ColumnList() ")" + { + return new ParenthesedExpressionList(expressions); + } +} + +ExpressionList ComplexExpressionList(): +{ + ExpressionList columns; + ExpressionList expressions = new ExpressionList(); + Expression expr; +} +{ + ( + LOOKAHEAD(2) expr=OracleNamedFunctionParameter() + | + LOOKAHEAD(2) expr=PostgresNamedFunctionParameter() + | + expr=Expression() + ) + { + expressions.add(expr); + } + + ( + LOOKAHEAD(2, {!interrupted}) "," + ( + LOOKAHEAD(2) expr=OracleNamedFunctionParameter() + | + LOOKAHEAD(2) expr=PostgresNamedFunctionParameter() + | + LOOKAHEAD(7) expr=LambdaExpression() + | + expr=Expression() + ) { expressions.add(expr); } + )* + + { + return expressions; + } +} + +// @Todo: Refactor this with proper SQL:2016 functions according to https://manticore-projects.com/SQL2016Parser/syntax.html#character-value-function +// substring(expr1 from expr2) +// substring(expr1 from expr2 for expr3) +// trim(expr1 from expr2) <-- Superceded by TrimFunction() below +// position(expr1 in expr2) +// overlay(expr1 placing expr2 from expr3) +// overlay(expr1 placing expr2 from expr3 for expr4) +// expr1 has already been consumed +NamedExpressionList NamedExpressionListExprFirst(): +{ + NamedExpressionList retval = new NamedExpressionList(); + List expressions = new ArrayList(); + List names = new ArrayList(); + Expression expr1 = null; + Expression expr2 = null; + Expression expr3 = null; + Expression expr4 = null; + Token tk2 = null; + Token tk3 = null; + Token tk4 = null; +} +{ + expr1=SimpleExpression() + (tk2=|tk2=|tk2=) + { + names.add(""); + expressions.add(expr1); + names.add(tk2.image); + } + ( + expr2=SimpleExpression() { expressions.add(expr2);} + ( + (tk3=|tk3=) + expr3=SimpleExpression() {names.add(tk3.image); expressions.add(expr3);} + ( + (tk4=) + expr4=SimpleExpression() {names.add(tk4.image); expressions.add(expr4);} + )? + )? + ) + + { + retval.setNames(names); + retval.setExpressions(expressions); + return retval; + } +} + +Expression ComparisonItem() : +{ + Expression retval = null; +} +{ + ( + LOOKAHEAD( 6 ) retval=AnyComparisonExpression() + | + LOOKAHEAD( 3 ) retval=SimpleExpression() + | + LOOKAHEAD( 3 ) retval=ParenthesedExpressionList() + | + LOOKAHEAD( 3 ) retval=RowConstructor() + | + retval=PrimaryExpression() + ) + + { + return retval; + } +} + +Expression AnyComparisonExpression() : +{ + AnyType anyType; + Select select; +} +{ + ( + { anyType = AnyType.ANY; } + | + { anyType = AnyType.SOME; } + | + { anyType = AnyType.ALL; } + ) + select = ParenthesedSelect() + { + return new AnyComparisonExpression(anyType, select); + } +} + +Expression SimpleExpression(): +{ + Expression retval = null; + UserVariable user = null; + Token operation = null; +} +{ + [ LOOKAHEAD( 5 ) user = UserVariable() ( operation = "=" | operation = ":=" ) ] + retval=ConcatExpression() + { + if (user != null) { + VariableAssignment assignment = new VariableAssignment(); + assignment.setVariable(user); + assignment.setOperation(operation.image); + assignment.setExpression(retval); + return assignment; + } else + return retval; + } +} + +Expression ConcatExpression(): +{ + Expression result = null; + Expression leftExpression = null; + Expression rightExpression = null; +} +{ + leftExpression=BitwiseAndOr() { result = leftExpression; } + (LOOKAHEAD(3) + /* Oracle allows space between the bars. */ + rightExpression=BitwiseAndOr() + { + Concat binExp = new Concat(); + binExp.setLeftExpression(leftExpression); + binExp.setRightExpression(rightExpression); + result = binExp; + leftExpression = result; + } + )* + + { return result; } +} + +Expression BitwiseAndOr(): +{ + Expression result = null; + Expression leftExpression = null; + Expression rightExpression = null; +} +{ + leftExpression=AdditiveExpression() { result = leftExpression; } + ( + LOOKAHEAD(2) ( + "|" { result = new BitwiseOr(); } + | + "&" { result = new BitwiseAnd(); } + | + "<<" { result = new BitwiseLeftShift(); } + | + ">>" { result = new BitwiseRightShift(); } + ) + + rightExpression=AdditiveExpression() + + { + BinaryExpression binExp = (BinaryExpression) result; + binExp.setLeftExpression(leftExpression); + binExp.setRightExpression(rightExpression); + leftExpression = result; + } + )* + + { return result; } +} + +Expression AdditiveExpression(): +{ + Expression result = null; + Expression leftExpression = null; + Expression rightExpression = null; +} +{ + leftExpression=MultiplicativeExpression() { result = leftExpression; } + ( LOOKAHEAD(2) + ("+" { result = new Addition(); } + | "-" { result = new Subtraction(); } ) + + rightExpression=MultiplicativeExpression() + { + BinaryExpression binExp = (BinaryExpression) result; + binExp.setLeftExpression(leftExpression); + binExp.setRightExpression(rightExpression); + leftExpression = result; + } + )* + + { return result; } +} + +Expression MultiplicativeExpression(): +{ + Expression result = null; + Expression leftExpression = null; + Expression rightExpression = null; +} +{ + ( + leftExpression=BitwiseXor() + ) + { result = leftExpression; } + ( + LOOKAHEAD(2) ("*" { result = new Multiplication(); } + | "/" { result = new Division(); } + | { result = new IntegerDivision(); } + | "%" { result = new Modulo(); } + ) + + rightExpression=BitwiseXor() + + { + BinaryExpression binExp = (BinaryExpression) result; + binExp.setLeftExpression(leftExpression); + binExp.setRightExpression(rightExpression); + leftExpression = result; + } + )* + { return result; } +} + +Expression BitwiseXor(): +{ + Expression result = null; + Expression leftExpression = null; + Expression rightExpression = null; +} +{ + leftExpression=PrimaryExpression() { result = leftExpression; } + ( LOOKAHEAD(2) + "^" + rightExpression=PrimaryExpression() + { + BitwiseXor binExp = new BitwiseXor(); + binExp.setLeftExpression(leftExpression); + binExp.setRightExpression(rightExpression); + result = binExp; + leftExpression = result; + } + )* + + { return result; } +} + +Expression ArrayExpression(Expression obj): { + Expression expr; + Expression idxExpr = null; + Expression startExpr = null; + Expression stopExpr = null; +} { + "[" [LOOKAHEAD(3) idxExpr = SimpleExpression()] [ (":" { startExpr=idxExpr; idxExpr=null; }) @@ -4398,6 +7588,7 @@ Expression ArrayExpression(Expression obj): { Expression PrimaryExpression() #PrimaryExpression: { Expression retval = null; + Expression expression = null; CastExpression castExpr = null; TimezoneExpression timezoneExpr = null; Expression timezoneRightExpr = null; @@ -4410,518 +7601,1161 @@ Expression PrimaryExpression() #PrimaryExpression: boolean dateExpressionAllowed = true; ExpressionList list; - final List> jsonIdents = new ArrayList>(); + final List> jsonIdents = new ArrayList>(); +} +{ + [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] + [sign="+" | sign="-" | sign="~"] + ( + { retval = new NullValue(); } + + | LOOKAHEAD(3, {!interrupted}) retval=CaseWhenExpression() + + | LOOKAHEAD(2, {!interrupted}) retval=CharacterPrimary() + + | LOOKAHEAD(6, {!interrupted}) retval=ImplicitCast() + + | retval = JdbcParameter() + + | LOOKAHEAD(2) retval =JdbcNamedParameter() + + | LOOKAHEAD(3) retval=UserVariable() + + | LOOKAHEAD(2, {!interrupted}) retval=NumericBind() + + | LOOKAHEAD(4 , {!interrupted}) retval=ExtractExpression() + + | retval=XMLSerializeExpr() + + | LOOKAHEAD(3, { !interrupted}) retval = JsonFunction() + + | LOOKAHEAD(3, { !interrupted}) retval = JsonAggregateFunction() + + | LOOKAHEAD(3, { !interrupted}) retval = FullTextSearch() + + | LOOKAHEAD(2, {!interrupted}) retval= CastExpression() + + | LOOKAHEAD({ !interrupted && isFunctionAhead() }) + retval = Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ] + + | LOOKAHEAD(2) retval = DateUnitExpression() + + | LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; } + + | token= { retval = new DoubleValue(token.image); } + + | token= { retval = new LongValue(token.image); } + + | token= { retval = new HexValue(token.image); } + + | LOOKAHEAD(3) retval=AllColumns(true) + + | LOOKAHEAD({ !interrupted && isAllTableColumnsAhead() }) + retval=AllTableColumns(true) + + // See issue #2207 + // there is a huge! performance deterioration from this production + //| LOOKAHEAD(FunctionAllColumns()) retval=FunctionAllColumns() + + // support timestamp expressions + | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new TimeKeyExpression(token.image); } + + | LOOKAHEAD(2, {!interrupted}) retval=DateTimeLiteralExpression() + + | LOOKAHEAD(3 , {!interrupted}) retval=StructType() + + | LOOKAHEAD(3, {!interrupted}) [ "<" type=ColDataType() ">" ] retval=ArrayConstructor(true) { if (type!=null) ((ArrayConstructor) retval).setDataType(type); } + + | LOOKAHEAD(3, {!interrupted}) retval=ArrayConstructor(false) + + | LOOKAHEAD(2, {!interrupted}) retval = NextValExpression() + + | retval=ConnectByRootOperator() + + | retval=ConnectByPriorOperator() + + | LOOKAHEAD(2, { !interrupted && getToken(1).kind == K_KEY && getToken(2).kind != OPENING_BRACKET }) retval=KeyExpression() + + | LOOKAHEAD(2, {!interrupted}) { retval = new AllValue(); } + + | LOOKAHEAD(2, {!interrupted}) retval=Column() + [ + LOOKAHEAD( "(" "+" ")" ("," | ")") ) + "(" "+" ")" { ((Column) retval).setOldOracleJoinSyntax(EqualsTo.ORACLE_JOIN_RIGHT); } + ] + + | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new BooleanValue(token.image); } + + | token= { retval = new StringValue(token.image); linkAST(retval,jjtThis); } + + | "{d" token= "}" { retval = new DateValue(token.image); } + + | "{t" token= "}" { retval = new TimeValue(token.image); } + + | "{ts" token= "}" { retval = new TimestampValue(token.image); } + + | LOOKAHEAD( Select() , { getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=Select() + + | LOOKAHEAD( ParenthesedSelect() , { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=ParenthesedSelect() + + | + ( + list=ParenthesedExpressionList() + // Mutli-Variable Lambda Expression, e. g. + // SELECT map_filter(my_column, (k,v) -> v.my_inner_column = 'some_value') + [ LOOKAHEAD(2) "->" + retval = Expression() + { + retval = LambdaExpression.from(list, retval); + } + ] + + + { + if (list.size() == 1) { + retval = new ParenthesedExpressionList( (Expression) list.getExpressions().get(0)); + } else { + retval = list; + } + } + + + // RowGet Expressions + ( LOOKAHEAD(2) "." tmp=RelObjectName() { retval = new RowGetExpression(retval, tmp); } )* + ) + ) + + [ + LOOKAHEAD(2) (token= | token= | token=) { retval = new CollateExpression(retval, token.image); } + ] + + [ + LOOKAHEAD(2, { dateExpressionAllowed } ) retval = IntervalExpressionWithoutInterval(retval) + ] + + [ LOOKAHEAD(2) retval = ArrayExpression(retval) ] + + ( LOOKAHEAD(2) "::" type=ColDataType() { + castExpr = new CastExpression(); + castExpr.setUseCastKeyword(false); + castExpr.setLeftExpression(retval); + castExpr.setColDataType(type); + retval=castExpr; + } + )* + + // Check for JSON operands + [ + LOOKAHEAD(2) ( + LOOKAHEAD(2) ( + token="->" + | + token=":" + | + token="->>" + | + token="#>" + | + token="#>>" + ) + + ( + LOOKAHEAD({getAsBoolean(Feature.allowComplexParsing) && !interrupted }) expression=Expression() + | + expression=SimpleExpression() + ) + { + jsonIdents.add(new AbstractMap.SimpleEntry(expression, token.image )); + } + )+ + retval = JsonExpression(retval, jsonIdents) + ] + + ( LOOKAHEAD(2) timezoneRightExpr=PrimaryExpression() { + if (timezoneExpr == null) + timezoneExpr = new TimezoneExpression(); + + timezoneExpr.addTimezoneExpression(timezoneRightExpr); + } + )* + + { + if (timezoneExpr != null && !timezoneExpr.getTimezoneExpressions().isEmpty()) { + timezoneExpr.setLeftExpression(retval); + retval=timezoneExpr; + } + if (sign != null) { + retval = new SignedExpression(sign.image.charAt(0), retval); + } + if (not) { + retval = new NotExpression(retval, exclamationMarkNot); + } + linkAST(retval, jjtThis); + return retval; + } +} + +/* https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/hierarchical_query_clause.html + + { CONNECT BY [ NOCYCLE ] condition [ START WITH condition ] + | START WITH condition CONNECT BY [ NOCYCLE ] condition + } + */ + +ConnectByRootOperator ConnectByRootOperator() #ConnectByRootOperator: { + Expression expression; +} +{ + expression = Expression() + { + return new ConnectByRootOperator(expression); + } +} + +ConnectByPriorOperator ConnectByPriorOperator() #ConnectByPriorOperator: { + Expression expression; +} +{ + expression = Expression() + { + return new ConnectByPriorOperator(expression); + } +} + +KeyExpression KeyExpression() #KeyExpression: { + Expression expression; } { - [ { not=true; } | "!" { not=true; exclamationMarkNot=true; } ] - [sign="+" | sign="-" | sign="~"] - ( - { retval = new NullValue(); } - - | LOOKAHEAD(3, {!interrupted}) retval=CaseWhenExpression() - - | LOOKAHEAD(2, {!interrupted}) retval=CharacterPrimary() - - | LOOKAHEAD( ImplicitCast(), {!interrupted}) retval=ImplicitCast() - - | retval = JdbcParameter() - - | LOOKAHEAD(2) retval =JdbcNamedParameter() - - | LOOKAHEAD(3) retval=UserVariable() + expression = Expression() + { + return new KeyExpression(expression); + } +} - | LOOKAHEAD(2, {!interrupted}) retval=NumericBind() - | LOOKAHEAD( ExtractExpression() , {!interrupted}) retval=ExtractExpression() +NextValExpression NextValExpression() : { + ObjectNames data = null; + Token token; +} +{ + token= data = RelObjectNames() + { + return new NextValExpression(data.getNames(), token.image); + } +} - | LOOKAHEAD(3) retval=MySQLGroupConcat() +JdbcNamedParameter JdbcNamedParameter() : { + JdbcNamedParameter parameter = new JdbcNamedParameter(); + String name; + String namePart; +} +{ + (":" | "&" { parameter.setParameterCharacter("&"); } ) + name=IdentifierChain() + { + parameter.setName(name); + return parameter; + } +} - | retval=XMLSerializeExpr() +OracleNamedFunctionParameter OracleNamedFunctionParameter() : { + Token token = null; + String name = null; + Expression expression; +} +{ + ( name=RelObjectNameExt() | token= ) + + expression=Expression() + { + return new OracleNamedFunctionParameter(name != null ? name : token.image, expression); + } +} - | LOOKAHEAD(3, { !interrupted}) retval = JsonFunction() +PostgresNamedFunctionParameter PostgresNamedFunctionParameter() : { + Token token = null; + String name = null; + Expression expression; +} +{ + ( name=RelObjectNameExt() | token= ) + + expression=Expression() + { + return new PostgresNamedFunctionParameter(name != null ? name : token.image, expression); + } +} - | LOOKAHEAD(3, { !interrupted}) retval = JsonAggregateFunction() +UserVariable UserVariable() : { + Token tk; + String varName; +} +{ + tk = varName=IdentifierChain2(tk.image) + { + return new UserVariable(varName); + } +} - | LOOKAHEAD(3, { !interrupted}) retval = FullTextSearch() +NumericBind NumericBind() : { + NumericBind var = new NumericBind(); + Token token; +} +{ + ":" token= + { + var.setBindId(Integer.valueOf(token.image)); + return var; + } +} - | LOOKAHEAD( Function(), { !interrupted}) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ] +DateTimeLiteralExpression DateTimeLiteralExpression() : { + DateTimeLiteralExpression expr = new DateTimeLiteralExpression(); + Token t; +} +{ + t= + { + expr.setType(DateTimeLiteralExpression.DateTime.from(t.image)); + } - | LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; } + ( t= | t= ) + { + expr.setValue(t.image); + return expr; + } +} - | token= { retval = new DoubleValue(token.image); } +DateUnitExpression DateUnitExpression() : { + Token t; +} +{ + t= { return new DateUnitExpression( t.image ); } +} - | token= { retval = new LongValue(token.image); } +RangeExpression RangeExpression(Expression startExpression): +{ + Expression endExpression; +} +{ + ":" endExpression = Expression() + { + return new RangeExpression(startExpression, endExpression); + } +} - | token= { retval = new HexValue(token.image); } +ArrayConstructor ArrayConstructor(boolean arrayKeyword) : { + ExpressionList expList = new ExpressionList(); + ArrayConstructor array = new ArrayConstructor(expList, arrayKeyword); + Expression exp; +} { + "[" + [ + ( + LOOKAHEAD(3) exp = Expression() [ exp=RangeExpression(exp) ] + | + exp = ArrayConstructor(false) + ) { expList.add(exp); } - | LOOKAHEAD(2, {!interrupted}) retval=CastExpression() + ( + "," + ( + LOOKAHEAD(3) exp = Expression() [ exp=RangeExpression(exp) ] + | + exp = ArrayConstructor(false) + ){ expList.add(exp); } + )* + ] + "]" + { return array; } +} +List> StructParameters(): +{ + String parameterName = ""; + ColDataType parameterType = null; + AbstractMap.SimpleEntry parameter = null; + List> parameters = new ArrayList>(); +} +{ + [ LOOKAHEAD(2) parameterName = RelObjectName() ] + parameterType = ColDataType() + { + parameters.add( new AbstractMap.SimpleEntry(parameterName, parameterType) ); + } - // support timestamp expressions - | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new TimeKeyExpression(token.image); } + ( + "," { parameterName=""; } - | LOOKAHEAD(2, {!interrupted}) retval=DateTimeLiteralExpression() + [ LOOKAHEAD(2) parameterName = RelObjectName() ] + parameterType = ColDataType() + { + parameters.add( new AbstractMap.SimpleEntry(parameterName, parameterType) ); + } + )* - | LOOKAHEAD( 3 , {!interrupted}) retval=StructType() + { + return parameters; + } +} - | LOOKAHEAD(3, {!interrupted}) retval=ArrayConstructor(true) +StructType StructType() #StruckType: +{ + StructType.Dialect dialect = StructType.Dialect.BIG_QUERY; + Token tk1; + String keyword = ""; + List> parameters = null; + List> arguments = null; + String id = null; + Expression expression = null; + StructType type; +} +{ + ( + LOOKAHEAD(4) ( + tk1= { keyword = tk1.image; } + "<" parameters = StructParameters() ">" + "(" arguments = SelectItemsList() ")" + ) + | + ( + tk1= { keyword = tk1.image; } + "(" arguments = SelectItemsList() ")" + ) + | + ( + { arguments= new ArrayList>(); dialect = StructType.Dialect.DUCKDB;} + ( id = RelObjectNameExt() | tk1= { id = tk1.image; } ) + expression = Expression() { arguments.add( new SelectItem( expression, id) ); } - | LOOKAHEAD(3, {!interrupted}) retval=ArrayConstructor(false) + ( + "," + ( id = RelObjectNameExt() | tk1= { id = tk1.image; } ) + expression = Expression() { arguments.add( new SelectItem( expression, id) ); } + )* + - | LOOKAHEAD(2, {!interrupted}) retval = NextValExpression() + ( + LOOKAHEAD(2) "::" "(" parameters = StructParameters() ")" + )* + ) + ) + { + type = new StructType(dialect, keyword, parameters, arguments); + linkAST(type,jjtThis); + return type; + } +} - | retval=ConnectByRootOperator() +JsonExpression JsonExpression(Expression expr, List> idents) : { + JsonExpression result = new JsonExpression(expr, idents); + Expression expression; + Token token=null; + ColDataType type = null; + CastExpression castExpr = null; +} +{ - | LOOKAHEAD(2, {!interrupted}) { retval = new AllValue(); } + // chaining JSON Expressions, e.g. + // '{"obj":{"field": "value"}}'::JSON -> 'obj'::TEXT ->> 'field'::TEXT + ( + LOOKAHEAD(2, {!interrupted} ) ( + LOOKAHEAD(2) ( + "::" type=ColDataType() + { + castExpr = new CastExpression(); + castExpr.setUseCastKeyword(false); + castExpr.setLeftExpression(result); + castExpr.setColDataType(type); + expr=castExpr; + } + ) + )+ + { + result = new JsonExpression(expr); + } - | LOOKAHEAD(2, {!interrupted}) retval=Column() + ( + LOOKAHEAD(2) ( + token="->" + | + token=":" + | + token="->>" + | + token="#>" + | + token="#>>" + ) - | token= { retval = new StringValue(token.image); linkAST(retval,jjtThis); } + ( + LOOKAHEAD({getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expression=Expression() + | + expression=SimpleExpression() + ) + { + result.addIdent( expression, token.image ); + } + )* + )* - | "{d" token= "}" { retval = new DateValue(token.image); } + { + result.setExpression(expr); + return result; + } +} - | "{t" token= "}" { retval = new TimeValue(token.image); } +JsonKeyValuePair JsonKeyValuePair(boolean isFirstEntry) : { + Token keyToken; - | "{ts" token= "}" { retval = new TimestampValue(token.image); } + boolean usingKeyKeyword = false; + boolean usingFormatJason = false; + String encoding = null; + boolean isWildcard = false; - | LOOKAHEAD( ParenthesedSelect() , {!interrupted} ) retval=ParenthesedSelect() + Object key = null; + Expression expression = null; + JsonFunctionExpression functionExpression; - | - ( - list=ParenthesedExpressionList() - { - if (list.size() == 1) { - retval = new ParenthesedExpressionList( (Expression) list.getExpressions().get(0)); - } else { - retval = list; - } - } - ["." tmp=RelObjectNameExt() { retval = new RowGetExpression(retval, tmp); }] + JsonKeyValuePairSeparator kvSeparator = JsonKeyValuePairSeparator.NOT_USED; +} +{ + ( + // lookahead because key is a valid column name + LOOKAHEAD(2) ( + { usingKeyKeyword = true; } + ( + keyToken = { key = keyToken.image; } | + key = Column() + ) ) + | + LOOKAHEAD(16) key = AllTableColumns(false) { isWildcard = true; } + | + LOOKAHEAD(2) key = AllColumns(false) { isWildcard = true; } + | + LOOKAHEAD(2) key = Column() + | + LOOKAHEAD({getAsBoolean(Feature.allowExpressionAsJsonObjectKey)}) key = Expression() + | + keyToken = { key = keyToken.image; } ) - [ - LOOKAHEAD(2) token= { retval = new CollateExpression(retval, token.image); } - ] - - [ - LOOKAHEAD(2, { dateExpressionAllowed } ) retval = IntervalExpressionWithoutInterval(retval) + // Optional Separator + Value - Is not allowed with * or t1.* + [ LOOKAHEAD(1, { !isWildcard } ) + ( + { kvSeparator = JsonKeyValuePairSeparator.VALUE; } + | + { kvSeparator = JsonKeyValuePairSeparator.COLON; } + | + LOOKAHEAD({getAsBoolean(Feature.allowCommaAsKeyValueSeparator)}) { kvSeparator = JsonKeyValuePairSeparator.COMMA; } + ) + expression = Expression() ] - [ LOOKAHEAD(2) retval = ArrayExpression(retval) ] - - ( "::" type=ColDataType() { - castExpr = new CastExpression(); - castExpr.setUseCastKeyword(false); - castExpr.setLeftExpression(retval); - castExpr.setColDataType(type); - retval=castExpr; - } - )* - - // Check for JSON operands + // Optional: FORMAT JSON [ ENCODING ... ] - Is not allowed with * or t1.* [ - LOOKAHEAD(2) ( - "->" (token= | token=) { jsonIdents.add(new AbstractMap.SimpleEntry(token.image,"->")); } - | - "->>" (token= | token=) { jsonIdents.add(new AbstractMap.SimpleEntry(token.image,"->>")); } - | - "#>" token= { jsonIdents.add(new AbstractMap.SimpleEntry(token.image,"#>")); } - | - "#>>" token= { jsonIdents.add(new AbstractMap.SimpleEntry(token.image,"#>>")); } - )+ - retval = JsonExpression(retval, jsonIdents) + LOOKAHEAD(1, { !isWildcard } ) { usingFormatJason = true; } + [ encoding = JsonEncoding() ] ] + { + final JsonKeyValuePair keyValuePair = new JsonKeyValuePair( key, expression, usingKeyKeyword, kvSeparator ); + keyValuePair.setUsingFormatJson( usingFormatJason ); + keyValuePair.setEncoding(encoding); + return keyValuePair; + } +} +JsonFunction JsonObjectBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.OBJECT); - ( LOOKAHEAD(2) timezoneRightExpr=PrimaryExpression() { - if (timezoneExpr == null) - timezoneExpr = new TimezoneExpression(); - - timezoneExpr.addTimezoneExpression(timezoneRightExpr); - } - )* + JsonKeyValuePair keyValuePair; + ColDataType dataType; + String encoding; +} +{ + ( "(" + ( + // First Element + LOOKAHEAD(2) keyValuePair = JsonKeyValuePair(true) { result.add(keyValuePair);} + // Next Elements + ( + keyValuePair = JsonKeyValuePair(false) { result.add(keyValuePair); } + )* + )? + [ + ( { result.setOnNullType( JsonAggregateOnNullType.NULL ); } ) + | + ( { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } ) + ] + [ { result.setStrict(true); } ] + [ + ( { result.setUniqueKeysType( JsonAggregateUniqueKeysType.WITH ); } ) + | + ( { result.setUniqueKeysType( JsonAggregateUniqueKeysType.WITHOUT ); } ) + ] + [ + dataType = ColDataType() { result.setReturningType(dataType); } + [ + { result.setReturningFormatJson(true); } + [ encoding = JsonEncoding() { result.setReturningEncoding(encoding); } ] + ] + ] + ")" ) { - if (timezoneExpr != null && !timezoneExpr.getTimezoneExpressions().isEmpty()) { - timezoneExpr.setLeftExpression(retval); - retval=timezoneExpr; - } - if (sign != null) { - retval = new SignedExpression(sign.image.charAt(0), retval); - } - if (not) { - retval = new NotExpression(retval, exclamationMarkNot); - } - linkAST(retval, jjtThis); - return retval; + return result; } } -ConnectByRootOperator ConnectByRootOperator() #ConnectByRootOperator: { - Column column; +JsonFunction JsonArrayBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.ARRAY); + + Expression expression = null; + JsonFunctionExpression functionExpression; + ColDataType dataType; + String encoding; } { - column = Column() + ( "(" + ( + LOOKAHEAD(2) ( + { result.setOnNullType( JsonAggregateOnNullType.NULL ); } + ) + | + expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } + + [ + LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } + [ LOOKAHEAD(2) encoding = JsonEncoding() { functionExpression.setEncoding(encoding); } ] + ] + ( + "," + expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } + [ + LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } + [ LOOKAHEAD(2) encoding = JsonEncoding() { functionExpression.setEncoding(encoding); } ] + ] + )* + )* + + [ + { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } + ] + [ + dataType = ColDataType() { result.setReturningType(dataType); } + [ + { result.setReturningFormatJson(true); } + [ encoding = JsonEncoding() { result.setReturningEncoding(encoding); } ] + ] + ] + ")" ) { - return new ConnectByRootOperator(column); + return result; } } -NextValExpression NextValExpression() : { - ObjectNames data = null; +void JsonKeyword(String expectedKeyword) : { Token token; } { - token= data = RelObjectNames() + token = { - return new NextValExpression(data.getNames(), token.image); + if (!token.image.equalsIgnoreCase(expectedKeyword)) { + throw new ParseException( + "Expected keyword " + expectedKeyword + " but found " + token.image); + } } } -JdbcNamedParameter JdbcNamedParameter() : { - JdbcNamedParameter parameter = new JdbcNamedParameter(); - String name; - String namePart; +String JsonEncoding() : { + Token token; } { - (":" | "&" { parameter.setParameterCharacter("&"); } ) - name=IdentifierChain() + token = { - parameter.setName(name); - return parameter; + if (token.image.equalsIgnoreCase("UTF8")) { + return "UTF8"; + } else if (token.image.equalsIgnoreCase("UTF16")) { + return "UTF16"; + } else if (token.image.equalsIgnoreCase("UTF32")) { + return "UTF32"; + } + throw new ParseException( + "Expected ENCODING value UTF8, UTF16 or UTF32 but found " + token.image); } } -OracleNamedFunctionParameter OracleNamedFunctionParameter() : { - String name; +JsonFunctionExpression JsonValueOrQueryInputExpression() : { Expression expression; + JsonFunctionExpression functionExpression; + String encoding; } { - name=RelObjectNameExt2() - - expression=Expression() + expression = Expression() { functionExpression = new JsonFunctionExpression(expression); } + [ + { functionExpression.setUsingFormatJson(true); } + [ encoding = JsonEncoding() { functionExpression.setEncoding(encoding); } ] + ] { - return new OracleNamedFunctionParameter(name, expression); + return functionExpression; } } -UserVariable UserVariable() : { - UserVariable var = new UserVariable(); - String varName; - String var2; +JsonFunction.JsonOnResponseBehavior JsonValueOnResponseBehavior() : { + JsonFunction.JsonOnResponseBehavior behavior; + Expression expression; } { - ("@" | "@@" { var.setDoubleAdd(true);} ) - varName=IdentifierChain() + ( + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.ERROR); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.NULL); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.EMPTY); + } + | + expression = Expression() + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.DEFAULT, expression); + } + ) { - var.setName(varName); - return var; + return behavior; } } -NumericBind NumericBind() : { - NumericBind var = new NumericBind(); +JsonFunction.JsonOnResponseBehavior JsonQueryOnResponseBehavior() : { + JsonFunction.JsonOnResponseBehavior behavior = null; Token token; } { - ":" token= - { - var.setBindId(Integer.valueOf(token.image)); - return var; - } -} - -DateTimeLiteralExpression DateTimeLiteralExpression() : { - DateTimeLiteralExpression expr = new DateTimeLiteralExpression(); - Token t; -} { - t= { expr.setType(DateTimeLiteralExpression.DateTime.from(t.image)); } - - ( t= | t= ) { expr.setValue(t.image); return expr; } -} - -RangeExpression RangeExpression(Expression startExpression): -{ - Expression endExpression; -} -{ - ":" endExpression = Expression() - { - return new RangeExpression(startExpression, endExpression); - } -} - -ArrayConstructor ArrayConstructor(boolean arrayKeyword) : { - ExpressionList expList = new ExpressionList(); - ArrayConstructor array = new ArrayConstructor(expList, arrayKeyword); - Expression exp; -} { - "[" - [ - ( - LOOKAHEAD(3) exp = Expression() [ exp=RangeExpression(exp) ] - | - exp = ArrayConstructor(false) - ) { expList.add(exp); } - - ( - "," + ( + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.ERROR); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.NULL); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.TRUE); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.FALSE); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.EMPTY); + } + [ ( - LOOKAHEAD(3) exp = Expression() [ exp=RangeExpression(exp) ] + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.EMPTY_ARRAY); + } | - exp = ArrayConstructor(false) - ){ expList.add(exp); } - )* - ] - "]" - { return array; } + JsonKeyword("OBJECT") + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.EMPTY_OBJECT); + } + ) + ] + ) + { + return behavior; + } } -List> StructParameters(): -{ - String parameterName = ""; - ColDataType parameterType = null; - AbstractMap.SimpleEntry parameter = null; - List> parameters = new ArrayList>(); +JsonFunction.JsonOnResponseBehavior JsonExistsOnResponseBehavior() : { + JsonFunction.JsonOnResponseBehavior behavior = null; } { - [ LOOKAHEAD(2) parameterName = RelObjectName() ] - parameterType = ColDataType() - { - parameters.add( new AbstractMap.SimpleEntry(parameterName, parameterType) ); - } - ( - "," { parameterName=""; } - - [ LOOKAHEAD(2) parameterName = RelObjectName() ] - parameterType = ColDataType() + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.TRUE); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.FALSE); + } + | + { - parameters.add( new AbstractMap.SimpleEntry(parameterName, parameterType) ); + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.UNKNOWN); } - )* - + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.ERROR); + } + ) { - return parameters; + return behavior; } } -StructType StructType() #StruckType: -{ - StructType.Dialect dialect = StructType.Dialect.BIG_QUERY; - Token tk1; - String keyword = ""; - List> parameters = null; - List> arguments = null; - String id = null; - Expression expression = null; - StructType type; +JsonFunction JsonExistsBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.EXISTS); + JsonFunctionExpression inputExpression; + Expression expression; + JsonFunction.JsonOnResponseBehavior behavior; } { - ( - LOOKAHEAD(4) ( - tk1= { keyword = tk1.image; } - "<" parameters = StructParameters() ">" - "(" { System.out.println("found arguments!"); } arguments = SelectItemsList() ")" - ) - | - ( - tk1= { keyword = tk1.image; } - "(" arguments = SelectItemsList() ")" - ) - | - ( - { arguments= new ArrayList>(); dialect = StructType.Dialect.DUCKDB;} - - id = RelObjectName() expression = Expression() { arguments.add( new SelectItem( expression, id) ); } - - ( - "," - id = RelObjectName() expression = Expression() { arguments.add( new SelectItem( expression, id) ); } - )* - + "(" + inputExpression = JsonValueOrQueryInputExpression() { result.setInputExpression(inputExpression); } + "," + expression = Expression() { result.setJsonPathExpression(expression); } - ( - LOOKAHEAD(2) "::" "(" parameters = StructParameters() ")" - )* - ) + [ + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("PASSING") }) + JsonKeyword("PASSING") + expression = Expression() { result.addPassingExpression(expression); } + ( LOOKAHEAD(2) "," expression = Expression() { result.addPassingExpression(expression); } )* + ] - // don't parse this as an Struct, but rather use an Expressionlist - // | - // arguments = StructArguments() - ) + [ + LOOKAHEAD( JsonExistsOnResponseBehavior() ) + behavior = JsonExistsOnResponseBehavior() + + { result.setOnErrorBehavior(behavior); } + ] + ")" { - type = new StructType(dialect, keyword, parameters, arguments); - linkAST(type,jjtThis); - return type; + return result; } } -Expression ParenthesedExpression(): -{ +JsonFunction JsonValueBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.VALUE); + JsonFunctionExpression inputExpression; Expression expression; + ColDataType dataType; + JsonFunction.JsonOnResponseBehavior behavior; } { - "(" expression = PrimaryExpression() ")" + "(" + inputExpression = JsonValueOrQueryInputExpression() { result.setInputExpression(inputExpression); } + "," + expression = Expression() { result.setJsonPathExpression(expression); } + + [ + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("PASSING") }) + JsonKeyword("PASSING") + expression = Expression() { result.addPassingExpression(expression); } + ( LOOKAHEAD(2) "," expression = Expression() { result.addPassingExpression(expression); } )* + ] + + [ dataType = ColDataType() { result.setReturningType(dataType); } ] + + [ + LOOKAHEAD( JsonValueOnResponseBehavior() ) + behavior = JsonValueOnResponseBehavior() + + { result.setOnEmptyBehavior(behavior); } + ] + + [ + LOOKAHEAD( JsonValueOnResponseBehavior() ) + behavior = JsonValueOnResponseBehavior() + + { result.setOnErrorBehavior(behavior); } + ] + ")" { - return new ParenthesedExpressionList(expression); + return result; } } -JsonExpression JsonExpression(Expression expr, List> idents) : { - JsonExpression result = new JsonExpression(expr, idents); - Token token; - ColDataType type = null; - CastExpression castExpr = null; +JsonFunction JsonQueryBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.QUERY); + JsonFunctionExpression inputExpression; + Expression expression; + ColDataType dataType; + JsonFunction.JsonOnResponseBehavior behavior; + Token token; + String encoding; + ColDataType additionalReturningType; + boolean additionalReturningFormatJson; + String additionalReturningEncoding; + JsonFunction.JsonWrapperType additionalWrapperType; + JsonFunction.JsonWrapperMode additionalWrapperMode; + boolean additionalWrapperArray; + JsonFunction.JsonQuotesType additionalQuotesType; + boolean additionalQuotesOnScalarString; + JsonFunction.JsonOnResponseBehavior additionalOnEmptyBehavior; + JsonFunction.JsonOnResponseBehavior additionalOnErrorBehavior; + StringBuilder additionalBuilder; + boolean hasPassingClause = false; } { + "(" + inputExpression = JsonValueOrQueryInputExpression() { result.setInputExpression(inputExpression); } + "," + expression = Expression() { result.setJsonPathExpression(expression); } - // chaining JSON Expressions, e.g. - // '{"obj":{"field": "value"}}'::JSON -> 'obj'::TEXT ->> 'field'::TEXT - ( - LOOKAHEAD(2, {!interrupted} ) ( - LOOKAHEAD(2) ( - "::" type=ColDataType() + [ + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("PASSING") }) + JsonKeyword("PASSING") { hasPassingClause = true; } + expression = Expression() { result.addPassingExpression(expression); } + ( LOOKAHEAD(2) "," expression = Expression() { result.addPassingExpression(expression); } )* + ] + + [ + dataType = ColDataType() { result.setReturningType(dataType); } + [ + { result.setReturningFormatJson(true); } + [ encoding = JsonEncoding() { result.setReturningEncoding(encoding); } ] + ] + ] + + [ + ( + { result.setWrapperType(JsonFunction.JsonWrapperType.WITHOUT); } + [ { result.setWrapperArray(true); } ] + JsonKeyword("WRAPPER") + | + { result.setWrapperType(JsonFunction.JsonWrapperType.WITH); } + [ + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && (getToken(1).image.equalsIgnoreCase("CONDITIONAL") + || getToken(1).image.equalsIgnoreCase("UNCONDITIONAL")) + }) + token = { - castExpr = new CastExpression(); - castExpr.setUseCastKeyword(false); - castExpr.setLeftExpression(result); - castExpr.setColDataType(type); - expr=castExpr; + if (token.image.equalsIgnoreCase("CONDITIONAL")) { + result.setWrapperMode(JsonFunction.JsonWrapperMode.CONDITIONAL); + } else { + result.setWrapperMode(JsonFunction.JsonWrapperMode.UNCONDITIONAL); + } } - ) - )+ - { - result = new JsonExpression(expr); - } + ] + [ { result.setWrapperArray(true); } ] + JsonKeyword("WRAPPER") + ) + ] + [ + LOOKAHEAD({ + getToken(1).kind == K_KEEP + || (getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("OMIT")) + }) ( - LOOKAHEAD(2) ( - "->" (token= | token=) {result.addIdent(token.image,"->");} - | - "->>" (token= | token=) {result.addIdent(token.image,"->>");} + { result.setQuotesType(JsonFunction.JsonQuotesType.KEEP); } + | + JsonKeyword("OMIT") { result.setQuotesType(JsonFunction.JsonQuotesType.OMIT); } + ) + JsonKeyword("QUOTES") + [ + JsonKeyword("SCALAR") + { result.setQuotesOnScalarString(true); } + ] + ] + + [ + LOOKAHEAD( JsonQueryOnResponseBehavior() ) + behavior = JsonQueryOnResponseBehavior() + + { result.setOnEmptyBehavior(behavior); } + ] + + [ + LOOKAHEAD( JsonQueryOnResponseBehavior() ) + behavior = JsonQueryOnResponseBehavior() + + { result.setOnErrorBehavior(behavior); } + ] + + ( + LOOKAHEAD(2, { !hasPassingClause }) + "," + { + additionalReturningType = null; + additionalReturningFormatJson = false; + additionalReturningEncoding = null; + additionalWrapperType = null; + additionalWrapperMode = null; + additionalWrapperArray = false; + additionalQuotesType = null; + additionalQuotesOnScalarString = false; + additionalOnEmptyBehavior = null; + additionalOnErrorBehavior = null; + } + expression = Expression() + [ + additionalReturningType = ColDataType() + [ + { additionalReturningFormatJson = true; } + [ additionalReturningEncoding = JsonEncoding() ] + ] + ] + [ + ( + + { additionalWrapperType = JsonFunction.JsonWrapperType.WITHOUT; } + [ { additionalWrapperArray = true; } ] + JsonKeyword("WRAPPER") | - "#>" token= {result.addIdent(token.image,"#>");} + + { additionalWrapperType = JsonFunction.JsonWrapperType.WITH; } + [ + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && (getToken(1).image.equalsIgnoreCase("CONDITIONAL") + || getToken(1).image.equalsIgnoreCase("UNCONDITIONAL")) + }) + token = + { + if (token.image.equalsIgnoreCase("CONDITIONAL")) { + additionalWrapperMode = JsonFunction.JsonWrapperMode.CONDITIONAL; + } else { + additionalWrapperMode = JsonFunction.JsonWrapperMode.UNCONDITIONAL; + } + } + ] + [ { additionalWrapperArray = true; } ] + JsonKeyword("WRAPPER") + ) + ] + [ + LOOKAHEAD({ + getToken(1).kind == K_KEEP + || (getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("OMIT")) + }) + ( + { additionalQuotesType = JsonFunction.JsonQuotesType.KEEP; } | - "#>>" token= {result.addIdent(token.image,"#>>");} + JsonKeyword("OMIT") { additionalQuotesType = JsonFunction.JsonQuotesType.OMIT; } ) - )* + JsonKeyword("QUOTES") + [ + JsonKeyword("SCALAR") { additionalQuotesOnScalarString = true; } + ] + ] + [ + LOOKAHEAD( JsonQueryOnResponseBehavior() ) + additionalOnEmptyBehavior = JsonQueryOnResponseBehavior() + + ] + [ + LOOKAHEAD( JsonQueryOnResponseBehavior() ) + additionalOnErrorBehavior = JsonQueryOnResponseBehavior() + + ] + { + additionalBuilder = new StringBuilder(); + additionalBuilder.append(expression); + if (additionalReturningType != null) { + additionalBuilder.append(" RETURNING ").append(additionalReturningType); + if (additionalReturningFormatJson) { + additionalBuilder.append(" FORMAT JSON"); + if (additionalReturningEncoding != null) { + additionalBuilder.append(" ENCODING ").append(additionalReturningEncoding); + } + } + } + if (additionalWrapperType != null) { + additionalBuilder.append(" ").append(additionalWrapperType); + if (additionalWrapperMode != null) { + additionalBuilder.append(" ").append(additionalWrapperMode); + } + if (additionalWrapperArray) { + additionalBuilder.append(" ARRAY"); + } + additionalBuilder.append(" WRAPPER"); + } + if (additionalQuotesType != null) { + additionalBuilder.append(" ").append(additionalQuotesType).append(" QUOTES"); + if (additionalQuotesOnScalarString) { + additionalBuilder.append(" ON SCALAR STRING"); + } + } + if (additionalOnEmptyBehavior != null) { + additionalBuilder.append(" ").append(additionalOnEmptyBehavior).append(" ON EMPTY"); + } + if (additionalOnErrorBehavior != null) { + additionalBuilder.append(" ").append(additionalOnErrorBehavior).append(" ON ERROR"); + } + result.addAdditionalQueryPathArgument(additionalBuilder.toString()); + } )* - + ")" { - result.setExpression(expr); return result; } } JsonFunction JsonFunction() : { - JsonFunction result = new JsonFunction(); - boolean usingKeyKeyword = false; - boolean usingValueKeyword = false; - boolean usingFormatJason = false; - Token keyToken; - Token valueToken = null; - Column column = null; - JsonKeyValuePair keyValuePair; - - Expression expression = null; - JsonFunctionExpression functionExpression; - + JsonFunction result; } { ( - ( - ( - "(" { result.setType( JsonFunctionType.OBJECT ); } - ( - ( - // SQL2016 compliant Syntax - ( - [ "KEY" { usingKeyKeyword = true; } ] - keyToken = - - ( LOOKAHEAD(2) - ( ":" | "," { result.setType( JsonFunctionType.POSTGRES_OBJECT ); } | "VALUE" { usingValueKeyword = true; } ) - ( - expression = Expression() - ) - [ { usingFormatJason = true; } ] - )? { - if (expression !=null) { - keyValuePair = new JsonKeyValuePair( keyToken.image, expression, usingKeyKeyword, usingValueKeyword ); - keyValuePair.setUsingFormatJson( usingFormatJason ); - result.add(keyValuePair); - } else { - result.setType( JsonFunctionType.POSTGRES_OBJECT ); - keyValuePair = new JsonKeyValuePair( keyToken.image, null, false, false ); - result.add(keyValuePair); - } - } - - // --- Next Elements - ( "," { usingKeyKeyword = false; usingValueKeyword = false; } - [ "KEY" { usingKeyKeyword = true; } ] - keyToken = - ( ":" | "," { result.setType( JsonFunctionType.MYSQL_OBJECT ); } | "VALUE" { usingValueKeyword = true; } ) - ( - expression = Expression() { keyValuePair = new JsonKeyValuePair( keyToken.image, expression, usingKeyKeyword, usingValueKeyword ); result.add(keyValuePair); } - ) - [ { keyValuePair.setUsingFormatJson( true ); } ] - )* - ) - )? - - [ - ( - { result.setOnNullType( JsonAggregateOnNullType.NULL ); } - ) - | - ( - { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } - ) - ] - - [ - ( - { result.setUniqueKeysType( JsonAggregateUniqueKeysType.WITH ); } - ) - | - ( - { result.setUniqueKeysType( JsonAggregateUniqueKeysType.WITHOUT ); } - ) - ] - ) - ")" - ) - | - ( - { result.setType( JsonFunctionType.ARRAY ); } - "(" - ( - LOOKAHEAD(2) ( - { result.setOnNullType( JsonAggregateOnNullType.NULL ); } - ) - | - expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } - - [ LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } ] - ( - "," - expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } - [ LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } ] - )* - )* - - [ - { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } - ] - - ")" - ) - ) + ( result = JsonObjectBody() ) + | + ( result = JsonArrayBody() ) + | + ( + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("JSON_VALUE") + }) + JsonKeyword("JSON_VALUE") + result = JsonValueBody() + ) + | + ( + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("JSON_QUERY") + }) + JsonKeyword("JSON_QUERY") + result = JsonQueryBody() + ) + | + ( + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("JSON_EXISTS") + }) + JsonKeyword("JSON_EXISTS") + result = JsonExistsBody() + ) ) - { return result; } @@ -4930,6 +8764,7 @@ JsonFunction JsonFunction() : { JsonAggregateFunction JsonAggregateFunction() : { JsonAggregateFunction result = new JsonAggregateFunction(); Token token; + Object key; Expression expression; List expressionOrderByList = null; @@ -4944,10 +8779,32 @@ JsonAggregateFunction JsonAggregateFunction() : { ( ( "(" { result.setType( JsonFunctionType.OBJECT ); } - [ "KEY" { result.setUsingKeyKeyword( true ); } ] - ( token = | token = | token = | token = | token = | token = | token = ) { result.setKey( token.image ); } - ( ":" | "VALUE" {result.setUsingValueKeyword( true ); } ) - ( token = | token = ) { result.setValue( token.image ); } + ( + LOOKAHEAD(2) ( + "KEY" { result.setUsingKeyKeyword( true ); } + ( + ( token = | token = | token = | token = | token = ) + { + key = token.image; + } + | + key = Column() + ) + ) + | + ( token = | token = | token = | token = | token = ) + { + key = token.image; + } + | + key = Column() + ) + { + result.setKey( key ); + } + + ( ":" | "," { result.setType( JsonFunctionType.MYSQL_OBJECT ); } | "VALUE" {result.setUsingValueKeyword( true ); } ) + expression = Expression() { result.setValue( expression ); } [ { result.setUsingFormatJson( true ); } ] @@ -5002,7 +8859,7 @@ JsonAggregateFunction JsonAggregateFunction() : { {result.setAnalyticType(AnalyticType.OVER);} "(" [ - (LOOKAHEAD(ComplexExpressionList()) expressionList=ComplexExpressionList() + (LOOKAHEAD(3) expressionList=ComplexExpressionList() | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" ) ] [olist=OrderByElements() ] @@ -5022,15 +8879,25 @@ JsonAggregateFunction JsonAggregateFunction() : { } IntervalExpression IntervalExpression() : { - IntervalExpression interval; + IntervalExpression interval = new IntervalExpression(); Token token = null; Expression expr = null; boolean signed = false; } { -{ interval = new IntervalExpression(); } - ["-" {signed=true;}] (token= | token= | token= | LOOKAHEAD(JdbcParameter()) expr = JdbcParameter() | expr = JdbcNamedParameter() | LOOKAHEAD(Function()) expr = Function() | expr = Column()) + + ( + + LOOKAHEAD(3) ( + [ "-" {signed=true;}] + (token= | token=) + ) + | + LOOKAHEAD(2) token= + | + expr = Expression() + ) { if (expr != null) { if (signed) expr = new SignedExpression('-', expr); @@ -5086,16 +8953,6 @@ void windowFun(AnalyticExpression retval):{ WindowDefinition winDef; } { ( - [ - ( - { retval.setNullHandling(Function.NullHandling.IGNORE_NULLS); retval.setIgnoreNullsOutside(true); } - ) - | - ( - { retval.setNullHandling(Function.NullHandling.RESPECT_NULLS); retval.setIgnoreNullsOutside(true); } - ) - ] - {retval.setType(AnalyticType.OVER);} | {retval.setType(AnalyticType.WITHIN_GROUP);} @@ -5109,7 +8966,7 @@ void windowFun(AnalyticExpression retval):{ [ LOOKAHEAD(2) "(" [ - (LOOKAHEAD(ComplexExpressionList()) expressionList=ComplexExpressionList() + (LOOKAHEAD(3) expressionList=ComplexExpressionList() | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" ) ] ")" { winDef.setPartitionExpressionList(expressionList, partitionByBrackets); retval.setType(AnalyticType.WITHIN_GROUP_OVER); } @@ -5126,7 +8983,7 @@ WindowDefinition windowDefinition() : { } { "(" [ - (LOOKAHEAD(ComplexExpressionList()) expressionList=ComplexExpressionList() + (LOOKAHEAD(3) expressionList=ComplexExpressionList() | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" ) ] [olist=OrderByElements() ] @@ -5146,8 +9003,13 @@ AnalyticExpression AnalyticExpression(Function function) : Expression filter = null; } { - (( "(" {retval.setType(AnalyticType.FILTER_ONLY);} filter = Expression() ")" [ LOOKAHEAD(2) windowFun(retval) ] ) - | windowFun(retval)) + ( + ( + "(" {retval.setType(AnalyticType.FILTER_ONLY);} filter = Expression() ")" + [ LOOKAHEAD(2) windowFun(retval) ] + ) + | windowFun(retval) + ) { retval.setFilterExpression(filter); return retval; @@ -5232,7 +9094,7 @@ CastExpression ImplicitCast() #ImplicitCast: int scale = -1; } { - colDataType = DataType() + colDataType = DataType() ( tk2 = | @@ -5398,22 +9260,14 @@ Execute Execute(): { FullTextSearch FullTextSearch() : { Token searchModifier; - Token againstValue; - JdbcParameter jdbcParameter; - JdbcNamedParameter jdbcNamedParameter; + Expression againstValue; FullTextSearch fs = new FullTextSearch(); ExpressionList matchedColumns; } { "(" matchedColumns=ColumnList() ")" - "(" - ( - againstValue= { fs.setAgainstValue(new StringValue(againstValue.image)); } - | - jdbcParameter=JdbcParameter() { fs.setAgainstValue( jdbcParameter ); } - | - jdbcNamedParameter=JdbcNamedParameter() { fs.setAgainstValue( jdbcNamedParameter ); } - ) + "(" + againstValue=SimpleExpression() { fs.setAgainstValue(againstValue); } [ ( searchModifier="IN NATURAL LANGUAGE MODE" @@ -5432,28 +9286,22 @@ FullTextSearch FullTextSearch() : { LambdaExpression LambdaExpression() #LambdaExpression: { + ExpressionList columns; String s; - ArrayList identifiers = new ArrayList(); Expression expression; LambdaExpression lambdaExpression; } { -// wip, right now the Grammar works but collides with Multi Value Lists -// ( -// LOOKAHEAD(3) "(" -// s = RelObjectName() { identifiers.add(s); } -// ( "," s = RelObjectName() { identifiers.add(s); } )* -// ")" -// ) -// | ( - s = RelObjectName() { identifiers.add(s); } + columns = ParenthesedColumnList() + | + s = RelObjectName() { columns = new ExpressionList(new Column(s)); } ) "->" expression = Expression() { - lambdaExpression = new LambdaExpression(identifiers, expression); + lambdaExpression = LambdaExpression.from(columns, expression); linkAST(lambdaExpression,jjtThis); return lambdaExpression; } @@ -5466,7 +9314,6 @@ Function Function() #Function: { ( "{" function = InternalFunction(true) "}" - | LOOKAHEAD( SimpleFunction(), { getAsBoolean(Feature.allowComplexParsing) }) function = SimpleFunction() | LOOKAHEAD(3) function = SpecialStringFunctionWithNamedParameters() | function = InternalFunction(false) ) @@ -5488,7 +9335,7 @@ Function SpecialStringFunctionWithNamedParameters() : "(" ( - LOOKAHEAD(NamedExpressionListExprFirst(), { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() + LOOKAHEAD( { isNamedExprListAhead() } ) namedExpressionList = NamedExpressionListExprFirst() | expressionList=ExpressionList() ) @@ -5502,55 +9349,21 @@ Function SpecialStringFunctionWithNamedParameters() : } } -// a simplified function with only one parameter -// useful for parsing nested functions fast -Function SimpleFunction(): -{ - Function function = new Function(); - ObjectNames name; - Expression expr=null; - Expression attributeExpression = null; - Column attributeColumn = null; -} -{ - name = RelObjectNames() - "(" - [ - ( - "*" { expr = new AllColumns(); } - | - LOOKAHEAD( AllTableColumns() ) expr=AllTableColumns() - | - LOOKAHEAD( 3 ) expr = ParenthesedSelect() - | - LOOKAHEAD( SimpleFunction() ) expr = SimpleFunction() - | - LOOKAHEAD( RegularCondition() ) expr = RegularCondition() - | - LOOKAHEAD( SimpleExpressionList() ) expr = SimpleExpressionList() - ) - ] - ")" - { - function.setName(name.getNames()); - if (expr!=null) { - function.setParameters(expr); +JAVACODE +List consumeKeywordArguments() { + List args = null; + while (isKeywordArgumentAhead()) { + String name = getNextToken().image; + ExpressionList exprList = SimpleExpressionList(); + if (args == null) { + args = new ArrayList(); } + Expression value = exprList.size() == 1 + ? (Expression) exprList.get(0) + : exprList; + args.add(new Function.KeywordArgument(name, value)); } - - [ "." ( - // tricky lookahead since we do need to support the following constructs - // schema.f1().f2() - Function with Function Column - // schema.f1().f2.f3 - Function with Attribute Column - LOOKAHEAD( Function() ) attributeExpression=Function() { function.setAttribute(attributeExpression); } - | - attributeColumn=Column() { function.setAttribute(attributeColumn); } - ) - ] - - { - return function; - } + return args; } Function InternalFunction(boolean escaped): @@ -5559,12 +9372,17 @@ Function InternalFunction(boolean escaped): Function retval = new Function(); ObjectNames funcName; ExpressionList expressionList = null; + ExpressionList chainedExpressionList = null; KeepExpression keep = null; Expression expr = null; Expression attributeExpression = null; Column attributeColumn = null; List orderByList; + String onOverflowTruncate = null; + Token overflowToken = null; Limit limit; + Token extraKeywordToken; + List keywordArgs = null; } { [ LOOKAHEAD(2) prefixToken = ] @@ -5580,9 +9398,21 @@ Function InternalFunction(boolean escaped): ) ] ( - LOOKAHEAD(3) expressionList=ExpressionList() [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ] + LOOKAHEAD(3) [ LOOKAHEAD(2) extraKeywordToken = { retval.setExtraKeyword(extraKeywordToken.image); } ] + expressionList=ExpressionList() + [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ] + + // https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/LISTAGG.html + [ + ( overflowToken= | overflowToken= ) { onOverflowTruncate=overflowToken.image; } + [ + overflowToken = { onOverflowTruncate+= " " + overflowToken.image; } + [ ( overflowToken= | overflowToken= ) { onOverflowTruncate+=" " + overflowToken.image + " COUNT"; }] + ] + ] { retval.setOnOverflowTruncate(onOverflowTruncate); } + | - expr = Select() { expressionList = new ExpressionList(expr); } + LOOKAHEAD({ !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) expr = Select() { expressionList = new ExpressionList(expr); } ) ] @@ -5608,25 +9438,55 @@ Function InternalFunction(boolean escaped): limit = PlainLimit() { retval.setLimit(limit); } ] + { + keywordArgs = consumeKeywordArguments(); + } + ")" - [ "." ( + [ + LOOKAHEAD(2) "(" chainedExpressionList = ExpressionList() ")" + ] + + + [ LOOKAHEAD(2) "." ( // tricky lookahead since we do need to support the following constructs // schema.f1().f2() - Function with Function Column // schema.f1().f2.f3 - Function with Attribute Column - LOOKAHEAD( Function() ) attributeExpression=Function() { retval.setAttribute(attributeExpression); } + LOOKAHEAD( 6 ) attributeExpression=Function() { retval.setAttribute(attributeExpression); } | attributeColumn=Column() { retval.setAttribute(attributeColumn); } ) ] + [ LOOKAHEAD(2) ( + ( + + { + retval.setNullHandling(Function.NullHandling.IGNORE_NULLS); + retval.setIgnoreNullsOutside(true); + } + ) + | + ( + + { + retval.setNullHandling(Function.NullHandling.RESPECT_NULLS); + retval.setIgnoreNullsOutside(true); + } + ) + ) + ] + [ LOOKAHEAD(2) keep = KeepExpression() ] { retval.setEscaped(escaped); retval.setParameters(expressionList); + retval.setChainedParameters(chainedExpressionList); retval.setName(funcName.getNames()); retval.setKeep(keep); + retval.setKeywordArguments(keywordArgs); return retval; } } @@ -5654,23 +9514,464 @@ XMLSerializeExpr XMLSerializeExpr(): { } } - -MySQLGroupConcat MySQLGroupConcat():{ - MySQLGroupConcat retval = new MySQLGroupConcat(); - ExpressionList expressionList = null; - List orderByList = null; - Token t; + +JsonTableFunction.JsonTablePassingClause JsonTablePassingClause() : { + Expression valueExpression; + String parameterName; +} +{ + valueExpression = Expression() + + parameterName = RelObjectName() + { + return new JsonTableFunction.JsonTablePassingClause(valueExpression, parameterName); + } +} + +JsonFunction.JsonOnResponseBehavior JsonTableOnEmptyBehavior() : { + JsonFunction.JsonOnResponseBehavior behavior = null; + Expression expression; + Token token; +} +{ + ( + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.ERROR); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.NULL); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.TRUE); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.FALSE); + } + | + expression = Expression() + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.DEFAULT, expression); + } + | + token = + { + if (!token.image.equalsIgnoreCase("EMPTY")) { + throw new ParseException( + "Expected EMPTY, ERROR, NULL or DEFAULT but found " + token.image); + } + } + ( + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("OBJECT") }) + JsonKeyword("OBJECT") + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.EMPTY_OBJECT); + } + | + [ ] + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.EMPTY_ARRAY); + } + ) + ) + { + if (behavior != null) { + return behavior; + } + } +} + +JsonTableFunction.JsonTableWrapperClause JsonTableWrapperClause(boolean beforePathExpr) : { + JsonTableFunction.JsonTableWrapperClause wrapperClause = + new JsonTableFunction.JsonTableWrapperClause(beforePathExpr); + Token token; +} +{ + ( + { + wrapperClause.setWrapperType(JsonFunction.JsonWrapperType.WITHOUT); + } + | + { + wrapperClause.setWrapperType(JsonFunction.JsonWrapperType.WITH); + } + [ + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && (getToken(1).image.equalsIgnoreCase("CONDITIONAL") + || getToken(1).image.equalsIgnoreCase("UNCONDITIONAL")) + }) + token = + { + if (token.image.equalsIgnoreCase("CONDITIONAL")) { + wrapperClause.setWrapperMode(JsonFunction.JsonWrapperMode.CONDITIONAL); + } else { + wrapperClause.setWrapperMode(JsonFunction.JsonWrapperMode.UNCONDITIONAL); + } + } + ] + ) + [ { wrapperClause.setArray(true); } ] + JsonKeyword("WRAPPER") + { + return wrapperClause; + } +} + +JsonTableFunction.JsonTableQuotesClause JsonTableQuotesClause() : { + JsonTableFunction.JsonTableQuotesClause quotesClause = + new JsonTableFunction.JsonTableQuotesClause(); +} +{ + ( + { quotesClause.setQuotesType(JsonFunction.JsonQuotesType.KEEP); } + | + JsonKeyword("OMIT") { quotesClause.setQuotesType(JsonFunction.JsonQuotesType.OMIT); } + ) + JsonKeyword("QUOTES") + [ + JsonKeyword("SCALAR") { quotesClause.setOnScalarString(true); } + ] + { + return quotesClause; + } +} + +JsonTableFunction.JsonTableColumnDefinition JsonTableColumnDefinition() : { + JsonTableFunction.JsonTableColumnDefinition columnDefinition = null; + JsonTableFunction.JsonTableNestedColumnDefinition nestedColumnDefinition; + JsonTableFunction.JsonTableValueColumnDefinition valueColumnDefinition; + String columnName; + ColDataType dataType; + Expression expression; + String pathName = null; + JsonTableFunction.JsonTableColumnsClause columnsClause; + JsonFunction.JsonOnResponseBehavior behavior; + JsonTableFunction.JsonTableWrapperClause wrapperClause; + JsonTableFunction.JsonTableQuotesClause quotesClause; + String encoding; +} +{ + ( + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("NESTED") }) + JsonKeyword("NESTED") + { nestedColumnDefinition = new JsonTableFunction.JsonTableNestedColumnDefinition(); } + [ LOOKAHEAD(2) { nestedColumnDefinition.setPathKeyword(true); } ] + expression = Expression() { nestedColumnDefinition.setPathExpression(expression); } + [ pathName = RelObjectName() { nestedColumnDefinition.setPathName(pathName); } ] + columnsClause = JsonTableColumnsClause() { + nestedColumnDefinition.setColumnsClause(columnsClause); + columnDefinition = nestedColumnDefinition; + } + | + columnName = RelObjectName() { + valueColumnDefinition = new JsonTableFunction.JsonTableValueColumnDefinition(); + valueColumnDefinition.setColumnName(columnName); + columnDefinition = valueColumnDefinition; + } + ( + { valueColumnDefinition.setForOrdinality(true); } + | + [ + // Very ugly: ColDataType can consume an IDENTIFIER, which is fine, but we don't want it to + // consume an ALLOW or DISALLOW because that's a keyword for Oracle in this place. + // So we make a LOOKAHEAD on ColDataType, BUT we exclude the two cases for the IDENTIFIER + + /* + [ ColDataType ] + [ FORMAT JSON ] + [ (ALLOW | DISALLOW) SCALARS ] + */ + + LOOKAHEAD( + ColDataType(), + { !(getToken(1).kind == S_IDENTIFIER && ( + getToken(1).image.equalsIgnoreCase("ALLOW") + || getToken(1).image.equalsIgnoreCase("DISALLOW"))) } ) + dataType = ColDataType() { valueColumnDefinition.setDataType(dataType); } + ] + [ + { valueColumnDefinition.setFormatJson(true); } + [ encoding = JsonEncoding() { valueColumnDefinition.setEncoding(encoding); } ] + ] + [ + ( + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("ALLOW") }) + JsonKeyword("ALLOW") { valueColumnDefinition.setScalarsType(JsonFunction.ScalarsType.ALLOW); } + | + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("DISALLOW") }) + JsonKeyword("DISALLOW") { valueColumnDefinition.setScalarsType(JsonFunction.ScalarsType.DISALLOW); } + ) + JsonKeyword("SCALARS") + ] + [ { valueColumnDefinition.setExistsKeyword(true); } ] + // In Oracle, the wrapper clause comes before the PATH expression + [ LOOKAHEAD(2) wrapperClause = JsonTableWrapperClause(true) { valueColumnDefinition.setWrapperClause(wrapperClause); } ] + [ expression = Expression() { valueColumnDefinition.setPathExpression(expression); } ] + // In Truno the wrapper clause comes after the PATH expression + [ wrapperClause = JsonTableWrapperClause(false) { valueColumnDefinition.setWrapperClause(wrapperClause); } ] + [ + LOOKAHEAD({ + getToken(1).kind == K_KEEP + || (getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("OMIT")) + }) + quotesClause = JsonTableQuotesClause() { valueColumnDefinition.setQuotesClause(quotesClause); } + ] + [ + LOOKAHEAD( JsonTableOnEmptyBehavior() ) + behavior = JsonTableOnEmptyBehavior() + + { valueColumnDefinition.setOnEmptyBehavior(behavior); } + ] + [ + LOOKAHEAD( JsonQueryOnResponseBehavior() ) + behavior = JsonQueryOnResponseBehavior() + + { valueColumnDefinition.setOnErrorBehavior(behavior); } + ] + [ + LOOKAHEAD( JsonTableOnEmptyBehavior() ) + behavior = JsonTableOnEmptyBehavior() + + { + valueColumnDefinition.setOnEmptyBehavior(behavior); + valueColumnDefinition.setOnEmptyAfterOnError(true); + } + ] + ) + ) + { + return columnDefinition; + } +} + +JsonTableFunction.JsonTableColumnsClause JsonTableColumnsClause() : { + JsonTableFunction.JsonTableColumnsClause columnsClause = + new JsonTableFunction.JsonTableColumnsClause(); + JsonTableFunction.JsonTableColumnDefinition columnDefinition; +} +{ + "(" + [ + columnDefinition = JsonTableColumnDefinition() { + columnsClause.addColumnDefinition(columnDefinition); + } + ( + "," + columnDefinition = JsonTableColumnDefinition() { + columnsClause.addColumnDefinition(columnDefinition); + } + )* + ] + ")" + { + return columnsClause; + } +} + +JsonTableFunction.JsonTablePlanTerm JsonTablePlanTerm() : { + JsonTableFunction.JsonTablePlanTerm term = null; + String value; + Expression expression; + JsonTableFunction.JsonTablePlanExpression nestedPlanExpression; +} +{ + ( + LOOKAHEAD(2) + "(" nestedPlanExpression = JsonTablePlanExpression() ")" { + term = new JsonTableFunction.JsonTablePlanTerm(); + term.setNestedPlanExpression(nestedPlanExpression); + } + | + LOOKAHEAD(2) + value = RelObjectName() { + term = new JsonTableFunction.JsonTablePlanTerm(); + term.setName(value); + } + | + expression = Expression() { + term = new JsonTableFunction.JsonTablePlanTerm(); + term.setExpression(expression); + } + ) + { + return term; + } +} + +JsonTableFunction.JsonTablePlanExpression JsonTablePlanExpression() : { + JsonTableFunction.JsonTablePlanExpression planExpression = + new JsonTableFunction.JsonTablePlanExpression(); + JsonTableFunction.JsonTablePlanTerm term; + Token operator = null; +} +{ + term = JsonTablePlanTerm() { planExpression.addTerm(term); } + ( + ( + operator = { + planExpression.addOperator(JsonTableFunction.JsonTablePlanOperator.COMMA); + } + | + operator = { + planExpression.addOperator(JsonTableFunction.JsonTablePlanOperator.INNER); + } + | + operator = { + planExpression.addOperator(JsonTableFunction.JsonTablePlanOperator.OUTER); + } + | + operator = { + planExpression.addOperator(JsonTableFunction.JsonTablePlanOperator.CROSS); + } + | + operator = { + planExpression.addOperator(JsonTableFunction.JsonTablePlanOperator.UNION); + } + ) + term = JsonTablePlanTerm() { planExpression.addTerm(term); } + )* + { + return planExpression; + } +} + +JsonTableFunction.JsonTablePlanClause JsonTablePlanClause() : { + JsonTableFunction.JsonTablePlanClause planClause = + new JsonTableFunction.JsonTablePlanClause(); + JsonTableFunction.JsonTablePlanExpression planExpression; +} +{ + + [ { planClause.setDefaultPlan(true); } ] + "(" planExpression = JsonTablePlanExpression() ")" { planClause.setPlanExpression(planExpression); } + { + return planClause; + } +} + +JsonTableFunction.JsonTableOnErrorClause JsonTableOnErrorClause(boolean beforeColumns) : { + JsonTableFunction.JsonTableOnErrorClause onErrorClause = + new JsonTableFunction.JsonTableOnErrorClause(beforeColumns); + Token token; +} +{ + ( + { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.ERROR); } + | + { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.EMPTY); } + | + { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.TRUE); } + | + { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.FALSE); } + | + { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.NULL); } + ) + + { + return onErrorClause; + } +} + +JsonTableFunction.JsonTableOnEmptyClause JsonTableOnEmptyClause() : { + JsonTableFunction.JsonTableOnEmptyClause onEmptyClause = + new JsonTableFunction.JsonTableOnEmptyClause(); + Token token; +} +{ + ( + { onEmptyClause.setType(JsonTableFunction.JsonTableOnEmptyType.ERROR); } + | + { onEmptyClause.setType(JsonTableFunction.JsonTableOnEmptyType.EMPTY); } + | + { onEmptyClause.setType(JsonTableFunction.JsonTableOnEmptyType.TRUE); } + | + { onEmptyClause.setType(JsonTableFunction.JsonTableOnEmptyType.FALSE); } + | + { onEmptyClause.setType(JsonTableFunction.JsonTableOnEmptyType.NULL); } + ) + + { + return onEmptyClause; + } +} + +JsonTableFunction.JsonTableParsingTypeClause JsonTableParsingTypeClause() : { + JsonTableFunction.JsonTableParsingTypeClause parsingType = new JsonTableFunction.JsonTableParsingTypeClause(); +} +{ + + + ( + { parsingType.setType(JsonTableFunction.JsonTableParsingType.STRICT); } + | + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("LAX") }) + JsonKeyword("LAX") { parsingType.setType(JsonTableFunction.JsonTableParsingType.LAX); } + ) + + { + return parsingType; + } +} + +JsonTableFunction JsonTableBody() : { + JsonTableFunction function = new JsonTableFunction(); + Expression jsonInput; + Expression jsonPath; + JsonTableFunction.JsonTablePassingClause passingClause; + String pathName = null; + JsonTableFunction.JsonTableColumnsClause columnsClause; + JsonTableFunction.JsonTablePlanClause planClause = null; + JsonTableFunction.JsonTableOnErrorClause onErrorClause = null; + JsonTableFunction.JsonTableParsingTypeClause parsingTypeClause = null; + JsonTableFunction.JsonTableOnEmptyClause onEmptyClause = null; } { - "(" - [ { retval.setDistinct(true); } ] - expressionList = ExpressionList() - [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ] - [ t= { retval.setSeparator(t.image); } ] + "(" + jsonInput = Expression() { + function.setJsonInputExpression(jsonInput); + } + [ { function.setFormatJson(true); } ] + [ + "," + jsonPath = Expression() { + function.setJsonPathExpression(jsonPath); + function.setParameters(new ExpressionList(jsonInput, jsonPath)); + } + [ pathName = RelObjectName() { function.setPathName(pathName); } ] + ] + [ + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("PASSING") }) + JsonKeyword("PASSING") + passingClause = JsonTablePassingClause() { function.addPassingClause(passingClause); } + ( + "," + passingClause = JsonTablePassingClause() { function.addPassingClause(passingClause); } + )* + ] + [ LOOKAHEAD(3) onErrorClause = JsonTableOnErrorClause(true) { function.setOnErrorClause(onErrorClause); } ] + [ parsingTypeClause = JsonTableParsingTypeClause() { function.setParsingTypeClause(parsingTypeClause); } ] + [ onEmptyClause = JsonTableOnEmptyClause() { function.setOnEmptyClause(onEmptyClause); } ] + columnsClause = JsonTableColumnsClause() { function.setColumnsClause(columnsClause); } + [ planClause = JsonTablePlanClause() { function.setPlanClause(planClause); } ] + [ onErrorClause = JsonTableOnErrorClause(false) { function.setOnErrorClause(onErrorClause); } ] ")" { - retval.setExpressionList(expressionList); - return retval; + return function; } } @@ -5678,15 +9979,29 @@ TableFunction TableFunction(): { Token prefix = null; Function function; - TableFunction functionItem; + Token withClause = null; } { [ prefix = ] - function=Function() + ( + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("JSON_TABLE") + }) + JsonKeyword("JSON_TABLE") + function = JsonTableBody() + | + function=Function() + ) + [ LOOKAHEAD(2) ( withClause = | withClause = ) ] { return prefix!=null - ? new TableFunction(prefix.image, function) - : new TableFunction(function); + ? withClause!=null + ? new TableFunction(prefix.image, function, withClause.image) + : new TableFunction(prefix.image, function) + : withClause!=null + ? new TableFunction(function, withClause.image) + : new TableFunction(function); } } @@ -5721,6 +10036,57 @@ List ColumnNamesWithParamsList() : { { return colNames; } } +Index.ColumnParams IndexColumnWithParams(): { + String columnName = null; + List parameter = null; + Expression expression = null; + Index.ColumnParams column = null; +} +{ + ( + columnName=RelObjectName() + { parameter = null; } + [ parameter = CreateParameter() ] + { + column = new Index.ColumnParams(columnName, parameter); + } + | + "(" expression=Expression() ")" + { parameter = null; } + [ LOOKAHEAD(2) parameter = CreateParameter() ] + { + column = new Index.ColumnParams(expression, parameter); + } + ) + { + return column; + } +} + +List IndexColumnsWithParamsList() : { + List colNames = new ArrayList(); + Index.ColumnParams column = null; +} +{ + "(" + column=IndexColumnWithParams() + { + colNames.add(column); + } + + ( + "," + column=IndexColumnWithParams() + { + colNames.add(column); + } + )* + + ")" + + { return colNames; } +} + Index Index(): { ObjectNames name; } @@ -5733,7 +10099,7 @@ CreateIndex CreateIndex(): CreateIndex createIndex = new CreateIndex(); Table table = null; List colNames; - Token using; + String indexType; Index index = null; List parameter = new ArrayList(); List tailParameters = new ArrayList(); @@ -5748,19 +10114,19 @@ CreateIndex CreateIndex(): ( LOOKAHEAD(3)( table=Table() - [ using= { index.setUsing(using.image); } ] + [ indexType=UsingIndexType() { index.setUsing(indexType); } ] ) | ( - [ using= { - index.setUsing(using.image); + [ indexType=UsingIndexType() { + index.setUsing(indexType); createIndex.setIndexTypeBeforeOn(true); - } + } ] table=Table() ) ) - colNames = ColumnNamesWithParamsList() + colNames = IndexColumnsWithParamsList() ( LOOKAHEAD(2) parameter=CreateParameter() { tailParameters.addAll(parameter); } )* { index.setColumns(colNames); @@ -5779,11 +10145,8 @@ ColumnDefinition ColumnDefinition(): { List parameter; } { columnName=RelObjectName() - - colDataType = ColDataType() - + colDataType=ColDataType() ( LOOKAHEAD(2) parameter=CreateParameter() { columnSpecs.addAll(parameter); } )* - { coldef = new ColumnDefinition(); coldef.setColumnName(columnName); @@ -5800,14 +10163,21 @@ CreateSchema CreateSchema(): CreateTable table = null; CreateView view = null; CreateSchema schema = new CreateSchema(); - //schema.setSchemaName(System.getProperty("user.name")); - //schema.setAuthorization(System.getProperty("user.name")); List schemaPath = null; List statements = new ArrayList(); } { - [ ( tk= | tk=) { schema.setSchemaName(tk.image); } ] + [ LOOKAHEAD(2) { schema.setIfNotExists(true); } ] + [ + ( tk= | tk=) { schema.setSchemaName(tk.image); } + + ( + "." { schema.setCatalogName(tk.image); } + ( tk= | tk=) { schema.setSchemaName(tk.image); } + )? + ] + [ (tk= | tk=) { schema.setAuthorization(tk.image); } ] @@ -5815,19 +10185,21 @@ CreateSchema CreateSchema(): [schemaPath=PathSpecification() { schema.setSchemaPath(schemaPath); }] ( - - - table = CreateTable(false) - { - table.getTable().setSchemaName(schema.getSchemaName()); - schema.addStatement(table); - } - | view = CreateView(false) - { - view.getView().setSchemaName(schema.getSchemaName()); - schema.addStatement(view); - } + LOOKAHEAD(2) ( + + table = CreateTable(false) + { + table.getTable().setSchemaName(schema.getSchemaName()); + schema.addStatement(table); + } + | + view = CreateView(false) + { + view.getView().setSchemaName(schema.getSchemaName()); + schema.addStatement(view); + } + ) )* { return schema; @@ -5847,37 +10219,125 @@ List PathSpecification(): } } +/** + * Parses a single table-level constraint inside CREATE TABLE (...). + * Handles INDEX, PRIMARY KEY, UNIQUE, KEY, FOREIGN KEY, CHECK, EXCLUDE. + * Returns an Index (which may be NamedConstraint, ForeignKeyIndex, CheckConstraint, ExcludeConstraint). + */ +Index CreateTableConstraint(): +{ + Token tk = null; + Token tk2 = null; + Token tk3 = null; + String sk3 = null; + List colNames = null; + List parameter = new ArrayList(); + List idxSpec = new ArrayList(); + Index index = null; + ForeignKeyIndex fkIndex = null; + CheckConstraint checkCs = null; + ExcludeConstraint excludeC = null; + Expression exp = null; +} +{ + ( + LOOKAHEAD(3) ( + { idxSpec.clear(); } + tk= + sk3=RelObjectName() + colNames = IndexColumnsWithParamsList() + ( parameter=CreateParameter() { idxSpec.addAll(parameter); } )* + { + index = new Index().withType(tk.image).withName(sk3).withColumns(colNames).withIndexSpec(new ArrayList(idxSpec)); + } + ) + | + LOOKAHEAD(3) ( + { + index = new NamedConstraint(); + tk2=null; + idxSpec.clear(); + } + [ sk3=RelObjectName() {index.setName(sk3);} ] + ( + tk= tk2= + | + tk= [ tk2= ] + ) + { + index.setType( tk.image + ( tk2!=null ? " " + tk2.image : "" )); + tk2=null; + } + colNames = ColumnNamesWithParamsList() + ( parameter=CreateParameter() { idxSpec.addAll(parameter); } )* + { + index.withColumns(colNames).withIndexSpec(new ArrayList(idxSpec)); + } + ) + | + LOOKAHEAD(3) ( + { + tk=null; + tk3=null; + idxSpec.clear(); + } + [ tk= ] + [ tk3= | tk3= ] tk2= + sk3=RelObjectName() + colNames = IndexColumnsWithParamsList() + ( parameter=CreateParameter() { idxSpec.addAll(parameter); } )* + { + index = new Index() + .withType( ( tk!=null ? tk.image + " " : "") + ( tk3!=null ? tk3.image + " ":"" ) + tk2.image) + .withName(sk3) + .withColumns(colNames) + .withIndexSpec(new ArrayList(idxSpec)); + } + ) + | + LOOKAHEAD(3) ( + { sk3=null; } + [ sk3=RelObjectName() ] + fkIndex = ForeignKeySpec(sk3) + { index = fkIndex; } + ) + | + LOOKAHEAD(3) ( + { sk3 = null; } + [ sk3 = RelObjectName() ] + checkCs = CheckConstraintSpec(sk3) + { index = checkCs; } + ) + | + LOOKAHEAD(2) ( + tk= { excludeC = new ExcludeConstraint(); } + (tk2= + ("(" exp = Expression() ")")* {excludeC.setExpression(exp);}) + { index = excludeC; } + ) + ) + { + return index; + } +} + + CreateTable CreateTable(boolean isUsingOrReplace): { CreateTable createTable = new CreateTable(); Table table = null; List columnDefinitions = new ArrayList(); - List columnSpecs = null; List tableOptions = new ArrayList(); List createOptions = new ArrayList(); - String columnName; Token tk = null; - Token tk2 = null; - Token tk3 = null; - String sk3 = null; - ColDataType colDataType = null; - String stringList = null; ColumnDefinition coldef = null; List indexes = new ArrayList(); - List colNames = null; - List colNames2 = null; Index index = null; - ForeignKeyIndex fkIndex = null; List parameter = new ArrayList(); - List idxSpec = new ArrayList(); - Table fkTable = null; SpannerInterleaveIn interleaveIn = null; Select select = null; Table likeTable = null; - CheckConstraint checkCs = null; - ExcludeConstraint excludeC = null; RowMovement rowMovement = null; - ReferentialAction.Action action = null; String tableColumn = null; List columns = new ArrayList(); } @@ -5887,8 +10347,6 @@ CreateTable CreateTable(boolean isUsingOrReplace): // table options, not required but 1 or none [ tk= { createOptions.add(tk.image);} ] - /* [ [ (tk= | tk=) {createOptions.add(tk.image);} ] - ( tk= | tk= ) {createOptions.add(tk.image);}] */ (parameter = CreateParameter() { createOptions.addAll(parameter); })* @@ -5896,142 +10354,32 @@ CreateTable CreateTable(boolean isUsingOrReplace): [ LOOKAHEAD(2) { createTable.setIfNotExists(true); }] table=Table() [ LOOKAHEAD(2) ( - LOOKAHEAD(3) - ("(" tableColumn=RelObjectName() { columns.add(tableColumn); } ("," tableColumn=RelObjectName() { columns.add(tableColumn); } )* ")") + LOOKAHEAD(3) ( + "(" tableColumn=RelObjectName() { columns.add(tableColumn); } ("," tableColumn=RelObjectName() { columns.add(tableColumn); } )* ")" + ) | - ("(" - coldef = ColumnDefinition() - - { columnDefinitions.add(coldef); } - ( - "," + "(" + coldef = ColumnDefinition() { columnDefinitions.add(coldef); } ( - LOOKAHEAD(3) ( - tk= - sk3=RelObjectName() - /* colNames=ColumnsNamesList() */ - colNames = ColumnNamesWithParamsList() - { idxSpec.clear(); } - ( parameter=CreateParameter() { idxSpec.addAll(parameter); } )* - { - index = new Index().withType(tk.image).withName(sk3).withColumns(colNames).withIndexSpec(new ArrayList(idxSpec)); - indexes.add(index); - } - ) - | - LOOKAHEAD(3) ( - { - index = new NamedConstraint(); - } - [ sk3=RelObjectName() {index.setName(sk3);} ] - - (tk= tk2= {index.setType(tk.image + " " + tk2.image);} - | tk= [ tk2= ] {index.setType(tk.image + (tk2!=null?" " + tk2.image:""));} - ) - /* colNames=ColumnsNamesList() */ - colNames = ColumnNamesWithParamsList() - { idxSpec.clear(); } - ( parameter=CreateParameter() { idxSpec.addAll(parameter); } )* - { - index.withColumns(colNames).withIndexSpec(new ArrayList(idxSpec)); - indexes.add(index); - } - // reset Token to null forcefullly - { - tk2=null; - } - ) - | - LOOKAHEAD(3) ( {tk=null;} - [ tk= ] [ tk3= ] tk2= - sk3=RelObjectName() - /* colNames=ColumnsNamesList() */ - colNames = ColumnNamesWithParamsList() - { idxSpec.clear(); } - ( parameter=CreateParameter() { idxSpec.addAll(parameter); } )* - { - index = new Index() - .withType((tk!=null?tk.image + " ":"") + (tk3!=null?tk3.image + " ":"") + tk2.image) - .withName(sk3) - .withColumns(colNames) - .withIndexSpec(new ArrayList(idxSpec)); - indexes.add(index); - } - ) - | - LOOKAHEAD(3)( - { - fkIndex = new ForeignKeyIndex(); - } - [ sk3=RelObjectName() {fkIndex.setName(sk3);} ] - tk= tk2= - /* colNames=ColumnsNamesList() */ - colNames = ColumnNamesWithParamsList() - { - fkIndex.withType(tk.image + " " + tk2.image).withColumns(colNames); - } - fkTable=Table() colNames2=ColumnsNamesList() - { - fkIndex.setTable(fkTable); - fkIndex.setReferencedColumnNames(colNames2); - indexes.add(fkIndex); - } - [LOOKAHEAD(2) ( (tk= | tk=) action = Action() - { fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); } - )] - [LOOKAHEAD(2) ( (tk= | tk=) action = Action() - { fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); } - )] - ) - | - LOOKAHEAD(3)( - [ sk3 = RelObjectName()] - {Expression exp = null;} - ("(" exp = Expression() ")")* { - checkCs = new CheckConstraint().withName(sk3).withExpression(exp); - indexes.add(checkCs); - } - ) - | - LOOKAHEAD(2) tk= {excludeC = new ExcludeConstraint(); Expression exp = null;} - (tk2= - ("(" exp = Expression() ")")* {excludeC.setExpression(exp);}) - { - indexes.add(excludeC); - } - | + "," ( - - coldef = ColumnDefinition() - - /* - columnName=RelObjectName() - - colDataType = ColDataType() - { - columnSpecs = new ArrayList(); - } - - ( parameter=CreateParameter() { columnSpecs.addAll(parameter); } )* - - { - coldef = new ColumnDefinition(); - coldef.setColumnName(columnName); - coldef.setColDataType(colDataType); - if (columnSpecs.size() > 0) - coldef.setColumnSpecs(columnSpecs); - columnDefinitions.add(coldef); - } */ - { columnDefinitions.add(coldef); } + LOOKAHEAD(3) ( + index = CreateTableConstraint() + { indexes.add(index); } + ) + | + ( + coldef = ColumnDefinition() + { columnDefinitions.add(coldef); } + ) ) - ) - )* + )* - ")" + ")" ) - ) + ) ] ( LOOKAHEAD(2, { getToken(1).kind != K_AS }) parameter=CreateParameter() { tableOptions.addAll(parameter); } )* @@ -6098,6 +10446,11 @@ ColDataType DataType(): } { ( + LOOKAHEAD(2) tk= { + type = tk.image; + return new ColDataType(type, precision, scale); + } + | LOOKAHEAD(2) tk= ( ("<" arrayType = ColDataType() ">") { colDataType.setDataType("ARRAY<" + arrayType.getDataType() + ">"); @@ -6106,16 +10459,17 @@ ColDataType DataType(): | ( ( tk= | tk= | tk = | tk = | tk = - | tk= | tk= | tk= | tk= + | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= ) { type = tk.image; } [ // MySQL seems to allow: INT UNSIGNED LOOKAHEAD(2) ( LOOKAHEAD(2) ( tk = | tk = | tk = - | tk= | tk= | tk= | tk= + | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= ) { type += " " + tk.image; } )+ ] [ LOOKAHEAD(2) "(" ( tk= { precision = Integer.valueOf(tk.image); } | tk= { precision = Integer.MAX_VALUE; } ) + [ | ] [ "," tk = { scale = Integer.valueOf(tk.image); } ] ")" ] @@ -6148,6 +10502,19 @@ ColDataType ColDataType(): } { ( + ( + + "(" + type = RelObjectNameExt() + colDataType = ColDataType() { argumentsStringList.add( type + " " + colDataType.toString()); } + ( + "," + type = RelObjectNameExt() + colDataType = ColDataType() { argumentsStringList.add( type + " " + colDataType.toString()); } + )* + ")" { colDataType = new ColDataType("STRUCT"); } + ) + | LOOKAHEAD(2) ( colDataType = DataType() ) @@ -6167,9 +10534,10 @@ ColDataType ColDataType(): | tk= | tk= | tk= + | tk= ) { schema = tk.image; } - [ "." arrayType = ColDataType() { schema += "." + arrayType.toString(); } ] + [ LOOKAHEAD(2) "." arrayType = ColDataType() { schema += "." + arrayType.toString(); } ] { colDataType.setDataType(schema); } ) @@ -6285,8 +10653,8 @@ List CreateViewTailComment(): if (op != null) { result.add(op); } - result.add(tk2.image); - } + result.add(tk2.image); + } { return result;} } @@ -6311,6 +10679,101 @@ ReferentialAction.Action Action(): { return action; } } +/** + * Parses optional referential actions: [ON DELETE|UPDATE action] [ON DELETE|UPDATE action] + * Shared between CREATE TABLE FK and ALTER TABLE FK definitions. + */ +void ReferentialActionsOnIndex(ForeignKeyIndex fkIndex): +{ + Token tk; + ReferentialAction.Action action = null; +} +{ + [ LOOKAHEAD(2) ( + + ( tk= | tk= ) action = Action() + { fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); } + )] + [ LOOKAHEAD(2) ( + + ( tk= | tk= ) action = Action() + { fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); } + )] +} + +/** + * Parses: CHECK ( expression ) + * Returns a CheckConstraint. Shared between CREATE TABLE and ALTER TABLE. + */ +CheckConstraint CheckConstraintSpec(String constraintName): +{ + Expression exp = null; +} +{ + ( LOOKAHEAD(2) "(" exp = Expression() ")" )* + { + return new CheckConstraint().withName(constraintName).withExpression(exp); + } +} + +/** + * Parses: FOREIGN KEY columns REFERENCES table [columns] [referential actions] + * Returns a populated ForeignKeyIndex. Shared between CREATE TABLE and ALTER TABLE. + */ +ForeignKeyIndex ForeignKeySpec(String constraintName): +{ + ForeignKeyIndex fkIndex = new ForeignKeyIndex(); + Token tk; + Token tk2; + List refColNames = null; + List colNames; + Table fkTable; +} +{ + tk= tk2= + colNames = ColumnNamesWithParamsList() + { + if (constraintName != null) { fkIndex.setName(constraintName); } + fkIndex.withType(tk.image + " " + tk2.image).withColumns(colNames); + } + fkTable=Table() [ LOOKAHEAD(2) refColNames=ColumnsNamesList() ] + { + fkIndex.setTable(fkTable); + fkIndex.setReferencedColumnNames(refColNames); + } + ReferentialActionsOnIndex(fkIndex) + { + return fkIndex; + } +} + +/** + * Parses USING [INDEX] name clause in ALTER TABLE constraint tails. + */ +void AlterExpressionUsingIndex(AlterExpression alterExp): +{ + String sk4; +} +{ + { alterExp.addParameters("USING"); } + [ LOOKAHEAD(2) { alterExp.addParameters("INDEX"); } ] + sk4=RelObjectName() { alterExp.addParameters(sk4); } +} + +/** + * Parses the common tail after a named constraint in ALTER TABLE: + * constraint_state [USING [INDEX] name] [COMMENT 'text'] + */ +void AlterExpressionConstraintTail(AlterExpression alterExp, Index index): +{ + List constraints; +} +{ + constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } + [ LOOKAHEAD(2) AlterExpressionUsingIndex(alterExp) ] + [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] +} + AlterView AlterView(boolean useReplace): { AlterView alterView = new AlterView(); @@ -6346,12 +10809,14 @@ List CreateParameter(): } | ( - (tk= | tk=) + //@todo: implement a proper identifier + (tk= | tk= | tk=) { retval+=tk.image; } [ "." - (tk2= | tk2=) + //@todo: implement a proper identifier + (tk2= | tk2= | tk=) { retval+="."+tk2.image; } ] { param.add(retval); } @@ -6361,14 +10826,15 @@ List CreateParameter(): { param.add("TABLESPACE " + retval); } | ( - tk= | tk= | tk= | tk= | tk= + tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk= | tk= | tk= | tk= | tk= | tk= + | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk = | tk = + | tk= | tk= | tk= | tk= | tk= | tk="=" ) { param.add(tk.image); } @@ -6422,8 +10888,8 @@ String AList(): "(" ( - ( (tk= | tk= | tk=) { retval.append(tk.image); } - | (name=RelObjectNameWithoutValue()) { retval.append(name); }) + ( (tk= | tk= | tk= | tk= | tk=) { retval.append(tk.image); } + | (name=RelObjectName()) { retval.append(name); }) [("," {retval.append(",");} | "=" {retval.append("=");})] )* ")" @@ -6436,11 +10902,13 @@ String AList(): String ColumnsNamesListItem(): { Token tk = null; + Token sortDirection = null; String item = null; } { ( item = RelObjectName() ) [ LOOKAHEAD(2) "(" tk = ")" { item = item + "(" + tk.image + ")"; } ] + [ LOOKAHEAD( ( | ) ( "," | ")" ) ) (sortDirection = | sortDirection = ) { item = item + " " + sortDirection.image; } ] { return item; } @@ -6481,223 +10949,957 @@ String FuncArgsListItem(): [ "(" tk = ")" { argType = argType + "(" + tk.image + ")"; } ] ) ) - { - return argName != null ? String.format("%s %s", argName, argType) : argType; - } + { + return argName != null ? String.format("%s %s", argName, argType) : argType; + } +} + +List FuncArgsList(): +{ + List retval = null; + String img = null; +} +{ + "(" + { retval = new ArrayList(); } + [ + img=FuncArgsListItem() { retval.add(img); } + ( "," img=FuncArgsListItem() { retval.add(img); } )* + ] + ")" + { + return retval; + } +} + +Drop Drop(): +{ + Drop drop = new Drop(); + Token tk = null; + Table name; + List dropArgs = new ArrayList(); + List funcArgs = null; + boolean useTemporary = false; +} +{ + + [ { drop.setMaterialized(true);} ] + ( + tk= + | + ( + [ {useTemporary=true;} ] tk= + ) + | + tk= + | + tk= + | + tk= + | + tk= + | + tk= + ) + { drop.setType(tk.image); } + + [ LOOKAHEAD(2) {drop.setIfExists(true);} ] + + name = Table() { drop.setName(name); } + [ LOOKAHEAD(2) funcArgs = FuncArgsList() ] + ( + ( + tk= | tk= | tk= + ) { dropArgs.add(tk.image); } + | + ( + name = Table() { dropArgs.add("ON"); dropArgs.add(name.toString()); } + ) + )* + { + if (dropArgs.size() > 0) { + drop.setParameters(dropArgs); + } + if (drop.getType().equals("FUNCTION")) { + drop.getTypeToParameters().put("FUNCTION", funcArgs); + } + + drop.setUsingTemporary(useTemporary); + + return drop; + } +} + +Truncate Truncate(): +{ + Truncate truncate = new Truncate(); + Table table; + List
tables = new ArrayList
(); + boolean only = false; + boolean cascade = false; +} +{ +/** +* TRUNCATE can be followed directly by the table name in Postgresql +* See: https://www.postgresql.org/docs/current/sql-truncate.html +* +* TRUNCATE [ TABLE ] [ ONLY ] name [ * ] [, ... ] +* [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ] +* +*/ + + [LOOKAHEAD(2) {truncate.setTableToken(true);}] + [ { only = true; }] + table=Table() { tables.add(table); } (LOOKAHEAD(2) "," table=Table() { tables.add(table); } )* + [ { cascade = true; }] + { + if (only && tables.size() > 1 ) { + throw new ParseException("Cannot TRUNCATE ONLY with multiple tables"); + } else { + return truncate + .withTables(tables) + .withTable(table) + .withOnly(only) + .withCascade(cascade); + } + } +} + +/** + * Parses common column-level changes shared between the COLUMN-prefixed and bare forms: + * DROP DEFAULT, SET DEFAULT, SET VISIBLE/INVISIBLE, and bracketed multi-column definitions. + */ +void AlterExpressionColumnChanges(AlterExpression alterExp): +{ + AlterExpression.ColumnDataType alterExpressionColumnDataType = null; + AlterExpression.ColumnDropDefault alterExpressionColumnDropDefault = null; + AlterExpression.ColumnSetDefault alterExpressionColumnSetDefault = null; + AlterExpression.ColumnSetVisibility alterExpressionColumnSetVisibility = null; +} +{ + ( + LOOKAHEAD(3) alterExpressionColumnDropDefault = AlterExpressionColumnDropDefault() + { alterExp.addColDropDefault(alterExpressionColumnDropDefault); } + | + LOOKAHEAD(3) alterExpressionColumnSetDefault = AlterExpressionColumnSetDefault() + { alterExp.addColSetDefault(alterExpressionColumnSetDefault); } + | + LOOKAHEAD(3) alterExpressionColumnSetVisibility = AlterExpressionColumnSetVisibility() + { alterExp.addColSetVisibility(alterExpressionColumnSetVisibility); } + | + LOOKAHEAD(4) ( + "(" + { alterExp.useBrackets(true);} + alterExpressionColumnDataType = AlterExpressionColumnDataType() { + alterExp.addColDataType(alterExpressionColumnDataType); + } + ( + "," + alterExpressionColumnDataType = AlterExpressionColumnDataType() { + alterExp.addColDataType(alterExpressionColumnDataType); + } + )* + ")" + ) + ) +} + + +AlterExpression.ColumnDataType AlterExpressionColumnDataType(): +{ + String columnName = null; + boolean withType = false; + ColDataType dataType = null; + List columnSpecs = null; + List parameter = null; +} +{ + columnName = RelObjectName() { columnSpecs = new ArrayList(); } + ( LOOKAHEAD(2) { withType = true; } )? + ( LOOKAHEAD(2) dataType = ColDataType() )? + ( LOOKAHEAD(2) parameter = CreateParameter() { columnSpecs.addAll(parameter); } )* + { + return new AlterExpression.ColumnDataType(columnName, withType, dataType, columnSpecs); + } +} + +AlterExpression.ColumnDropNotNull AlterExpressionColumnDropNotNull(): +{ + String columnName = null; + boolean withNot = false; + ColDataType dataType = null; + List columnSpecs = null; + List parameter = null; +} +{ + columnName = RelObjectName() + + ( { withNot = true; } )? + + { + return new AlterExpression.ColumnDropNotNull(columnName, withNot); + } +} + +AlterExpression.ColumnDropDefault AlterExpressionColumnDropDefault(): +{ + String columnName = null; + boolean withNot = false; + ColDataType dataType = null; + List columnSpecs = null; + List parameter = null; +} +{ + columnName = RelObjectName() + { + return new AlterExpression.ColumnDropDefault(columnName); + } +} + +AlterExpression.ColumnSetDefault AlterExpressionColumnSetDefault(): +{ + String columnName = null; + Expression defaultValue = null; +} +{ + columnName = RelObjectName() defaultValue = Expression() + { + return new AlterExpression.ColumnSetDefault(columnName, defaultValue.toString()); + } +} + +AlterExpression.ColumnSetVisibility AlterExpressionColumnSetVisibility(): +{ + String columnName = null; + boolean visible = true; +} +{ + columnName = RelObjectName() + ( + { visible = true; } | + { visible = false; } + ) + { + return new AlterExpression.ColumnSetVisibility(columnName, visible); + } +} + +List AlterExpressionConstraintState(): +{ + List retval = new ArrayList(); +} +{ + ( + ( + {retval.add(new DeferrableConstraint(false));} + ) + | + ( + {retval.add(new DeferrableConstraint(true));} + ) + | + ( + {retval.add(new ValidateConstraint(false));} + ) + | + ( + {retval.add(new ValidateConstraint(true));} + ) + | + ( + {retval.add(new EnableConstraint(false));} + ) + | + ( + {retval.add(new EnableConstraint(true));} + ) + )* + { + return retval; + } +} + +Index IndexWithComment(Index index): +{ + Token tk = null; +} +{ + tk= { + index.setCommentText(tk.image); + } + { + return index; + } +} + +void IndexOptionList(List list) : +{} +{ + ( + LOOKAHEAD(2) IndexOption(list) + )* +} + +String UsingIndexType() : +{ + String sk = null; +} +{ + ( sk = RelObjectName() ) + { + return sk; + } +} + +void IndexOption(List list) : +{ + Token tk1 = null; + Token tk2 = null; + String sk1 = null; + boolean useEqual = false; +} +{ + ( + tk1= ["=" { useEqual = true; } ] tk2= + { + list.add("KEY_BLOCK_SIZE" + (useEqual ? " = " : "") + tk2.image); + } + | + tk1= tk2= + { + list.add("WITH PARSER " + tk2.image); + } + | + tk1= tk2= + { + list.add("COMMENT " + tk2.image); + } + | + tk1= + { + list.add("VISIBLE"); + } + | + tk1= + { + list.add("INVISIBLE"); + } + | + sk1 = UsingIndexType(){ + list.add("USING " + sk1); + } + ) } -List FuncArgsList(): +List PartitionDefinitions(): { - List retval = null; - String img = null; + Token tk; + List partitionDefinitions = new ArrayList(); + PartitionDefinition partitionDef = null; + String partitionName = null; + String partitionOperation = null; + String storageEngine = null; + Expression exp = null; } { "(" - { retval = new ArrayList(); } - [ - img=FuncArgsListItem() { retval.add(img); } - ( "," img=FuncArgsListItem() { retval.add(img); } )* - ] + ( + + partitionName=RelObjectName() + { + List values = new ArrayList(); + } + + ( + + ( + "(" exp = Expression() ")"{ + values.add(exp.toString()); + } + | { values.add("MAXVALUE"); } + ) { + partitionOperation = "VALUES LESS THAN"; + } + ) + [ "ENGINE" "=" tk= { storageEngine = tk.image; } ] + { + partitionDef = new PartitionDefinition(partitionName, partitionOperation, values, storageEngine); + partitionDefinitions.add(partitionDef); + } + [ "," ] + )* ")" { - return retval; + return partitionDefinitions; } } -Drop Drop(): +List PartitionNamesList() : { - Drop drop = new Drop(); - Token tk = null; - Table name; - List dropArgs = new ArrayList(); - List funcArgs = null; - boolean useTemporary = false; + Token tk; + List partitionNames = new ArrayList(); } { - - [ { drop.setMaterialized(true);} ] ( - tk= + tk = { + partitionNames.add(tk.image); + } | + tk = { + partitionNames.add(tk.image); + } ( - [ {useTemporary=true;} ] tk= - ) - | - tk= - | - tk= - | - tk= - | - tk= - | - tk= + LOOKAHEAD(2) "," tk = { + partitionNames.add(tk.image); + } + )* ) - { drop.setType(tk.image); } - - [ LOOKAHEAD(2) {drop.setIfExists(true);} ] - - name = Table() { drop.setName(name); } - [ LOOKAHEAD(2) funcArgs = FuncArgsList() ] - ((tk= | tk= | tk= | tk=) { dropArgs.add(tk.image); })* - { - if (dropArgs.size() > 0) { - drop.setParameters(dropArgs); - } - if (drop.getType().equals("FUNCTION")) { - drop.getTypeToParameters().put("FUNCTION", funcArgs); - } - - drop.setUsingTemporary(useTemporary); - - return drop; + return partitionNames; } } -Truncate Truncate(): +/** + * Parses DISCARD/IMPORT (PARTITION names TABLESPACE | TABLESPACE). + * Both keywords share the same structure, differing only in operation enum. + */ +AlterExpression AlterExpressionDiscardOrImport(): { - Truncate truncate = new Truncate(); - Table table; + AlterExpression alterExp; + List partitions = null; + AlterOperation partOp; + AlterOperation tableOp; } { -/** -* TRUNCATE can be followed directly by the table name in Postgresql -* See: https://www.postgresql.org/docs/current/sql-truncate.html -* -* TRUNCATE [ TABLE ] [ ONLY ] name [ * ] [, ... ] -* [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ] -* -*/ - [LOOKAHEAD(2) {truncate.setTableToken(true);}] [ {truncate.setOnly(true);}] - table=Table() { truncate.setTable(table); truncate.setCascade(false); } [ {truncate.setCascade(true);} ] - { - return truncate; - } + ( + { partOp = AlterOperation.DISCARD_PARTITION; tableOp = AlterOperation.DISCARD_TABLESPACE; } + | + { partOp = AlterOperation.IMPORT_PARTITION; tableOp = AlterOperation.IMPORT_TABLESPACE; } + ) + ( + + { alterExp = new AlterExpressionPartition(); alterExp.setOperation(partOp); } + partitions = PartitionNamesList() + { alterExp.setPartitions(partitions); } + + { alterExp.setTableOption("TABLESPACE"); } + | + + { alterExp = new AlterExpressionTableOption(); alterExp.setOperation(tableOp); } + ) + { return alterExp; } } -AlterExpression.ColumnDataType AlterExpressionColumnDataType(): +/** + * Parses ADD/ALTER CONSTRAINT clause within AlterExpression. + * Handles: CONSTRAINT [UNIQUE [KEY|INDEX]] name columns + * CONSTRAINT name (FOREIGN KEY|PRIMARY KEY|UNIQUE|KEY|CHECK|[NOT] ENFORCED) + */ +void AlterExpressionAddConstraint(AlterExpression alterExp): { - String columnName = null; - boolean withType = false; - ColDataType dataType = null; - List columnSpecs = null; - List parameter = null; + Token tk; + Token tk2 = null; + String sk3 = null; + List columnNames = null; + ForeignKeyIndex fkIndex = null; + Index index = null; + Table fkTable; + List constraints = null; + CheckConstraint checkCs = null; } { - columnName = RelObjectName() { columnSpecs = new ArrayList(); } - ( LOOKAHEAD(2) { withType = true; } )? - ( LOOKAHEAD(2) dataType = ColDataType() )? - ( LOOKAHEAD(2) parameter = CreateParameter() { columnSpecs.addAll(parameter); } )* - { - return new AlterExpression.ColumnDataType(columnName, withType, dataType, columnSpecs); - } + + ( + LOOKAHEAD(2) + ( + ( { alterExp.setConstraintType("UNIQUE KEY"); } + | { alterExp.setConstraintType("UNIQUE INDEX"); } + | { alterExp.setConstraintType("UNIQUE"); } ) + sk3=RelObjectName() { + alterExp.setConstraintSymbol(sk3); + index = new Index(); + } + columnNames=ColumnsNamesList() { + index.setColumnsNames(columnNames); + alterExp.setIndex(index); + } + ) + | + sk3=RelObjectName() + ( + ( tk= tk2= + columnNames=ColumnsNamesList() + { + fkIndex = new ForeignKeyIndex() + .withName(sk3) + .withType(tk.image + " " + tk2.image) + .withColumnsNames(columnNames); + columnNames = null; + } + fkTable=Table() [ LOOKAHEAD(2) columnNames=ColumnsNamesList() ] + { + fkIndex.withTable(fkTable).withReferencedColumnNames(columnNames); + alterExp.setIndex(fkIndex); + } + ReferentialActionsOnIndex(fkIndex) + constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } + ) + | + ( tk= tk2= + columnNames=ColumnsNamesList() + { + index = new NamedConstraint() + .withName(sk3) + .withType(tk.image + " " + tk2.image) + .withColumnsNames(columnNames); + alterExp.setIndex(index); + } + AlterExpressionConstraintTail(alterExp, index) + ) + | + LOOKAHEAD(2) ( + { boolean enforced = true; } + [ tk = { enforced = false; } ] + { + alterExp.setEnforced(enforced); + alterExp.setConstraintType("CONSTRAINT"); + alterExp.setConstraintSymbol(sk3); + } + ) + | + ( + checkCs = CheckConstraintSpec(sk3) + { alterExp.setIndex(checkCs); } + ) + | + ( + tk= (tk2= { alterExp.setUk(true); } | tk2=)? + columnNames=ColumnsNamesList() + { + index = new NamedConstraint() + .withName(sk3) + .withType(tk.image + (tk2!=null?" " + tk2.image:"")) + .withColumnsNames(columnNames); + alterExp.setIndex(index); + } + AlterExpressionConstraintTail(alterExp, index) + ) + | + ( + tk= + columnNames=ColumnsNamesList() + { + index = new NamedConstraint() + .withName(sk3) + .withType(tk.image) + .withColumnsNames(columnNames); + alterExp.setIndex(index); + } + constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } + ) + ) + ) } -AlterExpression.ColumnDropNotNull AlterExpressionColumnDropNotNull(): +/** + * Parses the DROP operations within AlterExpression. + * Handles: DROP (PARTITION|columns|COLUMN|INDEX|KEY|UNIQUE|PRIMARY KEY|FOREIGN KEY|CONSTRAINT) + */ +AlterExpression AlterExpressionDrop(): { - String columnName = null; - boolean withNot = false; - ColDataType dataType = null; - List columnSpecs = null; - List parameter = null; + AlterExpression alterExp = new AlterExpressionDrop(); + Token tk; + Token tk2; + List columnNames = null; + List partitions = null; + Index index = null; } { - columnName = RelObjectName() - - ( { withNot = true; } )? - - { - return new AlterExpression.ColumnDropNotNull(columnName, withNot); - } + { alterExp.setOperation(AlterOperation.DROP); } + ( + ( + { + alterExp.setOperation(AlterOperation.DROP_PARTITION); + } + partitions=PartitionNamesList() { + alterExp.setPartitions(partitions); + } + ) + | + ( + // Oracle Multi Column Drop + columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); columnNames = null; } + [ "INVALIDATE" { alterExp.addParameters("INVALIDATE"); } ] + [ + "CASCADE" { alterExp.addParameters("CASCADE"); } + [ "CONSTRAINTS" { alterExp.addParameters("CONSTRAINTS"); } ] + ] + ) + | + ( + ( LOOKAHEAD(2) { alterExp.hasColumn(true); } )? + [ { alterExp.setUsingIfExists(true); } ] + (tk=KeywordOrIdentifier() ) { alterExp.setColumnName(tk.image); } + [ "INVALIDATE" { alterExp.addParameters("INVALIDATE"); } ] + [ + "CASCADE" { alterExp.addParameters("CASCADE"); } + [ "CONSTRAINTS" { alterExp.addParameters("CONSTRAINTS"); } ] + ] + ) + | + ( + ( tk= | tk= ) + ( tk2= | tk2= ) { + index = new Index().withType(tk.image).withName(tk2.image); + alterExp.setIndex(index); + } + ) + | + ( + tk= { alterExp.setOperation(AlterOperation.DROP_UNIQUE); } + columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); columnNames = null; } + [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] + ) + | + ( + tk= tk2= { alterExp.setOperation(AlterOperation.DROP_PRIMARY_KEY); } + [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] + ) + | + ( + tk= tk2= { alterExp.setOperation(AlterOperation.DROP_FOREIGN_KEY); } + columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); columnNames = null; } + [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] + ) + | + ( + [ { alterExp.setUsingIfExists(true); } ] + ( tk= | tk=) { alterExp.setConstraintName(tk.image); } + [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] + ) + ) + { return alterExp; } } -AlterExpression.ColumnDropDefault AlterExpressionColumnDropDefault(): +/** + * Parses partition maintenance operations within AlterExpression. + * Handles: TRUNCATE/ANALYZE/CHECK/OPTIMIZE/REBUILD/REPAIR PARTITION, + * COALESCE/REORGANIZE/EXCHANGE/PARTITION BY, REMOVE PARTITIONING + */ +AlterExpression AlterExpressionPartitionOp(): { - String columnName = null; - boolean withNot = false; - ColDataType dataType = null; - List columnSpecs = null; - List parameter = null; + AlterExpression alterExp = new AlterExpressionPartition(); + Token tk; + List partitions = null; + List partitionDefinition = null; + List columnNames = null; + Expression exp = null; } { - columnName = RelObjectName() - { - return new AlterExpression.ColumnDropDefault(columnName); - } + ( + LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.TRUNCATE_PARTITION); } + partitions=PartitionNamesList() { alterExp.setPartitions(partitions); } + | + LOOKAHEAD(2) tk= { + alterExp.setOperation(AlterOperation.COALESCE_PARTITION); + alterExp.setCoalescePartitionNumber(Integer.valueOf(tk.image)); + } + | + LOOKAHEAD(2) + partitions=PartitionNamesList() partitionDefinition=PartitionDefinitions() { + alterExp.setOperation(AlterOperation.REORGANIZE_PARTITION); + alterExp.setPartitions(partitions); + alterExp.setPartitionDefinitions(partitionDefinition); + } + | + LOOKAHEAD(2) partitions=PartitionNamesList() + tk= + [ + LOOKAHEAD(2) ( + { alterExp.setExchangePartitionWithValidation(true); } + | + { alterExp.setExchangePartitionWithoutValidation(false); } + ) + ] + { + alterExp.setOperation(AlterOperation.EXCHANGE_PARTITION); + alterExp.setPartitions(partitions); + alterExp.setExchangePartitionTableName(tk.image); + } + | + LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.ANALYZE_PARTITION); } + partitions=PartitionNamesList() { alterExp.setPartitions(partitions); } + | + LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.CHECK_PARTITION); } + partitions=PartitionNamesList() { alterExp.setPartitions(partitions); } + | + LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.OPTIMIZE_PARTITION); } + partitions=PartitionNamesList() { alterExp.setPartitions(partitions); } + | + LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.REBUILD_PARTITION); } + partitions=PartitionNamesList() { alterExp.setPartitions(partitions); } + | + LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.REPAIR_PARTITION); } + partitions=PartitionNamesList() { alterExp.setPartitions(partitions); } + | + LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.REMOVE_PARTITIONING); } + | + LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.PARTITION_BY); } + { alterExp.setPartitionType("RANGE"); } + ( + "(" exp=Expression() ")" { alterExp.setPartitionExpression(exp); } + | + columnNames=ColumnsNamesList() { alterExp.setPartitionColumns(columnNames); } + ) + partitionDefinition=PartitionDefinitions() { alterExp.setPartitionDefinitions(partitionDefinition); } + ) + { return alterExp; } } -List AlterExpressionConstraintState(): +/** + * Parses ADD/ALTER/MODIFY operations within ALTER TABLE. + * Handles: PRIMARY KEY, INDEX/KEY, SPATIAL/FULLTEXT, column COMMENT, + * ADD PARTITION, column definitions, UNIQUE, FOREIGN KEY, CHECK ENFORCED, CONSTRAINT. + */ +AlterExpression AlterExpressionAddAlterModify(): { - List retval = new ArrayList(); + AlterExpression alterExp = new AlterExpression(); + Token tk; + Token tk2 = null; + String sk3 = null; + String sk4 = null; + List columnNames = null; + List indexColumnNames = null; + List constraints = null; + Index index = null; + AlterExpression.ColumnDataType alterExpressionColumnDataType = null; + AlterExpression.ColumnDropNotNull alterExpressionColumnDropNotNull = null; + List indexSpec = new ArrayList(); + List partitionDefinition = null; } { ( - ( - {retval.add(new DeferrableConstraint(false));} + { alterExp.setOperation(AlterOperation.ADD); } + | + { alterExp.setOperation(AlterOperation.ALTER); } + | + { alterExp.setOperation(AlterOperation.MODIFY); } + ) + + ( + LOOKAHEAD(2) ( columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); }) + + constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } + [ + AlterExpressionUsingIndex(alterExp) + ] + | + LOOKAHEAD(2) ( + (tk= { alterExp.setUk(true); } | tk=) + ( + LOOKAHEAD(3) + sk3 = RelObjectName() + [ LOOKAHEAD(2) sk4 = UsingIndexType() ] + [ LOOKAHEAD(2) indexColumnNames = IndexColumnsWithParamsList() ] + | + [ LOOKAHEAD(2) sk4 = UsingIndexType() ] + [ LOOKAHEAD(2) indexColumnNames = IndexColumnsWithParamsList() ] + ) + IndexOptionList(indexSpec = new ArrayList()) + { + index = new Index() + .withIndexKeyword(tk.image) + .withName(sk3) + .withUsing(sk4) + .withColumns(indexColumnNames) + .withIndexSpec(indexSpec); + + alterExp.setIndex(index); + } + constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } ) | + LOOKAHEAD(4) ( - {retval.add(new DeferrableConstraint(true));} + ( tk= | tk= ) + [ LOOKAHEAD(2) ( tk2= | tk2= ) ] + ( + sk3 = RelObjectName() + columnNames = ColumnsNamesList() + | + columnNames = ColumnsNamesList() + ) + IndexOptionList(indexSpec = new ArrayList()) + { + String type = tk.image; + String keyword = tk2 != null ? tk2.image : null; + index = new Index() + .withType(type) + .withIndexKeyword(keyword) + .withColumnsNames(columnNames) + .withIndexSpec(indexSpec); + + if (sk3 != null) { + index.setName(sk3); + } + + alterExp.setIndex(index); + } ) | - ( - {retval.add(new ValidateConstraint(false));} + LOOKAHEAD(2) ( + sk3=RelObjectName() tk= { alterExp.withColumnName(sk3).withCommentText(tk.image); } + ) + | + LOOKAHEAD(3) ( + { + alterExp.setOperation(AlterOperation.ADD_PARTITION); + } + partitionDefinition=PartitionDefinitions() { + alterExp.setPartitionDefinitions(partitionDefinition); + } + ) + | + LOOKAHEAD(3) ( + ( LOOKAHEAD(2) + ( + { alterExp.hasColumn(true); } + | + { alterExp.hasColumns(true); } + ) + )? + [ LOOKAHEAD(2) { alterExp.setUseIfNotExists(true); } ] + ( + LOOKAHEAD(3) AlterExpressionColumnChanges(alterExp) + | + LOOKAHEAD(2) alterExpressionColumnDataType = AlterExpressionColumnDataType() + { alterExp.addColDataType(alterExpressionColumnDataType); } + | + LOOKAHEAD(3) alterExpressionColumnDropNotNull = AlterExpressionColumnDropNotNull() + { alterExp.addColDropNotNull( alterExpressionColumnDropNotNull);} + ) ) | + LOOKAHEAD(3) AlterExpressionColumnChanges(alterExp) + | ( - {retval.add(new ValidateConstraint(true));} + + ( + ( + { alterExp.setUk(true); } + | { alterExp.setUk(false); } + ) + [ (tk= | tk=) { alterExp.setUkName(tk.image); } ] + | + (tk= | tk=) { + alterExp.setUkTypeSpecified(false); + alterExp.setUkName(tk.image); + } + )? + columnNames=ColumnsNamesList() { alterExp.setUkColumns(columnNames); } + [ + AlterExpressionUsingIndex(alterExp) + ] + [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] ) | + // Standalone FK now uses ForeignKeyIndex, same as CONSTRAINT FK ( - {retval.add(new EnableConstraint(false));} + { ForeignKeyIndex fkIndex; ReferentialAction ra; } + fkIndex = ForeignKeySpec(null) + { + alterExp.setIndex(fkIndex); + // backward compat: populate deprecated FK fields from ForeignKeyIndex + alterExp.setFkColumns(fkIndex.getColumnsNames()); + if (fkIndex.getTable() != null) { + alterExp.setFkSourceSchema(fkIndex.getTable().getSchemaName()); + alterExp.setFkSourceTable(fkIndex.getTable().getName()); + } + alterExp.setFkSourceColumns(fkIndex.getReferencedColumnNames()); + ra = fkIndex.getReferentialAction(ReferentialAction.Type.DELETE); + if (ra != null) { alterExp.setReferentialAction(ra.getType(), ra.getAction()); } + ra = fkIndex.getReferentialAction(ReferentialAction.Type.UPDATE); + if (ra != null) { alterExp.setReferentialAction(ra.getType(), ra.getAction()); } + } + ) + | + LOOKAHEAD(3) ( + sk3=RelObjectName() + { boolean enforced = true; } + [ tk = { enforced = false; } ] + { + alterExp.setEnforced(enforced); + alterExp.setConstraintType("CHECK"); + alterExp.setConstraintSymbol(sk3); + } ) | ( - {retval.add(new EnableConstraint(true));} + AlterExpressionAddConstraint(alterExp) ) - )* - { - return retval; - } + ) + { return alterExp; } } -Index IndexWithComment(Index index): +/** + * Parses all RENAME variants within ALTER TABLE. + * Handles: RENAME [COLUMN] old TO new, RENAME TO tablename, + * RENAME INDEX/KEY/CONSTRAINT old TO new. + */ +AlterExpression AlterExpressionRenameOp(): { - Token tk = null; + AlterExpression alterExp = new AlterExpressionRename(); + Token tk; + Token tk2; + Index index; } { - tk= { - index.setCommentText(tk.image); - } - { - return index; - } + + ( + LOOKAHEAD(2) ( + ( + { alterExp.setOperation(AlterOperation.RENAME_INDEX); } + | { alterExp.setOperation(AlterOperation.RENAME_KEY); } + ) + | + { alterExp.setOperation(AlterOperation.RENAME_CONSTRAINT); } + ) + (tk= | tk=) { + alterExp.setOldIndex(new Index().withName(tk.image)); + } + + (tk2= | tk2=) { + index = new Index().withName(tk2.image); + alterExp.setIndex(index); + } + | + LOOKAHEAD(2) ( + { alterExp.setOperation(AlterOperation.RENAME_TABLE); } + (tk2= | tk2=) { alterExp.setNewTableName(tk2.image); } + ) + | + ( + { alterExp.setOperation(AlterOperation.RENAME); } + [ { alterExp.hasColumn(true); } ] + (tk=KeywordOrIdentifier()) { alterExp.setColOldName(tk.image); } + + (tk2=KeywordOrIdentifier()) { alterExp.setColumnName(tk2.image); } + ) + ) + { return alterExp; } } /** -* This production needs refactoring to multiple smaller productions. The target class should -* be splitted as well. +* Dispatcher production for all ALTER TABLE expression types. +* Delegates to focused sub-productions for each operation category. */ AlterExpression AlterExpression(): { - AlterExpression alterExp = new AlterExpression(); + AlterExpression alterExp = null; Token tk; Token tk2 = null; String sk3 = null; - String sk4 = null; - ColDataType dataType; - List columnNames = null; - List constraints = null; - ForeignKeyIndex fkIndex = null; - Index index = null; - Table fkTable = null; - AlterExpression.ColumnDataType alterExpressionColumnDataType = null; - AlterExpression.ColumnDropNotNull alterExpressionColumnDropNotNull = null; - AlterExpression.ColumnDropDefault alterExpressionColumnDropDefault = null; - ReferentialAction.Action action = null; - String truncatePartitionName = null; // for captureRest() List tokens = new LinkedList(); @@ -6705,295 +11907,184 @@ AlterExpression AlterExpression(): { ( - ( - ( - { alterExp.setOperation(AlterOperation.ADD); } - | - { alterExp.setOperation(AlterOperation.ALTER); } - | - { alterExp.setOperation(AlterOperation.MODIFY); } - ) - - ( - LOOKAHEAD(2) ( columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); }) - - constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] - | - LOOKAHEAD(2) ( - (tk= { alterExp.setUk(true); } | tk=) - sk3 = RelObjectName() - columnNames = ColumnsNamesList() - { - index = new Index().withType(tk.image).withName(sk3).withColumnsNames(columnNames); - alterExp.setIndex(index); - } - constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] - [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] - ) - | - LOOKAHEAD(2) ( - sk3=RelObjectName() tk= { alterExp.withColumnName(sk3).withCommentText(tk.image); } - ) - | - LOOKAHEAD(3) ( - ( LOOKAHEAD(2) { alterExp.hasColumn(true); } )? - [ { alterExp.setUseIfNotExists(true); } ] - ( - LOOKAHEAD(4) ( - "(" - { alterExp.useBrackets(true);} - alterExpressionColumnDataType = AlterExpressionColumnDataType() { - alterExp.addColDataType(alterExpressionColumnDataType); - } - ( - "," - alterExpressionColumnDataType = AlterExpressionColumnDataType() { - alterExp.addColDataType(alterExpressionColumnDataType); - } - )* - ")" - ) - | - LOOKAHEAD(2) alterExpressionColumnDataType = AlterExpressionColumnDataType() - { alterExp.addColDataType(alterExpressionColumnDataType); } - | - LOOKAHEAD(3) alterExpressionColumnDropNotNull = AlterExpressionColumnDropNotNull() - { alterExp.addColDropNotNull( alterExpressionColumnDropNotNull);} - | - alterExpressionColumnDropDefault = AlterExpressionColumnDropDefault() - { alterExp.addColDropDefault( alterExpressionColumnDropDefault); } - ) - ) - | - ( - "(" alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.addColDataType(alterExpressionColumnDataType); } - ("," - alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.addColDataType(alterExpressionColumnDataType); } - )* - ")" - ) - | - ( (( { alterExp.setUk(true); } | ) (tk= | tk=) { alterExp.setUkName(tk.image); } )? - columnNames=ColumnsNamesList() { alterExp.setUkColumns(columnNames); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] - [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] - ) - | - //following two choices regarding foreign keys should be merged - ( columnNames=ColumnsNamesList() { alterExp.setFkColumns(columnNames); columnNames = null; } - /* - tk= [ columnNames=ColumnsNamesList() ] - { alterExp.setFkSourceTable(tk.image); alterExp.setFkSourceColumns(columnNames); } - */ - fkTable=Table() [ LOOKAHEAD(2) columnNames=ColumnsNamesList() ] - { - alterExp.setFkSourceSchema(fkTable.getSchemaName()); - alterExp.setFkSourceTable(fkTable.getName()); - alterExp.setFkSourceColumns(columnNames); - } - - [LOOKAHEAD(2) ( (tk= | tk=) action = Action() - { alterExp.setReferentialAction(ReferentialAction.Type.from(tk.image), action); } - )] - [LOOKAHEAD(2) ( (tk= | tk=) action = Action() - { alterExp.setReferentialAction(ReferentialAction.Type.from(tk.image), action); } - )] - ) - | - ( - sk3=RelObjectName() - ( - ( tk= tk2= - columnNames=ColumnsNamesList() - { - fkIndex = new ForeignKeyIndex() - .withName(sk3) - .withType(tk.image + " " + tk2.image) - .withColumnsNames(columnNames); - columnNames = null; - } - fkTable=Table() [ LOOKAHEAD(2) columnNames=ColumnsNamesList() ] - { - fkIndex.withTable(fkTable).withReferencedColumnNames(columnNames); - alterExp.setIndex(fkIndex); - } - - [LOOKAHEAD(2) ( (tk= | tk=) action = Action() - { fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); } - )] - [LOOKAHEAD(2) ( (tk= | tk=) action = Action() - { fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); } - )] - constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - ) - | - ( tk= tk2= - columnNames=ColumnsNamesList() - { - index = new NamedConstraint() - .withName(sk3) - .withType(tk.image + " " + tk2.image) - .withColumnsNames(columnNames); - alterExp.setIndex(index); - } - constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] - [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] - ) - | - ( - {Expression exp = null;} (LOOKAHEAD(2) "(" exp = Expression() ")")* { - CheckConstraint checkCs = new CheckConstraint().withName(sk3).withExpression(exp); - alterExp.setIndex(checkCs); - } - ) - | - ( - tk= (tk2= { alterExp.setUk(true); } | tk2=)? - columnNames=ColumnsNamesList() - { - index = new NamedConstraint() - .withName(sk3) - .withType(tk.image + (tk2!=null?" " + tk2.image:"")) - .withColumnsNames(columnNames); - alterExp.setIndex(index); - } - constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] - [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] - ) - | - ( - tk= - columnNames=ColumnsNamesList() - { - index = new NamedConstraint() - .withName(sk3) - .withType(tk.image) - .withColumnsNames(columnNames); - alterExp.setIndex(index); - } - constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - ) - ) - ) - ) - ) + alterExp = AlterExpressionAddAlterModify() | ( + { alterExp = new AlterExpression(); } { alterExp.setOperation(AlterOperation.CHANGE); } [ { alterExp.hasColumn(true); alterExp.setOptionalSpecifier("COLUMN"); } ] ( - (tk= | tk=) + { AlterExpression.ColumnDataType alterExpressionColumnDataType; } + (tk=KeywordOrIdentifier()) alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.withColumnOldName(tk.image).addColDataType(alterExpressionColumnDataType); } ) ) | - { alterExp.setOperation(AlterOperation.DROP); } + alterExp = AlterExpressionDrop() + | + LOOKAHEAD(5) ( + { alterExp = new AlterExpression(); } + { + alterExp.setOperation(AlterOperation.FORCE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(5) ( + { alterExp = new AlterExpression(); } + { + alterExp.setOperation(AlterOperation.NO_FORCE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(1) ( + { alterExp = new AlterExpression(); } + { alterExp.setOperation(AlterOperation.FORCE); } + ) + | ( - ( - ( - // we use the PK Columns Field instead of the Column Field - // for holding multiple DROP Columns - columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); columnNames = null; } - - [ "INVALIDATE" { alterExp.addParameters("INVALIDATE"); } ] - - [ - "CASCADE" { alterExp.addParameters("CASCADE"); } - [ "CONSTRAINTS" { alterExp.addParameters("CONSTRAINTS"); } ] - ] - ) - | - ( - ( LOOKAHEAD(2) { alterExp.hasColumn(true); } )? - [ { alterExp.setUsingIfExists(true); } ] - (tk= | tk=) { alterExp.setColumnName(tk.image); } - - [ "INVALIDATE" { alterExp.addParameters("INVALIDATE"); } ] - - [ - "CASCADE" { alterExp.addParameters("CASCADE"); } - [ "CONSTRAINTS" { alterExp.addParameters("CONSTRAINTS"); } ] - ] - ) - ) - | - ( - ( tk= | tk= ) - ( tk2= | tk2= ) { - index = new Index().withType(tk.image).withName(tk2.image); - alterExp.setIndex(index); - } - ) - | - ( - tk= { alterExp.setOperation(AlterOperation.DROP_UNIQUE); } - columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); columnNames = null; } - [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] - ) - | - ( - tk= tk2= { alterExp.setOperation(AlterOperation.DROP_PRIMARY_KEY); } - [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] - ) - | - ( - tk= tk2= { alterExp.setOperation(AlterOperation.DROP_FOREIGN_KEY); } - columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); columnNames = null; } - [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] - ) - | - ( - [ { alterExp.setUsingIfExists(true); } ] - ( tk= | tk=) { alterExp.setConstraintName(tk.image); } - [ ( tk= | tk= ) { alterExp.addParameters(tk.image); } ] - ) + { alterExp = new AlterExpressionTableOption(); } + { alterExp.setOperation(AlterOperation.ALGORITHM); } + ["=" { alterExp.setUseEqual(true);} ] + sk3 = RelObjectName() { alterExp.setAlgorithmOption(sk3); } + ) + | + ( + { alterExp = new AlterExpressionTableOption(); } + { alterExp.setOperation(AlterOperation.KEY_BLOCK_SIZE); } + ["=" { alterExp.setUseEqual(true);} ] + tk= { alterExp.setKeyBlockSize(Integer.parseInt(tk.image)); } + ) + | + ( + { alterExp = new AlterExpressionTableOption(); } + { alterExp.setOperation(AlterOperation.LOCK); } + ["=" { alterExp.setUseEqual(true);} ] + sk3 = RelObjectName() { alterExp.setLockOption(sk3); } + ) + | + ( + { alterExp = new AlterExpressionTableOption(); } + { alterExp.setOperation(AlterOperation.ENGINE); } + ["=" { alterExp.setUseEqual(true);} ] + sk3 = RelObjectName() { alterExp.setEngineOption(sk3); } + ) + | + LOOKAHEAD(2) alterExp = AlterExpressionRenameOp() + | + ({ alterExp = new AlterExpressionCharset(); } + { + alterExp.setOperation(AlterOperation.CONVERT); + alterExp.setConvertType(AlterExpression.ConvertType.CONVERT_TO); + } + tk= { alterExp.setCharacterSet(tk.image); } + [ tk2= { alterExp.setCollation(tk2.image); }] + ) + | + LOOKAHEAD(3) + ( + { alterExp = new AlterExpressionCharset(); } + + ( + [ "=" { alterExp.setHasEqualForCharacterSet(true); } ] + tk= { + alterExp.setOperation(AlterOperation.CONVERT); + alterExp.setConvertType(AlterExpression.ConvertType.DEFAULT_CHARACTER_SET); + alterExp.setCharacterSet(tk.image); + } + [ [ "=" { alterExp.setHasEqualForCollate(true); } ] + tk2= { alterExp.setCollation(tk2.image); }] + | + + [ "=" { alterExp.setHasEqualForCollate(true); } ] + tk= { + alterExp.setOperation(AlterOperation.COLLATE); + alterExp.setCollation(tk.image); + alterExp.setDefaultCollateSpecified(true); + } + ) + ) + | + ({ alterExp = new AlterExpressionCharset(); } + [ "=" { alterExp.setHasEqualForCharacterSet(true); } ] + tk= { + alterExp.setOperation(AlterOperation.CONVERT); + alterExp.setConvertType(AlterExpression.ConvertType.CHARACTER_SET); + alterExp.setCharacterSet(tk.image); + } + [ [ "=" { alterExp.setHasEqualForCollate(true); } ] + tk2= { alterExp.setCollation(tk2.image); }] ) - | - ( - { - alterExp.setOperation(AlterOperation.ALGORITHM); - } - ["=" { alterExp.setUseEqual(true);} ] - sk3 = RelObjectName() {alterExp.addParameters(sk3); } + | + ({ alterExp = new AlterExpressionCharset(); } + { alterExp.setOperation(AlterOperation.COLLATE); } + [ "=" { alterExp.setHasEqualForCollate(true); } ] + tk= { alterExp.setCollation(tk.image); } ) | - LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.RENAME); } [ { alterExp.hasColumn(true);} ] - ( tk= | tk= ) { alterExp.setColOldName(tk.image); } - - (tk2= | tk2=) { alterExp.setColumnName(tk2.image); } + ({ alterExp = new AlterExpressionTableOption(); } + {alterExp.setOperation(AlterOperation.COMMENT);} + ["=" {alterExp.setOperation(AlterOperation.COMMENT_WITH_EQUAL_SIGN);} ] + tk= { alterExp.setCommentText(tk.image); } + ) | - LOOKAHEAD(2)( - {alterExp.setOperation(AlterOperation.RENAME_TABLE);} - (tk2= | tk2=) { alterExp.setNewTableName(tk2.image);} - ) + ({ alterExp = new AlterExpressionTableOption(); } + {alterExp.setOperation(AlterOperation.SET_TABLE_OPTION);} + ["=" { alterExp.setUseEqual(true);} ] + tk= { + if (alterExp.getUseEqual()) { + alterExp.setTableOption("ENCRYPTION = " + tk.image); + } else { + alterExp.setTableOption("ENCRYPTION " + tk.image); + } + } + ) | - ( {alterExp.setOperation(AlterOperation.COMMENT);} - ["=" {alterExp.setOperation(AlterOperation.COMMENT_WITH_EQUAL_SIGN);} ] - tk= { alterExp.setCommentText(tk.image); } - ) + alterExp = AlterExpressionDiscardOrImport() | - LOOKAHEAD(2) - ( (( {alterExp.setOperation(AlterOperation.RENAME_INDEX);} - | {alterExp.setOperation(AlterOperation.RENAME_KEY);}) - | { alterExp.setOperation(AlterOperation.RENAME_CONSTRAINT); } - ) - (tk= | tk=){ - alterExp.setOldIndex(new Index().withName(tk.image)); - } - - (tk2= | tk2=){ - index = new Index().withName(tk2.image); - alterExp.setIndex(index); - } - ) + LOOKAHEAD(4) ( + { alterExp = new AlterExpression(); } + { + alterExp.setOperation(AlterOperation.DISABLE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(2) ( + { alterExp = new AlterExpressionTableOption(); } + { + alterExp.setOperation(AlterOperation.DISABLE_KEYS); + } + ) + | + LOOKAHEAD(4) ( + { alterExp = new AlterExpression(); } + { + alterExp.setOperation(AlterOperation.ENABLE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(2) ( + { alterExp = new AlterExpressionTableOption(); } + { + alterExp.setOperation(AlterOperation.ENABLE_KEYS); + } + ) + | + ({ alterExp = new AlterExpressionTableOption(); } + {alterExp.setOperation(AlterOperation.SET_TABLE_OPTION);} + ["=" { alterExp.setUseEqual(true);} ] + tk= { + if (alterExp.getUseEqual()) { + alterExp.setTableOption("AUTO_INCREMENT = " + tk.image); + } else { + alterExp.setTableOption("AUTO_INCREMENT " + tk.image); + } + } + ) | - LOOKAHEAD(2) { alterExp.setOperation(AlterOperation.TRUNCATE_PARTITION); } truncatePartitionName = RelObjectName() { alterExp.setTruncatePartitionName(truncatePartitionName); } + alterExp = AlterExpressionPartitionOp() | - tokens = captureRest() { + { alterExp = new AlterExpression(); } + tokens = captureRest() { alterExp.setOperation(AlterOperation.UNSPECIFIC); StringBuilder optionalSpecifier = new StringBuilder(); int i=0; @@ -7014,7 +12105,6 @@ AlterExpression AlterExpression(): return alterExp; } } - Statement Alter(): { Statement statement; @@ -7156,57 +12246,57 @@ AlterSystemStatement AlterSystemStatement(): { ( ( - "ARCHIVE" "LOG" { operation = AlterSystemOperation.ARCHIVE_LOG; } + { operation = AlterSystemOperation.ARCHIVE_LOG; } ) | ( - "CHECKPOINT" { operation = AlterSystemOperation.CHECKPOINT; } + { operation = AlterSystemOperation.CHECKPOINT; } ) | ( - "DUMP" "ACTIVE" "SESSION" "HISTORY" { operation = AlterSystemOperation.DUMP_ACTIVE_SESSION_HISTORY; } + { operation = AlterSystemOperation.DUMP_ACTIVE_SESSION_HISTORY; } ) | ( ( - "DISTRIBUTED RECOVERY" { operation = AlterSystemOperation.ENABLE_DISTRIBUTED_RECOVERY; } - | "RESTRICTED SESSION" { operation = AlterSystemOperation.ENABLE_DISTRIBUTED_RECOVERY; } + "DISTRIBUTED" "RECOVERY" { operation = AlterSystemOperation.ENABLE_DISTRIBUTED_RECOVERY; } + | { operation = AlterSystemOperation.ENABLE_DISTRIBUTED_RECOVERY; } ) ) | ( ( - "DISTRIBUTED RECOVERY" { operation = AlterSystemOperation.DISABLE_DISTRIBUTED_RECOVERY; } - | "RESTRICTED SESSION" { operation = AlterSystemOperation.DISABLE_RESTRICTED_SESSION; } + "DISTRIBUTED" "RECOVERY" { operation = AlterSystemOperation.DISABLE_DISTRIBUTED_RECOVERY; } + | { operation = AlterSystemOperation.DISABLE_RESTRICTED_SESSION; } ) ) | ( - "FLUSH" { operation = AlterSystemOperation.FLUSH; } + { operation = AlterSystemOperation.FLUSH; } ) | ( - "DISCONNECT" "SESSION" { operation = AlterSystemOperation.DISCONNECT_SESSION; } + { operation = AlterSystemOperation.DISCONNECT_SESSION; } ) | ( - "KILL SESSION" { operation = AlterSystemOperation.KILL_SESSION; } + { operation = AlterSystemOperation.KILL_SESSION; } ) | ( - "SWITCH" { operation = AlterSystemOperation.SWITCH; } + { operation = AlterSystemOperation.SWITCH; } ) | ( - "SUSPEND" { operation = AlterSystemOperation.SUSPEND; } + { operation = AlterSystemOperation.SUSPEND; } ) | ( - "RESUME" { operation = AlterSystemOperation.RESUME; } + { operation = AlterSystemOperation.RESUME; } ) | ( - "QUIESCE" "RESTRICTED" { operation = AlterSystemOperation.QUIESCE; } + { operation = AlterSystemOperation.QUIESCE; } ) | ( @@ -7214,19 +12304,19 @@ AlterSystemStatement AlterSystemStatement(): ) | ( - "SHUTDOWN" { operation = AlterSystemOperation.SHUTDOWN; } + { operation = AlterSystemOperation.SHUTDOWN; } ) | ( - "REGISTER" { operation = AlterSystemOperation.REGISTER; } + { operation = AlterSystemOperation.REGISTER; } ) | ( - "SET" { operation = AlterSystemOperation.SET; } + { operation = AlterSystemOperation.SET; } ) | ( - "RESET" { operation = AlterSystemOperation.RESET; } + { operation = AlterSystemOperation.RESET; } ) ) parameters = captureRest() @@ -7342,23 +12432,21 @@ Grant Grant(): ( ( [readGrantTypes(privileges) ( readGrantTypes(privileges))*] - - ( - objName=RelObjectNames() { grant.setObjectName(objName.getNames()); } - ) - ) - | - ( - tk= { grant.setRole(tk.image); } - ) + objName=RelObjectNames() { grant.setObjectName(objName.getNames()); } + ) + | + ( + tk= { grant.setRole(tk.image); } ) - (users = UsersList() {grant.setUsers(users);}) + ) + users = UsersList() { - if(privileges.size() > 0) { - grant.setPrivileges(privileges); - } - return grant; - } + grant.setUsers(users); + if(privileges.size() > 0) { + grant.setPrivileges(privileges); + } + return grant; + } } List UsersList(): @@ -7406,93 +12494,108 @@ List SequenceParameters(): List sequenceParameters = new ArrayList(); Sequence.Parameter parameter = null; Token token = null; + Token byToken = null; + Token withToken = null; } { -( - ( token= - { - parameter = new Sequence.Parameter(Sequence.ParameterType.INCREMENT_BY); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); - } - ) - | - ( token= - { - parameter = new Sequence.Parameter(Sequence.ParameterType.START_WITH); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); - } - ) - | - ( [ LOOKAHEAD(2) token=] - { - parameter = new Sequence.Parameter(Sequence.ParameterType.RESTART_WITH); - if(token != null){ - parameter.setValue(Long.parseLong(token.image)); - } - sequenceParameters.add(parameter); - } - ) - | - ( - { - parameter = new Sequence.Parameter(Sequence.ParameterType.NOMAXVALUE); - sequenceParameters.add(parameter); - } - | token= - { - parameter = new Sequence.Parameter(Sequence.ParameterType.MAXVALUE); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); - } - ) - | - ( - { - parameter = new Sequence.Parameter(Sequence.ParameterType.NOMINVALUE); - sequenceParameters.add(parameter); - } - | token= - { - parameter = new Sequence.Parameter(Sequence.ParameterType.MINVALUE); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); - } - ) - | - ( { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOCYCLE)); } - | { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.CYCLE)); } - ) - | - ( - { - parameter = new Sequence.Parameter(Sequence.ParameterType.NOCACHE); - sequenceParameters.add(parameter); - } - | token= + ( + LOOKAHEAD(2) ( + ( + [ byToken= ] token= + { + if (byToken != null) { + parameter = new Sequence.Parameter(Sequence.ParameterType.INCREMENT_BY); + } else { + parameter = new Sequence.Parameter(Sequence.ParameterType.INCREMENT); + } + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + ) + | + ( + [ withToken= ] token= + { + if (withToken != null) { + parameter = new Sequence.Parameter(Sequence.ParameterType.START_WITH); + } else { + parameter = new Sequence.Parameter(Sequence.ParameterType.START); + } + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + ) + | + ( + [ LOOKAHEAD(2) token=] + { + parameter = new Sequence.Parameter(Sequence.ParameterType.RESTART_WITH); + if(token != null) { + parameter.setValue(Long.parseLong(token.image)); + } + sequenceParameters.add(parameter); + } + ) + | + + { + parameter = new Sequence.Parameter(Sequence.ParameterType.NOMAXVALUE); + sequenceParameters.add(parameter); + } + | + token= + { + parameter = new Sequence.Parameter(Sequence.ParameterType.MAXVALUE); + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + | + + { + parameter = new Sequence.Parameter(Sequence.ParameterType.NOMINVALUE); + sequenceParameters.add(parameter); + } + | + token= + { + parameter = new Sequence.Parameter(Sequence.ParameterType.MINVALUE); + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOCYCLE)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.CYCLE)); } + | + + { + parameter = new Sequence.Parameter(Sequence.ParameterType.NOCACHE); + sequenceParameters.add(parameter); + } + | + token= + { + parameter = new Sequence.Parameter(Sequence.ParameterType.CACHE); + parameter.setValue(Long.parseLong(token.image)); + sequenceParameters.add(parameter); + } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.ORDER)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOORDER)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.KEEP)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOKEEP)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.SESSION)); } + | + { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.GLOBAL)); } + ) + )* { - parameter = new Sequence.Parameter(Sequence.ParameterType.CACHE); - parameter.setValue(Long.parseLong(token.image)); - sequenceParameters.add(parameter); + return sequenceParameters; } - ) - | - ( { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.ORDER)); } - | { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOORDER)); } - ) - | - ( { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.KEEP)); } - | { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.NOKEEP)); } - ) - | - ( { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.SESSION)); } - | { sequenceParameters.add(new Sequence.Parameter(Sequence.ParameterType.GLOBAL)); } - ) - )* //zero or many times those productions - { - return sequenceParameters; - } } CreateSequence CreateSequence(): @@ -7500,9 +12603,11 @@ CreateSequence CreateSequence(): CreateSequence createSequence = new CreateSequence(); Sequence sequence; List sequenceParameters; + Token dataType = null; } { sequence=Sequence() { createSequence.setSequence(sequence); } + [ ( dataType= | dataType= ) { sequence.setDataType(dataType.image); } ] sequenceParameters = SequenceParameters() { sequence.setParameters(sequenceParameters); @@ -7547,6 +12652,8 @@ Statement Create(): | LOOKAHEAD(2) statement = CreateView(isUsingOrReplace) | + statement = CreatePolicy() + | // @fixme: must appear with TRIGGER before INDEX or it will collide with INDEX's CreateParameter() production ( tk= | tk= ) captureRest = captureRest() { @@ -7627,6 +12734,45 @@ Synonym Synonym() #Synonym : } } +CreatePolicy CreatePolicy() #CreatePolicy: +{ + CreatePolicy createPolicy = new CreatePolicy(); + String policyName; + Table table; + Token commandToken = null; + String roleName; + Expression usingExpr = null; + Expression checkExpr = null; +} +{ + policyName=RelObjectName() { createPolicy.setPolicyName(policyName); } + table=Table() { createPolicy.setTable(table); } + + [ + ( commandToken= + | commandToken= + | commandToken= + | commandToken= + | commandToken= + ) + { createPolicy.setCommand(commandToken.image); } + ] + + [ + roleName=RelObjectName() { createPolicy.addRole(roleName); } + ( "," roleName=RelObjectName() { createPolicy.addRole(roleName); } )* + ] + + [ "(" usingExpr=Expression() ")" { createPolicy.setUsingExpression(usingExpr); } ] + + [ LOOKAHEAD(2) "(" checkExpr=Expression() ")" { createPolicy.setWithCheckExpression(checkExpr); } ] + + { + + return createPolicy; + } +} + UnsupportedStatement UnsupportedStatement(): { List tokens = new LinkedList(); @@ -7690,6 +12836,43 @@ List captureFunctionBody() { return tokens; } +/** +* Reads the tokens of a Postgres dollar quoted string, + rebuilding the white space of the text based on each token's position and length + 1) $$...$$ + 2) $tag$...$tag$ +*/ + +JAVACODE +String getQuotedString(String closingQuote, String escapeChar) { + StringBuilder buffer = new StringBuilder(); + Deque windowQueue = new ArrayDeque(); + int delimiterLength = closingQuote.length(); + + Token prevToken = null; + Token token; + + while (true) { + token = getNextToken(); + if (token.kind == 0) { + throw new ParseException("Unterminated quoted string"); + } + appendWhitespaceFromTokenGap(buffer, prevToken, token); + appendTokenImageAndTrackDelimiter(buffer, windowQueue, delimiterLength, token.image, closingQuote); + if (endsWithDelimiter(windowQueue, closingQuote)) { + buffer.setLength(buffer.length() - delimiterLength); + return buffer.toString(); + } + prevToken = token; + } +} + +JAVACODE +String getQuotedIdentifier(String openingQuote, String closingQuote, String escapeChar) { + return openingQuote + getQuotedString(closingQuote, escapeChar) + closingQuote; +} + + JAVACODE List captureUnsupportedStatementDeclaration() { List tokens = new LinkedList(); @@ -7712,9 +12895,20 @@ String IdentifierChain(): String part; } { - identifierChain=RelObjectNameExt2() - ( "." part=RelObjectNameExt2() { identifierChain += "." + part; } )* + identifierChain=RelObjectNameExt() + ( LOOKAHEAD(2) "." part=RelObjectNameExt() { identifierChain += "." + part; } )* + + { + return identifierChain; + } +} +String IdentifierChain2(String identifierChain): +{ + String part; +} +{ + ( LOOKAHEAD(2) "." part=RelObjectNameExt() { identifierChain += "." + part; } )* { return identifierChain; } @@ -7749,6 +12943,7 @@ Expression CharacterPrimary(): TranscodingFunction TranscodingFunction() #TranscodingFunction : { + Token keywordToken; TranscodingFunction transcodingFunction; ColDataType colDataType; Expression expression; @@ -7756,17 +12951,16 @@ TranscodingFunction TranscodingFunction() #TranscodingFunction : Token style; } { - "(" + ( keywordToken= | keywordToken= | keywordToken= ) + "(" ( - LOOKAHEAD(ColDataType() ",") ( - colDataType = ColDataType() - "," expression = Expression() - [ "," style = { transcodingName = style.image; } ] + LOOKAHEAD(4) colDataType = ColDataType() + "," expression = Expression() + [ "," style = { transcodingName = style.image; } ] - { - transcodingFunction = new TranscodingFunction(colDataType, expression, transcodingName); - } - ) + { + transcodingFunction = new TranscodingFunction(keywordToken.image, colDataType, expression, transcodingName); + } | ( expression = Expression() @@ -7819,3 +13013,166 @@ TrimFunction TrimFunction(): return new TrimFunction(trimSpecification, expression, fromExpression, usesFrom); } } + +void SnowflakeTimeTravelAt(StringBuilder builder): +{ + Expression expression; + Token tk; +} +{ + // AT( { TIMESTAMP => | OFFSET => | STATEMENT => | STREAM => '' } ) + + { builder.append("AT ("); } + ( + //@fixme: this should be TIMESTAMP only but JavaCC-8 has issues with compound tokens! + "=>" expression = Expression() + { builder.append( "TIMESTAMP => ").append(expression.toString()); } + | + "=>" expression = Expression() + { builder.append( "OFFSET => ").append(expression.toString()); } + | + "=>" ( tk=| tk= | tk= ) + { builder.append( "STATEMENT => ").append(tk.image); } + | + "=>" tk= + { builder.append( "STREAM => ").append(tk.image); } + ) + { builder.append(")"); } +} + + +void SnowflakeTimeTravelBefore(StringBuilder builder): +{ + Expression expression; + Token tk; +} +{ + // BEFORE( STATEMENT => ) + + { builder.append("BEFORE ("); } + "=>" ( tk=| tk= | tk= ) + { builder.append( "STATEMENT => ").append(tk.image); } + { builder.append(")"); } +} + +void SnowflakeTimeTravelChange(StringBuilder builder): +{ + Expression expression; + Token tk; +} +{ + /* + CHANGES ( INFORMATION => { DEFAULT | APPEND_ONLY } ) + AT ( { TIMESTAMP => | OFFSET => | STATEMENT => | STREAM => '' } ) + | + BEFORE ( STATEMENT => ) + [ END( { TIMESTAMP => | OFFSET => | STATEMENT => } ) ] + */ + + "=>" + { builder.append("CHANGES (INFORMATION => ");} + + ( tk = | tk=) + { builder.append(tk.image); } + + { builder.append(") "); } + + ( + SnowflakeTimeTravelAt(builder) + | + SnowflakeTimeTravelBefore(builder) + ) + + [ + LOOKAHEAD(2) + { builder.append(" END ("); } + + ( + //@fixme: this should be TIMESTAMP only but JavaCC-8 has issues with compound tokens! + "=>" expression = Expression() + { builder.append( "TIMESTAMP => ").append(expression.toString()); } + | + "=>" expression = Expression() + { builder.append( "OFFSET => ").append(expression.toString()); } + | + "=>" ( tk=| tk= | tk= ) + { builder.append( "STATEMENT => ").append(tk.image); } + ) + + { builder.append(")"); } + ] +} + +void DataBricksTemporalSpec(StringBuilder builder): +{ + Token tk; + Expression expression; +} +{ + /* + temporal_spec https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-names#syntax-3 + { + @ timestamp_encoding | + @V version | + [ FOR ] { SYSTEM_TIMESTAMP | TIMESTAMP } AS OF timestamp_expression | + [ FOR ] { SYSTEM_VERSION | VERSION } AS OF version + } + */ + (tk= | tk=) { builder.append(tk.image).append(" "); } + (tk= | tk=) { builder.append(tk.image); } + | + [ { builder.append(" FOR"); } ] + + ( tk= | tk= ) + expression=Expression() + { builder.append(" ").append(tk.image).append(" AS OF ").append(expression.toString()); } + | + ( + ( tk= | tk= ) { builder.append(" ").append(tk.image); } + (tk= | tk= ) { builder.append(" AS OF ").append(tk.image); } + ) +} + +void BigQueryHistoricalVersion(StringBuilder builder): +{ + Token tk; + Expression expression; +} +{ + /* + FOR SYSTEM_TIME AS OF timestamp_expression + */ + expression=Expression() + { builder.append(" FOR SYSTEM_TIME AS OF ").append(expression.toString()); } +} + +String TimeTravelBeforeAlias(): +{ + StringBuilder builder = new StringBuilder(); +} +{ + ( + SnowflakeTimeTravelAt(builder) + | + SnowflakeTimeTravelBefore(builder) + | + SnowflakeTimeTravelChange(builder) + | + DataBricksTemporalSpec(builder) + ) + + { + return builder.toString(); + } +} + +String TimeTravelAfterAlias(): +{ + StringBuilder builder = new StringBuilder(); +} +{ + BigQueryHistoricalVersion(builder) + { + return builder.toString(); + } +} diff --git a/src/main/resources/rr/xhtml2rst.xsl b/src/main/resources/rr/xhtml2rst.xsl index b29b03413..edbc1b4ea 100644 --- a/src/main/resources/rr/xhtml2rst.xsl +++ b/src/main/resources/rr/xhtml2rst.xsl @@ -9,37 +9,38 @@ #L% --> - + indent="no"/> - - + + - + +
+ + +
+
    + -
    + +]]>
    @@ -47,32 +48,45 @@
    - + - |JSQLPARSER_SNAPSHOT_VERSION| - |JSQLPARSER_VERSION| - +SQL Syntax ]]> + + + |JSQLPARSER_SNAPSHOT_VERSION| + + + |JSQLPARSER_VERSION| + + + - |JSQLPARSER_SNAPSHOT_VERSION| - |JSQLPARSER_VERSION| - . +The EBNF and Railroad Diagrams for ]]> + + + |JSQLPARSER_SNAPSHOT_VERSION| + + + |JSQLPARSER_VERSION| + + + . - + - + +]]> + +]]> - + .. raw:: html @@ -94,7 +108,8 @@ The EBNF and Railroad Diagrams for Referenced by:
      - +
    @@ -108,7 +123,7 @@ The EBNF and Railroad Diagrams for
    - + @@ -117,10 +132,10 @@ The EBNF and Railroad Diagrams for
  • - + - + diff --git a/src/site/sphinx/_static/favicon.svg b/src/site/sphinx/_static/favicon.svg new file mode 100644 index 000000000..5a86c120b --- /dev/null +++ b/src/site/sphinx/_static/favicon.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + diff --git a/src/site/sphinx/_static/floating_toc.css b/src/site/sphinx/_static/floating_toc.css deleted file mode 100644 index 7080e42fd..000000000 --- a/src/site/sphinx/_static/floating_toc.css +++ /dev/null @@ -1,83 +0,0 @@ -/* Styling for the floating TOC */ -#floating-toc { - position: fixed; - top: 50%; - right: 20px; - transform: translateY(-50%); - background-color: rgba(255, 255, 255, 0.72); - border: 1px solid rgba(64, 64, 64, 0.2); /* Set the border style */ - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); - z-index: 9999; - height: 66%; - overflow-y: hide; - overflow-x: auto; - width: 240px; -} - -/* Styling for TOC list items */ -#floating-toc ul { - list-style-type: none; - padding-left: 26px; - margin-top: 36px; - line-height: 2px; -} - -/* Styling for heading levels in TOC */ -#floating-toc ul li { - /* no line breaks please */ - width: 250%; -} - -#floating-toc ul li a { - font-size: 14px; - font-weight: normal; -} - -#floating-toc ul li h1 a { - font-weight: bold; - font-size: 16px; -} - -#floating-toc ul li h2 a { - font-weight: bold; -} - -#floating-toc ul li h3 a { - font-style: italic; -} - - -/* Styling for search input */ -#floating-toc .search-container { - position: sticky; - top: 6px; - padding: 0px; -} - -#floating-toc input[type="text"] { - width: 186px; - height: 24px; - box-sizing: border-box; - background-color: rgba(255, 255, 255, 1.00); - color: rgba(128, 128, 128, 1.0); /* Set the text color */ - border: 1px solid rgba(0, 0, 0, 0.2); /* Set the border style */ - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); -} - - -#floating-toc input[type="button"] { - position: float; - width: 24px; - height: 24px; - padding: 0; - margin: 0; - box-sizing: border-box; - background-color: rgba(255, 255, 255, 0.72); - color: rgba(128, 128, 128, 1.0); /* Set the text color */ - border: 0px solid rgba(0, 0, 0, 0.2); /* Set the border style */ -} - -/* Highlighting current caption in TOC */ -#floating-toc ul li a.active { - font-weight: bold; -} diff --git a/src/site/sphinx/_static/floating_toc.js b/src/site/sphinx/_static/floating_toc.js deleted file mode 100644 index eb2aeab20..000000000 --- a/src/site/sphinx/_static/floating_toc.js +++ /dev/null @@ -1,98 +0,0 @@ -// JavaScript code for creating the floating TOC -window.addEventListener('DOMContentLoaded', function() { - var tocContainer = document.getElementById('floating-toc'); - var showBtn = document.getElementById('toc-hide-show-btn'); - var tocList = document.getElementById('toc-list'); - var headings = document.querySelectorAll('h1, h2, h3'); - var tocLevels = [0, 0, 0]; - - // Calculate the initial position of the TOC - const tocContainerRect = tocContainer.getBoundingClientRect(); - const tocContainerRight = tocContainer.style.right; - const buttonText = document.getElementById('buttonText'); - - headings.forEach(function(heading) { - var level = parseInt(heading.tagName.substr(1), 10) - 1; - - tocLevels[level]++; - for (var i = level + 1; i < 3; i++) { - tocLevels[i] = 0; - } - - var listItem = document.createElement('li'); - var link = document.createElement('a'); - - var number = tocLevels.slice(0, level + 1).join('.') + ' '; - link.textContent = number + heading.textContent.trim().replace(/#$/, '').replace(/¶$/, ''); - - var headingId = 'heading-' + Math.random().toString(36).substr(2, 9); - heading.setAttribute('id', headingId); - link.href = '#' + headingId; - - var styledHeading = document.createElement('h' + (level + 1)); - styledHeading.appendChild(link); - listItem.appendChild(styledHeading); - - tocList.appendChild(listItem); - }); - - // Toggle TOC visibility - showBtn.addEventListener('click', function() { - if (tocContainer.style.right != tocContainerRight) { - tocContainer.style.right = tocContainerRight; - // buttonText.innerText="H"; - } else { - tocContainer.style.right = `-${tocContainerRect.width-26}px`; - // buttonText.innerText="S"; - }; - }); - - // JavaScript code for searching the TOC - var searchInput = document.getElementById('toc-search'); - var tocItems = Array.from(tocList.getElementsByTagName('li')); - - searchInput.addEventListener('input', function() { - var searchValue = this.value.toLowerCase(); - - tocItems.forEach(function(item) { - var link = item.querySelector('a'); - var linkText = link.textContent.toLowerCase(); - - if (linkText.includes(searchValue)) { - item.style.display = 'block'; - } else { - item.style.display = 'none'; - } - }); - }); - - // JavaScript code for updating the floating TOC on scroll - window.addEventListener('scroll', function() { - var scrollPosition = window.pageYOffset || document.documentElement.scrollTop; - - var visibleHeading = null; - headings.forEach(function(heading) { - var rect = heading.getBoundingClientRect(); - if (rect.top > 0 && rect.top < window.innerHeight) { - visibleHeading = heading; - return; - } - }); - - if (visibleHeading) { - var activeLink = tocList.querySelector('a[href="#' + visibleHeading.id + '"]'); - if (activeLink) { - activeLink.classList.add('active'); - tocContainer.scrollTop = activeLink.offsetTop - tocContainer.offsetTop; - } - - // Remove 'active' class from other links - var allLinks = tocList.querySelectorAll('a'); - allLinks.forEach(function(link) { - if (link !== activeLink) { - link.classList.remove('active'); - } - }); - } - }); -}); diff --git a/src/site/sphinx/_static/jmh_results.txt b/src/site/sphinx/_static/jmh_results.txt new file mode 100644 index 000000000..17ef08bd3 --- /dev/null +++ b/src/site/sphinx/_static/jmh_results.txt @@ -0,0 +1,4 @@ +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 7.602 ± 0.135 ms/op +JSQLParserBenchmark.parseSQLStatements 5.3 avgt 15 80.758 ± 2.718 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 83.231 ± 2.200 ms/op diff --git a/src/site/sphinx/_static/logo-no-background.svg b/src/site/sphinx/_static/logo-no-background.svg new file mode 100644 index 000000000..3289bc15e --- /dev/null +++ b/src/site/sphinx/_static/logo-no-background.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/site/sphinx/conf.py b/src/site/sphinx/conf.py index 29ab663cf..54973ecf3 100644 --- a/src/site/sphinx/conf.py +++ b/src/site/sphinx/conf.py @@ -1,41 +1,57 @@ # -*- coding: utf-8 -*- +import os +import sys + +sys.path.insert(0, os.path.abspath("..")) # General options -needs_sphinx = '1.0' +needs_sphinx = "7.2" add_function_parentheses = True -extensions = ['myst_parser', 'sphinx.ext.autodoc', 'sphinx.ext.autosectionlabel', 'sphinx.ext.extlinks', 'sphinx-prompt', 'sphinx_substitution_extensions', 'sphinx_inline_tabs', 'pygments.sphinxext', ] +extensions = [ + "myst_parser", + "sphinx.ext.autodoc", + "sphinx.ext.autosectionlabel", + "sphinx.ext.extlinks", + "sphinx_substitution_extensions", + "sphinx_inline_tabs", + "pygments.sphinxext", + "sphinx_javadoc_xml", +] -issues_github_path = "JSQLParser/JSqlParser" -source_encoding = 'utf-8-sig' -#pygments_style = 'friendly' +source_encoding = "utf-8-sig" +# pygments_style = 'friendly' show_sphinx = False -master_doc = 'index' -exclude_patterns = ['_themes', '_static/css'] +master_doc = "index" +exclude_patterns = ["_themes", "_static/css"] logo_only = True # HTML options -html_theme = "furo" -html_theme_path = ["_themes"] +html_theme = "manticore_sphinx_theme" html_short_title = "JSQLParser" -htmlhelp_basename = "JSQLParser" + '-doc' +htmlhelp_basename = "JSQLParser" + "-doc" html_use_index = True html_show_sourcelink = False -html_static_path = ['_static'] -html_logo = '_images/logo-no-background.svg' -html_favicon = '_images/favicon.svg' -html_css_files = ['svg.css', 'floating_toc.css'] -html_js_files = ['floating_toc.js',] +html_static_path = ["_static"] +html_logo = "logo-no-background.svg" +html_favicon = "favicon.svg" +html_css_files = ["svg.css"] html_theme_options = { - 'path_to_docs': 'site/sphinx', - 'repository_url': 'https://github.com/JSQLParser/JSqlParser', - 'repository_branch': 'master', - 'use_issues_button': True, - 'use_download_button': True, - 'use_fullscreen_button': True, - 'use_repository_button': True, + "logo": "logo-no-background.svg", + "logo_alt": "JSQL Parser", + "favicon": "favicon.svg", + "color_primary": "#0063db", + "color_accent": "#d90000", + "color_sidebar_bg": "#f5f6fa", + "color_sidebar_text": "#2d2d48", + "navigation_depth": 1, + "show_breadcrumbs": True, + "footer_text": "All rights reserved.", + "show_powered_by": True, + "repo_url": "https://github.com/JSQLParser/JSqlParser", + "repo_name": "GitHub", + "landing_page": "", + "collapse_navigation": True, } - - diff --git a/src/site/sphinx/contribution.rst b/src/site/sphinx/contribution.rst index c001f8eb5..0114af33d 100644 --- a/src/site/sphinx/contribution.rst +++ b/src/site/sphinx/contribution.rst @@ -61,54 +61,63 @@ The JSQLParser is generated by ``JavaCC`` based on the provided Grammar. The Gra * The complete test suite must succeed. 5) Add the description of the new feature to the ``README.md`` file, section `Extensions`. - 6) Build the package with ``Maven`` and ensure, all checks do pass (PMD and CheckStyle and Code Formatting). + 6) Build the package with ``Gradle`` and ensure, all checks do pass (PMD and CheckStyle and Code Formatting). -Manage Reserved Keywords ------------------------------- + .. tab:: Gradle -Since JSQLParser is built by JavaCC from a Token based Grammar, ``Reserved Keywords`` need a special treatment. All Tokens of the Grammar would become ``Reserved Keywords`` -- unless explicitly allowed and white-listened. + .. code-block:: shell + :caption: Gradle `check` Task -.. code-block:: sql - :caption: White-list Keyword example + gradle check - -- is a Token, recently defined in the Grammar - -- Although it is not restricted by the SQL Standard and could be used for Column, Table and Alias names - -- Explicitly white-listing OVERLAPS by adding it to the RelObjectNameWithoutValue() Production will allow for parsing the following statement + .. tab:: Maven - SELECT Overlaps( overlaps ) AS overlaps - FROM overlaps.overlaps overlaps - WHERE overlaps = 'overlaps' - AND (CURRENT_TIME, INTERVAL '1' HOUR) OVERLAPS (CURRENT_TIME, INTERVAL -'1' HOUR) - ; + .. code-block:: shell + :caption: Maven `verify` Task -So we will need to define and white-list any Keywords which may be allowed for Object Names (such as `Schema`, `Table`, `Column`, `Function`, `Alias`). This White-List must be updated whenever the Tokens of the Grammar change (e. |_| g. when adding a new Token or Production). + mvn verify -There is a task ``updateKeywords`` for Gradle and Maven, which will: + 7) Verify the performance and avoid any deterioration - 1) Parse the Grammar in order to find all Token definitions - 2) Read the list of explicitly ``Reserved Keywords`` from ``net/sf/jsqlparser/parser/ParserKeywordsUtils.java`` - 3) Derive the list of ``White-Listed Keywords`` as difference between ``All Tokens`` and ``Reserved Keywords`` - 4) Modifies the Grammar Productions ``RelObjectNameWithoutValue...`` adding all Tokens according to ``White-Listed Keywords`` - 5) Run two special Unit Tests to verify parsing of all ``White-Listed Keywords`` (as `Schema`, `Table`, `Column`, `Function` or `Alias`) - 6) Update the web page about the Reserved Keywords + .. code-block:: shell + :caption: Gradle `check` Task + gradle jmh -.. tab:: Gradle + .. code-block:: text + :caption: JMH performance results - .. code-block:: shell - :caption: Gradle `updateKeywords` Task + Benchmark (version) Mode Cnt Score Error Units + JSQLParserBenchmark.parseSQLStatements latest avgt 30 83.504 ± 1.557 ms/op + JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 400.876 ± 8.291 ms/op + JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 85.731 ± 1.288 ms/op - gradle updateKeywords + 8) Create your `GitHub Pull Request `_ -.. tab:: Maven +Manage Reserved Keywords +------------------------------ - .. code-block:: shell - :caption: Maven `updateKeywords` Task +Since JSQLParser is built by JavaCC from a Token based Grammar, ``Reserved Keywords`` need a special treatment. All Tokens of the Grammar would become ``Reserved Keywords`` -- unless explicitly allowed as identifiers. - mvn exec:java +The Grammar uses a ``NonReservedWord()`` BNF production with inline token declarations, bracketed by ``MIN_NON_RESERVED_WORD`` and ``MAX_NON_RESERVED_WORD`` sentinel tokens. JavaCC assigns consecutive token kind values to the inline declarations, which enables an efficient O(1) range check in ``isIdentifierAhead()`` to determine whether a token can be used as an unquoted identifier. + +.. code-block:: sql + :caption: Non-reserved keyword example + + -- is defined as a non-reserved keyword inside the NonReservedWord() production + -- It can be used for Column, Table and Alias names without quoting + + SELECT Overlaps( overlaps ) AS overlaps + FROM overlaps.overlaps overlaps + WHERE overlaps = 'overlaps' + AND (CURRENT_TIME, INTERVAL '1' HOUR) OVERLAPS (CURRENT_TIME, INTERVAL -'1' HOUR) + ; +When adding a new keyword token to the Grammar: -Without this Gradle Task, any new Token or Production will become a ``Reserved Keyword`` automatically and can't be used for Object Names without quoting. + 1) If the keyword should be usable as an unquoted identifier (the common case), add its inline token declaration to the ``NonReservedWord()`` production. It will automatically be placed between the sentinel tokens and recognised by the range check. + 2) If the keyword must be reserved (e. |_| g. core SQL syntax like ``SELECT``, ``FROM``, ``WHERE``), add it to the ``Reserved SQL Keywords`` TOKEN block **after** the ``MAX_NON_RESERVED_WORD`` sentinel. + 3) Verify that existing tests pass and that the keyword can be used as a ``Schema``, ``Table``, ``Column``, ``Function`` or ``Alias`` name where expected. Commit a Pull Request @@ -165,4 +174,4 @@ Please consider using `Conventional Commits` and structure your commit message a * - **revert** - reverts one or many previous commits -Please visit `Better Programming `_ for more information and guidance. +Please visit `Better Programming `_ for more information and guidance. \ No newline at end of file diff --git a/src/site/sphinx/index.rst b/src/site/sphinx/index.rst index 916e4c07b..d8d4bfbde 100644 --- a/src/site/sphinx/index.rst +++ b/src/site/sphinx/index.rst @@ -12,7 +12,8 @@ Java SQL Parser Library usage contribution - migration + migration47 + migration50 SQL Grammar Stable SQL Grammar Snapshot Unsupported Grammar @@ -33,9 +34,9 @@ Java SQL Parser Library :alt: Maven Badge :target: https://mvnrepository.com/artifact/com.github.jsqlparser/jsqlparser -.. image:: https://github.com/JSQLParser/JSqlParser/actions/workflows/maven.yml/badge.svg - :alt: Maven Build Status - :target: https://github.com/JSQLParser/JSqlParser/actions/workflows/maven.yml +.. image:: https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml/badge.svg + :alt: CI Status + :target: https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml .. image:: https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master :alt: Coverage Status @@ -49,8 +50,10 @@ Java SQL Parser Library :alt: Java Docs :target: https://javadoc.io/doc/com.github.jsqlparser/jsqlparser/latest/index.html +A huge thank you to our sponsor, `Starlake.ai `_ who simplifies data ingestion, transformation, and orchestration, enabling faster delivery of high-quality data. Starlake has been instrumental in providing Piped SQL and numerous test cases for BigQuery, Redshift, DataBricks, and DuckDB. Show your support for ongoing development by visiting Starlake.ai and giving us a star! **JSQLParser** is a SQL statement parser built from JavaCC. It translates SQLs in a traversable hierarchy of Java classes. +Since the 5.0 release JSQLParser depends on Java 11 and has introduced new Visitors. Please see the :ref:`Migration to 5.0` guide. Latest stable release: |JSQLPARSER_STABLE_VERSION_LINK| @@ -87,6 +90,11 @@ SQL Dialects * MySQL and MariaDB * PostgreSQL * H2 + * DuckDB + * Google BigQuery + * Amazon Redshift + * DataBricks + * Snowflake ******************************* Features @@ -105,6 +113,7 @@ Features * Arrays vs. T-SQL Squared Bracket Quotes * Fluent API to create SQL Statements from java Code * Statement De-Parser to write SQL from Java Objects + * Piped SQL (also known as FROM SQL) diff --git a/src/site/sphinx/keywords.rst b/src/site/sphinx/keywords.rst index 91437ece5..a9058fbaa 100644 --- a/src/site/sphinx/keywords.rst +++ b/src/site/sphinx/keywords.rst @@ -1,241 +1,227 @@ *********************** -Restricted Keywords +Reserved Keywords *********************** -The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and must not be used for **Naming Objects**: +The following Keywords are **reserved** in JSQLParser-|JSQLPARSER_VERSION| and must not be used for **Naming Objects**: -+----------------------+-------------+-----------+ -| **Keyword** | JSQL Parser | SQL:2016 | -+----------------------+-------------+-----------+ -| ABSENT | Yes | Yes | -+----------------------+-------------+-----------+ -| ALL | Yes | Yes | -+----------------------+-------------+-----------+ -| AND | Yes | Yes | -+----------------------+-------------+-----------+ -| ANY | Yes | Yes | -+----------------------+-------------+-----------+ -| AS | Yes | Yes | -+----------------------+-------------+-----------+ -| BETWEEN | Yes | Yes | -+----------------------+-------------+-----------+ -| BOTH | Yes | Yes | -+----------------------+-------------+-----------+ -| CASEWHEN | Yes | | -+----------------------+-------------+-----------+ -| CHECK | Yes | Yes | -+----------------------+-------------+-----------+ -| CONNECT | Yes | | -+----------------------+-------------+-----------+ -| CONNECT_BY_ROOT | Yes | Yes | -+----------------------+-------------+-----------+ -| CONSTRAINT | Yes | Yes | -+----------------------+-------------+-----------+ -| CREATE | Yes | | -+----------------------+-------------+-----------+ -| CROSS | Yes | Yes | -+----------------------+-------------+-----------+ -| CURRENT | Yes | Yes | -+----------------------+-------------+-----------+ -| DISTINCT | Yes | Yes | -+----------------------+-------------+-----------+ -| DOUBLE | Yes | | -+----------------------+-------------+-----------+ -| ELSE | Yes | Yes | -+----------------------+-------------+-----------+ -| EXCEPT | Yes | Yes | -+----------------------+-------------+-----------+ -| EXCLUDES | Yes | Yes | -+----------------------+-------------+-----------+ -| EXISTS | Yes | Yes | -+----------------------+-------------+-----------+ -| FETCH | Yes | Yes | -+----------------------+-------------+-----------+ -| FINAL | Yes | Yes | -+----------------------+-------------+-----------+ -| FOR | Yes | Yes | -+----------------------+-------------+-----------+ -| FORCE | Yes | Yes | -+----------------------+-------------+-----------+ -| FOREIGN | Yes | Yes | -+----------------------+-------------+-----------+ -| FROM | Yes | Yes | -+----------------------+-------------+-----------+ -| FULL | Yes | Yes | -+----------------------+-------------+-----------+ -| GLOBAL | Yes | | -+----------------------+-------------+-----------+ -| GROUP | Yes | Yes | -+----------------------+-------------+-----------+ -| GROUPING | Yes | | -+----------------------+-------------+-----------+ -| QUALIFY | Yes | | -+----------------------+-------------+-----------+ -| HAVING | Yes | Yes | -+----------------------+-------------+-----------+ -| IF | Yes | Yes | -+----------------------+-------------+-----------+ -| IIF | Yes | | -+----------------------+-------------+-----------+ -| IGNORE | Yes | | -+----------------------+-------------+-----------+ -| ILIKE | Yes | Yes | -+----------------------+-------------+-----------+ -| IN | Yes | Yes | -+----------------------+-------------+-----------+ -| INCLUDES | Yes | Yes | -+----------------------+-------------+-----------+ -| INNER | Yes | Yes | -+----------------------+-------------+-----------+ -| INTERSECT | Yes | Yes | -+----------------------+-------------+-----------+ -| INTERVAL | Yes | Yes | -+----------------------+-------------+-----------+ -| INTO | Yes | Yes | -+----------------------+-------------+-----------+ -| IS | Yes | Yes | -+----------------------+-------------+-----------+ -| JOIN | Yes | Yes | -+----------------------+-------------+-----------+ -| LATERAL | Yes | Yes | -+----------------------+-------------+-----------+ -| LEFT | Yes | Yes | -+----------------------+-------------+-----------+ -| LIKE | Yes | Yes | -+----------------------+-------------+-----------+ -| LIMIT | Yes | Yes | -+----------------------+-------------+-----------+ -| MINUS | Yes | Yes | -+----------------------+-------------+-----------+ -| NATURAL | Yes | Yes | -+----------------------+-------------+-----------+ -| NOCYCLE | Yes | Yes | -+----------------------+-------------+-----------+ -| NOT | Yes | Yes | -+----------------------+-------------+-----------+ -| NULL | Yes | Yes | -+----------------------+-------------+-----------+ -| OFFSET | Yes | Yes | -+----------------------+-------------+-----------+ -| ON | Yes | Yes | -+----------------------+-------------+-----------+ -| ONLY | Yes | Yes | -+----------------------+-------------+-----------+ -| OPTIMIZE | Yes | | -+----------------------+-------------+-----------+ -| OR | Yes | Yes | -+----------------------+-------------+-----------+ -| ORDER | Yes | Yes | -+----------------------+-------------+-----------+ -| OUTER | Yes | Yes | -+----------------------+-------------+-----------+ -| OUTPUT | Yes | Yes | -+----------------------+-------------+-----------+ -| OPTIMIZE | Yes | Yes | -+----------------------+-------------+-----------+ -| PIVOT | Yes | Yes | -+----------------------+-------------+-----------+ -| PROCEDURE | Yes | | -+----------------------+-------------+-----------+ -| PUBLIC | Yes | | -+----------------------+-------------+-----------+ -| RETURNING | Yes | Yes | -+----------------------+-------------+-----------+ -| RIGHT | Yes | Yes | -+----------------------+-------------+-----------+ -| SAMPLE | Yes | | -+----------------------+-------------+-----------+ -| SEL | Yes | | -+----------------------+-------------+-----------+ -| SELECT | Yes | | -+----------------------+-------------+-----------+ -| SEMI | Yes | Yes | -+----------------------+-------------+-----------+ -| SET | Yes | Yes | -+----------------------+-------------+-----------+ -| SOME | Yes | Yes | -+----------------------+-------------+-----------+ -| START | Yes | Yes | -+----------------------+-------------+-----------+ -| TABLES | Yes | | -+----------------------+-------------+-----------+ -| TOP | Yes | Yes | -+----------------------+-------------+-----------+ -| TRAILING | Yes | Yes | -+----------------------+-------------+-----------+ -| UNBOUNDED | Yes | Yes | -+----------------------+-------------+-----------+ -| UNION | Yes | Yes | -+----------------------+-------------+-----------+ -| UNIQUE | Yes | Yes | -+----------------------+-------------+-----------+ -| UNPIVOT | Yes | Yes | -+----------------------+-------------+-----------+ -| USE | Yes | Yes | -+----------------------+-------------+-----------+ -| USING | Yes | Yes | -+----------------------+-------------+-----------+ -| SQL_CACHE | Yes | Yes | -+----------------------+-------------+-----------+ -| SQL_CALC_FOUND_ROWS | Yes | Yes | -+----------------------+-------------+-----------+ -| SQL_NO_CACHE | Yes | Yes | -+----------------------+-------------+-----------+ -| STRAIGHT_JOIN | Yes | Yes | -+----------------------+-------------+-----------+ -| TABLESAMPLE | Yes | | -+----------------------+-------------+-----------+ -| VALUE | Yes | Yes | -+----------------------+-------------+-----------+ -| VALUES | Yes | Yes | -+----------------------+-------------+-----------+ -| VARYING | Yes | Yes | -+----------------------+-------------+-----------+ -| WHEN | Yes | Yes | -+----------------------+-------------+-----------+ -| WHERE | Yes | Yes | -+----------------------+-------------+-----------+ -| WINDOW | Yes | Yes | -+----------------------+-------------+-----------+ -| WITH | Yes | Yes | -+----------------------+-------------+-----------+ -| XOR | Yes | Yes | -+----------------------+-------------+-----------+ -| XMLSERIALIZE | Yes | Yes | -+----------------------+-------------+-----------+ -| SEL | Yes | Yes | -+----------------------+-------------+-----------+ -| SELECT | Yes | Yes | -+----------------------+-------------+-----------+ -| DATE | Yes | Yes | -+----------------------+-------------+-----------+ -| TIME | Yes | Yes | -+----------------------+-------------+-----------+ -| TIMESTAMP | Yes | Yes | -+----------------------+-------------+-----------+ -| YEAR | Yes | Yes | -+----------------------+-------------+-----------+ -| MONTH | Yes | Yes | -+----------------------+-------------+-----------+ -| DAY | Yes | Yes | -+----------------------+-------------+-----------+ -| HOUR | Yes | Yes | -+----------------------+-------------+-----------+ -| MINUTE | Yes | Yes | -+----------------------+-------------+-----------+ -| SECOND | Yes | Yes | -+----------------------+-------------+-----------+ -| SUBSTR | Yes | Yes | -+----------------------+-------------+-----------+ -| SUBSTRING | Yes | Yes | -+----------------------+-------------+-----------+ -| TRIM | Yes | Yes | -+----------------------+-------------+-----------+ -| POSITION | Yes | Yes | -+----------------------+-------------+-----------+ -| OVERLAY | Yes | Yes | -+----------------------+-------------+-----------+ -| NEXTVAL | Yes | | -+----------------------+-------------+-----------+ -| 0x | Yes | Yes | -+----------------------+-------------+-----------+ ++---------------------------+ +| **Keyword** | ++---------------------------+ +| ABSENT | ++---------------------------+ +| ALL | ++---------------------------+ +| AND | ++---------------------------+ +| ANY | ++---------------------------+ +| ARRAY | ++---------------------------+ +| AS | ++---------------------------+ +| BETWEEN | ++---------------------------+ +| BOTH | ++---------------------------+ +| CASEWHEN | ++---------------------------+ +| CHECK | ++---------------------------+ +| CONNECT | ++---------------------------+ +| CONNECT_BY_ROOT | ++---------------------------+ +| CONSTRAINT | ++---------------------------+ +| CREATE | ++---------------------------+ +| CROSS | ++---------------------------+ +| CSV | ++---------------------------+ +| CURRENT | ++---------------------------+ +| DISTINCT | ++---------------------------+ +| DISTINCTROW | ++---------------------------+ +| ELSE | ++---------------------------+ +| ERRORS | ++---------------------------+ +| EXCEPT | ++---------------------------+ +| EXCLUDES | ++---------------------------+ +| EXISTS | ++---------------------------+ +| EXTEND | ++---------------------------+ +| FALSE | ++---------------------------+ +| FBV | ++---------------------------+ +| FETCH | ++---------------------------+ +| FILE | ++---------------------------+ +| FINAL | ++---------------------------+ +| FOR | ++---------------------------+ +| FOREIGN | ++---------------------------+ +| FROM | ++---------------------------+ +| FULL | ++---------------------------+ +| GLOBAL | ++---------------------------+ +| GROUP | ++---------------------------+ +| GROUPING | ++---------------------------+ +| HAVING | ++---------------------------+ +| IF | ++---------------------------+ +| IIF | ++---------------------------+ +| ILIKE | ++---------------------------+ +| IMPORT | ++---------------------------+ +| IN | ++---------------------------+ +| INCLUDES | ++---------------------------+ +| INNER | ++---------------------------+ +| INTERSECT | ++---------------------------+ +| INTERVAL | ++---------------------------+ +| INTO | ++---------------------------+ +| IS | ++---------------------------+ +| JOIN | ++---------------------------+ +| LATERAL | ++---------------------------+ +| LEFT | ++---------------------------+ +| LIKE | ++---------------------------+ +| LIMIT | ++---------------------------+ +| MINUS | ++---------------------------+ +| NATURAL | ++---------------------------+ +| NOCYCLE | ++---------------------------+ +| NOT | ++---------------------------+ +| NULL | ++---------------------------+ +| OFFSET | ++---------------------------+ +| ON | ++---------------------------+ +| ONLY | ++---------------------------+ +| OPTIMIZE | ++---------------------------+ +| OR | ++---------------------------+ +| ORDER | ++---------------------------+ +| OUTER | ++---------------------------+ +| OUTPUT | ++---------------------------+ +| PIVOT | ++---------------------------+ +| PREFERRING | ++---------------------------+ +| PREWHERE | ++---------------------------+ +| PRIOR | ++---------------------------+ +| PROCEDURE | ++---------------------------+ +| PUBLIC | ++---------------------------+ +| QUALIFY | ++---------------------------+ +| RETURNING | ++---------------------------+ +| RETURNS | ++---------------------------+ +| RIGHT | ++---------------------------+ +| SAMPLE | ++---------------------------+ +| SCRIPT | ++---------------------------+ +| SET | ++---------------------------+ +| SETTINGS | ++---------------------------+ +| SOME | ++---------------------------+ +| SQL_CACHE | ++---------------------------+ +| SQL_CALC_FOUND_ROWS | ++---------------------------+ +| SQL_NO_CACHE | ++---------------------------+ +| START | ++---------------------------+ +| STATEMENT | ++---------------------------+ +| STRAIGHT_JOIN | ++---------------------------+ +| TABLES | ++---------------------------+ +| TABLESAMPLE | ++---------------------------+ +| TOP | ++---------------------------+ +| TRAILING | ++---------------------------+ +| TRUE | ++---------------------------+ +| UNBOUNDED | ++---------------------------+ +| UNION | ++---------------------------+ +| UNIQUE | ++---------------------------+ +| UNKNOWN | ++---------------------------+ +| UNPIVOT | ++---------------------------+ +| USE | ++---------------------------+ +| USING | ++---------------------------+ +| VALUE | ++---------------------------+ +| VALUES | ++---------------------------+ +| VERIFY | ++---------------------------+ +| WHEN | ++---------------------------+ +| WHERE | ++---------------------------+ +| WINDOW | ++---------------------------+ +| WITH | ++---------------------------+ +| XMLSERIALIZE | ++---------------------------+ +| XOR | ++---------------------------+ diff --git a/src/site/sphinx/migration.rst b/src/site/sphinx/migration47.rst similarity index 100% rename from src/site/sphinx/migration.rst rename to src/site/sphinx/migration47.rst diff --git a/src/site/sphinx/migration50.rst b/src/site/sphinx/migration50.rst new file mode 100644 index 000000000..eb0a9926a --- /dev/null +++ b/src/site/sphinx/migration50.rst @@ -0,0 +1,96 @@ +********************************* +Migration to 5.0 +********************************* + +The new JSQLParser 5 introduces API-breaking changes: + +1. **Dependency on Java 11 or newer** + +2. **Reworked AST Visitors** + + The AST Visitors have been reworked to pass a Generic Context from the Root Node down to the Leaves. + + .. code-block:: java + :caption: Generic Interface + + public interface SelectVisitor { + + T visit(PlainSelect plainSelect, S context); + + default void visit(PlainSelect plainSelect) { + this.visit(plainSelect, null); + } + + } + + .. code-block:: java + :caption: Sample Implementation + + public class JSQLColumnResolver + implements SelectVisitor, FromItemVisitor { + + @Override + public JdbcResultSetMetaData visit(PlainSelect select, S context) { + if (context instanceof JdbcMetaData) { + return visit(select, (JdbcMetaData) context); + } + return null; + } + + public JdbcResultSetMetaData visit(PlainSelect select, JdbcMetaData metaData) { + JdbcResultSetMetaData resultSetMetaData = new JdbcResultSetMetaData(); + + // Logic to retrieve the column information + resultSetMetaData = getColumn(metaData, select.getFromItem(), select.getJoins()); + + return resultSetMetaData; + } + } + +3. **Generic Result from Leaves to Root** + + Node objects now return a Generic Result from the Leaves up to the Root. + + .. code-block:: java + :caption: AST Node + + public class PlainSelect extends Select { + @Override + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); + } + } + +How is this useful? Consider resolving the `AllColumns` ``*`` or `AllTableColumns` ``t.*`` expressions to retrieve the actual column names. This process depends on the database's physical metadata and the context of the current scope, including virtual data frames (like sub-selects and with-clauses). + +Therefore, every branch of the AST must receive scoped metadata from its parent node. Each AST node must receive the resolved columns from its child nodes. A global result object (like the `StringBuilder` in the `DepParser` implementations) is inadequate. + +Alternatively, consider substituting `TimeValueKey` (``CURRENT_DATE``, ``CURRENT_TIME``, etc.) with actual date or time values. You can push a simple `Map` of key/value pairs down to the Expression Visitor: + + .. code-block:: java + :caption: Expression Visitor + + @Override + public StringBuilder visit(TimeKeyExpression expression, S context) { + if (context instanceof Map) { + return visit(expression, (Map) substitutions); + } else { + return expression.toString(); + } + } + + public StringBuilder visit(TimeKeyExpression expression, Map substitutions) { + // Remove possible trailing brackets "()" + String value = expression.getStringValue().toUpperCase().replaceAll("[()]", ""); + + if (substitutions.containsKey(value)) { + // @todo: Cast Date/Time types + return castDateTime(substitutions.get(value).toString()).accept(this, null); + } else { + return super.visit(expression, null); + } + } + +Another advantage is parallel processing: Without relying on a global result object, the AST can be traversed in parallel (whereas it currently must be traversed strictly in serial). + +Finally, any child node can now know its parent and identify who called it. diff --git a/src/site/sphinx/syntax_snapshot.rst b/src/site/sphinx/syntax_snapshot.rst new file mode 100644 index 000000000..76af0c6bf --- /dev/null +++ b/src/site/sphinx/syntax_snapshot.rst @@ -0,0 +1,20923 @@ + +********************************************************************* +SQL Syntax |JSQLPARSER_SNAPSHOT_VERSION| +********************************************************************* + +The EBNF and Railroad Diagrams for |JSQLPARSER_SNAPSHOT_VERSION|. + + +====================================================================================================================== +NonReservedWord +====================================================================================================================== + + +.. raw:: html + + + + + + ACTION + + ACTIVE + + ADD + + ADVANCE + + ADVISE + + AGAINST + + AGGREGATE + + ALGORITHM + + ALIGN + + ALTER + + ALWAYS + + ANALYZE + + APPEND_ONLY + + APPLY + + APPROXIMATE + + ARCHIVE + + ARRAY + + ASYMMETRIC + + AT + + ASC + + AUTHORIZATION + + AUTO + + AUTO_INCREMENT + + AZURE + + BASE64 + + BEFORE + + BEGIN + + BERNOULLI + + BINARY + + BIT + + BLOBSTORAGE + + BLOCK + + BOOLEAN + + BREADTH + + BRANCH + + BROWSE + + BY + + BYTES + + CACHE + + BUFFERS + + BYTE + + CALL + + CASCADE + + CASE + + CAST + + CERTIFICATE + + CHARACTER + + CHANGE + + CHANGES + + CHECKPOINT + + CHAR + + CLOSE + + CLOUD + + COALESCE + + COLLATE + + COLUMN + + COLUMNS + + COMMIT + + COMMENT + + COMMENTS + + CONFLICT + + CONSTRAINTS + + CONVERT + + CORRESPONDING + + COSTS + + COUNT + + CREATED + + CYCLE + + DATABASE + + DATA + + DECLARE + + DBA_RECYCLEBIN + + DEFAULTS + + DEPTH + + DEFERRABLE + + DELAYED + + DELETE + + DELIMIT + + DELIMITER + + DESC + + DESCRIBE + + DISABLE + + DISCARD + + DISCONNECT + + DIV + + DDL + + DML + + DO + + DOMAIN + + DRIVER + + DROP + + DUMP + + DUPLICATE + + ELEMENTS + + EMIT + + ENABLE + + ENCODING + + ENCRYPTION + + END + + ENFORCED + + ENGINE + + ERROR + + ESCAPE + + EXA + + EXCHANGE + + EXCLUDE + + EXCLUDING + + EXCLUSIVE + + EXEC + + EXECUTE + + EXPLAIN + + EXPLICIT + + EXTENDED + + EXTRACT + + EXPORT + + K_ISOLATION + FILTER + + FIRST + + FLUSH + + FOLLOWING + + FORMAT + + FULLTEXT + + FUNCTION + + GRANT + + GROUP_CONCAT + + GUARD + + HASH + + HIGH + + HIGH_PRIORITY + + HISTORY + + HOPPING + + IDENTIFIED + + IDENTITY + + INCLUDE + + INCLUDE_NULL_VALUES + + INCLUDING + + INCREMENT + + INDEX + + INFORMATION + + INSERT + + INTERLEAVE + + INTERPRET + + INVALIDATE + + INVERSE + + INVISIBLE + + ISNULL + + JDBC + + JSON + + JSON_OBJECT + + JSON_OBJECTAGG + + JSON_ARRAY + + JSON_ARRAYAGG + + KEEP + + KEY_BLOCK_SIZE + + KEY + + KEYS + + KILL + + FN + + LAST + + LEADING + + LESS + + LEVEL + + LOCAL + + LOCK + + LOCKED + + LINK + + LOG + + LOOP + + LOW + + LOW_PRIORITY + + LTRIM + + MATCH + + MATCH_ANY + + MATCH_ALL + + MATCH_PHRASE + + MATCH_PHRASE_PREFIX + + MATCH_REGEXP + + MATCHED + + MATERIALIZED + + MAX + + MAXVALUE + + MEMBER + + MERGE + + MIN + + MINVALUE + + MODE + + MODIFY + + MOVEMENT + + NAMES + + NAME + + NEVER + + NEXT + + K_NEXTVAL + NO + + NOCACHE + + NOKEEP + + NOLOCK + + NOMAXVALUE + + NOMINVALUE + + NONE + + NOORDER + + NOTHING + + NOTNULL + + NOVALIDATE + + NULLS + + NOWAIT + + OF + + OFF + + OPEN + + ORA + + ORDINALITY + + OVER + + OVERFLOW + + OVERLAPS + + OVERRIDING + + OVERWRITE + + PADDING + + PARALLEL + + PARENT + + PARSER + + PARTITION + + PARTITIONING + + PATH + + PERCENT + + PLACING + + PLAN + + PLUS + + PRECEDING + + PRIMARY + + POLICY + + PURGE + + QUERY + + QUICK + + QUIESCE + + RANGE + + RAW + + READ + + REBUILD + + RECYCLEBIN + + RECURSIVE + + REFERENCES + + REFRESH + + REGEXP + + REJECT + + RESPECT + + RLIKE + + REGEXP_LIKE + + REGISTER + + REMOTE + + REMOVE + + RENAME + + REORGANIZE + + REPAIR + + REPEATABLE + + REPLACE + + RESET + + RESTART + + RESUMABLE + + RESUME + + RESTRICT + + RESTRICTED + + RETURN + + ROLLBACK + + ROLLUP + + ROOT + + ROW + + ROWS + + RTRIM + + SAFE_CAST + + SAFE_CONVERT + + SAVEPOINT + + SCHEMA + + SEARCH + + SECURE + + SECURITY + + SEED + + SEQUENCE + + SEPARATOR + + SESSION + + SETS + + SHOW + + SHUTDOWN + + SHARE + + SIBLINGS + + SIMILAR + + SIZE + + SKIP + + SPATIAL + + STORED + + STREAM + + STRICT + + STRING + + STRUCT + + SUMMARIZE + + SUSPEND + + SWITCH + + SYMMETRIC + + SYNONYM + + SYSTEM + + SYSTEM_TIME + + SYSTEM_TIMESTAMP + + SYSTEM_VERSION + + TABLE + + TABLESPACE + + TRIGGER + + THEN + + TEMP + + K_TEXT_LITERAL + TEMPORARY + + THAN + + K_TIME_KEY_EXPR + TIMEOUT + + TO + + TRIM + + TRUNCATE + + TRY_CAST + + TRY_CONVERT + + TUMBLING + + TYPE + + UNLIMITED + + UNLOGGED + + UPDATE + + UPSERT + + UNQIESCE + + USER + + SIGNED + + K_STRING_FUNCTION_NAME + UNSIGNED + + VALIDATE + + VALIDATION + + VERBOSE + + VERSION + + VIEW + + VISIBLE + + VOLATILE + + CONCURRENTLY + + WAIT + + WITH TIES + + WITHIN + + WITHOUT + + WITHOUT_ARRAY_WRAPPER + + WORK + + XML + + XMLAGG + + XMLDATA + + XMLSCHEMA + + XMLTEXT + + XSINIL + + YAML + + YES + + ZONE + + +
    + + +
             ::= 'ACTION'
    +
               | 'ACTIVE'
    +
               | 'ADD'
    +
               | 'ADVANCE'
    +
               | 'ADVISE'
    +
               | 'AGAINST'
    +
               | 'AGGREGATE'
    +
               | 'ALGORITHM'
    +
               | 'ALIGN'
    +
               | 'ALTER'
    +
               | 'ALWAYS'
    +
               | 'ANALYZE'
    +
               | 'APPEND_ONLY'
    +
               | 'APPLY'
    +
               | 'APPROXIMATE'
    +
               | 'ARCHIVE'
    +
               | 'ARRAY'
    +
               | 'ASYMMETRIC'
    +
               | 'AT'
    +
               | 'ASC'
    +
               | 'AUTHORIZATION'
    +
               | 'AUTO'
    +
               | 'AUTO_INCREMENT'
    +
               | 'AZURE'
    +
               | 'BASE64'
    +
               | 'BEFORE'
    +
               | 'BEGIN'
    +
               | 'BERNOULLI'
    +
               | 'BINARY'
    +
               | 'BIT'
    +
               | 'BLOBSTORAGE'
    +
               | 'BLOCK'
    +
               | 'BOOLEAN'
    +
               | 'BREADTH'
    +
               | 'BRANCH'
    +
               | 'BROWSE'
    +
               | 'BY'
    +
               | 'BYTES'
    +
               | 'CACHE'
    +
               | 'BUFFERS'
    +
               | 'BYTE'
    +
               | 'CALL'
    +
               | 'CASCADE'
    +
               | 'CASE'
    +
               | 'CAST'
    +
               | 'CERTIFICATE'
    +
               | 'CHARACTER'
    +
               | 'CHANGE'
    +
               | 'CHANGES'
    +
               | 'CHECKPOINT'
    +
               | 'CHAR'
    +
               | 'CLOSE'
    +
               | 'CLOUD'
    +
               | 'COALESCE'
    +
               | 'COLLATE'
    +
               | 'COLUMN'
    +
               | 'COLUMNS'
    +
               | 'COMMIT'
    +
               | 'COMMENT'
    +
               | 'COMMENTS'
    +
               | 'CONFLICT'
    +
               | 'CONSTRAINTS'
    +
               | 'CONVERT'
    +
               | 'CORRESPONDING'
    +
               | 'COSTS'
    +
               | 'COUNT'
    +
               | 'CREATED'
    +
               | 'CYCLE'
    +
               | 'DATABASE'
    +
               | 'DATA'
    +
               | 'DECLARE'
    +
               | 'DBA_RECYCLEBIN'
    +
               | 'DEFAULTS'
    +
               | 'DEPTH'
    +
               | 'DEFERRABLE'
    +
               | 'DELAYED'
    +
               | 'DELETE'
    +
               | 'DELIMIT'
    +
               | 'DELIMITER'
    +
               | 'DESC'
    +
               | 'DESCRIBE'
    +
               | 'DISABLE'
    +
               | 'DISCARD'
    +
               | 'DISCONNECT'
    +
               | 'DIV'
    +
               | 'DDL'
    +
               | 'DML'
    +
               | 'DO'
    +
               | 'DOMAIN'
    +
               | 'DRIVER'
    +
               | 'DROP'
    +
               | 'DUMP'
    +
               | 'DUPLICATE'
    +
               | 'ELEMENTS'
    +
               | 'EMIT'
    +
               | 'ENABLE'
    +
               | 'ENCODING'
    +
               | 'ENCRYPTION'
    +
               | 'END'
    +
               | 'ENFORCED'
    +
               | 'ENGINE'
    +
               | 'ERROR'
    +
               | 'ESCAPE'
    +
               | 'EXA'
    +
               | 'EXCHANGE'
    +
               | 'EXCLUDE'
    +
               | 'EXCLUDING'
    +
               | 'EXCLUSIVE'
    +
               | 'EXEC'
    +
               | 'EXECUTE'
    +
               | 'EXPLAIN'
    +
               | 'EXPLICIT'
    +
               | 'EXTENDED'
    +
               | 'EXTRACT'
    +
               | 'EXPORT'
    +
               | K_ISOLATION
    +
               | 'FILTER'
    +
               | 'FIRST'
    +
               | 'FLUSH'
    +
               | 'FOLLOWING'
    +
               | 'FORMAT'
    +
               | 'FULLTEXT'
    +
               | 'FUNCTION'
    +
               | 'GRANT'
    +
               | 'GROUP_CONCAT'
    +
               | 'GUARD'
    +
               | 'HASH'
    +
               | 'HIGH'
    +
               | 'HIGH_PRIORITY'
    +
               | 'HISTORY'
    +
               | 'HOPPING'
    +
               | 'IDENTIFIED'
    +
               | 'IDENTITY'
    +
               | 'INCLUDE'
    +
               | 'INCLUDE_NULL_VALUES'
    +
               | 'INCLUDING'
    +
               | 'INCREMENT'
    +
               | 'INDEX'
    +
               | 'INFORMATION'
    +
               | 'INSERT'
    +
               | 'INTERLEAVE'
    +
               | 'INTERPRET'
    +
               | 'INVALIDATE'
    +
               | 'INVERSE'
    +
               | 'INVISIBLE'
    +
               | 'ISNULL'
    +
               | 'JDBC'
    +
               | 'JSON'
    +
               | 'JSON_OBJECT'
    +
               | 'JSON_OBJECTAGG'
    +
               | 'JSON_ARRAY'
    +
               | 'JSON_ARRAYAGG'
    +
               | 'KEEP'
    +
               | 'KEY_BLOCK_SIZE'
    +
               | 'KEY'
    +
               | 'KEYS'
    +
               | 'KILL'
    +
               | 'FN'
    +
               | 'LAST'
    +
               | 'LEADING'
    +
               | 'LESS'
    +
               | 'LEVEL'
    +
               | 'LOCAL'
    +
               | 'LOCK'
    +
               | 'LOCKED'
    +
               | 'LINK'
    +
               | 'LOG'
    +
               | 'LOOP'
    +
               | 'LOW'
    +
               | 'LOW_PRIORITY'
    +
               | 'LTRIM'
    +
               | 'MATCH'
    +
               | 'MATCH_ANY'
    +
               | 'MATCH_ALL'
    +
               | 'MATCH_PHRASE'
    +
               | 'MATCH_PHRASE_PREFIX'
    +
               | 'MATCH_REGEXP'
    +
               | 'MATCHED'
    +
               | 'MATERIALIZED'
    +
               | 'MAX'
    +
               | 'MAXVALUE'
    +
               | 'MEMBER'
    +
               | 'MERGE'
    +
               | 'MIN'
    +
               | 'MINVALUE'
    +
               | 'MODE'
    +
               | 'MODIFY'
    +
               | 'MOVEMENT'
    +
               | 'NAMES'
    +
               | 'NAME'
    +
               | 'NEVER'
    +
               | 'NEXT'
    +
               | K_NEXTVAL
    +
               | 'NO'
    +
               | 'NOCACHE'
    +
               | 'NOKEEP'
    +
               | 'NOLOCK'
    +
               | 'NOMAXVALUE'
    +
               | 'NOMINVALUE'
    +
               | 'NONE'
    +
               | 'NOORDER'
    +
               | 'NOTHING'
    +
               | 'NOTNULL'
    +
               | 'NOVALIDATE'
    +
               | 'NULLS'
    +
               | 'NOWAIT'
    +
               | 'OF'
    +
               | 'OFF'
    +
               | 'OPEN'
    +
               | 'ORA'
    +
               | 'ORDINALITY'
    +
               | 'OVER'
    +
               | 'OVERFLOW'
    +
               | 'OVERLAPS'
    +
               | 'OVERRIDING'
    +
               | 'OVERWRITE'
    +
               | 'PADDING'
    +
               | 'PARALLEL'
    +
               | 'PARENT'
    +
               | 'PARSER'
    +
               | 'PARTITION'
    +
               | 'PARTITIONING'
    +
               | 'PATH'
    +
               | 'PERCENT'
    +
               | 'PLACING'
    +
               | 'PLAN'
    +
               | 'PLUS'
    +
               | 'PRECEDING'
    +
               | 'PRIMARY'
    +
               | 'POLICY'
    +
               | 'PURGE'
    +
               | 'QUERY'
    +
               | 'QUICK'
    +
               | 'QUIESCE'
    +
               | 'RANGE'
    +
               | 'RAW'
    +
               | 'READ'
    +
               | 'REBUILD'
    +
               | 'RECYCLEBIN'
    +
               | 'RECURSIVE'
    +
               | 'REFERENCES'
    +
               | 'REFRESH'
    +
               | 'REGEXP'
    +
               | 'REJECT'
    +
               | 'RESPECT'
    +
               | 'RLIKE'
    +
               | 'REGEXP_LIKE'
    +
               | 'REGISTER'
    +
               | 'REMOTE'
    +
               | 'REMOVE'
    +
               | 'RENAME'
    +
               | 'REORGANIZE'
    +
               | 'REPAIR'
    +
               | 'REPEATABLE'
    +
               | 'REPLACE'
    +
               | 'RESET'
    +
               | 'RESTART'
    +
               | 'RESUMABLE'
    +
               | 'RESUME'
    +
               | 'RESTRICT'
    +
               | 'RESTRICTED'
    +
               | 'RETURN'
    +
               | 'ROLLBACK'
    +
               | 'ROLLUP'
    +
               | 'ROOT'
    +
               | 'ROW'
    +
               | 'ROWS'
    +
               | 'RTRIM'
    +
               | 'SAFE_CAST'
    +
               | 'SAFE_CONVERT'
    +
               | 'SAVEPOINT'
    +
               | 'SCHEMA'
    +
               | 'SEARCH'
    +
               | 'SECURE'
    +
               | 'SECURITY'
    +
               | 'SEED'
    +
               | 'SEQUENCE'
    +
               | 'SEPARATOR'
    +
               | 'SESSION'
    +
               | 'SETS'
    +
               | 'SHOW'
    +
               | 'SHUTDOWN'
    +
               | 'SHARE'
    +
               | 'SIBLINGS'
    +
               | 'SIMILAR'
    +
               | 'SIZE'
    +
               | 'SKIP'
    +
               | 'SPATIAL'
    +
               | 'STORED'
    +
               | 'STREAM'
    +
               | 'STRICT'
    +
               | 'STRING'
    +
               | 'STRUCT'
    +
               | 'SUMMARIZE'
    +
               | 'SUSPEND'
    +
               | 'SWITCH'
    +
               | 'SYMMETRIC'
    +
               | 'SYNONYM'
    +
               | 'SYSTEM'
    +
               | 'SYSTEM_TIME'
    +
               | 'SYSTEM_TIMESTAMP'
    +
               | 'SYSTEM_VERSION'
    +
               | 'TABLE'
    +
               | 'TABLESPACE'
    +
               | 'TRIGGER'
    +
               | 'THEN'
    +
               | 'TEMP'
    +
               | K_TEXT_LITERAL
    +
               | 'TEMPORARY'
    +
               | 'THAN'
    +
               | K_TIME_KEY_EXPR
    +
               | 'TIMEOUT'
    +
               | 'TO'
    +
               | 'TRIM'
    +
               | 'TRUNCATE'
    +
               | 'TRY_CAST'
    +
               | 'TRY_CONVERT'
    +
               | 'TUMBLING'
    +
               | 'TYPE'
    +
               | 'UNLIMITED'
    +
               | 'UNLOGGED'
    +
               | 'UPDATE'
    +
               | 'UPSERT'
    +
               | 'UNQIESCE'
    +
               | 'USER'
    +
               | 'SIGNED'
    +
               | K_STRING_FUNCTION_NAME
    +
               | 'UNSIGNED'
    +
               | 'VALIDATE'
    +
               | 'VALIDATION'
    +
               | 'VERBOSE'
    +
               | 'VERSION'
    +
               | 'VIEW'
    +
               | 'VISIBLE'
    +
               | 'VOLATILE'
    +
               | 'CONCURRENTLY'
    +
               | 'WAIT'
    +
               | 'WITH TIES'
    +
               | 'WITHIN'
    +
               | 'WITHOUT'
    +
               | 'WITHOUT_ARRAY_WRAPPER'
    +
               | 'WORK'
    +
               | 'XML'
    +
               | 'XMLAGG'
    +
               | 'XMLDATA'
    +
               | 'XMLSCHEMA'
    +
               | 'XMLTEXT'
    +
               | 'XSINIL'
    +
               | 'YAML'
    +
               | 'YES'
    +
               | 'ZONE'
    +
    + Referenced by: +
    + + +====================================================================================================================== +KeywordOrIdentifier +====================================================================================================================== + + +.. raw:: html + + + + + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + NAME + + NEXT + + VALUE + + PUBLIC + + STRING + + DATA + + +
    + + +
             ::= S_IDENTIFIER
    +
               | S_QUOTED_IDENTIFIER
    +
               | 'NAME'
    +
               | 'NEXT'
    +
               | 'VALUE'
    +
               | 'PUBLIC'
    +
               | 'STRING'
    +
               | 'DATA'
    +
    + + +====================================================================================================================== +Statement +====================================================================================================================== + + +.. raw:: html + + + + + + IF + + Condition + + SingleStatement + + Block + + ST_SEMICOLON + ELSE + + SingleStatement + + Block + + ST_SEMICOLON + + SingleStatement + + Block + + ST_SEMICOLON + + EOF + + UnsupportedStatement + +
    + + +
             ::= 'IF' Condition ( SingleStatement | Block ) ST_SEMICOLON? ( 'ELSE' ( SingleStatement | Block ) ST_SEMICOLON? )?
    +
               | ( SingleStatement | Block ) ( ST_SEMICOLON | EOF )
    +
               | UnsupportedStatement
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +SingleStatement +====================================================================================================================== + + +.. raw:: html + + + + + + WithList + + SelectWithWithItems + + InsertWithWithItems + + UpdateWithWithItems + + DeleteWithWithItems + + Merge + + Select + + TableStatement + + Upsert + + Alter + + RenameTableStatement + + Create + + Drop + + Analyze + + Truncate + + Execute + + Set + + Reset + + Show + + RefreshMaterializedView + + Use + + SavepointStatement + + RollbackStatement + COMMIT + + Comment + + Describe + + Explain + + Declare + + Grant + + PurgeStatement + + SessionStatement + + LockStatement + + Import + + Export + +
    + + + +
               | Select
    +
               | TableStatement
    +
               | Upsert
    +
               | Alter
    +
               | RenameTableStatement
    +
               | Create
    +
               | Drop
    +
               | Analyze
    +
               | Truncate
    +
               | Execute
    +
               | Set
    +
               | Reset
    +
               | Show
    +
               | RefreshMaterializedView
    +
               | Use
    +
               | SavepointStatement
    +
               | RollbackStatement
    +
               | 'COMMIT'
    +
               | Comment
    +
               | Describe
    +
               | Explain
    +
               | Declare
    +
               | Grant
    +
               | PurgeStatement
    +
               | SessionStatement
    +
               | LockStatement
    +
               | Import
    +
               | Export
    +
    + Referenced by: +
    + + +====================================================================================================================== +Block +====================================================================================================================== + + +.. raw:: html + + + + + + BEGIN + + ST_SEMICOLON + + SingleStatement + + Block + + ST_SEMICOLON + END + + ST_SEMICOLON + +
    + +
    Block    ::= 'BEGIN' ST_SEMICOLON* ( ( SingleStatement | Block ) ST_SEMICOLON )+ 'END' ST_SEMICOLON?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Statements +====================================================================================================================== + + +.. raw:: html + + + + + + ST_SEMICOLON + IF + + Condition + + SingleStatement + + Block + + ST_SEMICOLON + ELSE + + SingleStatement + + Block + + ST_SEMICOLON + + SingleStatement + + Block + + ST_SEMICOLON + + EOF + + ST_SEMICOLON + IF + + Condition + + SingleStatement + + Block + + ST_SEMICOLON + ELSE + + SingleStatement + + Block + + ST_SEMICOLON + + UnsupportedStatement + + EOF + +
    + + + +
    + Not referenced by any. +
    + + +====================================================================================================================== +LockStatement +====================================================================================================================== + + +.. raw:: html + + + + + + LOCK + + TABLE + + Table + IN + + ROW + + SHARE + + EXCLUSIVE + + SHARE + + ROW + + EXCLUSIVE + + UPDATE + + EXCLUSIVE + + MODE + + NOWAIT + + WAIT + + S_LONG + +
    + + +
             ::= 'LOCK' 'TABLE' Table 'IN' ( 'ROW' ( 'SHARE' | 'EXCLUSIVE' ) | 'SHARE' ( 'ROW' 'EXCLUSIVE' | 'UPDATE' )? + | 'EXCLUSIVE' ) 'MODE' ( 'NOWAIT' | 'WAIT' S_LONG )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +LikeClause +====================================================================================================================== + + +.. raw:: html + + + + + + LIKE + + Table + ( + + ColumnSelectItemsList + ) + + INCLUDING + + EXCLUDING + + DEFAULTS + + INCLUDING + + EXCLUDING + + IDENTITY + + INCLUDING + + EXCLUDING + + COMMENTS + + +
    + + +
             ::= 'LIKE' Table ( '(' ColumnSelectItemsList ')' )? ( ( 'INCLUDING' | 'EXCLUDING' ) 'DEFAULTS' )? ( ( 'INCLUDING' | 'EXCLUDING' + ) 'IDENTITY' )? ( ( 'INCLUDING' | 'EXCLUDING' ) 'COMMENTS' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Export +====================================================================================================================== + + +.. raw:: html + + + + + + EXPORT + + Table + + ParenthesedColumnList + + ParenthesedSelect + INTO + + ExportIntoItem + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +Import +====================================================================================================================== + + +.. raw:: html + + + + + + IMPORT + + INTO + + Table + + ParenthesedColumnList + + ImportColumns + FROM + + ImportFromItem + +
    + +
    Import   ::= 'IMPORT' ( 'INTO' ( Table ParenthesedColumnList? | ImportColumns ) )? 'FROM' ImportFromItem
    +
    + Referenced by: +
    + + +====================================================================================================================== +SubImport +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + IMPORT + + INTO + + ImportColumns + FROM + + ImportFromItem + ) + + +
    + + +
             ::= '(' 'IMPORT' ( 'INTO' ImportColumns )? 'FROM' ImportFromItem ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ImportColumns +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + ColumnDefinition + + LikeClause + , + + ) + + +
    + + +
             ::= '(' ( ColumnDefinition | LikeClause ) ( ',' ( ColumnDefinition | LikeClause ) )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExportIntoItem +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSDestination + + FileDestination + + ScriptSourceDestination + + ErrorClause + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +ImportFromItem +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSSource + + FileSource + + ScriptSourceDestination + + ErrorClause + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSDestination +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSType + + ConnectionDefinition + TABLE + + Table + + ParenthesedColumnList + + DBMSTableDestinationOptionList + + ImportExportStatement + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSTableDestinationOption +====================================================================================================================== + + +.. raw:: html + + + + + + REPLACE + + TRUNCATE + + CREATED + + BY + + S_CHAR_LITERAL + +
    + + +
             ::= 'REPLACE'
    +
               | 'TRUNCATE'
    +
               | 'CREATED' 'BY' S_CHAR_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSTableDestinationOptionList +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSTableDestinationOption + +
    + + +
             ::= DBMSTableDestinationOption+
    +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSSource +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSType + + ConnectionDefinition + TABLE + + Table + + ParenthesedColumnList + + ImportExportStatementsList + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSType +====================================================================================================================== + + +.. raw:: html + + + + + + EXA + + ORA + + JDBC + + DRIVER + + = + + S_CHAR_LITERAL + +
    + +
    DBMSType ::= 'EXA'
    +
               | 'ORA'
    +
               | 'JDBC' ( 'DRIVER' '=' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileType +====================================================================================================================== + + +.. raw:: html + + + + + + CSV + + FBV + + +
    + +
    FileType ::= 'CSV'
    +
               | 'FBV'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ImportExportStatement +====================================================================================================================== + + +.. raw:: html + + + + + + STATEMENT + + S_CHAR_LITERAL + +
    + + +
             ::= 'STATEMENT' S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +ImportExportStatementsList +====================================================================================================================== + + +.. raw:: html + + + + + + ImportExportStatement + +
    + + +
             ::= ImportExportStatement+
    +
    + Referenced by: +
    + + +====================================================================================================================== +File +====================================================================================================================== + + +.. raw:: html + + + + + + FILE + + S_CHAR_LITERAL + +
    + +
    File     ::= 'FILE' S_CHAR_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileList +====================================================================================================================== + + +.. raw:: html + + + + + + File + +
    + + +
    + + +====================================================================================================================== +ConnectionFileDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + ConnectionOrCloudConnectionDefinition + + FileList + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +ConnectionFileDefinitionList +====================================================================================================================== + + +.. raw:: html + + + + + + ConnectionFileDefinition + +
    + + +
             ::= ConnectionFileDefinition+
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVDestinationColumn +====================================================================================================================== + + +.. raw:: html + + + + + + S_LONG + .. + + S_LONG + FORMAT + + = + + S_CHAR_LITERAL + DELIMIT + + = + + ALWAYS + + NEVER + + AUTO + + +
    + + +
             ::= S_LONG ( '..' S_LONG | ( 'FORMAT' '=' S_CHAR_LITERAL )? ( 'DELIMIT' '=' ( 'ALWAYS' | 'NEVER' | 'AUTO' ) )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVDestinationColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + CSVDestinationColumn + , + + +
    + + +
             ::= CSVDestinationColumn ( ',' CSVDestinationColumn )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVSourceColumn +====================================================================================================================== + + +.. raw:: html + + + + + + S_LONG + .. + + S_LONG + FORMAT + + = + + S_CHAR_LITERAL + +
    + + +
             ::= S_LONG ( '..' S_LONG | 'FORMAT' '=' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVSourceColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + CSVSourceColumn + , + + +
    + + +
             ::= CSVSourceColumn ( ',' CSVSourceColumn )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +FBVDestinationColumn +====================================================================================================================== + + +.. raw:: html + + + + + + SIZE + + = + + S_LONG + FORMAT + + PADDING + + = + + S_CHAR_LITERAL + ALIGN + + = + + LEFT + + RIGHT + + +
    + + +
             ::= 'SIZE' '=' S_LONG
    +
               | ( 'FORMAT' | 'PADDING' ) '=' S_CHAR_LITERAL
    +
               | 'ALIGN' '=' ( 'LEFT' | 'RIGHT' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +FBVDestinationColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + FBVDestinationColumn + , + + +
    + + +
             ::= FBVDestinationColumn ( ','? FBVDestinationColumn )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +FBVSourceColumn +====================================================================================================================== + + +.. raw:: html + + + + + + SIZE + + START + + = + + S_LONG + FORMAT + + PADDING + + = + + S_CHAR_LITERAL + ALIGN + + = + + LEFT + + RIGHT + + +
    + + +
             ::= ( 'SIZE' | 'START' ) '=' S_LONG
    +
               | ( 'FORMAT' | 'PADDING' ) '=' S_CHAR_LITERAL
    +
               | 'ALIGN' '=' ( 'LEFT' | 'RIGHT' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +FBVSourceColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + FBVSourceColumn + , + + +
    + + +
             ::= FBVSourceColumn ( ','? FBVSourceColumn )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileDestinationOption +====================================================================================================================== + + +.. raw:: html + + + + + + REPLACE + + TRUNCATE + + WITH + + COLUMN + + NAMES + + ENCODING + + NULL + + BOOLEAN + + ROW + + SEPARATOR + + COLUMN + + SEPARATOR + + DELIMITER + + = + + S_CHAR_LITERAL + DELIMIT + + = + + ALWAYS + + NEVER + + AUTO + + +
    + + +
             ::= 'REPLACE'
    +
               | 'TRUNCATE'
    +
               | 'WITH' 'COLUMN' 'NAMES'
    +
               | ( 'ENCODING' | 'NULL' | 'BOOLEAN' | 'ROW' 'SEPARATOR' | 'COLUMN' ( 'SEPARATOR' + | 'DELIMITER' ) ) '=' S_CHAR_LITERAL
    +
               | 'DELIMIT' '=' ( 'ALWAYS' | 'NEVER' | 'AUTO' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileDestinationOptionList +====================================================================================================================== + + +.. raw:: html + + + + + + FileDestinationOption + +
    + + +
             ::= FileDestinationOption+
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileSourceOption +====================================================================================================================== + + +.. raw:: html + + + + + + TRIM + + LTRIM + + RTRIM + + ENCODING + + NULL + + COLUMN + + SEPARATOR + + DELIMITER + + = + + S_CHAR_LITERAL + SKIP + + = + + S_LONG + ROW + + SEPARATOR + + = + + S_CHAR_LITERAL + SIZE + + = + + S_LONG + +
    + + +
             ::= 'TRIM'
    +
               | 'LTRIM'
    +
               | 'RTRIM'
    +
               | ( 'ENCODING' | 'NULL' | 'COLUMN' ( 'SEPARATOR' | 'DELIMITER' ) ) '=' + S_CHAR_LITERAL
    +
               | 'SKIP' '=' S_LONG
    +
               | 'ROW' ( 'SEPARATOR' '=' S_CHAR_LITERAL | 'SIZE' '=' S_LONG )
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileSourceOptionList +====================================================================================================================== + + +.. raw:: html + + + + + + FileSourceOption + +
    + + +
             ::= FileSourceOption+
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileDestination +====================================================================================================================== + + +.. raw:: html + + + + + + FileType + + ConnectionFileDefinitionList + LOCAL + + SECURE + + FileType + + FileList + ( + + CSVDestinationColumnList + + FBVDestinationColumnList + ) + + FileDestinationOptionList + + CertificateVerification + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +FileSource +====================================================================================================================== + + +.. raw:: html + + + + + + FileType + + ConnectionFileDefinitionList + LOCAL + + SECURE + + FileType + + FileList + ( + + CSVSourceColumnList + + FBVSourceColumnList + ) + + FileSourceOptionList + + CertificateVerification + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +CertificateVerification +====================================================================================================================== + + +.. raw:: html + + + + + + IGNORE + + VERIFY + + CERTIFICATE + + PUBLIC + + KEY + + S_CHAR_LITERAL + PUBLIC + + KEY + + S_CHAR_LITERAL + +
    + + +
             ::= ( 'IGNORE' | 'VERIFY' ) 'CERTIFICATE' ( 'PUBLIC' 'KEY' S_CHAR_LITERAL )?
    +
               | 'PUBLIC' 'KEY' S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +ScriptSourceDestination +====================================================================================================================== + + +.. raw:: html + + + + + + SCRIPT + + Table + + ConnectionDefinition + WITH + + RelObjectName + = + + S_CHAR_LITERAL + +
    + + +
             ::= 'SCRIPT' Table ConnectionDefinition? ( 'WITH' ( RelObjectName '=' S_CHAR_LITERAL )+ )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +UserIdentification +====================================================================================================================== + + +.. raw:: html + + + + + + USER + + S_CHAR_LITERAL + IDENTIFIED + + BY + + S_CHAR_LITERAL + +
    + + +
             ::= 'USER' S_CHAR_LITERAL 'IDENTIFIED' 'BY' S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +ConnectionDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + AT + + RelObjectName + + S_CHAR_LITERAL + + UserIdentification + + CertificateVerification + +
    + + + +
    + + +====================================================================================================================== +CloudConnectionDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + AT + + CLOUD + + NONE + + AZURE + + BLOBSTORAGE + + RelObjectName + + S_CHAR_LITERAL + + UserIdentification + +
    + + +
             ::= 'AT' 'CLOUD' ( 'NONE' | 'AZURE' 'BLOBSTORAGE' ) ( RelObjectName | S_CHAR_LITERAL ) UserIdentification?
    +
    + + +====================================================================================================================== +ConnectionOrCloudConnectionDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + CloudConnectionDefinition + + ConnectionDefinition + +
    + + +
             ::= CloudConnectionDefinition
    +
               | ConnectionDefinition
    +
    + + +====================================================================================================================== +ErrorClause +====================================================================================================================== + + +.. raw:: html + + + + + + ERRORS + + INTO + + ErrorDestination + ( + + Expression + ) + + REPLACE + + TRUNCATE + + RejectClause + + RejectClause + +
    + + +
             ::= 'ERRORS' 'INTO' ErrorDestination ( '(' Expression ')' )? ( 'REPLACE' | 'TRUNCATE' )? RejectClause?
    +
               | RejectClause
    +
    + Referenced by: +
    + + +====================================================================================================================== +RejectClause +====================================================================================================================== + + +.. raw:: html + + + + + + REJECT + + LIMIT + + S_LONG + UNLIMITED + + ERRORS + + +
    + + +
             ::= 'REJECT' 'LIMIT' ( S_LONG | 'UNLIMITED' ) 'ERRORS'?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ErrorDestination +====================================================================================================================== + + +.. raw:: html + + + + + + CSVFileDestination + + Table + +
    + + +
             ::= CSVFileDestination
    +
               | Table
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVFileDestination +====================================================================================================================== + + +.. raw:: html + + + + + + CSV + + ConnectionOrCloudConnectionDefinition + LOCAL + + SECURE + + CSV + + File + +
    + + +
             ::= ( 'CSV' ConnectionOrCloudConnectionDefinition | 'LOCAL' 'SECURE'? 'CSV' ) File
    +
    + Referenced by: +
    + + +====================================================================================================================== +Declare +====================================================================================================================== + + +.. raw:: html + + + + + + DECLARE + + UserVariable + TABLE + + ( + + ColumnDefinition + , + + ) + + AS + + RelObjectName + + ColDataType + = + + Expression + + UserVariable + , + + +
    + +
    Declare  ::= 'DECLARE' UserVariable ( 'TABLE' '(' ColumnDefinition ( ',' ColumnDefinition )* ')' | 'AS' RelObjectName | ColDataType ( '=' Expression )? ( ',' UserVariable ColDataType ( '=' Expression )? )* )
    +
    + Referenced by: +
    + + +====================================================================================================================== +SessionStatement +====================================================================================================================== + + +.. raw:: html + + + + + + SESSION + + BRANCH + + START + + APPLY + + DROP + + SHOW + + DESCRIBE + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + S_CHAR_LITERAL + + S_LONG + . + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + S_CHAR_LITERAL + + S_LONG + WITH + + S_IDENTIFIER + KEEP + + = + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + S_CHAR_LITERAL + + S_LONG + TRUE + + FALSE + + ON + + OFF + + YES + + NO + + , + + +
    + + +
             ::= ( 'SESSION' | 'BRANCH' ) ( 'START' | 'APPLY' | 'DROP' | 'SHOW' | 'DESCRIBE' + ) ( ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | S_CHAR_LITERAL | S_LONG ) ( '.' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | S_CHAR_LITERAL | S_LONG ) )? )? ( 'WITH' ( S_IDENTIFIER | 'KEEP' ) '=' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | S_CHAR_LITERAL | S_LONG | 'TRUE' | 'FALSE' | 'ON' | 'OFF' | 'YES' | 'NO' ) ( ',' ( S_IDENTIFIER | 'KEEP' ) '=' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | S_CHAR_LITERAL | S_LONG | 'TRUE' | 'FALSE' | 'ON' | 'OFF' | 'YES' | 'NO' ) )* )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Set +====================================================================================================================== + + +.. raw:: html + + + + + + SET + + LOCAL + + SESSION + + K_DATETIMELITERAL + ZONE + + UserVariable + + IdentifierChain + = + + Expression + ZONE + + K_DATETIMELITERAL + = + + RelObjectName + , + + +
    + +
    Set      ::= 'SET' ( 'LOCAL' | 'SESSION' )? ( K_DATETIMELITERAL 'ZONE' | ( UserVariable | IdentifierChain ) '='? ) Expression ( ',' ( K_DATETIMELITERAL 'ZONE' | RelObjectName '='? )? Expression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Reset +====================================================================================================================== + + +.. raw:: html + + + + + + RESET + + K_DATETIMELITERAL + ZONE + + RelObjectName + ALL + + +
    + +
    Reset    ::= 'RESET' ( K_DATETIMELITERAL 'ZONE' | RelObjectName | 'ALL' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +RenameTableStatement +====================================================================================================================== + + +.. raw:: html + + + + + + RENAME + + TABLE + + IF + + EXISTS + + Table + WAIT + + S_LONG + NOWAIT + + TO + + Table + + Table + , + + +
    + + +
             ::= 'RENAME' 'TABLE'? ( 'IF' 'EXISTS' )? Table ( 'WAIT' S_LONG | 'NOWAIT' )? 'TO' Table ( ',' Table 'TO' Table )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +PurgeStatement +====================================================================================================================== + + +.. raw:: html + + + + + + PURGE + + TABLE + + Table + INDEX + + Index + RECYCLEBIN + + DBA_RECYCLEBIN + + TABLESPACE + + S_IDENTIFIER + USER + + S_IDENTIFIER + +
    + + +
             ::= 'PURGE' ( 'TABLE' Table | 'INDEX' Index | 'RECYCLEBIN' | 'DBA_RECYCLEBIN' | 'TABLESPACE' S_IDENTIFIER ( 'USER' S_IDENTIFIER )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +Describe +====================================================================================================================== + + +.. raw:: html + + + + + + DESCRIBE + + DESC + + Table + +
    + +
    Describe ::= ( 'DESCRIBE' | 'DESC' ) Table
    +
    + Referenced by: +
    + + +====================================================================================================================== +Explain +====================================================================================================================== + + +.. raw:: html + + + + + + EXPLAIN + + SUMMARIZE + + ExplainStatementOptions + + WithList + + SelectWithWithItems + + InsertWithWithItems + + UpdateWithWithItems + + DeleteWithWithItems + + Merge + + Table + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +ExplainOptionBoolean +====================================================================================================================== + + +.. raw:: html + + + + + + TRUE + + FALSE + + ON + + OFF + + +
    + + +
             ::= ( 'TRUE' | 'FALSE' | 'ON' | 'OFF' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExplainFormatOption +====================================================================================================================== + + +.. raw:: html + + + + + + XML + + JSON + + YAML + + +
    + + +
             ::= ( 'XML' | 'JSON' | 'YAML' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExplainStatementOptions +====================================================================================================================== + + +.. raw:: html + + + + + + ANALYZE + + BUFFERS + + COSTS + + VERBOSE + + ExplainOptionBoolean + FORMAT + + PLAN + + FOR + + ExplainFormatOption + +
    + + +
             ::= ( ( 'ANALYZE' | 'BUFFERS' | 'COSTS' | 'VERBOSE' ) ExplainOptionBoolean | ( 'FORMAT' | 'PLAN' 'FOR'? ) ExplainFormatOption )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Use +====================================================================================================================== + + +.. raw:: html + + + + + + USE + + SCHEMA + + RelObjectName + +
    + +
    Use      ::= 'USE' 'SCHEMA'? RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +Show +====================================================================================================================== + + +.. raw:: html + + + + + + SHOW + + ShowColumns + + ShowIndex + + ShowTables + + captureRest + +
    + +
    Show     ::= 'SHOW' ( ShowColumns | ShowIndex | ShowTables | captureRest )
    +
    + Referenced by: +
    + + +====================================================================================================================== +ShowColumns +====================================================================================================================== + + +.. raw:: html + + + + + + COLUMNS + + FROM + + RelObjectName + +
    + + +
             ::= 'COLUMNS' 'FROM' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +ShowIndex +====================================================================================================================== + + +.. raw:: html + + + + + + INDEX + + FROM + + RelObjectName + +
    + + +
             ::= 'INDEX' 'FROM' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +RefreshMaterializedView +====================================================================================================================== + + +.. raw:: html + + + + + + REFRESH + + MATERIALIZED + + VIEW + + CONCURRENTLY + + Table + WITH + + NO + + DATA + + captureRest + +
    + + +
             ::= 'REFRESH' 'MATERIALIZED' 'VIEW' 'CONCURRENTLY'? Table ( 'WITH' 'NO'? 'DATA' )? captureRest
    +
    + Referenced by: +
    + + +====================================================================================================================== +ShowTables +====================================================================================================================== + + +.. raw:: html + + + + + + EXTENDED + + FULL + + TABLES + + FROM + + IN + + RelObjectName + LIKE + + SimpleExpression + WHERE + + Expression + +
    + + +
             ::= 'EXTENDED'? 'FULL'? 'TABLES' ( ( 'FROM' | 'IN' ) RelObjectName )? ( 'LIKE' SimpleExpression | 'WHERE' Expression )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Values +====================================================================================================================== + + +.. raw:: html + + + + + + VALUES + + VALUE + + ExpressionList + +
    + +
    Values   ::= ( 'VALUES' | 'VALUE' ) ExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReturningClause +====================================================================================================================== + + +.. raw:: html + + + + + + RETURNING + + RETURN + + ReturningOutputAliasList + + SelectItemsList + INTO + + Table + + UserVariable + , + + +
    + + +
             ::= ( 'RETURNING' | 'RETURN' ) ReturningOutputAliasList? SelectItemsList ( 'INTO' ( Table | UserVariable ) ( ',' ( Table | UserVariable ) )* )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReturningReferenceKind +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + +
    + + +
             ::= RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReturningOutputAliasDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + ReturningReferenceKind + AS + + RelObjectName + +
    + + +
             ::= ReturningReferenceKind 'AS' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReturningOutputAliasList +====================================================================================================================== + + +.. raw:: html + + + + + + WITH + + ( + + ReturningOutputAliasDefinition + , + + ) + + +
    + + +
             ::= 'WITH' '(' ReturningOutputAliasDefinition ( ',' ReturningOutputAliasDefinition )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +UpdateWithWithItems +====================================================================================================================== + + +.. raw:: html + + + + + + Update + +
    + + +
             ::= Update
    +
    + Referenced by: +
    + + +====================================================================================================================== +Update +====================================================================================================================== + + +.. raw:: html + + + + + + UPDATE + + LOW_PRIORITY + + IGNORE + + TableWithAliasAndMysqlIndexHint + + JoinsList + SET + + UpdateSets + + OutputClause + FROM + + FromItem + + JoinsList + + WhereClause + + PreferringClause + + OrderByElements + + PlainLimit + + ReturningClause + +
    + + +
    + + +====================================================================================================================== +UpdateSets +====================================================================================================================== + + +.. raw:: html + + + + + + Column + = + + Expression + + ParenthesedExpressionList + = + + ParenthesedSelect + + ParenthesedExpressionList + , + + Column + = + + Expression + + ParenthesedExpressionList + = + + ParenthesedSelect + + ParenthesedExpressionList + +
    + + + +
    + + +====================================================================================================================== +Partitions +====================================================================================================================== + + +.. raw:: html + + + + + + Column + = + + Expression + , + + +
    + + +
             ::= Column ( '=' Expression )? ( ',' Column ( '=' Expression )? )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +InsertWithWithItems +====================================================================================================================== + + +.. raw:: html + + + + + + Insert + +
    + + +
             ::= Insert
    +
    + Referenced by: +
    + + +====================================================================================================================== +Insert +====================================================================================================================== + + +.. raw:: html + + + + + + INSERT + + LOW_PRIORITY + + DELAYED + + HIGH_PRIORITY + + IGNORE + + ALL + + FIRST + + OracleMultiInsertClause + + OracleMultiInsertWhenBranch + + OracleMultiInsertElseBranch + + Select + OVERWRITE + + TABLE + + INTO + + TABLE + + Table + PARTITION + + ( + + Partitions + ) + + AS + + RelObjectName + ( + + ColumnList + ) + + OVERRIDING + + SYSTEM + + VALUE + + OutputClause + DEFAULT + + VALUES + + SET + + UpdateSets + + Select + + Alias + ON + + DUPLICATE + + KEY + + UPDATE + + InsertDuplicateAction + ON + + CONFLICT + + InsertConflictTarget + + InsertConflictAction + + ReturningClause + +
    + +
    Insert   ::= 'INSERT' ( 'LOW_PRIORITY' | 'DELAYED' | 'HIGH_PRIORITY' )? 'IGNORE'? ( ( 'ALL' + | 'FIRST' ) ( OracleMultiInsertClause+ | OracleMultiInsertWhenBranch+ OracleMultiInsertElseBranch? ) Select | ( 'OVERWRITE' 'TABLE' | 'INTO' 'TABLE'? )? Table ( 'PARTITION' '(' Partitions ')' )? ( 'AS'? RelObjectName )? ( '(' ColumnList ')' )? ( 'OVERRIDING' 'SYSTEM' 'VALUE' )? OutputClause? ( 'DEFAULT' 'VALUES' | 'SET' UpdateSets | Select ) Alias? ( 'ON' 'DUPLICATE' 'KEY' 'UPDATE' InsertDuplicateAction )? ( 'ON' 'CONFLICT' InsertConflictTarget? InsertConflictAction )? ReturningClause? )
    +
    + + +====================================================================================================================== +OracleMultiInsertClause +====================================================================================================================== + + +.. raw:: html + + + + + + INTO + + Table + ( + + ColumnList + ) + + Select + +
    + + +
             ::= 'INTO' Table ( '(' ColumnList ')' )? Select
    +
    + + +====================================================================================================================== +OracleMultiInsertWhenBranch +====================================================================================================================== + + +.. raw:: html + + + + + + WHEN + + Expression + THEN + + OracleMultiInsertClauseList + +
    + + +
             ::= 'WHEN' Expression 'THEN' OracleMultiInsertClauseList
    +
    + Referenced by: +
    + + +====================================================================================================================== +OracleMultiInsertElseBranch +====================================================================================================================== + + +.. raw:: html + + + + + + ELSE + + OracleMultiInsertClauseList + +
    + + +
             ::= 'ELSE' OracleMultiInsertClauseList
    +
    + Referenced by: +
    + + +====================================================================================================================== +OracleMultiInsertClauseList +====================================================================================================================== + + +.. raw:: html + + + + + + OracleMultiInsertClause + +
    + + +
             ::= OracleMultiInsertClause+
    +
    + + +====================================================================================================================== +InsertConflictTarget +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + RelObjectNameExt + , + + ) + + WhereClause + ON + + CONSTRAINT + + RelObjectNameExt + +
    + + +
             ::= '(' RelObjectNameExt ( ',' RelObjectNameExt )* ')' WhereClause?
    +
               | 'ON' 'CONSTRAINT' RelObjectNameExt
    +
    + Referenced by: +
    + + +====================================================================================================================== +InsertConflictAction +====================================================================================================================== + + +.. raw:: html + + + + + + DO + + NOTHING + + UPDATE + + SET + + UpdateSets + + WhereClause + +
    + + +
             ::= 'DO' ( 'NOTHING' | 'UPDATE' 'SET' UpdateSets WhereClause? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +InsertDuplicateAction +====================================================================================================================== + + +.. raw:: html + + + + + + NOTHING + + UpdateSets + + WhereClause + +
    + + +
             ::= 'NOTHING'
    +
               | UpdateSets WhereClause?
    +
    + Referenced by: +
    + + +====================================================================================================================== +OutputClause +====================================================================================================================== + + +.. raw:: html + + + + + + OUTPUT + + SelectItemsList + INTO + + UserVariable + + Table + + ColumnsNamesList + +
    + + +
             ::= 'OUTPUT' SelectItemsList ( 'INTO' ( UserVariable | Table ) ColumnsNamesList? )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Upsert +====================================================================================================================== + + +.. raw:: html + + + + + + UPSERT + + INSERT + + OR + + REPLACE + + INTO + + Table + + ParenthesedColumnList + SET + + UpdateSets + + Select + ON + + DUPLICATE + + KEY + + UPDATE + + InsertDuplicateAction + +
    + +
    Upsert   ::= ( 'UPSERT' | ( 'INSERT' 'OR' )? 'REPLACE' ) 'INTO'? Table ParenthesedColumnList? ( 'SET' UpdateSets | Select ) ( 'ON' 'DUPLICATE' 'KEY' 'UPDATE' InsertDuplicateAction )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +DeleteWithWithItems +====================================================================================================================== + + +.. raw:: html + + + + + + Delete + +
    + + +
             ::= Delete
    +
    + Referenced by: +
    + + +====================================================================================================================== +Delete +====================================================================================================================== + + +.. raw:: html + + + + + + DELETE + + LOW_PRIORITY + + QUICK + + IGNORE + + TableWithAlias + , + + OutputClause + FROM + + TableWithAlias + + JoinsList + USING + + FromItem + , + + WhereClause + + PreferringClause + + OrderByElements + + PlainLimit + + ReturningClause + +
    + +
    Delete   ::= 'DELETE' 'LOW_PRIORITY'? 'QUICK'? 'IGNORE'? ( ( TableWithAlias ( ',' TableWithAlias )* OutputClause? )? 'FROM' )? ( TableWithAlias JoinsList? )? ( 'USING' FromItem ( ',' FromItem )* )? WhereClause? PreferringClause? OrderByElements? PlainLimit? ReturningClause?
    +
    + + +====================================================================================================================== +Merge +====================================================================================================================== + + +.. raw:: html + + + + + + MERGE + + INTO + + TableWithAlias + USING + + FromItem + ON + + Expression + + MergeOperations + + OutputClause + +
    + +
    Merge    ::= 'MERGE' 'INTO' TableWithAlias 'USING' FromItem 'ON' Expression MergeOperations OutputClause?
    +
    + Referenced by: +
    + + +====================================================================================================================== +MergeOperations +====================================================================================================================== + + +.. raw:: html + + + + + + MergeWhenMatched + + MergeWhenNotMatched + +
    + + +
             ::= ( MergeWhenMatched | MergeWhenNotMatched )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +MergeWhenMatched +====================================================================================================================== + + +.. raw:: html + + + + + + WHEN + + MATCHED + + AND + + Expression + THEN + + DELETE + + MergeUpdateClause + +
    + + +
             ::= 'WHEN' 'MATCHED' ( 'AND' Expression )? 'THEN' ( 'DELETE' | MergeUpdateClause )
    +
    + Referenced by: +
    + + +====================================================================================================================== +MergeUpdateClause +====================================================================================================================== + + +.. raw:: html + + + + + + UPDATE + + SET + + UpdateSets + WHERE + + Expression + DELETE + + WHERE + + Expression + +
    + + +
             ::= 'UPDATE' 'SET' UpdateSets ( 'WHERE' Expression )? ( 'DELETE' 'WHERE' Expression )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +MergeWhenNotMatched +====================================================================================================================== + + +.. raw:: html + + + + + + WHEN + + NOT + + MATCHED + + AND + + Expression + THEN + + INSERT + + ( + + ColumnList + ) + + VALUES + + ( + + SimpleExpressionList + ) + + WHERE + + Expression + +
    + + +
             ::= 'WHEN' 'NOT' 'MATCHED' ( 'AND' Expression )? 'THEN' 'INSERT' ( '(' ColumnList ')' )? 'VALUES' '(' SimpleExpressionList ')' ( 'WHERE' Expression )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +RelObjectNames +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ... + + .. + + . + + : + + RelObjectNameExt + +
    + + +
             ::= RelObjectName ( ( '...' | '..' | '.' | ':' ) RelObjectNameExt )*
    +
    + + +====================================================================================================================== +ColumnIdentifier +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ... + + .. + + . + + RelObjectNameExt + +
    + + +
             ::= RelObjectName ( ( '...' | '..' | '.' ) RelObjectNameExt )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Column +====================================================================================================================== + + +.. raw:: html + + + + + + ColumnIdentifier + COMMENT + + S_CHAR_LITERAL + . + + K_NEXTVAL + + ArrayConstructor + +
    + + +
    + + +====================================================================================================================== +RelObjectName +====================================================================================================================== + + +.. raw:: html + + + + + + DATA_TYPE + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + K_DATETIMELITERAL + + K_DATE_LITERAL + + NonReservedWord + ALL + + ANY + + CASEWHEN + + CONNECT + + CREATE + + DEFAULT + + GLOBAL + + GROUP + + GROUPING + + IF + + IIF + + IGNORE + + IN + + INTERVAL + + LEFT + + LIMIT + + K_NEXTVAL + OFFSET + + ON + + OPTIMIZE + + ORDER + + PROCEDURE + + PUBLIC + + QUALIFY + + RIGHT + + SET + + SOME + + START + + TABLES + + TOP + + VALUE + + VALUES + + +
    + + +
             ::= DATA_TYPE
    +
               | S_IDENTIFIER
    +
               | S_QUOTED_IDENTIFIER
    +
               | K_DATETIMELITERAL
    +
               | K_DATE_LITERAL
    +
               | NonReservedWord
    +
               | 'ALL'
    +
               | 'ANY'
    +
               | 'CASEWHEN'
    +
               | 'CONNECT'
    +
               | 'CREATE'
    +
               | 'DEFAULT'
    +
               | 'GLOBAL'
    +
               | 'GROUP'
    +
               | 'GROUPING'
    +
               | 'IF'
    +
               | 'IIF'
    +
               | 'IGNORE'
    +
               | 'IN'
    +
               | 'INTERVAL'
    +
               | 'LEFT'
    +
               | 'LIMIT'
    +
               | K_NEXTVAL
    +
               | 'OFFSET'
    +
               | 'ON'
    +
               | 'OPTIMIZE'
    +
               | 'ORDER'
    +
               | 'PROCEDURE'
    +
               | 'PUBLIC'
    +
               | 'QUALIFY'
    +
               | 'RIGHT'
    +
               | 'SET'
    +
               | 'SOME'
    +
               | 'START'
    +
               | 'TABLES'
    +
               | 'TOP'
    +
               | 'VALUE'
    +
               | 'VALUES'
    +
    + + +====================================================================================================================== +RelObjectNameExt +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + FROM + + K_SELECT + CURRENT + + +
    + + +
             ::= RelObjectName
    +
               | 'FROM'
    +
               | K_SELECT
    +
               | 'CURRENT'
    +
    + + +====================================================================================================================== +Table +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNames + + TimeTravelBeforeAlias + + S_CHAR_LITERAL + +
    + + +
               | S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +TableWithAlias +====================================================================================================================== + + +.. raw:: html + + + + + + Table + + Alias + +
    + + +
             ::= Table Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +TableWithAliasAndMysqlIndexHint +====================================================================================================================== + + +.. raw:: html + + + + + + Table + + Alias + + MySQLIndexHint + +
    + + +
             ::= Table Alias? MySQLIndexHint?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Number +====================================================================================================================== + + +.. raw:: html + + + + + + S_DOUBLE + + S_LONG + +
    + +
    Number   ::= S_DOUBLE
    +
               | S_LONG
    +
    + Referenced by: +
    + + +====================================================================================================================== +SampleClause +====================================================================================================================== + + +.. raw:: html + + + + + + SAMPLE + + BLOCK + + TABLESAMPLE + + USING + + SAMPLE + + SYSTEM + + BERNOULLI + + ( + + Number + % + + PERCENT + + ROWS + + ) + + REPEATABLE + + ( + + Number + ) + + SEED + + ( + + Number + ) + + Number + OFFSET + + Number + +
    + + +
             ::= ( 'SAMPLE' 'BLOCK'? | ( 'TABLESAMPLE' | 'USING' 'SAMPLE' ) ( 'SYSTEM' + | 'BERNOULLI' ) ) ( '(' Number ( '%' | 'PERCENT' | 'ROWS' )? ')' ( 'REPEATABLE' '(' Number ')' )? ( 'SEED' '(' Number ')' )? | Number ( 'OFFSET' Number )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +SelectWithWithItems +====================================================================================================================== + + +.. raw:: html + + + + + + Select + +
    + + +
             ::= Select
    +
    + Referenced by: +
    + + +====================================================================================================================== +Select +====================================================================================================================== + + +.. raw:: html + + + + + + WithList + + FromQuery + + PlainSelect + + Values + + ParenthesedSelect + + Alias + + FromQueryFromSelect + + SetOperationList + + OrderByElements + + LimitWithOffset + + Offset + + Fetch + + WithIsolation + +
    + + +
    + + +====================================================================================================================== +FromQuery +====================================================================================================================== + + +.. raw:: html + + + + + + FROM + + FromItem + + LateralViews + + JoinsList + |> + + PipeOperator + +
    + + +
             ::= 'FROM' FromItem LateralViews? JoinsList? ( '|>' PipeOperator )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +FromQueryFromSelect +====================================================================================================================== + + +.. raw:: html + + + + + + |> + + PipeOperator + +
    + + +
             ::= ( '|>' PipeOperator )+
    +
    + Referenced by: +
    + + +====================================================================================================================== +PipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + SelectPipeOperator + + SetPipeOperator + + DropPipeOperator + + AsPipeOperator + + WherePipeOperator + + LimitPipeOperator + + AggregatePipeOperator + + OrderByPipeOperator + + SetOperationPipeOperator + + JoinPipeOperator + + CallPipeOperator + + TableSamplePipeOperator + + PivotPipeOperator + + UnPivotPipeOperator + +
    + + +
             ::= SelectPipeOperator
    +
               | SetPipeOperator
    +
               | DropPipeOperator
    +
               | AsPipeOperator
    +
               | WherePipeOperator
    +
               | LimitPipeOperator
    +
               | AggregatePipeOperator
    +
               | OrderByPipeOperator
    +
               | SetOperationPipeOperator
    +
               | JoinPipeOperator
    +
               | CallPipeOperator
    +
               | TableSamplePipeOperator
    +
               | PivotPipeOperator
    +
               | UnPivotPipeOperator
    +
    + Referenced by: +
    + + +====================================================================================================================== +SelectPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + K_SELECT + DISTINCT + + ALL + + EXTEND + + WINDOW + + RENAME + + SelectItem + , + + +
    + + +
             ::= ( K_SELECT ( 'DISTINCT' | 'ALL' )? | 'EXTEND' | 'WINDOW' | 'RENAME' ) SelectItem ( ',' SelectItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +WherePipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + WHERE + + Expression + +
    + + +
             ::= 'WHERE' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +OrderSuffix +====================================================================================================================== + + +.. raw:: html + + + + + + ASC + + DESC + + NULLS + + FIRST + + LAST + + +
    + + +
             ::= ( 'ASC' | 'DESC' ) ( 'NULLS' ( 'FIRST' | 'LAST' ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +AggregatePipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + AGGREGATE + + SelectItem + + OrderSuffix + , + + GROUP + + AND + + ORDER + + BY + + SelectItem + + OrderSuffix + , + + +
    + + +
             ::= 'AGGREGATE' SelectItem OrderSuffix? ( ',' SelectItem OrderSuffix? )* ( 'GROUP' ( 'AND' 'ORDER' )? 'BY' SelectItem OrderSuffix? ( ',' SelectItem OrderSuffix? )* )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +OrderByPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + OrderByElements + +
    + + +
             ::= OrderByElements
    +
    + Referenced by: +
    + + +====================================================================================================================== +AsPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + AS + + Alias + +
    + + +
             ::= 'AS' Alias
    +
    + Referenced by: +
    + + +====================================================================================================================== +JoinPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + JoinerExpression + +
    + + +
             ::= JoinerExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +SetPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + SET + + UpdateSets + +
    + + +
             ::= 'SET' UpdateSets
    +
    + Referenced by: +
    + + +====================================================================================================================== +DropPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + DROP + + ColumnList + +
    + + +
             ::= 'DROP' ColumnList
    +
    + Referenced by: +
    + + +====================================================================================================================== +LimitPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + LIMIT + + Expression + OFFSET + + Expression + +
    + + +
             ::= 'LIMIT' Expression ( 'OFFSET' Expression )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +SetOperationModifier +====================================================================================================================== + + +.. raw:: html + + + + + + ALL + + DISTINCT + + BY + + NAME + + MATCHING + + ( + + RelObjectName + , + + ) + + STRICT + + CORRESPONDING + + ALL + + DISTINCT + + BY + + ALL + + DISTINCT + + ( + + RelObjectName + , + + ) + + ALL + + DISTINCT + + +
    + + +
             ::= ( 'ALL' | 'DISTINCT' )? 'BY' 'NAME' ( 'MATCHING' '(' RelObjectName ( ',' RelObjectName )* ')' )?
    +
               | 'STRICT'? 'CORRESPONDING' ( 'ALL' | 'DISTINCT' )? ( 'BY' ( 'ALL' | 'DISTINCT' + )? '(' RelObjectName ( ',' RelObjectName )* ')' )?
    +
               | 'ALL'
    +
               | 'DISTINCT'
    +
    + + +====================================================================================================================== +SetOperationPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + UNION + + INTERSECT + + EXCEPT + + SetOperationModifier + + ParenthesedSelect + , + + +
    + + +
             ::= ( 'UNION' | 'INTERSECT' | 'EXCEPT' ) SetOperationModifier? ParenthesedSelect ( ',' ParenthesedSelect )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CallPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + CALL + + TableFunction + + Alias + +
    + + +
             ::= 'CALL' TableFunction Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +TableSamplePipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + TABLESAMPLE + + SYSTEM + + ( + + S_DOUBLE + + S_LONG + PERCENT + + ) + + +
    + + +
             ::= 'TABLESAMPLE' 'SYSTEM' '(' ( S_DOUBLE | S_LONG ) 'PERCENT' ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + PIVOT + + ( + + Function + FOR + + Column + IN + + ( + + SelectItemsList + ) + + ) + + Alias + +
    + + +
             ::= 'PIVOT' '(' Function 'FOR' Column 'IN' '(' SelectItemsList ')' ')' Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnPivotPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + UNPIVOT + + ( + + Column + FOR + + Column + IN + + ( + + SelectItemsList + ) + + ) + + Alias + +
    + + +
             ::= 'UNPIVOT' '(' Column 'FOR' Column 'IN' '(' SelectItemsList ')' ')' Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +TableStatement +====================================================================================================================== + + +.. raw:: html + + + + + + TABLE + + Table + + OrderByElements + + LimitWithOffset + + Offset + +
    + + +
             ::= 'TABLE' Table OrderByElements? LimitWithOffset? Offset?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ParenthesedSelect +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Select + ) + + +
    + + +
             ::= '(' Select ')'
    +
    + + +====================================================================================================================== +ParenthesedInsert +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Insert + ) + + +
    + + +
             ::= '(' Insert ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ParenthesedUpdate +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Update + ) + + +
    + + +
             ::= '(' Update ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ParenthesedDelete +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Delete + ) + + +
    + + +
             ::= '(' Delete ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +LateralView +====================================================================================================================== + + +.. raw:: html + + + + + + LATERAL + + VIEW + + OUTER + + Function + + RelObjectName + AS + + RelObjectName + , + + RelObjectName + +
    + + +
             ::= 'LATERAL' 'VIEW' 'OUTER'? Function RelObjectName? 'AS' RelObjectName ( ',' RelObjectName )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ForClause +====================================================================================================================== + + +.. raw:: html + + + + + + FOR + + BROWSE + + XML + + RAW + + ( + + S_CHAR_LITERAL + ) + + AUTO + + , + + BINARY + + BASE64 + + TYPE + + ROOT + + XMLSCHEMA + + ( + + S_CHAR_LITERAL + ) + + XMLDATA + + ELEMENTS + + XSINIL + + ABSENT + + EXPLICIT + + , + + BINARY + + BASE64 + + TYPE + + ROOT + + ( + + S_CHAR_LITERAL + ) + + XMLDATA + + PATH + + ( + + S_CHAR_LITERAL + ) + + , + + BINARY + + BASE64 + + TYPE + + ROOT + + ( + + S_CHAR_LITERAL + ) + + ELEMENTS + + XSINIL + + ABSENT + + JSON + + AUTO + + PATH + + , + + ROOT + + ( + + S_CHAR_LITERAL + ) + + INCLUDE_NULL_VALUES + + WITHOUT_ARRAY_WRAPPER + + +
    + + +
             ::= 'FOR' ( 'BROWSE' | 'XML' ( ( 'RAW' ( '(' S_CHAR_LITERAL ')' )? | 'AUTO' ) ( ',' ( 'BINARY' 'BASE64' | 'TYPE' | ( 'ROOT' | 'XMLSCHEMA' ) ( + '(' S_CHAR_LITERAL ')' )? | 'XMLDATA' | 'ELEMENTS' ( 'XSINIL' | 'ABSENT' )? ) )* | 'EXPLICIT' ( ',' + ( 'BINARY' 'BASE64' | 'TYPE' | 'ROOT' ( '(' S_CHAR_LITERAL ')' )? | 'XMLDATA' ) )* | 'PATH' ( '(' S_CHAR_LITERAL ')' )? ( ',' ( 'BINARY' 'BASE64' | 'TYPE' | 'ROOT' ( '(' S_CHAR_LITERAL ')' )? | 'ELEMENTS' ( 'XSINIL' | 'ABSENT' )? ) )* ) | 'JSON' ( 'AUTO' | 'PATH' ) + ( ',' ( 'ROOT' ( '(' S_CHAR_LITERAL ')' )? | 'INCLUDE_NULL_VALUES' | 'WITHOUT_ARRAY_WRAPPER' ) )* )
    +
    + Referenced by: +
    + + +====================================================================================================================== +LateralViews +====================================================================================================================== + + +.. raw:: html + + + + + + LateralView + +
    + + +
             ::= LateralView+
    +
    + Referenced by: +
    + + +====================================================================================================================== +LateralSubSelect +====================================================================================================================== + + +.. raw:: html + + + + + + LATERAL + + ( + + Select + ) + + +
    + + +
             ::= 'LATERAL' '(' Select ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +PlainSelect +====================================================================================================================== + + +.. raw:: html + + + + + + K_SELECT + STRAIGHT_JOIN + + Skip + + First + + Top + ALL + + DISTINCT + + ON + + ( + + SelectItemsList + ) + + DISTINCTROW + + UNIQUE + + SQL_CALC_FOUND_ROWS + + SQL_NO_CACHE + + SQL_CACHE + + AS + + STRUCT + + VALUE + + Top + + SelectItemsList + + IntoClause + FROM + + FromItem + + LateralViews + + JoinsList + FROM + + ONLY + + FromItem + + LateralViews + + JoinsList + FINAL + + KSQLWindowClause + + PreWhereClause + + WhereClause + + OracleHierarchicalQueryClause + + PreferringClause + PARTITION + + BY + + ComplexExpressionList + ( + + ComplexExpressionList + ) + + Having + + GroupByColumnReferences + + Having + + Qualify + + OrderByElements + WINDOW + + RelObjectName + AS + + windowDefinition + , + + OrderByElements + + ForClause + EMIT + + CHANGES + + LimitBy + + LimitWithOffset + + Offset + + LimitWithOffset + + Fetch + + WithIsolation + FOR + + NO + + KEY + + UPDATE + + KEY + + SHARE + + READ + + FETCH + + ONLY + + OF + + Table + + Wait + NOWAIT + + SKIP + + LOCKED + + SETTINGS + + UpdateSets + + OptimizeFor + INTO + + TEMP + + Table + WITH + + NO + + LOG + + +
    + + +
             ::= K_SELECT 'STRAIGHT_JOIN'? Skip? First? Top? ( 'ALL' | 'DISTINCT' ( 'ON' '(' SelectItemsList ')' )? | 'DISTINCTROW' | 'UNIQUE' | 'SQL_CALC_FOUND_ROWS' | 'SQL_NO_CACHE' | 'SQL_CACHE' + )? ( 'AS' ( 'STRUCT' | 'VALUE' ) )? Top? SelectItemsList IntoClause? ( 'FROM' FromItem LateralViews? JoinsList? )? ( 'FROM' 'ONLY' FromItem LateralViews? JoinsList? )? 'FINAL'? KSQLWindowClause? PreWhereClause? WhereClause? OracleHierarchicalQueryClause? ( PreferringClause ( 'PARTITION' 'BY' ( ComplexExpressionList | '(' ComplexExpressionList ')' ) )? )? Having? GroupByColumnReferences? Having? Qualify? OrderByElements? ( 'WINDOW' RelObjectName 'AS' windowDefinition ( ',' RelObjectName 'AS' windowDefinition )* )? OrderByElements? ForClause? ( 'EMIT' 'CHANGES' )? LimitBy? LimitWithOffset? Offset? LimitWithOffset? Fetch? WithIsolation? ( 'FOR' ( ( 'NO' 'KEY' )? 'UPDATE' | 'KEY'? 'SHARE' | ( 'READ' | 'FETCH' ) 'ONLY' + ) ( 'OF' Table )? Wait? ( 'NOWAIT' | 'SKIP' 'LOCKED' )? )? ( 'SETTINGS' UpdateSets )? OptimizeFor? ( 'INTO' 'TEMP' Table )? ( 'WITH' 'NO' 'LOG' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +SetOperationList +====================================================================================================================== + + +.. raw:: html + + + + + + UNION + + INTERSECT + + MINUS + + EXCEPT + + SetOperationModifier + + PlainSelect + + Values + + ParenthesedSelect + + OrderByElements + + LimitWithOffset + + Offset + + LimitWithOffset + + Fetch + + WithIsolation + +
    + + +
             ::= ( ( 'UNION' | 'INTERSECT' | 'MINUS' | 'EXCEPT' ) SetOperationModifier? ( PlainSelect | Values | ParenthesedSelect ) )+ OrderByElements? LimitWithOffset? Offset? LimitWithOffset? Fetch? WithIsolation?
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithList +====================================================================================================================== + + +.. raw:: html + + + + + + WITH + + WithItem + , + + +
    + +
    WithList ::= 'WITH' WithItem ( ',' WithItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithItem +====================================================================================================================== + + +.. raw:: html + + + + + + FUNCTION + + WithFunctionDeclaration + RECURSIVE + + RelObjectName + ( + + SelectItemsList + ) + + AS + + NOT + + MATERIALIZED + + ParenthesedSelect + + ParenthesedInsert + + ParenthesedUpdate + + ParenthesedDelete + + WithSearchClause + +
    + +
    WithItem ::= ( 'FUNCTION' WithFunctionDeclaration | 'RECURSIVE'? RelObjectName ( '(' SelectItemsList ')' )? 'AS' ( 'NOT'? 'MATERIALIZED' )? ( ParenthesedSelect | ParenthesedInsert | ParenthesedUpdate | ParenthesedDelete ) ) WithSearchClause?
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithSearchClause +====================================================================================================================== + + +.. raw:: html + + + + + + SEARCH + + BREADTH + + DEPTH + + FIRST + + BY + + Column + , + + SET + + RelObjectName + +
    + + +
             ::= 'SEARCH' ( 'BREADTH' | 'DEPTH' ) 'FIRST' 'BY' Column ( ',' Column )* 'SET' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithFunctionDeclaration +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ( + + WithFunctionParameter + , + + ) + + RETURNS + + RelObjectName + RETURN + + Expression + +
    + + +
             ::= RelObjectName '(' ( WithFunctionParameter ( ',' WithFunctionParameter )* )? ')' 'RETURNS' RelObjectName 'RETURN' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithFunctionParameter +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ARRAY + + < + + RelObjectName + > + + RelObjectName + +
    + + +
             ::= RelObjectName ( 'ARRAY' '<' RelObjectName '>' | RelObjectName )
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnSelectItemsList +====================================================================================================================== + + +.. raw:: html + + + + + + SelectItem + , + + +
    + + +
             ::= SelectItem ( ',' SelectItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +SelectItemsList +====================================================================================================================== + + +.. raw:: html + + + + + + SelectItem + , + + +
    + + +
             ::= SelectItem ( ',' SelectItem )*
    +
    + + +====================================================================================================================== +FunctionAllColumns +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Function + ) + + . + + * + + +
    + + +
             ::= '('+ Function ')'+ '.' '*'
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +SelectItem +====================================================================================================================== + + +.. raw:: html + + + + + + ConnectByPriorOperator + + XorExpression + + ConcatExpression + + Expression + + Alias + +
    + + + +
    + + +====================================================================================================================== +AllColumns +====================================================================================================================== + + +.. raw:: html + + + + + + * + + EXCEPT + + EXCLUDE + + ParenthesedColumnList + REPLACE + + ( + + SelectItemsList + ) + + +
    + + +
             ::= '*' ( ( 'EXCEPT' | 'EXCLUDE' ) ParenthesedColumnList )? ( 'REPLACE' '(' SelectItemsList ')' )?
    +
    + + +====================================================================================================================== +AllTableColumns +====================================================================================================================== + + +.. raw:: html + + + + + + Table + . + + AllColumns + +
    + + +
             ::= Table '.' AllColumns
    +
    + + +====================================================================================================================== +Alias +====================================================================================================================== + + +.. raw:: html + + + + + + AS + + RelObjectName + ( + + RelObjectName + + ColDataType + , + + ) + + AS + + RelObjectName + + S_CHAR_LITERAL + ( + + RelObjectName + + ColDataType + , + + ) + + +
    + + +
               | 'AS'? ( RelObjectName | S_CHAR_LITERAL ) ( '(' RelObjectName ColDataType? ( ',' RelObjectName ColDataType? )* ')' )?
    +
    + + +====================================================================================================================== +SQLServerHint +====================================================================================================================== + + +.. raw:: html + + + + + + INDEX + + ( + + RelObjectName + ) + + NOLOCK + + +
    + + +
             ::= 'INDEX' '(' RelObjectName ')'
    +
               | 'NOLOCK'
    +
    + Referenced by: +
    + + +====================================================================================================================== +SQLServerHints +====================================================================================================================== + + +.. raw:: html + + + + + + WITH + + ( + + SQLServerHint + , + + ) + + +
    + + +
             ::= 'WITH' '(' SQLServerHint ( ',' SQLServerHint )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +MySQLIndexHint +====================================================================================================================== + + +.. raw:: html + + + + + + USE + + SHOW + + IGNORE + + FORCE + + INDEX + + KEY + + ( + + RelObjectName + , + + ) + + +
    + + +
             ::= ( 'USE' | 'SHOW' | 'IGNORE' | 'FORCE' ) ( 'INDEX' | 'KEY' ) '(' RelObjectName ( ',' RelObjectName )* ')'
    +
    + + +====================================================================================================================== +FunctionItem +====================================================================================================================== + + +.. raw:: html + + + + + + Function + + Alias + +
    + + +
             ::= Function Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotForColumns +====================================================================================================================== + + +.. raw:: html + + + + + + ParenthesedColumnList + + Column + +
    + + +
             ::= ParenthesedColumnList
    +
               | Column
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotFunctionItems +====================================================================================================================== + + +.. raw:: html + + + + + + FunctionItem + , + + +
    + + +
             ::= FunctionItem ( ',' FunctionItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExpressionListItem +====================================================================================================================== + + +.. raw:: html + + + + + + ParenthesedExpressionList + + Alias + +
    + + +
             ::= ParenthesedExpressionList Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotMultiInItems +====================================================================================================================== + + +.. raw:: html + + + + + + ExpressionListItem + , + + +
    + + +
             ::= ExpressionListItem ( ',' ExpressionListItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Pivot +====================================================================================================================== + + +.. raw:: html + + + + + + PIVOT + + ( + + PivotFunctionItems + FOR + + PivotForColumns + IN + + ( + + SelectItemsList + + PivotMultiInItems + ) + + ) + + Alias + +
    + +
    Pivot    ::= 'PIVOT' '(' PivotFunctionItems 'FOR' PivotForColumns 'IN' '(' ( SelectItemsList | PivotMultiInItems ) ')' ')' Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotXml +====================================================================================================================== + + +.. raw:: html + + + + + + PIVOT + + XML + + ( + + PivotFunctionItems + FOR + + PivotForColumns + IN + + ( + + ANY + + Select + + SelectItemsList + + PivotMultiInItems + ) + + ) + + +
    + +
    PivotXml ::= 'PIVOT' 'XML' '(' PivotFunctionItems 'FOR' PivotForColumns 'IN' '(' ( 'ANY' | Select | SelectItemsList | PivotMultiInItems ) ')' ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnPivot +====================================================================================================================== + + +.. raw:: html + + + + + + UNPIVOT + + INCLUDE + + EXCLUDE + + NULLS + + ( + + PivotForColumns + FOR + + PivotForColumns + IN + + ( + + SelectItemsList + ) + + ) + + Alias + +
    + +
    UnPivot  ::= 'UNPIVOT' ( ( 'INCLUDE' | 'EXCLUDE' ) 'NULLS' )? '(' PivotForColumns 'FOR' PivotForColumns 'IN' '(' SelectItemsList ')' ')' Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IntoClause +====================================================================================================================== + + +.. raw:: html + + + + + + INTO + + Table + , + + +
    + + +
             ::= 'INTO' Table ( ',' Table )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +ParenthesedFromItem +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + FromItem + + JoinsList + ) + + +
    + + +
             ::= '(' FromItem JoinsList? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +FromItem +====================================================================================================================== + + +.. raw:: html + + + + + + Values + + TableFunction + + Table + + ParenthesedFromItem + + ParenthesedSelect + + Pivot + + UnPivot + + LateralSubSelect + + SubImport + + Select + + Alias + + TimeTravelAfterAlias + + SampleClause + + UnPivot + + PivotXml + + Pivot + + MySQLIndexHint + + SQLServerHints + +
    + + +
    + + +====================================================================================================================== +JoinsList +====================================================================================================================== + + +.. raw:: html + + + + + + JoinerExpression + +
    + + +
             ::= JoinerExpression+
    +
    + + +====================================================================================================================== +JoinHint +====================================================================================================================== + + +.. raw:: html + + + + + + LOOP + + HASH + + MERGE + + REMOTE + + +
    + +
    JoinHint ::= 'LOOP'
    +
               | 'HASH'
    +
               | 'MERGE'
    +
               | 'REMOTE'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JoinerExpression +====================================================================================================================== + + +.. raw:: html + + + + + + GLOBAL + + ANY + + ALL + + NATURAL + + LEFT + + SEMI + + OUTER + + ANY + + ALL + + RIGHT + + FULL + + OUTER + + ANY + + ALL + + INNER + + CROSS + + OUTER + + JoinHint + JOIN + + FETCH + + , + + OUTER + + STRAIGHT_JOIN + + APPLY + + FromItem + WITHIN + + ( + + JoinWindow + ) + + ON + + Expression + USING + + ( + + Column + , + + ) + + +
    + + +
             ::= 'GLOBAL'? ( 'ANY' | 'ALL' )? 'NATURAL'? ( 'LEFT' ( 'SEMI' | 'OUTER' | + 'ANY' | 'ALL' )? | ( 'RIGHT' | 'FULL' ) ( 'OUTER' | 'ANY' | 'ALL' )? | 'INNER' | 'CROSS' + | 'OUTER' )? ( JoinHint? 'JOIN' 'FETCH'? | ',' 'OUTER'? | 'STRAIGHT_JOIN' | 'APPLY' ) FromItem ( ( 'WITHIN' '(' JoinWindow ')' )? ( 'ON' Expression )+ | 'USING' '(' Column ( ',' Column )* ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JoinWindow +====================================================================================================================== + + +.. raw:: html + + + + + + S_LONG + + S_IDENTIFIER + + K_DATE_LITERAL + , + + S_LONG + + S_IDENTIFIER + + K_DATE_LITERAL + +
    + + +
             ::= S_LONG ( S_IDENTIFIER | K_DATE_LITERAL ) ( ',' S_LONG ( S_IDENTIFIER | K_DATE_LITERAL ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +KSQLWindowClause +====================================================================================================================== + + +.. raw:: html + + + + + + WINDOW + + HOPPING + + ( + + SIZE + + S_LONG + + S_IDENTIFIER + , + + ADVANCE + + BY + + SESSION + + ( + + TUMBLING + + ( + + SIZE + + S_LONG + + S_IDENTIFIER + ) + + +
    + + +
             ::= 'WINDOW' ( 'HOPPING' '(' 'SIZE' S_LONG S_IDENTIFIER ',' 'ADVANCE' 'BY' | 'SESSION' '(' | 'TUMBLING' '(' 'SIZE' ) S_LONG S_IDENTIFIER ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +WhereClause +====================================================================================================================== + + +.. raw:: html + + + + + + WHERE + + Expression + +
    + + +
             ::= 'WHERE' Expression
    +
    + + +====================================================================================================================== +PreWhereClause +====================================================================================================================== + + +.. raw:: html + + + + + + PREWHERE + + Expression + +
    + + +
             ::= 'PREWHERE' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +OracleHierarchicalQueryClause +====================================================================================================================== + + +.. raw:: html + + + + + + START + + WITH + + XorExpression + CONNECT + + BY + + NOCYCLE + + CONNECT + + BY + + NOCYCLE + + XorExpression + START + + WITH + + XorExpression + +
    + + +
             ::= ( 'START' 'WITH' XorExpression 'CONNECT' 'BY' 'NOCYCLE'? | 'CONNECT' 'BY' 'NOCYCLE'? ( XorExpression 'START' 'WITH' )? ) XorExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +PreferringClause +====================================================================================================================== + + +.. raw:: html + + + + + + PREFERRING + + PreferenceTerm + +
    + + +
             ::= 'PREFERRING' PreferenceTerm
    +
    + Referenced by: +
    + + +====================================================================================================================== +PreferenceTerm +====================================================================================================================== + + +.. raw:: html + + + + + + Plus + +
    + + +
             ::= Plus
    +
    + Referenced by: +
    + + +====================================================================================================================== +Plus +====================================================================================================================== + + +.. raw:: html + + + + + + PriorTo + PLUS + + +
    + +
    Plus     ::= PriorTo ( 'PLUS' PriorTo )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +PriorTo +====================================================================================================================== + + +.. raw:: html + + + + + + PreferenceTermTerminal + ( + + PreferenceTerm + ) + + TO + + PRIOR + + +
    + +
    PriorTo  ::= ( PreferenceTermTerminal | '(' PreferenceTerm ')' ) ( 'PRIOR' 'TO' ( PreferenceTermTerminal | '(' PreferenceTerm ')' ) )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +PreferenceTermTerminal +====================================================================================================================== + + +.. raw:: html + + + + + + HighExpression + + LowExpression + + Inverse + + Condition + +
    + + +
             ::= HighExpression
    +
               | LowExpression
    +
               | Inverse
    +
               | Condition
    +
    + Referenced by: +
    + + +====================================================================================================================== +HighExpression +====================================================================================================================== + + +.. raw:: html + + + + + + HIGH + + Expression + +
    + + +
             ::= 'HIGH' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +LowExpression +====================================================================================================================== + + +.. raw:: html + + + + + + LOW + + Expression + +
    + + +
             ::= 'LOW' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +Inverse +====================================================================================================================== + + +.. raw:: html + + + + + + INVERSE + + ( + + PreferenceTerm + ) + + +
    + +
    Inverse  ::= 'INVERSE' '(' PreferenceTerm ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +GroupByColumnReferences +====================================================================================================================== + + +.. raw:: html + + + + + + GROUP + + BY + + GROUPING + + SETS + + ( + + GroupingSet + , + + ) + + ExpressionList + GROUPING + + SETS + + ( + + GroupingSet + , + + ) + + WITH + + ROLLUP + + +
    + + +
             ::= 'GROUP' 'BY' ( 'GROUPING' 'SETS' '(' GroupingSet ( ',' GroupingSet )* ')' | ExpressionList ( 'GROUPING' 'SETS' '(' GroupingSet ( ',' GroupingSet )* ')' )? ( 'WITH' 'ROLLUP' )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +GroupingSet +====================================================================================================================== + + +.. raw:: html + + + + + + ParenthesedExpressionList + + SimpleExpression + +
    + + +
             ::= ParenthesedExpressionList
    +
               | SimpleExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +Having +====================================================================================================================== + + +.. raw:: html + + + + + + HAVING + + Expression + +
    + +
    Having   ::= 'HAVING' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +Qualify +====================================================================================================================== + + +.. raw:: html + + + + + + QUALIFY + + Expression + +
    + +
    Qualify  ::= 'QUALIFY' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +OrderByElements +====================================================================================================================== + + +.. raw:: html + + + + + + ORDER + + SIBLINGS + + BY + + OrderByElement + , + + +
    + + +
             ::= 'ORDER' 'SIBLINGS'? 'BY' OrderByElement ( ',' OrderByElement )*
    +
    + + +====================================================================================================================== +OrderByElement +====================================================================================================================== + + +.. raw:: html + + + + + + Expression + COLLATE + + S_CHAR_LITERAL + + S_QUOTED_IDENTIFIER + ASC + + DESC + + NULLS + + FIRST + + LAST + + WITH + + ROLLUP + + +
    + + +
             ::= Expression ( 'COLLATE' ( S_CHAR_LITERAL | S_QUOTED_IDENTIFIER ) )? ( 'ASC' | 'DESC' )? ( 'NULLS' ( 'FIRST' | 'LAST' )? )? ( 'WITH' 'ROLLUP' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JdbcParameter +====================================================================================================================== + + +.. raw:: html + + + + + + ? + + S_PARAMETER + + S_LONG + +
    + + +
             ::= ( '?' | S_PARAMETER ) S_LONG?
    +
    + + +====================================================================================================================== +LimitWithOffset +====================================================================================================================== + + +.. raw:: html + + + + + + LIMIT + + ParenthesedSelect + + Expression + , + + Expression + +
    + + +
             ::= 'LIMIT' ( ParenthesedSelect | Expression ) ( ',' Expression )?
    +
    + + +====================================================================================================================== +PlainLimit +====================================================================================================================== + + +.. raw:: html + + + + + + LIMIT + + ParenthesedSelect + + Expression + +
    + + +
             ::= 'LIMIT' ( ParenthesedSelect | Expression )
    +
    + Referenced by: +
    + + +====================================================================================================================== +LimitBy +====================================================================================================================== + + +.. raw:: html + + + + + + LimitWithOffset + BY + + ExpressionList + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +Offset +====================================================================================================================== + + +.. raw:: html + + + + + + OFFSET + + Expression + ROWS + + ROW + + +
    + +
    Offset   ::= 'OFFSET' Expression ( 'ROWS' | 'ROW' )?
    +
    + + +====================================================================================================================== +Fetch +====================================================================================================================== + + +.. raw:: html + + + + + + FETCH + + FIRST + + NEXT + + Expression + PERCENT + + ROWS + + ROW + + ONLY + + WITH TIES + + +
    + +
    Fetch    ::= 'FETCH' ( 'FIRST' | 'NEXT' ) ( Expression 'PERCENT'? )? ( 'ROWS' | 'ROW' ) ( 'ONLY' | 'WITH TIES' )
    +
    + + +====================================================================================================================== +WithIsolation +====================================================================================================================== + + +.. raw:: html + + + + + + WITH + + K_ISOLATION + +
    + + +
             ::= 'WITH' K_ISOLATION
    +
    + + +====================================================================================================================== +OptimizeFor +====================================================================================================================== + + +.. raw:: html + + + + + + OPTIMIZE + + FOR + + S_LONG + ROWS + + +
    + + +
             ::= 'OPTIMIZE' 'FOR' S_LONG 'ROWS'
    +
    + Referenced by: +
    + + +====================================================================================================================== +Top +====================================================================================================================== + + +.. raw:: html + + + + + + TOP + + S_LONG + + JdbcParameter + : + + S_IDENTIFIER + ( + + AdditiveExpression + ) + + PERCENT + + WITH TIES + + +
    + +
    Top      ::= 'TOP' ( S_LONG | JdbcParameter | ':' S_IDENTIFIER? | '(' AdditiveExpression ')' ) 'PERCENT'? 'WITH TIES'?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Skip +====================================================================================================================== + + +.. raw:: html + + + + + + SKIP + + S_LONG + + S_IDENTIFIER + + JdbcParameter + +
    + +
    Skip     ::= 'SKIP' ( S_LONG | S_IDENTIFIER | JdbcParameter )
    +
    + Referenced by: +
    + + +====================================================================================================================== +First +====================================================================================================================== + + +.. raw:: html + + + + + + FIRST + + LIMIT + + S_LONG + + S_IDENTIFIER + + JdbcParameter + +
    + +
    First    ::= ( 'FIRST' | 'LIMIT' ) ( S_LONG | S_IDENTIFIER | JdbcParameter )
    +
    + Referenced by: +
    + + +====================================================================================================================== +Expression +====================================================================================================================== + + +.. raw:: html + + + + + + XorExpression + +
    + + +
             ::= XorExpression
    +
    + + +====================================================================================================================== +XorExpression +====================================================================================================================== + + +.. raw:: html + + + + + + OrExpression + XOR + + +
    + + +
             ::= OrExpression ( 'XOR' OrExpression )*
    +
    + + +====================================================================================================================== +OrExpression +====================================================================================================================== + + +.. raw:: html + + + + + + AndExpression + OR + + +
    + + +
             ::= AndExpression ( 'OR' AndExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +AndExpression +====================================================================================================================== + + +.. raw:: html + + + + + + Condition + NOT + + ! + + ( + + XorExpression + ) + + AND + + && + + +
    + + +
             ::= ( Condition | ( 'NOT' | '!' )? '(' XorExpression ')' ) ( ( 'AND' | '&&' ) ( Condition | ( 'NOT' | '!' )? '(' XorExpression ')' ) )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Condition +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + ! + + ExistsExpression + PRIOR + + SimpleExpression + ( + + + + + ) + + RegularConditionRHS + + OverlapsCondition + + InExpression + + ExcludesExpression + + IncludesExpression + + Between + + MemberOfExpression + + IsNullExpression + + IsBooleanExpression + + IsUnknownExpression + + LikeExpression + + IsDistinctExpression + + SimilarToExpression + +
    + + + +
    + + +====================================================================================================================== +RegularConditionRHS +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + + + + ) + + > + + < + + = + + OP_GREATERTHANEQUALS + + OP_MINORTHANEQUALS + + OP_NOTEQUALSSTANDARD + + OP_NOTEQUALSBANG + + OP_NOTEQUALSHAT + *= + + =* + + && + + &> + + <& + + @@ + + ~ + + ~* + + !~ + + !~* + + @> + + <@ + + ? + + ?| + + ?& + + OP_CONCAT + - + + -# + + <-> + + <#> + + <=> + + PRIOR + + ComparisonItem + ( + + + + + ) + + +
    + + +
             ::= ( '(' '+' ')' )? ( '>' | '<' | '=' | OP_GREATERTHANEQUALS | OP_MINORTHANEQUALS | OP_NOTEQUALSSTANDARD | OP_NOTEQUALSBANG | OP_NOTEQUALSHAT | '*=' | '=*' | '&&' | '&>' | '<&' | '@@' | '~' | '~*' | '!~' | '!~*' | '@>' | '<@' + | '?' | '?|' | '?&' | OP_CONCAT | '-' | '-#' | '<->' | '<#>' | '<=>' ) 'PRIOR'? ComparisonItem ( '(' '+' ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +OverlapsCondition +====================================================================================================================== + + +.. raw:: html + + + + + + OVERLAPS + + ParenthesedExpressionList + +
    + + +
             ::= 'OVERLAPS' ParenthesedExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +SQLCondition +====================================================================================================================== + + +.. raw:: html + + + + + + ExistsExpression + + SimpleExpression + + OverlapsCondition + + InExpression + + ExcludesExpression + + IncludesExpression + + Between + + MemberOfExpression + + IsNullExpression + + IsBooleanExpression + + IsUnknownExpression + + LikeExpression + + IsDistinctExpression + + SimilarToExpression + +
    + + +
             ::= ExistsExpression
    +
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +InExpression +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + + + + ) + + GLOBAL + + NOT + + IN + + S_CHAR_LITERAL + + PrimaryExpression + +
    + + +
             ::= ( '(' '+' ')' )? 'GLOBAL'? 'NOT'? 'IN' ( S_CHAR_LITERAL | PrimaryExpression )
    +
    + Referenced by: +
    + + +====================================================================================================================== +IncludesExpression +====================================================================================================================== + + +.. raw:: html + + + + + + INCLUDES + + ParenthesedExpressionList + +
    + + +
             ::= 'INCLUDES' ParenthesedExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExcludesExpression +====================================================================================================================== + + +.. raw:: html + + + + + + EXCLUDES + + ParenthesedExpressionList + +
    + + +
             ::= 'EXCLUDES' ParenthesedExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +Between +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + BETWEEN + + SYMMETRIC + + ASYMMETRIC + + ParenthesedSelect + + SimpleExpression + + RegularConditionRHS + AND + + ParenthesedSelect + + SimpleExpression + + RegularConditionRHS + +
    + +
    Between  ::= 'NOT'? 'BETWEEN' ( 'SYMMETRIC' | 'ASYMMETRIC' )? ( ParenthesedSelect | SimpleExpression RegularConditionRHS? ) 'AND' ( ParenthesedSelect | SimpleExpression RegularConditionRHS? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +LikeExpression +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + LIKE + + ILIKE + + RLIKE + + REGEXP_LIKE + + REGEXP + + K_SIMILAR_TO + MATCH_ANY + + MATCH_ALL + + MATCH_PHRASE + + MATCH_PHRASE_PREFIX + + MATCH_REGEXP + + BINARY + + SimpleExpression + ESCAPE + + S_CHAR_LITERAL + + Expression + +
    + + +
             ::= 'NOT'? ( 'LIKE' | 'ILIKE' | 'RLIKE' | 'REGEXP_LIKE' | 'REGEXP' | K_SIMILAR_TO | 'MATCH_ANY' | 'MATCH_ALL' | 'MATCH_PHRASE' | 'MATCH_PHRASE_PREFIX' | 'MATCH_REGEXP' + ) 'BINARY'? SimpleExpression ( 'ESCAPE' ( S_CHAR_LITERAL | Expression ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +SimilarToExpression +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + SIMILAR + + TO + + SimpleExpression + ESCAPE + + S_CHAR_LITERAL + +
    + + +
             ::= 'NOT'? 'SIMILAR' 'TO' SimpleExpression ( 'ESCAPE' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IsDistinctExpression +====================================================================================================================== + + +.. raw:: html + + + + + + IS + + NOT + + DISTINCT + + FROM + + SimpleExpression + +
    + + +
             ::= 'IS' 'NOT'? 'DISTINCT' 'FROM' SimpleExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +IsNullExpression +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + ISNULL + + NOTNULL + + IS + + NOT + + NULL + + +
    + + +
             ::= 'NOT'? 'ISNULL'
    +
               | 'NOTNULL'
    +
               | 'IS' 'NOT'? 'NULL'
    +
    + Referenced by: +
    + + +====================================================================================================================== +IsBooleanExpression +====================================================================================================================== + + +.. raw:: html + + + + + + IS + + NOT + + TRUE + + FALSE + + +
    + + +
             ::= 'IS' 'NOT'? ( 'TRUE' | 'FALSE' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +IsUnknownExpression +====================================================================================================================== + + +.. raw:: html + + + + + + IS + + NOT + + UNKNOWN + + +
    + + +
             ::= 'IS' 'NOT'? 'UNKNOWN'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExistsExpression +====================================================================================================================== + + +.. raw:: html + + + + + + EXISTS + + SimpleExpression + +
    + + +
             ::= 'EXISTS' SimpleExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +MemberOfExpression +====================================================================================================================== + + +.. raw:: html + + + + + + MEMBER + + OF + + Expression + +
    + + +
             ::= 'MEMBER' 'OF' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExpressionList +====================================================================================================================== + + +.. raw:: html + + + + + + ComplexExpressionList + + SimpleExpressionList + + ParenthesedExpressionList + +
    + + +
             ::= ComplexExpressionList
    +
               | SimpleExpressionList
    +
               | ParenthesedExpressionList
    +
    + + +====================================================================================================================== +ParenthesedExpressionList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + ComplexExpressionList + + SimpleExpressionList + ) + + +
    + + +
             ::= '(' ( ComplexExpressionList | SimpleExpressionList )? ')'
    +
    + + +====================================================================================================================== +SimpleExpressionList +====================================================================================================================== + + +.. raw:: html + + + + + + SimpleExpression + , + + LambdaExpression + + SimpleExpression + +
    + + +
             ::= SimpleExpression ( ',' ( LambdaExpression | SimpleExpression ) )*
    +
    + + +====================================================================================================================== +ColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + Column + , + + +
    + + +
             ::= Column ( ',' Column )*
    +
    + + +====================================================================================================================== +ParenthesedColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + ColumnList + ) + + +
    + + +
             ::= '(' ColumnList ')'
    +
    + + +====================================================================================================================== +ComplexExpressionList +====================================================================================================================== + + +.. raw:: html + + + + + + OracleNamedFunctionParameter + + PostgresNamedFunctionParameter + + Expression + , + + OracleNamedFunctionParameter + + PostgresNamedFunctionParameter + + LambdaExpression + + Expression + +
    + + + +
    + + +====================================================================================================================== +NamedExpressionListExprFirst +====================================================================================================================== + + +.. raw:: html + + + + + + SimpleExpression + FROM + + IN + + PLACING + + SimpleExpression + FOR + + FROM + + SimpleExpression + FOR + + SimpleExpression + +
    + + +
             ::= SimpleExpression ( 'FROM' | 'IN' | 'PLACING' ) SimpleExpression ( ( 'FOR' | 'FROM' ) SimpleExpression ( 'FOR' SimpleExpression )? )?
    +
    + + +====================================================================================================================== +ComparisonItem +====================================================================================================================== + + +.. raw:: html + + + + + + AnyComparisonExpression + + SimpleExpression + + ParenthesedExpressionList + + RowConstructor + + PrimaryExpression + +
    + + +
             ::= AnyComparisonExpression
    +
               | SimpleExpression
    +
               | ParenthesedExpressionList
    +
               | RowConstructor
    +
               | PrimaryExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +AnyComparisonExpression +====================================================================================================================== + + +.. raw:: html + + + + + + ANY + + SOME + + ALL + + ParenthesedSelect + +
    + + +
             ::= ( 'ANY' | 'SOME' | 'ALL' ) ParenthesedSelect
    +
    + Referenced by: +
    + + +====================================================================================================================== +SimpleExpression +====================================================================================================================== + + +.. raw:: html + + + + + + UserVariable + = + + := + + ConcatExpression + +
    + + +
             ::= ( UserVariable ( '=' | ':=' ) )? ConcatExpression
    +
    + + +====================================================================================================================== +ConcatExpression +====================================================================================================================== + + +.. raw:: html + + + + + + BitwiseAndOr + + OP_CONCAT + +
    + + +
             ::= BitwiseAndOr ( OP_CONCAT BitwiseAndOr )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +BitwiseAndOr +====================================================================================================================== + + +.. raw:: html + + + + + + AdditiveExpression + | + + & + + << + + >> + + +
    + + +
             ::= AdditiveExpression ( ( '|' | '&' | '<<' | '>>' ) AdditiveExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +AdditiveExpression +====================================================================================================================== + + +.. raw:: html + + + + + + MultiplicativeExpression + + + + - + + +
    + + +
             ::= MultiplicativeExpression ( ( '+' | '-' ) MultiplicativeExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +MultiplicativeExpression +====================================================================================================================== + + +.. raw:: html + + + + + + BitwiseXor + * + + / + + DIV + + % + + +
    + + +
             ::= BitwiseXor ( ( '*' | '/' | 'DIV' | '%' ) BitwiseXor )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +BitwiseXor +====================================================================================================================== + + +.. raw:: html + + + + + + PrimaryExpression + ^ + + +
    + + +
             ::= PrimaryExpression ( '^' PrimaryExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +ArrayExpression +====================================================================================================================== + + +.. raw:: html + + + + + + [ + + SimpleExpression + : + + SimpleExpression + ] + + +
    + + +
             ::= ( '[' SimpleExpression? ( ':' SimpleExpression? )? ']' )+
    +
    + Referenced by: +
    + + +====================================================================================================================== +PrimaryExpression +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + ! + + + + + - + + ~ + + NULL + + CaseWhenExpression + + CharacterPrimary + + ImplicitCast + + JdbcParameter + + JdbcNamedParameter + + UserVariable + + NumericBind + + ExtractExpression + + XMLSerializeExpr + + JsonFunction + + JsonAggregateFunction + + FullTextSearch + + CastExpression + + Function + + AnalyticExpression + + DateUnitExpression + + IntervalExpression + + S_DOUBLE + + S_LONG + + S_HEX + + AllColumns + + AllTableColumns + + K_TIME_KEY_EXPR + CURRENT + + DateTimeLiteralExpression + + StructType + ARRAY + + < + + ColDataType + > + + ArrayConstructor + + NextValExpression + + ConnectByRootOperator + + ConnectByPriorOperator + ALL + + Column + ( + + + + + ) + + TRUE + + FALSE + + S_CHAR_LITERAL + {d + + {t + + {ts + + S_CHAR_LITERAL + } + + Select + + ParenthesedSelect + + ParenthesedExpressionList + -> + + Expression + . + + RelObjectName + COLLATE + + S_CHAR_LITERAL + + S_QUOTED_IDENTIFIER + + S_IDENTIFIER + + IntervalExpressionWithoutInterval + + ArrayExpression + :: + + ColDataType + -> + + : + + ->> + + #> + + #>> + + Expression + + SimpleExpression + + JsonExpression + AT + + K_DATETIMELITERAL + ZONE + + PrimaryExpression + +
    + + +
             ::= ( 'NOT' | '!' )? ( '+' | '-' | '~' )? ( 'NULL' | CaseWhenExpression | CharacterPrimary | ImplicitCast | JdbcParameter | JdbcNamedParameter | UserVariable | NumericBind | ExtractExpression | XMLSerializeExpr | JsonFunction | JsonAggregateFunction | FullTextSearch | CastExpression | Function AnalyticExpression? | DateUnitExpression | IntervalExpression | S_DOUBLE | S_LONG | S_HEX | AllColumns | AllTableColumns | K_TIME_KEY_EXPR | 'CURRENT' | DateTimeLiteralExpression | StructType | ( 'ARRAY' ( '<' ColDataType '>' )? )? ArrayConstructor | NextValExpression | ConnectByRootOperator | ConnectByPriorOperator | 'ALL' | Column ( '(' '+' ')' )? | 'TRUE' | 'FALSE' | S_CHAR_LITERAL | ( '{d' | '{t' | '{ts' ) S_CHAR_LITERAL '}' | Select | ParenthesedSelect | ParenthesedExpressionList ( '->' Expression )? ( '.' RelObjectName )* ) ( 'COLLATE' ( S_CHAR_LITERAL | S_QUOTED_IDENTIFIER | S_IDENTIFIER ) )? IntervalExpressionWithoutInterval? ArrayExpression? ( '::' ColDataType )* ( ( ( '->' | ':' | '->>' | '#>' | '#>>' ) ( Expression | SimpleExpression ) )+ JsonExpression )? ( 'AT' K_DATETIMELITERAL 'ZONE' PrimaryExpression )*
    +
    + + +====================================================================================================================== +ConnectByRootOperator +====================================================================================================================== + + +.. raw:: html + + + + + + CONNECT_BY_ROOT + + Expression + +
    + + +
             ::= 'CONNECT_BY_ROOT' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +ConnectByPriorOperator +====================================================================================================================== + + +.. raw:: html + + + + + + PRIOR + + Expression + +
    + + +
             ::= 'PRIOR' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +NextValExpression +====================================================================================================================== + + +.. raw:: html + + + + + + K_NEXTVAL + + RelObjectNames + +
    + + +
             ::= K_NEXTVAL RelObjectNames
    +
    + Referenced by: +
    + + +====================================================================================================================== +JdbcNamedParameter +====================================================================================================================== + + +.. raw:: html + + + + + + : + + & + + IdentifierChain + +
    + + +
             ::= ( ':' | '&' ) IdentifierChain
    +
    + + +====================================================================================================================== +OracleNamedFunctionParameter +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNameExt + OUTER + + => + + Expression + +
    + + +
             ::= ( RelObjectNameExt | 'OUTER' ) '=>' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +PostgresNamedFunctionParameter +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNameExt + OUTER + + := + + Expression + +
    + + +
             ::= ( RelObjectNameExt | 'OUTER' ) ':=' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +UserVariable +====================================================================================================================== + + +.. raw:: html + + + + + + S_AT_IDENTIFIER + + IdentifierChain2 + +
    + + +
             ::= S_AT_IDENTIFIER IdentifierChain2
    +
    + + +====================================================================================================================== +NumericBind +====================================================================================================================== + + +.. raw:: html + + + + + + : + + S_LONG + +
    + + +
             ::= ':' S_LONG
    +
    + Referenced by: +
    + + +====================================================================================================================== +DateTimeLiteralExpression +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATETIMELITERAL + + S_CHAR_LITERAL + + S_QUOTED_IDENTIFIER + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +DateUnitExpression +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATE_LITERAL + +
    + + +
             ::= K_DATE_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +RangeExpression +====================================================================================================================== + + +.. raw:: html + + + + + + : + + Expression + +
    + + +
             ::= ':' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +ArrayConstructor +====================================================================================================================== + + +.. raw:: html + + + + + + [ + + Expression + + RangeExpression + + ArrayConstructor + , + + ] + + +
    + + +
             ::= '[' ( ( Expression RangeExpression? | ArrayConstructor ) ( ',' ( Expression RangeExpression? | ArrayConstructor ) )* )? ']'
    +
    + + +====================================================================================================================== +StructParameters +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + + ColDataType + , + + +
    + + +
             ::= RelObjectName? ColDataType ( ',' RelObjectName? ColDataType )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +StructType +====================================================================================================================== + + +.. raw:: html + + + + + + STRUCT + + < + + StructParameters + > + + ( + + SelectItemsList + ) + + { + + RelObjectNameExt + + S_CHAR_LITERAL + : + + Expression + , + + } + + :: + + STRUCT + + ( + + StructParameters + ) + + +
    + + +
             ::= 'STRUCT' ( '<' StructParameters '>' )? '(' SelectItemsList ')'
    +
               | '{' ( RelObjectNameExt | S_CHAR_LITERAL ) ':' Expression ( ',' ( RelObjectNameExt | S_CHAR_LITERAL ) ':' Expression )* '}' ( '::' 'STRUCT' '(' StructParameters ')' )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonExpression +====================================================================================================================== + + +.. raw:: html + + + + + + :: + + ColDataType + -> + + : + + ->> + + #> + + #>> + + Expression + + SimpleExpression + +
    + + +
             ::= ( ( '::' ColDataType )+ ( ( '->' | ':' | '->>' | '#>' | '#>>' ) ( Expression | SimpleExpression ) )* )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonKeyValuePair +====================================================================================================================== + + +.. raw:: html + + + + + + KEY + + S_CHAR_LITERAL + + Column + + AllTableColumns + + AllColumns + + Expression + VALUE + + : + + , + + Expression + FORMAT + + JSON + + ENCODING + + JsonEncoding + +
    + + +
             ::= ( 'KEY'? ( S_CHAR_LITERAL | Column ) | AllTableColumns | AllColumns | Expression ) ( ( 'VALUE' | ':' | ',' ) Expression )? ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonObjectBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonKeyValuePair + , + + NULL + + ABSENT + + ON + + NULL + + STRICT + + WITH + + WITHOUT + + UNIQUE + + KEYS + + RETURNING + + ColDataType + FORMAT + + JSON + + ENCODING + + JsonEncoding + ) + + +
    + + +
             ::= '(' ( JsonKeyValuePair ( ',' JsonKeyValuePair )* )? ( ( 'NULL' | 'ABSENT' ) 'ON' 'NULL' )? 'STRICT'? ( ( 'WITH' | 'WITHOUT' ) 'UNIQUE' + 'KEYS' )? ( 'RETURNING' ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonArrayBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + NULL + + ON + + NULL + + Expression + FORMAT + + JSON + + ENCODING + + JsonEncoding + , + + ABSENT + + ON + + NULL + + RETURNING + + ColDataType + FORMAT + + JSON + + ENCODING + + JsonEncoding + ) + + +
    + + +
             ::= '(' ( 'NULL' 'ON' 'NULL' | Expression ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? ( ',' Expression ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )* )* ( 'ABSENT' 'ON' 'NULL' )? ( 'RETURNING' ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonKeyword +====================================================================================================================== + + +.. raw:: html + + + + + + S_IDENTIFIER + +
    + + +
             ::= S_IDENTIFIER
    +
    + + +====================================================================================================================== +JsonEncoding +====================================================================================================================== + + +.. raw:: html + + + + + + S_IDENTIFIER + +
    + + +
             ::= S_IDENTIFIER
    +
    + + +====================================================================================================================== +JsonValueOrQueryInputExpression +====================================================================================================================== + + +.. raw:: html + + + + + + Expression + FORMAT + + JSON + + ENCODING + + JsonEncoding + +
    + + +
             ::= Expression ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )?
    +
    + + +====================================================================================================================== +JsonValueOnResponseBehavior +====================================================================================================================== + + +.. raw:: html + + + + + + ERROR + + NULL + + DEFAULT + + Expression + +
    + + +
             ::= 'ERROR'
    +
               | 'NULL'
    +
               | 'DEFAULT' Expression
    +
    + + +====================================================================================================================== +JsonQueryOnResponseBehavior +====================================================================================================================== + + +.. raw:: html + + + + + + ERROR + + NULL + + S_IDENTIFIER + ARRAY + + JsonKeyword + +
    + + +
             ::= 'ERROR'
    +
               | 'NULL'
    +
               | S_IDENTIFIER ( 'ARRAY' | JsonKeyword )
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonExistsOnResponseBehavior +====================================================================================================================== + + +.. raw:: html + + + + + + TRUE + + FALSE + + UNKNOWN + + ERROR + + +
    + + +
             ::= 'TRUE'
    +
               | 'FALSE'
    +
               | 'UNKNOWN'
    +
               | 'ERROR'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonExistsBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonValueOrQueryInputExpression + , + + Expression + + JsonKeyword + + Expression + , + + JsonExistsOnResponseBehavior + ON + + ERROR + + ) + + +
    + + +
             ::= '(' JsonValueOrQueryInputExpression ',' Expression ( JsonKeyword Expression ( ',' Expression )* )? ( JsonExistsOnResponseBehavior 'ON' 'ERROR' )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonValueBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonValueOrQueryInputExpression + , + + Expression + + JsonKeyword + + Expression + , + + RETURNING + + ColDataType + + JsonValueOnResponseBehavior + ON + + JsonKeyword + + JsonValueOnResponseBehavior + ON + + ERROR + + ) + + +
    + + +
             ::= '(' JsonValueOrQueryInputExpression ',' Expression ( JsonKeyword Expression ( ',' Expression )* )? ( 'RETURNING' ColDataType )? ( JsonValueOnResponseBehavior 'ON' JsonKeyword )? ( JsonValueOnResponseBehavior 'ON' 'ERROR' )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonQueryBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonValueOrQueryInputExpression + , + + Expression + + JsonKeyword + + Expression + , + + RETURNING + + ColDataType + FORMAT + + JSON + + ENCODING + + JsonEncoding + WITHOUT + + WITH + + S_IDENTIFIER + ARRAY + + JsonKeyword + KEEP + + JsonKeyword + + JsonKeyword + ON + + JsonKeyword + STRING + + JsonQueryOnResponseBehavior + ON + + JsonKeyword + + JsonQueryOnResponseBehavior + ON + + ERROR + + Expression + , + + ) + + +
    + + +
             ::= '(' JsonValueOrQueryInputExpression ',' Expression ( JsonKeyword Expression ( ',' Expression )* )? ( 'RETURNING' ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )? ( ( 'WITHOUT' | 'WITH' S_IDENTIFIER? ) 'ARRAY'? JsonKeyword )? ( ( 'KEEP' | JsonKeyword ) JsonKeyword ( 'ON' JsonKeyword 'STRING' )? )? ( JsonQueryOnResponseBehavior 'ON' JsonKeyword )? ( JsonQueryOnResponseBehavior 'ON' 'ERROR' )? ( ',' Expression ( 'RETURNING' ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )? ( ( 'WITHOUT' | 'WITH' S_IDENTIFIER? ) 'ARRAY'? JsonKeyword )? ( ( 'KEEP' | JsonKeyword ) JsonKeyword ( 'ON' JsonKeyword 'STRING' )? )? ( JsonQueryOnResponseBehavior 'ON' JsonKeyword )? ( JsonQueryOnResponseBehavior 'ON' 'ERROR' )? )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonFunction +====================================================================================================================== + + +.. raw:: html + + + + + + JSON_OBJECT + + JsonObjectBody + JSON_ARRAY + + JsonArrayBody + + JsonKeyword + + JsonValueBody + + JsonQueryBody + + JsonExistsBody + +
    + + +
             ::= 'JSON_OBJECT' JsonObjectBody
    +
               | 'JSON_ARRAY' JsonArrayBody
    +
               | JsonKeyword ( JsonValueBody | JsonQueryBody | JsonExistsBody )
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonAggregateFunction +====================================================================================================================== + + +.. raw:: html + + + + + + JSON_OBJECTAGG + + ( + + KEY + + DT_ZONE + + S_DOUBLE + + S_LONG + + S_HEX + + S_CHAR_LITERAL + + Column + : + + , + + VALUE + + Expression + FORMAT + + JSON + + NULL + + ABSENT + + ON + + NULL + + WITH + + WITHOUT + + UNIQUE + + KEYS + + JSON_ARRAYAGG + + ( + + Expression + FORMAT + + JSON + + OrderByElements + NULL + + ABSENT + + ON + + NULL + + ) + + FILTER + + ( + + WHERE + + Expression + ) + + OVER + + ( + + PARTITION + + BY + + ComplexExpressionList + ( + + ComplexExpressionList + ) + + OrderByElements + + WindowElement + ) + + +
    + + +
             ::= ( 'JSON_OBJECTAGG' '(' 'KEY'? ( DT_ZONE | S_DOUBLE | S_LONG | S_HEX | S_CHAR_LITERAL | Column ) ( ':' | ',' | 'VALUE' ) Expression ( 'FORMAT' 'JSON' )? ( ( 'NULL' | 'ABSENT' ) 'ON' 'NULL' )? ( ( 'WITH' | 'WITHOUT' + ) 'UNIQUE' 'KEYS' )? | 'JSON_ARRAYAGG' '(' Expression ( 'FORMAT' 'JSON' )? OrderByElements? ( ( 'NULL' | 'ABSENT' ) 'ON' 'NULL' )? ) ')' ( 'FILTER' '(' 'WHERE' Expression ')' )? ( 'OVER' '(' ( 'PARTITION' 'BY' ( ComplexExpressionList | '(' ComplexExpressionList ')' ) )? OrderByElements? WindowElement? ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IntervalExpression +====================================================================================================================== + + +.. raw:: html + + + + + + INTERVAL + + - + + S_LONG + + S_DOUBLE + + S_CHAR_LITERAL + + Expression + + S_IDENTIFIER + + K_DATE_LITERAL + +
    + + +
             ::= 'INTERVAL' ( '-'? ( S_LONG | S_DOUBLE ) | S_CHAR_LITERAL | Expression ) ( S_IDENTIFIER | K_DATE_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IntervalExpressionWithoutInterval +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATE_LITERAL + +
    + + +
             ::= K_DATE_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +KeepExpression +====================================================================================================================== + + +.. raw:: html + + + + + + KEEP + + ( + + S_IDENTIFIER + FIRST + + LAST + + OrderByElements + ) + + +
    + + +
             ::= 'KEEP' '(' S_IDENTIFIER ( 'FIRST' | 'LAST' ) OrderByElements ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +windowFun +====================================================================================================================== + + +.. raw:: html + + + + + + OVER + + WITHIN + + GROUP + + RelObjectName + + windowDefinition + OVER + + ( + + PARTITION + + BY + + ComplexExpressionList + ( + + ComplexExpressionList + ) + + ) + + +
    + + +
             ::= ( 'OVER' | 'WITHIN' 'GROUP' ) ( RelObjectName | windowDefinition ( 'OVER' '(' ( 'PARTITION' 'BY' ( ComplexExpressionList | '(' ComplexExpressionList ')' ) )? ')' )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +windowDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + PARTITION + + BY + + ComplexExpressionList + ( + + ComplexExpressionList + ) + + OrderByElements + + WindowElement + ) + + +
    + + +
             ::= '(' ( 'PARTITION' 'BY' ( ComplexExpressionList | '(' ComplexExpressionList ')' ) )? OrderByElements? WindowElement? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AnalyticExpression +====================================================================================================================== + + +.. raw:: html + + + + + + FILTER + + ( + + WHERE + + Expression + ) + + windowFun + + windowFun + +
    + + +
             ::= 'FILTER' '(' 'WHERE' Expression ')' windowFun?
    +
               | windowFun
    +
    + Referenced by: +
    + + +====================================================================================================================== +WindowElement +====================================================================================================================== + + +.. raw:: html + + + + + + ROWS + + RANGE + + BETWEEN + + WindowOffset + AND + + WindowOffset + +
    + + +
             ::= ( 'ROWS' | 'RANGE' ) ( 'BETWEEN' WindowOffset 'AND' )? WindowOffset
    +
    + + +====================================================================================================================== +WindowOffset +====================================================================================================================== + + +.. raw:: html + + + + + + UNBOUNDED + + SimpleExpression + PRECEDING + + FOLLOWING + + CURRENT + + ROW + + +
    + + +
             ::= ( 'UNBOUNDED' | SimpleExpression ) ( 'PRECEDING' | 'FOLLOWING' )
    +
               | 'CURRENT' 'ROW'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExtractExpression +====================================================================================================================== + + +.. raw:: html + + + + + + EXTRACT + + ( + + RelObjectName + + S_CHAR_LITERAL + FROM + + SimpleExpression + ) + + +
    + + +
             ::= 'EXTRACT' '(' ( RelObjectName | S_CHAR_LITERAL ) 'FROM' SimpleExpression ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ImplicitCast +====================================================================================================================== + + +.. raw:: html + + + + + + DataType + + S_CHAR_LITERAL + + S_LONG + + S_DOUBLE + +
    + + +
             ::= DataType ( S_CHAR_LITERAL | S_LONG | S_DOUBLE )
    +
    + Referenced by: +
    + + +====================================================================================================================== +CastExpression +====================================================================================================================== + + +.. raw:: html + + + + + + CAST + + SAFE_CAST + + TRY_CAST + + INTERPRET + + ( + + SimpleExpression + AS + + ROW + + ( + + ColumnDefinition + , + + ) + + ColDataType + FORMAT + + S_CHAR_LITERAL + ) + + +
    + + +
             ::= ( 'CAST' | 'SAFE_CAST' | 'TRY_CAST' | 'INTERPRET' ) '(' SimpleExpression 'AS' ( 'ROW' '(' ColumnDefinition ( ',' ColumnDefinition )* ')' | ColDataType ) ( 'FORMAT' S_CHAR_LITERAL )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +CaseWhenExpression +====================================================================================================================== + + +.. raw:: html + + + + + + CASE + + Expression + + WhenThenSearchCondition + ELSE + + Expression + + SimpleExpression + END + + +
    + + +
             ::= 'CASE' Expression? WhenThenSearchCondition+ ( 'ELSE' ( Expression | SimpleExpression ) )? 'END'
    +
    + Referenced by: +
    + + +====================================================================================================================== +WhenThenSearchCondition +====================================================================================================================== + + +.. raw:: html + + + + + + WHEN + + Expression + THEN + + Expression + + SimpleExpression + +
    + + +
             ::= 'WHEN' Expression 'THEN' ( Expression | SimpleExpression )
    +
    + Referenced by: +
    + + +====================================================================================================================== +RowConstructor +====================================================================================================================== + + +.. raw:: html + + + + + + ROW + + ParenthesedExpressionList + +
    + + +
             ::= 'ROW' ParenthesedExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +VariableExpression +====================================================================================================================== + + +.. raw:: html + + + + + + UserVariable + = + + SimpleExpression + +
    + + +
             ::= UserVariable '=' SimpleExpression
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +Execute +====================================================================================================================== + + +.. raw:: html + + + + + + EXEC + + EXECUTE + + CALL + + RelObjectNames + + ExpressionList + +
    + +
    Execute  ::= ( 'EXEC' | 'EXECUTE' | 'CALL' ) RelObjectNames ExpressionList?
    +
    + Referenced by: +
    + + +====================================================================================================================== +FullTextSearch +====================================================================================================================== + + +.. raw:: html + + + + + + MATCH + + ( + + ColumnList + ) + + AGAINST + + ( + + S_CHAR_LITERAL + + JdbcParameter + + JdbcNamedParameter + IN NATURAL LANGUAGE MODE + + IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION + + IN BOOLEAN MODE + + WITH QUERY EXPANSION + + ) + + +
    + + +
             ::= 'MATCH' '(' ColumnList ')' 'AGAINST' '(' ( S_CHAR_LITERAL | JdbcParameter | JdbcNamedParameter ) ( 'IN NATURAL LANGUAGE MODE' | 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION' + | 'IN BOOLEAN MODE' | 'WITH QUERY EXPANSION' )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +LambdaExpression +====================================================================================================================== + + +.. raw:: html + + + + + + ParenthesedColumnList + + RelObjectName + -> + + Expression + +
    + + +
             ::= ( ParenthesedColumnList | RelObjectName ) '->' Expression
    +
    + + +====================================================================================================================== +Function +====================================================================================================================== + + +.. raw:: html + + + + + + { + + FN + + InternalFunction + } + + SpecialStringFunctionWithNamedParameters + + InternalFunction + +
    + +
    Function ::= '{' 'FN' InternalFunction '}'
    + +
               | InternalFunction
    +
    + + +====================================================================================================================== +SpecialStringFunctionWithNamedParameters +====================================================================================================================== + + +.. raw:: html + + + + + + K_STRING_FUNCTION_NAME + ( + + NamedExpressionListExprFirst + + ExpressionList + ) + + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +InternalFunction +====================================================================================================================== + + +.. raw:: html + + + + + + APPROXIMATE + + RelObjectNames + ( + + DISTINCT + + ALL + + UNIQUE + + TABLE + + ExpressionList + + OrderByElements + ON + + OVERFLOW + + TRUNCATE + + ERROR + + S_CHAR_LITERAL + WITH + + WITHOUT + + COUNT + + Select + HAVING + + MIN + + MAX + + Expression + IGNORE + + RESPECT + + NULLS + + PlainLimit + ) + + ( + + ExpressionList + ) + + . + + Function + + Column + IGNORE + + RESPECT + + NULLS + + KeepExpression + +
    + + +
             ::= 'APPROXIMATE'? RelObjectNames '(' ( ( 'DISTINCT' | 'ALL' | 'UNIQUE' )? ( 'TABLE'? ExpressionList OrderByElements? ( 'ON' 'OVERFLOW' ( 'TRUNCATE' | 'ERROR' ) ( S_CHAR_LITERAL ( ( 'WITH' | 'WITHOUT' ) 'COUNT' )? )? )? | Select ) )? ( 'HAVING' ( 'MIN' | 'MAX' ) Expression )? ( ( 'IGNORE' | 'RESPECT' ) 'NULLS' )? PlainLimit? ')' ( '(' ExpressionList ')' )? ( '.' ( Function | Column ) )? ( ( 'IGNORE' | 'RESPECT' ) 'NULLS' )? KeepExpression?
    +
    + Referenced by: +
    + + +====================================================================================================================== +XMLSerializeExpr +====================================================================================================================== + + +.. raw:: html + + + + + + XMLSERIALIZE + + ( + + XMLAGG + + ( + + XMLTEXT + + ( + + SimpleExpression + ) + + OrderByElements + ) + + AS + + ColDataType + ) + + +
    + + +
             ::= 'XMLSERIALIZE' '(' 'XMLAGG' '(' 'XMLTEXT' '(' SimpleExpression ')' OrderByElements? ')' 'AS' ColDataType ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTablePassingClause +====================================================================================================================== + + +.. raw:: html + + + + + + Expression + AS + + RelObjectName + +
    + + +
             ::= Expression 'AS' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableOnEmptyBehavior +====================================================================================================================== + + +.. raw:: html + + + + + + ERROR + + NULL + + DEFAULT + + Expression + + S_IDENTIFIER + + JsonKeyword + ARRAY + + +
    + + +
             ::= 'ERROR'
    +
               | 'NULL'
    +
               | 'DEFAULT' Expression
    +
               | S_IDENTIFIER ( JsonKeyword | 'ARRAY' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableWrapperClause +====================================================================================================================== + + +.. raw:: html + + + + + + WITHOUT + + WITH + + S_IDENTIFIER + ARRAY + + JsonKeyword + +
    + + +
             ::= ( 'WITHOUT' | 'WITH' S_IDENTIFIER? ) 'ARRAY'? JsonKeyword
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableQuotesClause +====================================================================================================================== + + +.. raw:: html + + + + + + KEEP + + JsonKeyword + + JsonKeyword + ON + + JsonKeyword + STRING + + +
    + + +
             ::= ( 'KEEP' | JsonKeyword ) JsonKeyword ( 'ON' JsonKeyword 'STRING' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableColumnDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + JsonKeyword + PATH + + Expression + AS + + RelObjectName + + JsonTableColumnsClause + + RelObjectName + FOR + + JsonKeyword + + ColDataType + FORMAT + + JSON + + ENCODING + + JsonEncoding + PATH + + Expression + + JsonTableWrapperClause + + JsonTableQuotesClause + + JsonTableOnEmptyBehavior + ON + + JsonKeyword + + JsonValueOnResponseBehavior + ON + + ERROR + + +
    + + +
             ::= JsonKeyword 'PATH'? Expression ( 'AS' RelObjectName )? JsonTableColumnsClause
    +
               | RelObjectName ( 'FOR' JsonKeyword | ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? ( 'PATH' Expression )? JsonTableWrapperClause? JsonTableQuotesClause? ( JsonTableOnEmptyBehavior 'ON' JsonKeyword )? ( JsonValueOnResponseBehavior 'ON' 'ERROR' )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableColumnsClause +====================================================================================================================== + + +.. raw:: html + + + + + + COLUMNS + + ( + + JsonTableColumnDefinition + , + + ) + + +
    + + +
             ::= 'COLUMNS' '(' ( JsonTableColumnDefinition ( ',' JsonTableColumnDefinition )* )? ')'
    +
    + + +====================================================================================================================== +JsonTablePlanTerm +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonTablePlanExpression + ) + + RelObjectName + + Expression + +
    + + +
             ::= '(' JsonTablePlanExpression ')'
    +
               | RelObjectName
    +
               | Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTablePlanExpression +====================================================================================================================== + + +.. raw:: html + + + + + + JsonTablePlanTerm + , + + INNER + + OUTER + + CROSS + + UNION + + +
    + + +
             ::= JsonTablePlanTerm ( ( ',' | 'INNER' | 'OUTER' | 'CROSS' | 'UNION' ) JsonTablePlanTerm )*
    +
    + + +====================================================================================================================== +JsonTablePlanClause +====================================================================================================================== + + +.. raw:: html + + + + + + PLAN + + DEFAULT + + ( + + JsonTablePlanExpression + ) + + +
    + + +
             ::= 'PLAN' 'DEFAULT'? '(' JsonTablePlanExpression ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableOnErrorClause +====================================================================================================================== + + +.. raw:: html + + + + + + ERROR + + S_IDENTIFIER + ON + + ERROR + + +
    + + +
             ::= ( 'ERROR' | S_IDENTIFIER ) 'ON' 'ERROR'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Expression + , + + Expression + AS + + RelObjectName + + JsonKeyword + + JsonTablePassingClause + , + + JsonTableColumnsClause + + JsonTablePlanClause + + JsonTableOnErrorClause + ) + + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +TableFunction +====================================================================================================================== + + +.. raw:: html + + + + + + LATERAL + + JsonKeyword + + JsonTableBody + + Function + WITH + + OFFSET + + ORDINALITY + + +
    + + +
             ::= 'LATERAL'? ( JsonKeyword JsonTableBody | Function ) ( 'WITH' ( 'OFFSET' | 'ORDINALITY' ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnNamesWithParamsList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + RelObjectName + + CreateParameter + , + + ) + + +
    + + +
             ::= '(' RelObjectName CreateParameter? ( ',' RelObjectName CreateParameter? )* ')'
    +
    + + +====================================================================================================================== +IndexColumnWithParams +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ( + + Expression + ) + + CreateParameter + +
    + + +
             ::= ( RelObjectName | '(' Expression ')' ) CreateParameter?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IndexColumnsWithParamsList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + IndexColumnWithParams + , + + ) + + +
    + + +
             ::= '(' IndexColumnWithParams ( ',' IndexColumnWithParams )* ')'
    +
    + + +====================================================================================================================== +Index +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNames + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +CreateIndex +====================================================================================================================== + + +.. raw:: html + + + + + + CreateParameter + INDEX + + IF + + NOT + + EXISTS + + Index + ON + + Table + + UsingIndexType + + UsingIndexType + ON + + Table + + IndexColumnsWithParamsList + + CreateParameter + +
    + + +
             ::= CreateParameter? 'INDEX' ( 'IF' 'NOT' 'EXISTS' )? Index ( 'ON' Table UsingIndexType? | UsingIndexType? 'ON' Table ) IndexColumnsWithParamsList CreateParameter*
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + + ColDataType + + CreateParameter + +
    + + + +
    + + +====================================================================================================================== +CreateSchema +====================================================================================================================== + + +.. raw:: html + + + + + + SCHEMA + + IF + + NOT + + EXISTS + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + . + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + AUTHORIZATION + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + PathSpecification + CREATE + + CreateTable + + CreateView + +
    + + +
             ::= 'SCHEMA' ( 'IF' 'NOT' 'EXISTS' )? ( ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ( '.' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) )? )? ( 'AUTHORIZATION' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) )? PathSpecification? ( 'CREATE' CreateTable | CreateView )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +PathSpecification +====================================================================================================================== + + +.. raw:: html + + + + + + PATH + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + , + + +
    + + +
             ::= 'PATH' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ( ',' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateTableConstraint +====================================================================================================================== + + +.. raw:: html + + + + + + INDEX + + UNIQUE + + FULLTEXT + + SPATIAL + + KEY + + RelObjectName + + IndexColumnsWithParamsList + + CreateParameter + CONSTRAINT + + RelObjectName + PRIMARY + + KEY + + UNIQUE + + KEY + + ColumnNamesWithParamsList + + CreateParameter + + ForeignKeySpec + + CheckConstraintSpec + EXCLUDE + + WHERE + + ( + + Expression + ) + + +
    + + +
             ::= ( 'INDEX' | 'UNIQUE'? ( 'FULLTEXT' | 'SPATIAL' )? 'KEY' ) RelObjectName IndexColumnsWithParamsList CreateParameter*
    +
               | ( 'CONSTRAINT' RelObjectName )? ( ( 'PRIMARY' 'KEY' | 'UNIQUE' 'KEY'? ) ColumnNamesWithParamsList CreateParameter* | ForeignKeySpec | CheckConstraintSpec )
    +
               | 'EXCLUDE' 'WHERE' ( '(' Expression ')' )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateTable +====================================================================================================================== + + +.. raw:: html + + + + + + UNLOGGED + + GLOBAL + + CreateParameter + TABLE + + IF + + NOT + + EXISTS + + Table + ( + + RelObjectName + , + + ColumnDefinition + , + + CreateTableConstraint + + ColumnDefinition + ) + + CreateParameter + + RowMovement + AS + + Select + LIKE + + ( + + Table + ) + + Table + , + + SpannerInterleaveIn + +
    + + +
             ::= 'UNLOGGED'? 'GLOBAL'? CreateParameter* 'TABLE' ( 'IF' 'NOT' 'EXISTS' )? Table ( '(' ( RelObjectName ( ',' RelObjectName )* | ColumnDefinition ( ',' ( CreateTableConstraint | ColumnDefinition ) )* ) ')' )? CreateParameter* RowMovement? ( 'AS' Select )? ( 'LIKE' ( '(' Table ')' | Table ) )? ( ',' SpannerInterleaveIn )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +SpannerInterleaveIn +====================================================================================================================== + + +.. raw:: html + + + + + + INTERLEAVE + + IN + + PARENT + + Table + ON + + DELETE + + NO + + ACTION + + CASCADE + + +
    + + +
             ::= 'INTERLEAVE' 'IN' 'PARENT' Table ( 'ON' 'DELETE' ( 'NO' 'ACTION' | 'CASCADE' ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +DataType +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATETIMELITERAL + + DT_ZONE + + DATA_TYPE + SIGNED + + UNSIGNED + + CHARACTER + + BIT + + BYTES + + BINARY + + BOOLEAN + + CHAR + + JSON + + STRING + + DATA_TYPE + SIGNED + + UNSIGNED + + CHARACTER + + BIT + + BYTES + + BINARY + + BOOLEAN + + CHAR + + JSON + + STRING + + ( + + S_LONG + MAX + + , + + S_LONG + ) + + K_TEXT_LITERAL + ARRAY + + < + + ColDataType + > + + +
    + + +
               | 'ARRAY' '<' ColDataType '>'
    +
               | ( K_DATETIMELITERAL | DT_ZONE | DATA_TYPE | 'SIGNED' | 'UNSIGNED' | 'CHARACTER' | 'BIT' | 'BYTES' | 'BINARY' | 'BOOLEAN' | + 'CHAR' | 'JSON' | 'STRING' ) ( DATA_TYPE | 'SIGNED' | 'UNSIGNED' | 'CHARACTER' | 'BIT' | 'BYTES' | 'BINARY' | 'BOOLEAN' | + 'CHAR' | 'JSON' | 'STRING' )* ( '(' ( S_LONG | 'MAX' ) ( ',' S_LONG )? ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColDataType +====================================================================================================================== + + +.. raw:: html + + + + + + STRUCT + + ( + + RelObjectNameExt + + ColDataType + , + + ) + + DataType + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + K_DATETIMELITERAL + + K_DATE_LITERAL + XML + + INTERVAL + + DT_ZONE + CHAR + + SET + + BINARY + + JSON + + STRING + + PUBLIC + + DATA + + NAME + + . + + ColDataType + ( + + S_LONG + MAX + + BYTE + + CHAR + + S_CHAR_LITERAL + + S_IDENTIFIER + CHAR + + , + + ) + + [ + + S_LONG + ] + + CHARACTER + + SET + + S_IDENTIFIER + BINARY + + +
    + + +
             ::= ( 'STRUCT' '(' RelObjectNameExt ColDataType ( ',' RelObjectNameExt ColDataType )* ')' | DataType | ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | K_DATETIMELITERAL | K_DATE_LITERAL | 'XML' | 'INTERVAL' | DT_ZONE | 'CHAR' | 'SET' | 'BINARY' | 'JSON' | 'STRING' | 'PUBLIC' | 'DATA' | 'NAME' ) ( + '.' ColDataType )? ) ( '(' ( ( ( S_LONG | 'MAX' ) ( 'BYTE' | 'CHAR' )? | S_CHAR_LITERAL | S_IDENTIFIER | 'CHAR' ) ','? )* ')' )? ( '[' S_LONG? ']' )* ( 'CHARACTER' 'SET' ( S_IDENTIFIER | 'BINARY' ) )?
    +
    + + +====================================================================================================================== +Analyze +====================================================================================================================== + + +.. raw:: html + + + + + + ANALYZE + + Table + +
    + +
    Analyze  ::= 'ANALYZE' Table
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnWithCommentList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Column + , + + ) + + +
    + + +
             ::= '(' Column ( ',' Column )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateView +====================================================================================================================== + + +.. raw:: html + + + + + + NO + + FORCE + + SECURE + + TEMP + + TEMPORARY + + VOLATILE + + MATERIALIZED + + VIEW + + Table + AUTO + + REFRESH + + YES + + NO + + IF + + NOT + + EXISTS + + ColumnWithCommentList + + CreateViewTailComment + AS + + Select + WITH + + READ + + ONLY + + +
    + + +
             ::= ( 'NO'? 'FORCE' )? 'SECURE'? ( 'TEMP' | 'TEMPORARY' | 'VOLATILE' )? 'MATERIALIZED'? + 'VIEW' Table ( 'AUTO' 'REFRESH' ( 'YES' | 'NO' ) )? ( 'IF' 'NOT' 'EXISTS' )? ColumnWithCommentList? CreateViewTailComment? 'AS' Select ( 'WITH' 'READ' 'ONLY' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateViewTailComment +====================================================================================================================== + + +.. raw:: html + + + + + + COMMENT + + = + + S_CHAR_LITERAL + +
    + + +
             ::= 'COMMENT' '='? S_CHAR_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +Action +====================================================================================================================== + + +.. raw:: html + + + + + + CASCADE + + RESTRICT + + NO + + ACTION + + SET + + NULL + + DEFAULT + + +
    + +
    Action   ::= 'CASCADE'
    +
               | 'RESTRICT'
    +
               | 'NO' 'ACTION'
    +
               | 'SET' ( 'NULL' | 'DEFAULT' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReferentialActionsOnIndex +====================================================================================================================== + + +.. raw:: html + + + + + + ON + + DELETE + + UPDATE + + Action + ON + + DELETE + + UPDATE + + Action + +
    + + +
             ::= ( 'ON' ( 'DELETE' | 'UPDATE' ) Action )? ( 'ON' ( 'DELETE' | 'UPDATE' ) Action )?
    +
    + + +====================================================================================================================== +CheckConstraintSpec +====================================================================================================================== + + +.. raw:: html + + + + + + CHECK + + ( + + Expression + ) + + +
    + + +
             ::= 'CHECK' ( '(' Expression ')' )*
    +
    + + +====================================================================================================================== +ForeignKeySpec +====================================================================================================================== + + +.. raw:: html + + + + + + FOREIGN + + KEY + + ColumnNamesWithParamsList + REFERENCES + + Table + + ColumnsNamesList + + ReferentialActionsOnIndex + +
    + + +
             ::= 'FOREIGN' 'KEY' ColumnNamesWithParamsList 'REFERENCES' Table ColumnsNamesList? ReferentialActionsOnIndex
    +
    + + +====================================================================================================================== +AlterExpressionUsingIndex +====================================================================================================================== + + +.. raw:: html + + + + + + USING + + INDEX + + RelObjectName + +
    + + +
             ::= 'USING' 'INDEX'? RelObjectName
    +
    + + +====================================================================================================================== +AlterExpressionConstraintTail +====================================================================================================================== + + +.. raw:: html + + + + + + AlterExpressionConstraintState + + AlterExpressionUsingIndex + + IndexWithComment + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +AlterView +====================================================================================================================== + + +.. raw:: html + + + + + + VIEW + + Table + + ColumnsNamesList + AS + + Select + +
    + + +
             ::= 'VIEW' Table ColumnsNamesList? 'AS' Select
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateParameter +====================================================================================================================== + + +.. raw:: html + + + + + + K_NEXTVAL + ( + + S_CHAR_LITERAL + :: + + ColDataType + ) + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + NAME + + . + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + NAME + + USING + + INDEX + + TABLESPACE + + RelObjectName + + S_CHAR_LITERAL + NULL + + NOT + + AUTO_INCREMENT + + PRIMARY + + FOREIGN + + REFERENCES + + KEY + + STORED + + ON + + COMMIT + + DROP + + ROWS + + UNIQUE + + CASCADE + + DELETE + + UPDATE + + CONSTRAINT + + WITH + + EXCLUDE + + WHERE + + TEMP + + TEMPORARY + + PARTITION + + BY + + IN + + TYPE + + COMMENT + + USING + + COLLATE + + ASC + + DESC + + TRUE + + FALSE + + PARALLEL + + BINARY + + START + + ORDER + + K_TIME_KEY_EXPR + RAW + + HASH + + FIRST + + LAST + + SIGNED + + UNSIGNED + + ENGINE + + IDENTITY + + MATERIALIZED + + SAMPLE + + ALWAYS + + = + + DEFAULT + + AS + + CHECK + + ( + + Expression + ) + + + + + - + + S_LONG + + S_DOUBLE + + AList + CHARACTER + + SET + + ARRAY + + ArrayConstructor + :: + + ColDataType + +
    + + +
             ::= K_NEXTVAL '(' S_CHAR_LITERAL '::' ColDataType ')'
    +
               | ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | 'NAME' ) ( '.' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | 'NAME' ) )?
    +
               | ( 'USING' 'INDEX' )? 'TABLESPACE' RelObjectName
    +
               | S_CHAR_LITERAL
    +
               | 'NULL'
    +
               | 'NOT'
    +
               | 'AUTO_INCREMENT'
    +
               | 'PRIMARY'
    +
               | 'FOREIGN'
    +
               | 'REFERENCES'
    +
               | 'KEY'
    +
               | 'STORED'
    +
               | 'ON'
    +
               | 'COMMIT'
    +
               | 'DROP'
    +
               | 'ROWS'
    +
               | 'UNIQUE'
    +
               | 'CASCADE'
    +
               | 'DELETE'
    +
               | 'UPDATE'
    +
               | 'CONSTRAINT'
    +
               | 'WITH'
    +
               | 'EXCLUDE'
    +
               | 'WHERE'
    +
               | 'TEMP'
    +
               | 'TEMPORARY'
    +
               | 'PARTITION'
    +
               | 'BY'
    +
               | 'IN'
    +
               | 'TYPE'
    +
               | 'COMMENT'
    +
               | 'USING'
    +
               | 'COLLATE'
    +
               | 'ASC'
    +
               | 'DESC'
    +
               | 'TRUE'
    +
               | 'FALSE'
    +
               | 'PARALLEL'
    +
               | 'BINARY'
    +
               | 'START'
    +
               | 'ORDER'
    +
               | K_TIME_KEY_EXPR
    +
               | 'RAW'
    +
               | 'HASH'
    +
               | 'FIRST'
    +
               | 'LAST'
    +
               | 'SIGNED'
    +
               | 'UNSIGNED'
    +
               | 'ENGINE'
    +
               | 'IDENTITY'
    +
               | 'MATERIALIZED'
    +
               | 'SAMPLE'
    +
               | 'ALWAYS'
    +
               | '='
    +
               | ( 'DEFAULT' | 'AS' | 'CHECK' ) ( '(' Expression ')' )?
    +
               | ( '+' | '-' )? S_LONG
    +
               | S_DOUBLE
    +
               | AList
    +
               | 'CHARACTER' 'SET'
    +
               | 'ARRAY' ArrayConstructor
    +
               | '::' ColDataType
    +
    + + +====================================================================================================================== +RowMovement +====================================================================================================================== + + +.. raw:: html + + + + + + ENABLE + + DISABLE + + ROW + + MOVEMENT + + +
    + + +
             ::= ( 'ENABLE' | 'DISABLE' ) 'ROW' 'MOVEMENT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + S_LONG + + S_DOUBLE + + S_CHAR_LITERAL + TRUE + + FALSE + + RelObjectName + , + + = + + ) + + +
    + +
    AList    ::= '(' ( ( S_LONG | S_DOUBLE | S_CHAR_LITERAL | 'TRUE' | 'FALSE' | RelObjectName ) ( ',' | '=' )? )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnsNamesListItem +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ( + + S_LONG + ) + + ASC + + DESC + + +
    + + +
             ::= RelObjectName ( '(' S_LONG ')' )? ( 'ASC' | 'DESC' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnsNamesList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + ColumnsNamesListItem + , + + ) + + +
    + + +
             ::= '(' ColumnsNamesListItem ( ',' ColumnsNamesListItem )* ')'
    +
    + + +====================================================================================================================== +FuncArgsListItem +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + + RelObjectName + ( + + S_LONG + ) + + +
    + + +
             ::= RelObjectName RelObjectName? ( '(' S_LONG ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +FuncArgsList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + FuncArgsListItem + , + + ) + + +
    + + +
             ::= '(' ( FuncArgsListItem ( ',' FuncArgsListItem )* )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +Drop +====================================================================================================================== + + +.. raw:: html + + + + + + DROP + + MATERIALIZED + + S_IDENTIFIER + TEMPORARY + + TABLE + + INDEX + + VIEW + + SCHEMA + + SEQUENCE + + FUNCTION + + IF + + EXISTS + + Table + + FuncArgsList + + S_IDENTIFIER + CASCADE + + RESTRICT + + ON + + Table + +
    + +
    Drop     ::= 'DROP' 'MATERIALIZED'? ( S_IDENTIFIER | 'TEMPORARY'? 'TABLE' | 'INDEX' | 'VIEW' | 'SCHEMA' | 'SEQUENCE' | 'FUNCTION' ) + ( 'IF' 'EXISTS' )? Table FuncArgsList? ( S_IDENTIFIER | 'CASCADE' | 'RESTRICT' | 'ON' Table )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Truncate +====================================================================================================================== + + +.. raw:: html + + + + + + TRUNCATE + + TABLE + + ONLY + + Table + , + + CASCADE + + +
    + +
    Truncate ::= 'TRUNCATE' 'TABLE'? 'ONLY'? Table ( ',' Table )* 'CASCADE'?
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnChanges +====================================================================================================================== + + +.. raw:: html + + + + + + AlterExpressionColumnDropDefault + + AlterExpressionColumnSetDefault + + AlterExpressionColumnSetVisibility + ( + + AlterExpressionColumnDataType + , + + ) + + +
    + + +
             ::= AlterExpressionColumnDropDefault
    +
               | AlterExpressionColumnSetDefault
    +
               | AlterExpressionColumnSetVisibility
    +
               | '(' AlterExpressionColumnDataType ( ',' AlterExpressionColumnDataType )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnDataType +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + TYPE + + ColDataType + + CreateParameter + +
    + + +
             ::= RelObjectName 'TYPE'? ColDataType? CreateParameter*
    +
    + + +====================================================================================================================== +AlterExpressionColumnDropNotNull +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + DROP + + NOT + + NULL + + +
    + + +
             ::= RelObjectName 'DROP' 'NOT'? 'NULL'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnDropDefault +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + DROP + + DEFAULT + + +
    + + +
             ::= RelObjectName 'DROP' 'DEFAULT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnSetDefault +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + SET + + DEFAULT + + Expression + +
    + + +
             ::= RelObjectName 'SET' 'DEFAULT' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnSetVisibility +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + SET + + VISIBLE + + INVISIBLE + + +
    + + +
             ::= RelObjectName 'SET' ( 'VISIBLE' | 'INVISIBLE' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionConstraintState +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + DEFERRABLE + + VALIDATE + + NOVALIDATE + + ENABLE + + DISABLE + + +
    + + +
             ::= ( 'NOT'? 'DEFERRABLE' | 'VALIDATE' | 'NOVALIDATE' | 'ENABLE' | 'DISABLE' + )*
    +
    + + +====================================================================================================================== +IndexWithComment +====================================================================================================================== + + +.. raw:: html + + + + + + COMMENT + + S_CHAR_LITERAL + +
    + + +
             ::= 'COMMENT' S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +IndexOptionList +====================================================================================================================== + + +.. raw:: html + + + + + + IndexOption + +
    + + +
             ::= IndexOption*
    +
    + Referenced by: +
    + + +====================================================================================================================== +UsingIndexType +====================================================================================================================== + + +.. raw:: html + + + + + + USING + + RelObjectName + +
    + + +
             ::= 'USING' RelObjectName
    +
    + + +====================================================================================================================== +IndexOption +====================================================================================================================== + + +.. raw:: html + + + + + + KEY_BLOCK_SIZE + + = + + S_LONG + WITH + + PARSER + + S_IDENTIFIER + COMMENT + + S_CHAR_LITERAL + VISIBLE + + INVISIBLE + + UsingIndexType + +
    + + +
             ::= 'KEY_BLOCK_SIZE' '='? S_LONG
    +
               | 'WITH' 'PARSER' S_IDENTIFIER
    +
               | 'COMMENT' S_CHAR_LITERAL
    +
               | 'VISIBLE'
    +
               | 'INVISIBLE'
    +
               | UsingIndexType
    +
    + Referenced by: +
    + + +====================================================================================================================== +PartitionDefinitions +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + PARTITION + + RelObjectName + VALUES + + LESS + + THAN + + ( + + Expression + ) + + MAXVALUE + + ENGINE + + = + + S_IDENTIFIER + , + + ) + + +
    + + +
             ::= '(' ( 'PARTITION' RelObjectName 'VALUES' 'LESS' 'THAN' ( '(' Expression ')' | 'MAXVALUE' ) ( 'ENGINE' '=' S_IDENTIFIER )? ','? )* ')'
    +
    + + +====================================================================================================================== +PartitionNamesList +====================================================================================================================== + + +.. raw:: html + + + + + + ALL + + S_IDENTIFIER + , + + +
    + + +
             ::= 'ALL'
    +
               | S_IDENTIFIER ( ',' S_IDENTIFIER )*
    +
    + + +====================================================================================================================== +AlterExpressionDiscardOrImport +====================================================================================================================== + + +.. raw:: html + + + + + + DISCARD + + IMPORT + + PARTITION + + PartitionNamesList + TABLESPACE + + +
    + + +
             ::= ( 'DISCARD' | 'IMPORT' ) ( 'PARTITION' PartitionNamesList )? 'TABLESPACE'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionAddConstraint +====================================================================================================================== + + +.. raw:: html + + + + + + CONSTRAINT + + UNIQUE + + KEY + + INDEX + + RelObjectName + + ColumnsNamesList + + RelObjectName + FOREIGN + + KEY + + ColumnsNamesList + REFERENCES + + Table + + ColumnsNamesList + + ReferentialActionsOnIndex + KEY + + ColumnsNamesList + + AlterExpressionConstraintState + PRIMARY + + KEY + + UNIQUE + + KEY + + INDEX + + ColumnsNamesList + + AlterExpressionConstraintTail + NOT + + ENFORCED + + CheckConstraintSpec + +
    + + +
             ::= 'CONSTRAINT' ( 'UNIQUE' ( 'KEY' | 'INDEX' )? RelObjectName ColumnsNamesList | RelObjectName ( ( 'FOREIGN' 'KEY' ColumnsNamesList 'REFERENCES' Table ColumnsNamesList? ReferentialActionsOnIndex | 'KEY' ColumnsNamesList ) AlterExpressionConstraintState | ( 'PRIMARY' 'KEY' | 'UNIQUE' ( 'KEY' | 'INDEX' )? ) ColumnsNamesList AlterExpressionConstraintTail | 'NOT'? 'ENFORCED' | CheckConstraintSpec ) )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionDrop +====================================================================================================================== + + +.. raw:: html + + + + + + DROP + + PARTITION + + PartitionNamesList + + ColumnsNamesList + COLUMN + + IF + + EXISTS + + KeywordOrIdentifier + INVALIDATE + + CASCADE + + CONSTRAINTS + + INDEX + + KEY + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + UNIQUE + + FOREIGN + + KEY + + ColumnsNamesList + PRIMARY + + KEY + + CONSTRAINT + + IF + + EXISTS + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + CASCADE + + RESTRICT + + +
    + + +
             ::= 'DROP' ( 'PARTITION' PartitionNamesList | ( ColumnsNamesList | 'COLUMN'? ( 'IF' 'EXISTS' )? KeywordOrIdentifier ) 'INVALIDATE'? ( 'CASCADE' 'CONSTRAINTS'? )? | ( 'INDEX' | 'KEY' ) ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) | ( ( 'UNIQUE' | 'FOREIGN' 'KEY' ) ColumnsNamesList | 'PRIMARY' 'KEY' | 'CONSTRAINT' ( 'IF' 'EXISTS' )? ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ) ( 'CASCADE' | 'RESTRICT' )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionPartitionOp +====================================================================================================================== + + +.. raw:: html + + + + + + TRUNCATE + + ANALYZE + + CHECK + + OPTIMIZE + + REBUILD + + REPAIR + + PARTITION + + PartitionNamesList + COALESCE + + PARTITION + + S_LONG + REORGANIZE + + PARTITION + + PartitionNamesList + INTO + + PARTITION + + BY + + RANGE + + ( + + Expression + ) + + COLUMNS + + ColumnsNamesList + + PartitionDefinitions + EXCHANGE + + PARTITION + + PartitionNamesList + WITH + + TABLE + + S_IDENTIFIER + WITH + + WITHOUT + + VALIDATION + + REMOVE + + PARTITIONING + + +
    + + +
             ::= ( 'TRUNCATE' | 'ANALYZE' | 'CHECK' | 'OPTIMIZE' | 'REBUILD' | 'REPAIR' + ) 'PARTITION' PartitionNamesList
    +
               | 'COALESCE' 'PARTITION' S_LONG
    +
               | ( 'REORGANIZE' 'PARTITION' PartitionNamesList 'INTO' | 'PARTITION' 'BY' 'RANGE' ( '(' Expression ')' | 'COLUMNS' ColumnsNamesList ) ) PartitionDefinitions
    +
               | 'EXCHANGE' 'PARTITION' PartitionNamesList 'WITH' 'TABLE' S_IDENTIFIER ( ( 'WITH' | 'WITHOUT' ) 'VALIDATION' )?
    +
               | 'REMOVE' 'PARTITIONING'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionAddAlterModify +====================================================================================================================== + + +.. raw:: html + + + + + + ADD + + ALTER + + MODIFY + + PRIMARY + + KEY + + ColumnsNamesList + + AlterExpressionConstraintState + + AlterExpressionUsingIndex + KEY + + INDEX + + RelObjectName + + UsingIndexType + + IndexColumnsWithParamsList + + IndexOptionList + + AlterExpressionConstraintState + SPATIAL + + FULLTEXT + + INDEX + + KEY + + RelObjectName + + ColumnsNamesList + + IndexOptionList + + RelObjectName + COMMENT + + S_CHAR_LITERAL + PARTITION + + PartitionDefinitions + COLUMN + + COLUMNS + + IF + + NOT + + EXISTS + + AlterExpressionColumnChanges + + AlterExpressionColumnDataType + + AlterExpressionColumnDropNotNull + + AlterExpressionColumnChanges + UNIQUE + + KEY + + INDEX + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + ColumnsNamesList + + AlterExpressionUsingIndex + + IndexWithComment + + ForeignKeySpec + CHECK + + RelObjectName + NOT + + ENFORCED + + AlterExpressionAddConstraint + +
    + + +
             ::= ( 'ADD' | 'ALTER' | 'MODIFY' ) ( 'PRIMARY' 'KEY' ColumnsNamesList AlterExpressionConstraintState AlterExpressionUsingIndex? | ( 'KEY' | 'INDEX' ) RelObjectName? UsingIndexType? IndexColumnsWithParamsList? IndexOptionList AlterExpressionConstraintState | ( 'SPATIAL' | 'FULLTEXT' ) ( 'INDEX' | 'KEY' )? RelObjectName? ColumnsNamesList IndexOptionList | RelObjectName 'COMMENT' S_CHAR_LITERAL | 'PARTITION' PartitionDefinitions | ( 'COLUMN' | 'COLUMNS' )? ( 'IF' 'NOT' 'EXISTS' )? ( AlterExpressionColumnChanges | AlterExpressionColumnDataType | AlterExpressionColumnDropNotNull ) | AlterExpressionColumnChanges | 'UNIQUE' ( 'KEY' | 'INDEX' )? ( S_IDENTIFIER | S_QUOTED_IDENTIFIER )? ColumnsNamesList AlterExpressionUsingIndex? IndexWithComment? | ForeignKeySpec | 'CHECK' RelObjectName 'NOT'? 'ENFORCED' | AlterExpressionAddConstraint )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionRenameOp +====================================================================================================================== + + +.. raw:: html + + + + + + RENAME + + INDEX + + KEY + + CONSTRAINT + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + TO + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + COLUMN + + KeywordOrIdentifier + TO + + KeywordOrIdentifier + +
    + + +
             ::= 'RENAME' ( ( ( 'INDEX' | 'KEY' | 'CONSTRAINT' ) ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) )? 'TO' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) | 'COLUMN'? KeywordOrIdentifier 'TO' KeywordOrIdentifier )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpression +====================================================================================================================== + + +.. raw:: html + + + + + + AlterExpressionAddAlterModify + CHANGE + + COLUMN + + KeywordOrIdentifier + + AlterExpressionColumnDataType + + AlterExpressionDrop + FORCE + + ROW + + LEVEL + + SECURITY + + NO + + FORCE + + ROW + + LEVEL + + SECURITY + + ALGORITHM + + LOCK + + ENGINE + + = + + RelObjectName + KEY_BLOCK_SIZE + + AUTO_INCREMENT + + = + + S_LONG + + AlterExpressionRenameOp + CONVERT + + TO + + CHARACTER + + SET + + S_IDENTIFIER + COLLATE + + DEFAULT + + CHARACTER + + SET + + = + + S_IDENTIFIER + COLLATE + + COLLATE + + = + + S_IDENTIFIER + COMMENT + + ENCRYPTION + + = + + S_CHAR_LITERAL + + AlterExpressionDiscardOrImport + DISABLE + + ENABLE + + ROW + + LEVEL + + SECURITY + + KEYS + + AlterExpressionPartitionOp + + captureRest + +
    + + +
             ::= AlterExpressionAddAlterModify
    +
               | 'CHANGE' 'COLUMN'? KeywordOrIdentifier AlterExpressionColumnDataType
    +
               | AlterExpressionDrop
    +
               | 'FORCE' ( 'ROW' 'LEVEL' 'SECURITY' )?
    +
               | 'NO' 'FORCE' 'ROW' 'LEVEL' 'SECURITY'
    +
               | ( 'ALGORITHM' | 'LOCK' | 'ENGINE' ) '='? RelObjectName
    +
               | ( 'KEY_BLOCK_SIZE' | 'AUTO_INCREMENT' ) '='? S_LONG
    +
               | AlterExpressionRenameOp
    +
               | ( 'CONVERT' 'TO' 'CHARACTER' 'SET' ( S_IDENTIFIER 'COLLATE' )? | 'DEFAULT'? ( 'CHARACTER' 'SET' ( '='? S_IDENTIFIER 'COLLATE' )? | 'COLLATE' ) '='? ) S_IDENTIFIER
    +
               | ( 'COMMENT' | 'ENCRYPTION' ) '='? S_CHAR_LITERAL
    +
               | AlterExpressionDiscardOrImport
    +
               | ( 'DISABLE' | 'ENABLE' ) ( 'ROW' 'LEVEL' 'SECURITY' | 'KEYS' )
    +
               | AlterExpressionPartitionOp
    +
               | captureRest
    +
    + Referenced by: +
    + + +====================================================================================================================== +Alter +====================================================================================================================== + + +.. raw:: html + + + + + + ALTER + + AlterTable + + AlterSession + + AlterView + + AlterSystemStatement + + AlterSequence + + captureRest + REPLACE + + AlterView + + captureRest + +
    + + +
               | 'REPLACE' ( AlterView | captureRest )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterTable +====================================================================================================================== + + +.. raw:: html + + + + + + TABLE + + ONLY + + IF + + EXISTS + + Table + + AlterExpression + , + + +
    + + +
             ::= 'TABLE' 'ONLY'? ( 'IF' 'EXISTS' )? Table AlterExpression ( ',' AlterExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterSession +====================================================================================================================== + + +.. raw:: html + + + + + + SESSION + + ADVISE + + COMMIT + + ROLLBACK + + NOTHING + + CLOSE + + DATABASE + + LINK + + ENABLE + + DISABLE + + COMMIT + + IN + + PROCEDURE + + GUARD + + PARALLEL + + DML + + DDL + + QUERY + + RESUMABLE + + FORCE + + PARALLEL + + DML + + DDL + + QUERY + + SET + + S_CHAR_LITERAL + + S_IDENTIFIER + = + + S_LONG + PARALLEL + + +
    + + +
             ::= 'SESSION' ( 'ADVISE' ( 'COMMIT' | 'ROLLBACK' | 'NOTHING' ) | 'CLOSE' + 'DATABASE' 'LINK' | ( 'ENABLE' | 'DISABLE' ) ( 'COMMIT' 'IN' 'PROCEDURE' | 'GUARD' + | 'PARALLEL' ( 'DML' | 'DDL' | 'QUERY' ) | 'RESUMABLE' ) | 'FORCE' 'PARALLEL' ( 'DML' + | 'DDL' | 'QUERY' ) | 'SET' ) ( S_CHAR_LITERAL | S_IDENTIFIER | '=' | S_LONG | 'PARALLEL' )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterSystemStatement +====================================================================================================================== + + +.. raw:: html + + + + + + SYSTEM + + ARCHIVE + + LOG + + CHECKPOINT + + DUMP + + ACTIVE + + SESSION + + HISTORY + + ENABLE + + DISABLE + + DISTRIBUTED + + RECOVERY + + RESTRICTED + + SESSION + + FLUSH + + DISCONNECT + + KILL + + SESSION + + SWITCH + + SUSPEND + + RESUME + + QUIESCE + + RESTRICTED + + UNQIESCE + + SHUTDOWN + + REGISTER + + SET + + RESET + + captureRest + +
    + + +
             ::= 'SYSTEM' ( 'ARCHIVE' 'LOG' | 'CHECKPOINT' | 'DUMP' 'ACTIVE' 'SESSION' + 'HISTORY' | ( 'ENABLE' | 'DISABLE' ) ( 'DISTRIBUTED' 'RECOVERY' | 'RESTRICTED' 'SESSION' + ) | 'FLUSH' | ( 'DISCONNECT' | 'KILL' ) 'SESSION' | 'SWITCH' | 'SUSPEND' | 'RESUME' + | 'QUIESCE' 'RESTRICTED' | 'UNQIESCE' | 'SHUTDOWN' | 'REGISTER' | 'SET' | 'RESET' + ) captureRest
    +
    + Referenced by: +
    + + +====================================================================================================================== +Wait +====================================================================================================================== + + +.. raw:: html + + + + + + WAIT + + S_LONG + +
    + +
    Wait     ::= 'WAIT' S_LONG
    +
    + Referenced by: +
    + + +====================================================================================================================== +SavepointStatement +====================================================================================================================== + + +.. raw:: html + + + + + + SAVEPOINT + + S_IDENTIFIER + +
    + + +
             ::= 'SAVEPOINT' S_IDENTIFIER
    +
    + Referenced by: +
    + + +====================================================================================================================== +RollbackStatement +====================================================================================================================== + + +.. raw:: html + + + + + + ROLLBACK + + WORK + + TO + + SAVEPOINT + + S_IDENTIFIER + FORCE + + S_CHAR_LITERAL + +
    + + +
             ::= 'ROLLBACK' 'WORK'? ( 'TO' 'SAVEPOINT'? S_IDENTIFIER | 'FORCE' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Comment +====================================================================================================================== + + +.. raw:: html + + + + + + COMMENT + + ON + + TABLE + + VIEW + + Table + COLUMN + + Column + IS + + S_CHAR_LITERAL + +
    + +
    Comment  ::= 'COMMENT' 'ON' ( ( 'TABLE' | 'VIEW' ) Table | 'COLUMN' Column ) 'IS' S_CHAR_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +Grant +====================================================================================================================== + + +.. raw:: html + + + + + + GRANT + + readGrantTypes + , + + ON + + RelObjectNames + + S_IDENTIFIER + TO + + UsersList + +
    + +
    Grant    ::= 'GRANT' ( ( readGrantTypes ( ',' readGrantTypes )* )? 'ON' RelObjectNames | S_IDENTIFIER ) 'TO' UsersList
    +
    + Referenced by: +
    + + +====================================================================================================================== +UsersList +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + , + + ColumnsNamesListItem + +
    + + +
             ::= RelObjectName ( ',' ColumnsNamesListItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +readGrantTypes +====================================================================================================================== + + +.. raw:: html + + + + + + K_SELECT + INSERT + + UPDATE + + DELETE + + EXECUTE + + ALTER + + DROP + + +
    + + +
             ::= K_SELECT
    +
               | 'INSERT'
    +
               | 'UPDATE'
    +
               | 'DELETE'
    +
               | 'EXECUTE'
    +
               | 'ALTER'
    +
               | 'DROP'
    +
    + Referenced by: +
    + + +====================================================================================================================== +Sequence +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNames + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +SequenceParameters +====================================================================================================================== + + +.. raw:: html + + + + + + INCREMENT + + BY + + START + + WITH + + MAXVALUE + + MINVALUE + + CACHE + + S_LONG + RESTART + + WITH + + S_LONG + NOMAXVALUE + + NOMINVALUE + + NOCYCLE + + CYCLE + + NOCACHE + + ORDER + + NOORDER + + KEEP + + NOKEEP + + SESSION + + GLOBAL + + +
    + + +
             ::= ( ( 'INCREMENT' 'BY'? | 'START' 'WITH'? | 'MAXVALUE' | 'MINVALUE' | 'CACHE' + ) S_LONG | 'RESTART' ( 'WITH' S_LONG )? | 'NOMAXVALUE' | 'NOMINVALUE' | 'NOCYCLE' | 'CYCLE' | 'NOCACHE' | 'ORDER' | 'NOORDER' + | 'KEEP' | 'NOKEEP' | 'SESSION' | 'GLOBAL' )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateSequence +====================================================================================================================== + + +.. raw:: html + + + + + + SEQUENCE + + Sequence + AS + + S_IDENTIFIER + + DATA_TYPE + + SequenceParameters + +
    + + +
             ::= 'SEQUENCE' Sequence ( 'AS' ( S_IDENTIFIER | DATA_TYPE ) )? SequenceParameters
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterSequence +====================================================================================================================== + + +.. raw:: html + + + + + + SEQUENCE + + Sequence + + SequenceParameters + +
    + + +
             ::= 'SEQUENCE' Sequence SequenceParameters
    +
    + Referenced by: +
    + + +====================================================================================================================== +Create +====================================================================================================================== + + +.. raw:: html + + + + + + CREATE + + OR + + REPLACE + + CreateFunctionStatement + + CreateSchema + + CreateSequence + + CreateSynonym + + CreateTable + + CreateView + + CreatePolicy + TRIGGER + + DOMAIN + + captureRest + + CreateIndex + +
    + +
    Create   ::= 'CREATE' ( 'OR' 'REPLACE' )? ( CreateFunctionStatement | CreateSchema | CreateSequence | CreateSynonym | CreateTable | CreateView | CreatePolicy | ( 'TRIGGER' | 'DOMAIN' )? captureRest | CreateIndex )
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateFunctionStatement +====================================================================================================================== + + +.. raw:: html + + + + + + FUNCTION + + PROCEDURE + + captureFunctionBody + +
    + + +
             ::= ( 'FUNCTION' | 'PROCEDURE' ) captureFunctionBody
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateSynonym +====================================================================================================================== + + +.. raw:: html + + + + + + PUBLIC + + SYNONYM + + Synonym + FOR + + RelObjectNames + +
    + + +
             ::= 'PUBLIC'? 'SYNONYM' Synonym 'FOR' RelObjectNames
    +
    + Referenced by: +
    + + +====================================================================================================================== +Synonym +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNames + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +CreatePolicy +====================================================================================================================== + + +.. raw:: html + + + + + + POLICY + + RelObjectName + ON + + Table + FOR + + ALL + + K_SELECT + INSERT + + UPDATE + + DELETE + + TO + + RelObjectName + , + + USING + + ( + + Expression + ) + + WITH + + CHECK + + ( + + Expression + ) + + +
    + + +
             ::= 'POLICY' RelObjectName 'ON' Table ( 'FOR' ( 'ALL' | K_SELECT | 'INSERT' | 'UPDATE' | 'DELETE' ) )? ( 'TO' RelObjectName ( ',' RelObjectName )* )? ( 'USING' '(' Expression ')' )? ( 'WITH' 'CHECK' '(' Expression ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnsupportedStatement +====================================================================================================================== + + +.. raw:: html + + + + + + captureUnsupportedStatementDeclaration + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +IdentifierChain +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNameExt + . + + +
    + + +
             ::= RelObjectNameExt ( '.' RelObjectNameExt )*
    +
    + + +====================================================================================================================== +IdentifierChain2 +====================================================================================================================== + + +.. raw:: html + + + + + + . + + RelObjectNameExt + +
    + + +
             ::= ( '.' RelObjectNameExt )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CharacterPrimary +====================================================================================================================== + + +.. raw:: html + + + + + + TranscodingFunction + + TrimFunction + +
    + + +
             ::= TranscodingFunction
    +
               | TrimFunction
    +
    + Referenced by: +
    + + +====================================================================================================================== +TranscodingFunction +====================================================================================================================== + + +.. raw:: html + + + + + + TRY_CONVERT + + SAFE_CONVERT + + CONVERT + + ( + + ColDataType + , + + Expression + , + + S_LONG + + Expression + USING + + IdentifierChain + ) + + +
    + + +
             ::= ( 'TRY_CONVERT' | 'SAFE_CONVERT' | 'CONVERT' ) '(' ( ColDataType ',' Expression ( ',' S_LONG )? | Expression 'USING' IdentifierChain ) ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TrimFunction +====================================================================================================================== + + +.. raw:: html + + + + + + TRIM + + ( + + LEADING + + TRAILING + + BOTH + + Expression + , + + FROM + + Expression + ) + + +
    + + +
             ::= 'TRIM' '(' ( 'LEADING' | 'TRAILING' | 'BOTH' )? Expression? ( ( ',' | 'FROM' ) Expression )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +SnowflakeTimeTravelAt +====================================================================================================================== + + +.. raw:: html + + + + + + AT + + ( + + K_DATETIMELITERAL + OFFSET + + => + + Expression + STATEMENT + + => + + S_CHAR_LITERAL + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + STREAM + + => + + S_CHAR_LITERAL + ) + + +
    + + +
             ::= 'AT' '(' ( ( K_DATETIMELITERAL | 'OFFSET' ) '=>' Expression | 'STATEMENT' '=>' ( S_CHAR_LITERAL | S_IDENTIFIER | S_QUOTED_IDENTIFIER ) | 'STREAM' '=>' S_CHAR_LITERAL ) ')'
    +
    + + +====================================================================================================================== +SnowflakeTimeTravelBefore +====================================================================================================================== + + +.. raw:: html + + + + + + BEFORE + + ( + + STATEMENT + + => + + S_CHAR_LITERAL + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + ) + + +
    + + +
             ::= 'BEFORE' '(' 'STATEMENT' '=>' ( S_CHAR_LITERAL | S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ')'
    +
    + + +====================================================================================================================== +SnowflakeTimeTravelChange +====================================================================================================================== + + +.. raw:: html + + + + + + CHANGES + + ( + + INFORMATION + + => + + DEFAULT + + APPEND_ONLY + + ) + + SnowflakeTimeTravelAt + + SnowflakeTimeTravelBefore + END + + ( + + K_DATETIMELITERAL + OFFSET + + => + + Expression + STATEMENT + + => + + S_CHAR_LITERAL + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + ) + + +
    + + +
             ::= 'CHANGES' '(' 'INFORMATION' '=>' ( 'DEFAULT' | 'APPEND_ONLY' ) ')' ( + SnowflakeTimeTravelAt | SnowflakeTimeTravelBefore ) ( 'END' '(' ( ( K_DATETIMELITERAL | 'OFFSET' ) '=>' Expression | 'STATEMENT' '=>' ( S_CHAR_LITERAL | S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ) ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +DataBricksTemporalSpec +====================================================================================================================== + + +.. raw:: html + + + + + + @ + + @V + + S_CHAR_LITERAL + + S_LONG + FOR + + SYSTEM_TIMESTAMP + + K_DATETIMELITERAL + AS + + OF + + Expression + SYSTEM_VERSION + + VERSION + + AS + + OF + + S_LONG + + S_CHAR_LITERAL + +
    + + +
             ::= ( '@' | '@V' ) ( S_CHAR_LITERAL | S_LONG )
    +
               | 'FOR'? ( 'SYSTEM_TIMESTAMP' | K_DATETIMELITERAL ) 'AS' 'OF' Expression
    +
               | ( 'SYSTEM_VERSION' | 'VERSION' ) 'AS' 'OF' ( S_LONG | S_CHAR_LITERAL )
    +
    + Referenced by: +
    + + +====================================================================================================================== +BigQueryHistoricalVersion +====================================================================================================================== + + +.. raw:: html + + + + + + FOR + + SYSTEM_TIME + + AS + + OF + + Expression + +
    + + +
             ::= 'FOR' 'SYSTEM_TIME' 'AS' 'OF' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +TimeTravelBeforeAlias +====================================================================================================================== + + +.. raw:: html + + + + + + SnowflakeTimeTravelAt + + SnowflakeTimeTravelBefore + + SnowflakeTimeTravelChange + + DataBricksTemporalSpec + +
    + + +
             ::= SnowflakeTimeTravelAt
    +
               | SnowflakeTimeTravelBefore
    +
               | SnowflakeTimeTravelChange
    +
               | DataBricksTemporalSpec
    +
    + Referenced by: +
    + + +====================================================================================================================== +TimeTravelAfterAlias +====================================================================================================================== + + +.. raw:: html + + + + + + BigQueryHistoricalVersion + +
    + + +
             ::= BigQueryHistoricalVersion
    +
    + Referenced by: +
    + + +====================================================================================================================== +WHITESPACE +====================================================================================================================== + + +.. raw:: html + + + + + + + + [#x9] + + [#xD] + + [#xA] + + +
    + + +
             ::= [ #x9#xD#xA]
    +
    + + +====================================================================================================================== +K_ISOLATION +====================================================================================================================== + + +.. raw:: html + + + + + + UR + + RS + + RR + + CS + + +
    + + +
             ::= 'UR'
    +
               | 'RS'
    +
               | 'RR'
    +
               | 'CS'
    +
    + Referenced by: +
    + + +====================================================================================================================== +K_NEXTVAL +====================================================================================================================== + + +.. raw:: html + + + + + + NEXTVAL + + + + FOR + + NEXT + + + + VALUE + + + + FOR + + +
    + + +
             ::= 'NEXTVAL' ( ' '+ 'FOR' )?
    +
               | 'NEXT' ' '+ 'VALUE' ' '+ 'FOR'
    +
    + + +====================================================================================================================== +K_TEXT_LITERAL +====================================================================================================================== + + +.. raw:: html + + + + + + TEXT + + TINYTEXT + + MEDIUMTEXT + + LONGTEXT + + +
    + + +
             ::= 'TEXT'
    +
               | 'TINYTEXT'
    +
               | 'MEDIUMTEXT'
    +
               | 'LONGTEXT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +K_TIME_KEY_EXPR +====================================================================================================================== + + +.. raw:: html + + + + + + CURRENT + + _ + + + + TIMESTAMP + + TIME + + DATE + + TIMEZONE + + () + + +
    + + +
             ::= 'CURRENT' ( '_' | ' '+ ) ( 'TIMESTAMP' | 'TIME' | 'DATE' | 'TIMEZONE' + ) '()'?
    +
    + + +====================================================================================================================== +K_STRING_FUNCTION_NAME +====================================================================================================================== + + +.. raw:: html + + + + + + SUBSTR + + SUBSTRING + + TRIM + + POSITION + + OVERLAY + + +
    + + +
             ::= 'SUBSTR'
    +
               | 'SUBSTRING'
    +
               | 'TRIM'
    +
               | 'POSITION'
    +
               | 'OVERLAY'
    +
    + + +====================================================================================================================== +K_DATETIMELITERAL +====================================================================================================================== + + +.. raw:: html + + + + + + DATE + + DATETIME + + TIME + + TIMESTAMP + + TIMESTAMPTZ + + +
    + + +
             ::= 'DATE'
    +
               | 'DATETIME'
    +
               | 'TIME'
    +
               | 'TIMESTAMP'
    +
               | 'TIMESTAMPTZ'
    +
    + + +====================================================================================================================== +K_DATE_LITERAL +====================================================================================================================== + + +.. raw:: html + + + + + + YEAR + + MONTH + + DAY + + HOUR + + MINUTE + + SECOND + + +
    + + +
             ::= 'YEAR'
    +
               | 'MONTH'
    +
               | 'DAY'
    +
               | 'HOUR'
    +
               | 'MINUTE'
    +
               | 'SECOND'
    +
    + + +====================================================================================================================== +K_SELECT +====================================================================================================================== + + +.. raw:: html + + + + + + SELECT + + SEL + + +
    + +
    K_SELECT ::= 'SELECT'
    +
               | 'SEL'
    +
    + + +====================================================================================================================== +K_SIMILAR_TO +====================================================================================================================== + + +.. raw:: html + + + + + + SIMILAR + + + + TO + + +
    + + +
             ::= 'SIMILAR' ' '+ 'TO'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ST_SEMICOLON +====================================================================================================================== + + +.. raw:: html + + + + + + ; + + [#xA] + + / + + [#xA] + + go + + [#xA] + + +
    + + +
             ::= ';'
    +
               | #xA ( [/#xA] | 'go' ) #xA
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_GREATERTHANEQUALS +====================================================================================================================== + + +.. raw:: html + + + + + + > + + WHITESPACE + = + + +
    + + +
             ::= '>' WHITESPACE* '='
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_MINORTHANEQUALS +====================================================================================================================== + + +.. raw:: html + + + + + + < + + WHITESPACE + = + + +
    + + +
             ::= '<' WHITESPACE* '='
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_NOTEQUALSSTANDARD +====================================================================================================================== + + +.. raw:: html + + + + + + < + + WHITESPACE + > + + +
    + + +
             ::= '<' WHITESPACE* '>'
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_NOTEQUALSBANG +====================================================================================================================== + + +.. raw:: html + + + + + + ! + + WHITESPACE + = + + +
    + + +
             ::= '!' WHITESPACE* '='
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_NOTEQUALSHAT +====================================================================================================================== + + +.. raw:: html + + + + + + ^ + + WHITESPACE + = + + +
    + + +
             ::= '^' WHITESPACE* '='
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_CONCAT +====================================================================================================================== + + +.. raw:: html + + + + + + | + + WHITESPACE + | + + +
    + + +
             ::= '|' WHITESPACE* '|'
    +
    + + +====================================================================================================================== +DT_ZONE +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATETIMELITERAL + + WHITESPACE + ( + + S_LONG + ) + + WHITESPACE + WITH + + WITHOUT + + WHITESPACE + LOCAL + + WHITESPACE + TIME + + WHITESPACE + ZONE + + +
    + +
    DT_ZONE  ::= K_DATETIMELITERAL WHITESPACE* ( '(' S_LONG ')' )? WHITESPACE* ( 'WITH' | 'WITHOUT' ) WHITESPACE+ ( 'LOCAL' WHITESPACE+ )? 'TIME' WHITESPACE+ 'ZONE'
    +
    + + +====================================================================================================================== +DATA_TYPE +====================================================================================================================== + + +.. raw:: html + + + + + + BISTRING + + TYPE_BLOB + + TYPE_BOOLEAN + ENUM + + TYPE_REAL + + TYPE_DOUBLE + UUID + + MAP + + TYPE_TINYINT + + TYPE_SMALLINT + + TYPE_INTEGER + + TYPE_BIGINT + HUGEINT + + UTINYINT + + USMALLINT + + UINTEGER + + UBIGINT + + UHUGEINT + + TYPE_DECIMAL + + TYPE_VARCHAR + TIMETZ + + TYPE_TIMESTAMP + +
    + + +
             ::= 'BISTRING'
    +
               | TYPE_BLOB
    +
               | TYPE_BOOLEAN
    +
               | 'ENUM'
    +
               | TYPE_REAL
    +
               | TYPE_DOUBLE
    +
               | 'UUID'
    +
               | 'MAP'
    +
               | TYPE_TINYINT
    +
               | TYPE_SMALLINT
    +
               | TYPE_INTEGER
    +
               | TYPE_BIGINT
    +
               | 'HUGEINT'
    +
               | 'UTINYINT'
    +
               | 'USMALLINT'
    +
               | 'UINTEGER'
    +
               | 'UBIGINT'
    +
               | 'UHUGEINT'
    +
               | TYPE_DECIMAL
    +
               | TYPE_VARCHAR
    +
               | 'TIMETZ'
    +
               | TYPE_TIMESTAMP
    +
    + + +====================================================================================================================== +TYPE_BLOB +====================================================================================================================== + + +.. raw:: html + + + + + + BLOB + + BYTEA + + BINARY + + VARBINARY + + BYTES + + +
    + + +
             ::= 'BLOB'
    +
               | 'BYTEA'
    +
               | 'BINARY'
    +
               | 'VARBINARY'
    +
               | 'BYTES'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_BOOLEAN +====================================================================================================================== + + +.. raw:: html + + + + + + BOOLEAN + + BOOL + + +
    + + +
             ::= 'BOOLEAN'
    +
               | 'BOOL'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_DECIMAL +====================================================================================================================== + + +.. raw:: html + + + + + + DECIMAL + + NUMBER + + NUMERIC + + +
    + + +
             ::= 'DECIMAL'
    +
               | 'NUMBER'
    +
               | 'NUMERIC'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_TINYINT +====================================================================================================================== + + +.. raw:: html + + + + + + TINYINT + + INT1 + + +
    + + +
             ::= 'TINYINT'
    +
               | 'INT1'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_SMALLINT +====================================================================================================================== + + +.. raw:: html + + + + + + SMALLINT + + INT2 + + SHORT + + +
    + + +
             ::= 'SMALLINT'
    +
               | 'INT2'
    +
               | 'SHORT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_INTEGER +====================================================================================================================== + + +.. raw:: html + + + + + + INTEGER + + INT + + INT4 + + SIGNED + + UNSIGNED + + +
    + + +
             ::= 'INTEGER'
    +
               | 'INT'
    +
               | 'INT4'
    +
               | 'SIGNED'
    +
               | 'UNSIGNED'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_BIGINT +====================================================================================================================== + + +.. raw:: html + + + + + + BIGINT + + INT8 + + LONG + + +
    + + +
             ::= 'BIGINT'
    +
               | 'INT8'
    +
               | 'LONG'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_REAL +====================================================================================================================== + + +.. raw:: html + + + + + + REAL + + FLOAT4 + + FLOAT + + +
    + + +
             ::= 'REAL'
    +
               | 'FLOAT4'
    +
               | 'FLOAT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_DOUBLE +====================================================================================================================== + + +.. raw:: html + + + + + + DOUBLE + + PRECISION + + FLOAT8 + + FLOAT64 + + +
    + + +
             ::= 'DOUBLE'
    +
               | 'PRECISION'
    +
               | 'FLOAT8'
    +
               | 'FLOAT64'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_VARCHAR +====================================================================================================================== + + +.. raw:: html + + + + + + NVARCHAR + + VARCHAR + + NCHAR + + CHAR + + BPCHAR + + TEXT + + STRING + + CHARACTER + + VARYING + + +
    + + +
             ::= 'NVARCHAR'
    +
               | 'VARCHAR'
    +
               | 'NCHAR'
    +
               | 'CHAR'
    +
               | 'BPCHAR'
    +
               | 'TEXT'
    +
               | 'STRING'
    +
               | 'CHARACTER'
    +
               | 'VARYING'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_TIMESTAMP +====================================================================================================================== + + +.. raw:: html + + + + + + TIMESTAMP_NS + + TIMESTAMP_MS + + TIMESTAMP_S + + +
    + + +
             ::= 'TIMESTAMP_NS'
    +
               | 'TIMESTAMP_MS'
    +
               | 'TIMESTAMP_S'
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_DOUBLE +====================================================================================================================== + + +.. raw:: html + + + + + + S_LONG + . + + S_LONG + e + + E + + + + + [#x2D] + + S_LONG + + S_LONG + . + + e + + E + + + + + [#x2D] + + S_LONG + e + + E + + + + + [#x2D] + + S_LONG + +
    + +
    S_DOUBLE ::= S_LONG? '.' S_LONG ( [eE] [+#x2D]? S_LONG )?
    +
               | S_LONG ( '.' ( [eE] [+#x2D]? S_LONG )? | [eE] [+#x2D]? S_LONG )
    +
    + + +====================================================================================================================== +S_LONG +====================================================================================================================== + + +.. raw:: html + + + + + + DIGIT + +
    + +
    S_LONG   ::= DIGIT+
    +
    + + +====================================================================================================================== +DIGIT +====================================================================================================================== + + +.. raw:: html + + + + + + [0-9] + + +
    + +
    DIGIT    ::= [0-9]
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_HEX +====================================================================================================================== + + +.. raw:: html + + + + + + X + + ' + + HEX_VALUE + ' + + + + 0x + + HEX_VALUE + +
    + +
    S_HEX    ::= 'X' ( "'" HEX_VALUE* "'" ' '* )+
    +
               | '0x' HEX_VALUE+
    +
    + + +====================================================================================================================== +HEX_VALUE +====================================================================================================================== + + +.. raw:: html + + + + + + [0-9] + + [A-F] + + + + +
    + + +
             ::= [0-9A-F ]
    +
    + Referenced by: +
    + + +====================================================================================================================== +LINE_COMMENT +====================================================================================================================== + + +.. raw:: html + + + + + + -- + + // + + [^#xD#xA] + + +
    + + +
             ::= ( '--' | '//' ) [^#xD#xA]*
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +MULTI_LINE_COMMENT +====================================================================================================================== + + +.. raw:: html + + + + + + . + + +
    + + +
             ::= .
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +S_PARAMETER +====================================================================================================================== + + +.. raw:: html + + + + + + $ + + [0-9] + + +
    + + +
             ::= '$' [0-9]+
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_IDENTIFIER +====================================================================================================================== + + +.. raw:: html + + + + + + LETTER + + PART_LETTER + +
    + + +
             ::= LETTER PART_LETTER*
    +
    + + +====================================================================================================================== +LETTER +====================================================================================================================== + + +.. raw:: html + + + + + + UnicodeIdentifierStart + + Nd + $ + + _ + + [#x23] + + +
    + + +
               | Nd
    +
               | [$_#x23]
    +
    + Referenced by: +
    + + +====================================================================================================================== +PART_LETTER +====================================================================================================================== + + +.. raw:: html + + + + + + UnicodeIdentifierStart + + UnicodeIdentifierExtend + $ + + _ + + @ + + [#x23] + + +
    + + +
             ::= UnicodeIdentifierStart
    +
               | UnicodeIdentifierExtend
    +
               | [$_@#x23]
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_AT_IDENTIFIER +====================================================================================================================== + + +.. raw:: html + + + + + + @ + + @ + + S_IDENTIFIER + +
    + + +
             ::= '@' '@'? S_IDENTIFIER
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnicodeIdentifierStart +====================================================================================================================== + + +.. raw:: html + + + + + + [#xB7] + + Ll + + Lm + + Lo + + Lt + + Lu + + Nl + + CJK + +
    + + +
             ::= #xB7
    +
               | Ll
    +
               | Lm
    +
               | Lo
    +
               | Lt
    +
               | Lu
    +
               | Nl
    +
               | CJK
    +
    + Referenced by: +
    + + +====================================================================================================================== +Ll +====================================================================================================================== + + +.. raw:: html + + + + + + [a-z] + + [#xB5] + + [#xDF-#xF6] + + [#xF8-#xFF] + + [#x101] + + [#x103] + + [#x105] + + [#x107] + + [#x109] + + [#x10B] + + [#x10D] + + [#x10F] + + [#x111] + + [#x113] + + [#x115] + + [#x117] + + [#x119] + + [#x11B] + + [#x11D] + + [#x11F] + + [#x121] + + [#x123] + + [#x125] + + [#x127] + + [#x129] + + [#x12B] + + [#x12D] + + [#x12F] + + [#x131] + + [#x133] + + [#x135] + + [#x137-#x138] + + [#x13A] + + [#x13C] + + [#x13E] + + [#x140] + + [#x142] + + [#x144] + + [#x146] + + [#x148-#x149] + + [#x14B] + + [#x14D] + + [#x14F] + + [#x151] + + [#x153] + + [#x155] + + [#x157] + + [#x159] + + [#x15B] + + [#x15D] + + [#x15F] + + [#x161] + + [#x163] + + [#x165] + + [#x167] + + [#x169] + + [#x16B] + + [#x16D] + + [#x16F] + + [#x171] + + [#x173] + + [#x175] + + [#x177] + + [#x17A] + + [#x17C] + + [#x17E-#x180] + + [#x183] + + [#x185] + + [#x188] + + [#x18C-#x18D] + + [#x192] + + [#x195] + + [#x199-#x19B] + + [#x19E] + + [#x1A1] + + [#x1A3] + + [#x1A5] + + [#x1A8] + + [#x1AA-#x1AB] + + [#x1AD] + + [#x1B0] + + [#x1B4] + + [#x1B6] + + [#x1B9-#x1BA] + + [#x1BD-#x1BF] + + [#x1C6] + + [#x1C9] + + [#x1CC] + + [#x1CE] + + [#x1D0] + + [#x1D2] + + [#x1D4] + + [#x1D6] + + [#x1D8] + + [#x1DA] + + [#x1DC-#x1DD] + + [#x1DF] + + [#x1E1] + + [#x1E3] + + [#x1E5] + + [#x1E7] + + [#x1E9] + + [#x1EB] + + [#x1ED] + + [#x1EF-#x1F0] + + [#x1F3] + + [#x1F5] + + [#x1F9] + + [#x1FB] + + [#x1FD] + + [#x1FF] + + [#x201] + + [#x203] + + [#x205] + + [#x207] + + [#x209] + + [#x20B] + + [#x20D] + + [#x20F] + + [#x211] + + [#x213] + + [#x215] + + [#x217] + + [#x219] + + [#x21B] + + [#x21D] + + [#x21F] + + [#x221] + + [#x223] + + [#x225] + + [#x227] + + [#x229] + + [#x22B] + + [#x22D] + + [#x22F] + + [#x231] + + [#x233-#x239] + + [#x23C] + + [#x23F-#x240] + + [#x242] + + [#x247] + + [#x249] + + [#x24B] + + [#x24D] + + [#x24F-#x293] + + [#x295-#x2AF] + + [#x371] + + [#x373] + + [#x377] + + [#x37B-#x37D] + + [#x390] + + [#x3AC-#x3CE] + + [#x3D0-#x3D1] + + [#x3D5-#x3D7] + + [#x3D9] + + [#x3DB] + + [#x3DD] + + [#x3DF] + + [#x3E1] + + [#x3E3] + + [#x3E5] + + [#x3E7] + + [#x3E9] + + [#x3EB] + + [#x3ED] + + [#x3EF-#x3F3] + + [#x3F5] + + [#x3F8] + + [#x3FB-#x3FC] + + [#x430-#x45F] + + [#x461] + + [#x463] + + [#x465] + + [#x467] + + [#x469] + + [#x46B] + + [#x46D] + + [#x46F] + + [#x471] + + [#x473] + + [#x475] + + [#x477] + + [#x479] + + [#x47B] + + [#x47D] + + [#x47F] + + [#x481] + + [#x48B] + + [#x48D] + + [#x48F] + + [#x491] + + [#x493] + + [#x495] + + [#x497] + + [#x499] + + [#x49B] + + [#x49D] + + [#x49F] + + [#x4A1] + + [#x4A3] + + [#x4A5] + + [#x4A7] + + [#x4A9] + + [#x4AB] + + [#x4AD] + + [#x4AF] + + [#x4B1] + + [#x4B3] + + [#x4B5] + + [#x4B7] + + [#x4B9] + + [#x4BB] + + [#x4BD] + + [#x4BF] + + [#x4C2] + + [#x4C4] + + [#x4C6] + + [#x4C8] + + [#x4CA] + + [#x4CC] + + [#x4CE-#x4CF] + + [#x4D1] + + [#x4D3] + + [#x4D5] + + [#x4D7] + + [#x4D9] + + [#x4DB] + + [#x4DD] + + [#x4DF] + + [#x4E1] + + [#x4E3] + + [#x4E5] + + [#x4E7] + + [#x4E9] + + [#x4EB] + + [#x4ED] + + [#x4EF] + + [#x4F1] + + [#x4F3] + + [#x4F5] + + [#x4F7] + + [#x4F9] + + [#x4FB] + + [#x4FD] + + [#x4FF] + + [#x501] + + [#x503] + + [#x505] + + [#x507] + + [#x509] + + [#x50B] + + [#x50D] + + [#x50F] + + [#x511] + + [#x513] + + [#x515] + + [#x517] + + [#x519] + + [#x51B] + + [#x51D] + + [#x51F] + + [#x521] + + [#x523] + + [#x525] + + [#x527] + + [#x529] + + [#x52B] + + [#x52D] + + [#x52F] + + [#x560-#x588] + + [#x10D0-#x10FA] + + [#x10FD-#x10FF] + + [#x13F8-#x13FD] + + [#x1C80-#x1C88] + + [#x1D00-#x1D2B] + + [#x1D6B-#x1D77] + + [#x1D79-#x1D9A] + + [#x1E01] + + [#x1E03] + + [#x1E05] + + [#x1E07] + + [#x1E09] + + [#x1E0B] + + [#x1E0D] + + [#x1E0F] + + [#x1E11] + + [#x1E13] + + [#x1E15] + + [#x1E17] + + [#x1E19] + + [#x1E1B] + + [#x1E1D] + + [#x1E1F] + + [#x1E21] + + [#x1E23] + + [#x1E25] + + [#x1E27] + + [#x1E29] + + [#x1E2B] + + [#x1E2D] + + [#x1E2F] + + [#x1E31] + + [#x1E33] + + [#x1E35] + + [#x1E37] + + [#x1E39] + + [#x1E3B] + + [#x1E3D] + + [#x1E3F] + + [#x1E41] + + [#x1E43] + + [#x1E45] + + [#x1E47] + + [#x1E49] + + [#x1E4B] + + [#x1E4D] + + [#x1E4F] + + [#x1E51] + + [#x1E53] + + [#x1E55] + + [#x1E57] + + [#x1E59] + + [#x1E5B] + + [#x1E5D] + + [#x1E5F] + + [#x1E61] + + [#x1E63] + + [#x1E65] + + [#x1E67] + + [#x1E69] + + [#x1E6B] + + [#x1E6D] + + [#x1E6F] + + [#x1E71] + + [#x1E73] + + [#x1E75] + + [#x1E77] + + [#x1E79] + + [#x1E7B] + + [#x1E7D] + + [#x1E7F] + + [#x1E81] + + [#x1E83] + + [#x1E85] + + [#x1E87] + + [#x1E89] + + [#x1E8B] + + [#x1E8D] + + [#x1E8F] + + [#x1E91] + + [#x1E93] + + [#x1E95-#x1E9D] + + [#x1E9F] + + [#x1EA1] + + [#x1EA3] + + [#x1EA5] + + [#x1EA7] + + [#x1EA9] + + [#x1EAB] + + [#x1EAD] + + [#x1EAF] + + [#x1EB1] + + [#x1EB3] + + [#x1EB5] + + [#x1EB7] + + [#x1EB9] + + [#x1EBB] + + [#x1EBD] + + [#x1EBF] + + [#x1EC1] + + [#x1EC3] + + [#x1EC5] + + [#x1EC7] + + [#x1EC9] + + [#x1ECB] + + [#x1ECD] + + [#x1ECF] + + [#x1ED1] + + [#x1ED3] + + [#x1ED5] + + [#x1ED7] + + [#x1ED9] + + [#x1EDB] + + [#x1EDD] + + [#x1EDF] + + [#x1EE1] + + [#x1EE3] + + [#x1EE5] + + [#x1EE7] + + [#x1EE9] + + [#x1EEB] + + [#x1EED] + + [#x1EEF] + + [#x1EF1] + + [#x1EF3] + + [#x1EF5] + + [#x1EF7] + + [#x1EF9] + + [#x1EFB] + + [#x1EFD] + + [#x1EFF-#x1F07] + + [#x1F10-#x1F15] + + [#x1F20-#x1F27] + + [#x1F30-#x1F37] + + [#x1F40-#x1F45] + + [#x1F50-#x1F57] + + [#x1F60-#x1F67] + + [#x1F70-#x1F7D] + + [#x1F80-#x1F87] + + [#x1F90-#x1F97] + + [#x1FA0-#x1FA7] + + [#x1FB0-#x1FB4] + + [#x1FB6-#x1FB7] + + [#x1FBE] + + [#x1FC2-#x1FC4] + + [#x1FC6-#x1FC7] + + [#x1FD0-#x1FD3] + + [#x1FD6-#x1FD7] + + [#x1FE0-#x1FE7] + + [#x1FF2-#x1FF4] + + [#x1FF6-#x1FF7] + + [#x210A] + + [#x210E-#x210F] + + [#x2113] + + [#x212F] + + [#x2134] + + [#x2139] + + [#x213C-#x213D] + + [#x2146-#x2149] + + [#x214E] + + [#x2184] + + [#x2C30-#x2C5F] + + [#x2C61] + + [#x2C65-#x2C66] + + [#x2C68] + + [#x2C6A] + + [#x2C6C] + + [#x2C71] + + [#x2C73-#x2C74] + + [#x2C76-#x2C7B] + + [#x2C81] + + [#x2C83] + + [#x2C85] + + [#x2C87] + + [#x2C89] + + [#x2C8B] + + [#x2C8D] + + [#x2C8F] + + [#x2C91] + + [#x2C93] + + [#x2C95] + + [#x2C97] + + [#x2C99] + + [#x2C9B] + + [#x2C9D] + + [#x2C9F] + + [#x2CA1] + + [#x2CA3] + + [#x2CA5] + + [#x2CA7] + + [#x2CA9] + + [#x2CAB] + + [#x2CAD] + + [#x2CAF] + + [#x2CB1] + + [#x2CB3] + + [#x2CB5] + + [#x2CB7] + + [#x2CB9] + + [#x2CBB] + + [#x2CBD] + + [#x2CBF] + + [#x2CC1] + + [#x2CC3] + + [#x2CC5] + + [#x2CC7] + + [#x2CC9] + + [#x2CCB] + + [#x2CCD] + + [#x2CCF] + + [#x2CD1] + + [#x2CD3] + + [#x2CD5] + + [#x2CD7] + + [#x2CD9] + + [#x2CDB] + + [#x2CDD] + + [#x2CDF] + + [#x2CE1] + + [#x2CE3-#x2CE4] + + [#x2CEC] + + [#x2CEE] + + [#x2CF3] + + [#x2D00-#x2D25] + + [#x2D27] + + [#x2D2D] + + [#xA641] + + [#xA643] + + [#xA645] + + [#xA647] + + [#xA649] + + [#xA64B] + + [#xA64D] + + [#xA64F] + + [#xA651] + + [#xA653] + + [#xA655] + + [#xA657] + + [#xA659] + + [#xA65B] + + [#xA65D] + + [#xA65F] + + [#xA661] + + [#xA663] + + [#xA665] + + [#xA667] + + [#xA669] + + [#xA66B] + + [#xA66D] + + [#xA681] + + [#xA683] + + [#xA685] + + [#xA687] + + [#xA689] + + [#xA68B] + + [#xA68D] + + [#xA68F] + + [#xA691] + + [#xA693] + + [#xA695] + + [#xA697] + + [#xA699] + + [#xA69B] + + [#xA723] + + [#xA725] + + [#xA727] + + [#xA729] + + [#xA72B] + + [#xA72D] + + [#xA72F-#xA731] + + [#xA733] + + [#xA735] + + [#xA737] + + [#xA739] + + [#xA73B] + + [#xA73D] + + [#xA73F] + + [#xA741] + + [#xA743] + + [#xA745] + + [#xA747] + + [#xA749] + + [#xA74B] + + [#xA74D] + + [#xA74F] + + [#xA751] + + [#xA753] + + [#xA755] + + [#xA757] + + [#xA759] + + [#xA75B] + + [#xA75D] + + [#xA75F] + + [#xA761] + + [#xA763] + + [#xA765] + + [#xA767] + + [#xA769] + + [#xA76B] + + [#xA76D] + + [#xA76F] + + [#xA771-#xA778] + + [#xA77A] + + [#xA77C] + + [#xA77F] + + [#xA781] + + [#xA783] + + [#xA785] + + [#xA787] + + [#xA78C] + + [#xA78E] + + [#xA791] + + [#xA793-#xA795] + + [#xA797] + + [#xA799] + + [#xA79B] + + [#xA79D] + + [#xA79F] + + [#xA7A1] + + [#xA7A3] + + [#xA7A5] + + [#xA7A7] + + [#xA7A9] + + [#xA7AF] + + [#xA7B5] + + [#xA7B7] + + [#xA7B9] + + [#xA7BB] + + [#xA7BD] + + [#xA7BF] + + [#xA7C1] + + [#xA7C3] + + [#xA7C8] + + [#xA7CA] + + [#xA7D1] + + [#xA7D3] + + [#xA7D5] + + [#xA7D7] + + [#xA7D9] + + [#xA7F6] + + [#xA7FA] + + [#xAB30-#xAB5A] + + [#xAB60-#xAB68] + + [#xAB70-#xABBF] + + [#xFB00-#xFB06] + + [#xFB13-#xFB17] + + [#xFF41-#xFF5A] + + +
    + +
    Ll       ::= [a-z#xB5#xDF-#xF6#xF8-#xFF#x101#x103#x105#x107#x109#x10B#x10D#x10F#x111#x113#x115#x117#x119#x11B#x11D#x11F#x121#x123#x125#x127#x129#x12B#x12D#x12F#x131#x133#x135#x137-#x138#x13A#x13C#x13E#x140#x142#x144#x146#x148-#x149#x14B#x14D#x14F#x151#x153#x155#x157#x159#x15B#x15D#x15F#x161#x163#x165#x167#x169#x16B#x16D#x16F#x171#x173#x175#x177#x17A#x17C#x17E-#x180#x183#x185#x188#x18C-#x18D#x192#x195#x199-#x19B#x19E#x1A1#x1A3#x1A5#x1A8#x1AA-#x1AB#x1AD#x1B0#x1B4#x1B6#x1B9-#x1BA#x1BD-#x1BF#x1C6#x1C9#x1CC#x1CE#x1D0#x1D2#x1D4#x1D6#x1D8#x1DA#x1DC-#x1DD#x1DF#x1E1#x1E3#x1E5#x1E7#x1E9#x1EB#x1ED#x1EF-#x1F0#x1F3#x1F5#x1F9#x1FB#x1FD#x1FF#x201#x203#x205#x207#x209#x20B#x20D#x20F#x211#x213#x215#x217#x219#x21B#x21D#x21F#x221#x223#x225#x227#x229#x22B#x22D#x22F#x231#x233-#x239#x23C#x23F-#x240#x242#x247#x249#x24B#x24D#x24F-#x293#x295-#x2AF#x371#x373#x377#x37B-#x37D#x390#x3AC-#x3CE#x3D0-#x3D1#x3D5-#x3D7#x3D9#x3DB#x3DD#x3DF#x3E1#x3E3#x3E5#x3E7#x3E9#x3EB#x3ED#x3EF-#x3F3#x3F5#x3F8#x3FB-#x3FC#x430-#x45F#x461#x463#x465#x467#x469#x46B#x46D#x46F#x471#x473#x475#x477#x479#x47B#x47D#x47F#x481#x48B#x48D#x48F#x491#x493#x495#x497#x499#x49B#x49D#x49F#x4A1#x4A3#x4A5#x4A7#x4A9#x4AB#x4AD#x4AF#x4B1#x4B3#x4B5#x4B7#x4B9#x4BB#x4BD#x4BF#x4C2#x4C4#x4C6#x4C8#x4CA#x4CC#x4CE-#x4CF#x4D1#x4D3#x4D5#x4D7#x4D9#x4DB#x4DD#x4DF#x4E1#x4E3#x4E5#x4E7#x4E9#x4EB#x4ED#x4EF#x4F1#x4F3#x4F5#x4F7#x4F9#x4FB#x4FD#x4FF#x501#x503#x505#x507#x509#x50B#x50D#x50F#x511#x513#x515#x517#x519#x51B#x51D#x51F#x521#x523#x525#x527#x529#x52B#x52D#x52F#x560-#x588#x10D0-#x10FA#x10FD-#x10FF#x13F8-#x13FD#x1C80-#x1C88#x1D00-#x1D2B#x1D6B-#x1D77#x1D79-#x1D9A#x1E01#x1E03#x1E05#x1E07#x1E09#x1E0B#x1E0D#x1E0F#x1E11#x1E13#x1E15#x1E17#x1E19#x1E1B#x1E1D#x1E1F#x1E21#x1E23#x1E25#x1E27#x1E29#x1E2B#x1E2D#x1E2F#x1E31#x1E33#x1E35#x1E37#x1E39#x1E3B#x1E3D#x1E3F#x1E41#x1E43#x1E45#x1E47#x1E49#x1E4B#x1E4D#x1E4F#x1E51#x1E53#x1E55#x1E57#x1E59#x1E5B#x1E5D#x1E5F#x1E61#x1E63#x1E65#x1E67#x1E69#x1E6B#x1E6D#x1E6F#x1E71#x1E73#x1E75#x1E77#x1E79#x1E7B#x1E7D#x1E7F#x1E81#x1E83#x1E85#x1E87#x1E89#x1E8B#x1E8D#x1E8F#x1E91#x1E93#x1E95-#x1E9D#x1E9F#x1EA1#x1EA3#x1EA5#x1EA7#x1EA9#x1EAB#x1EAD#x1EAF#x1EB1#x1EB3#x1EB5#x1EB7#x1EB9#x1EBB#x1EBD#x1EBF#x1EC1#x1EC3#x1EC5#x1EC7#x1EC9#x1ECB#x1ECD#x1ECF#x1ED1#x1ED3#x1ED5#x1ED7#x1ED9#x1EDB#x1EDD#x1EDF#x1EE1#x1EE3#x1EE5#x1EE7#x1EE9#x1EEB#x1EED#x1EEF#x1EF1#x1EF3#x1EF5#x1EF7#x1EF9#x1EFB#x1EFD#x1EFF-#x1F07#x1F10-#x1F15#x1F20-#x1F27#x1F30-#x1F37#x1F40-#x1F45#x1F50-#x1F57#x1F60-#x1F67#x1F70-#x1F7D#x1F80-#x1F87#x1F90-#x1F97#x1FA0-#x1FA7#x1FB0-#x1FB4#x1FB6-#x1FB7#x1FBE#x1FC2-#x1FC4#x1FC6-#x1FC7#x1FD0-#x1FD3#x1FD6-#x1FD7#x1FE0-#x1FE7#x1FF2-#x1FF4#x1FF6-#x1FF7#x210A#x210E-#x210F#x2113#x212F#x2134#x2139#x213C-#x213D#x2146-#x2149#x214E#x2184#x2C30-#x2C5F#x2C61#x2C65-#x2C66#x2C68#x2C6A#x2C6C#x2C71#x2C73-#x2C74#x2C76-#x2C7B#x2C81#x2C83#x2C85#x2C87#x2C89#x2C8B#x2C8D#x2C8F#x2C91#x2C93#x2C95#x2C97#x2C99#x2C9B#x2C9D#x2C9F#x2CA1#x2CA3#x2CA5#x2CA7#x2CA9#x2CAB#x2CAD#x2CAF#x2CB1#x2CB3#x2CB5#x2CB7#x2CB9#x2CBB#x2CBD#x2CBF#x2CC1#x2CC3#x2CC5#x2CC7#x2CC9#x2CCB#x2CCD#x2CCF#x2CD1#x2CD3#x2CD5#x2CD7#x2CD9#x2CDB#x2CDD#x2CDF#x2CE1#x2CE3-#x2CE4#x2CEC#x2CEE#x2CF3#x2D00-#x2D25#x2D27#x2D2D#xA641#xA643#xA645#xA647#xA649#xA64B#xA64D#xA64F#xA651#xA653#xA655#xA657#xA659#xA65B#xA65D#xA65F#xA661#xA663#xA665#xA667#xA669#xA66B#xA66D#xA681#xA683#xA685#xA687#xA689#xA68B#xA68D#xA68F#xA691#xA693#xA695#xA697#xA699#xA69B#xA723#xA725#xA727#xA729#xA72B#xA72D#xA72F-#xA731#xA733#xA735#xA737#xA739#xA73B#xA73D#xA73F#xA741#xA743#xA745#xA747#xA749#xA74B#xA74D#xA74F#xA751#xA753#xA755#xA757#xA759#xA75B#xA75D#xA75F#xA761#xA763#xA765#xA767#xA769#xA76B#xA76D#xA76F#xA771-#xA778#xA77A#xA77C#xA77F#xA781#xA783#xA785#xA787#xA78C#xA78E#xA791#xA793-#xA795#xA797#xA799#xA79B#xA79D#xA79F#xA7A1#xA7A3#xA7A5#xA7A7#xA7A9#xA7AF#xA7B5#xA7B7#xA7B9#xA7BB#xA7BD#xA7BF#xA7C1#xA7C3#xA7C8#xA7CA#xA7D1#xA7D3#xA7D5#xA7D7#xA7D9#xA7F6#xA7FA#xAB30-#xAB5A#xAB60-#xAB68#xAB70-#xABBF#xFB00-#xFB06#xFB13-#xFB17#xFF41-#xFF5A]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Lm +====================================================================================================================== + + +.. raw:: html + + + + + + [#x2B0-#x2C1] + + [#x2C6-#x2D1] + + [#x2E0-#x2E4] + + [#x2EC] + + [#x2EE] + + [#x374] + + [#x37A] + + [#x559] + + [#x640] + + [#x6E5-#x6E6] + + [#x7F4-#x7F5] + + [#x7FA] + + [#x81A] + + [#x824] + + [#x828] + + [#x8C9] + + [#x971] + + [#xE46] + + [#xEC6] + + [#x10FC] + + [#x17D7] + + [#x1843] + + [#x1AA7] + + [#x1C78-#x1C7D] + + [#x1D2C-#x1D6A] + + [#x1D78] + + [#x1D9B-#x1DBF] + + [#x2071] + + [#x207F] + + [#x2090-#x209C] + + [#x2C7C-#x2C7D] + + [#x2D6F] + + [#x2E2F] + + [#x3005] + + [#x3031-#x3035] + + [#x303B] + + [#x309D-#x309E] + + [#x30FC-#x30FE] + + [#xA015] + + [#xA4F8-#xA4FD] + + [#xA60C] + + [#xA67F] + + [#xA69C-#xA69D] + + [#xA717-#xA71F] + + [#xA770] + + [#xA788] + + [#xA7F2-#xA7F4] + + [#xA7F8-#xA7F9] + + [#xA9CF] + + [#xA9E6] + + [#xAA70] + + [#xAADD] + + [#xAAF3-#xAAF4] + + [#xAB5C-#xAB5F] + + [#xAB69] + + [#xFF70] + + [#xFF9E-#xFF9F] + + +
    + +
    Lm       ::= [#x2B0-#x2C1#x2C6-#x2D1#x2E0-#x2E4#x2EC#x2EE#x374#x37A#x559#x640#x6E5-#x6E6#x7F4-#x7F5#x7FA#x81A#x824#x828#x8C9#x971#xE46#xEC6#x10FC#x17D7#x1843#x1AA7#x1C78-#x1C7D#x1D2C-#x1D6A#x1D78#x1D9B-#x1DBF#x2071#x207F#x2090-#x209C#x2C7C-#x2C7D#x2D6F#x2E2F#x3005#x3031-#x3035#x303B#x309D-#x309E#x30FC-#x30FE#xA015#xA4F8-#xA4FD#xA60C#xA67F#xA69C-#xA69D#xA717-#xA71F#xA770#xA788#xA7F2-#xA7F4#xA7F8-#xA7F9#xA9CF#xA9E6#xAA70#xAADD#xAAF3-#xAAF4#xAB5C-#xAB5F#xAB69#xFF70#xFF9E-#xFF9F]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Lo +====================================================================================================================== + + +.. raw:: html + + + + + + [#xAA] + + [#xBA] + + [#x1BB] + + [#x1C0-#x1C3] + + [#x294] + + [#x5D0-#x5EA] + + [#x5EF-#x5F2] + + [#x620-#x63F] + + [#x641-#x64A] + + [#x66E-#x66F] + + [#x671-#x6D3] + + [#x6D5] + + [#x6EE-#x6EF] + + [#x6FA-#x6FC] + + [#x6FF] + + [#x710] + + [#x712-#x72F] + + [#x74D-#x7A5] + + [#x7B1] + + [#x7CA-#x7EA] + + [#x800-#x815] + + [#x840-#x858] + + [#x860-#x86A] + + [#x870-#x887] + + [#x889-#x88E] + + [#x8A0-#x8C8] + + [#x904-#x939] + + [#x93D] + + [#x950] + + [#x958-#x961] + + [#x972-#x980] + + [#x985-#x98C] + + [#x98F-#x990] + + [#x993-#x9A8] + + [#x9AA-#x9B0] + + [#x9B2] + + [#x9B6-#x9B9] + + [#x9BD] + + [#x9CE] + + [#x9DC-#x9DD] + + [#x9DF-#x9E1] + + [#x9F0-#x9F1] + + [#x9FC] + + [#xA05-#xA0A] + + [#xA0F-#xA10] + + [#xA13-#xA28] + + [#xA2A-#xA30] + + [#xA32-#xA33] + + [#xA35-#xA36] + + [#xA38-#xA39] + + [#xA59-#xA5C] + + [#xA5E] + + [#xA72-#xA74] + + [#xA85-#xA8D] + + [#xA8F-#xA91] + + [#xA93-#xAA8] + + [#xAAA-#xAB0] + + [#xAB2-#xAB3] + + [#xAB5-#xAB9] + + [#xABD] + + [#xAD0] + + [#xAE0-#xAE1] + + [#xAF9] + + [#xB05-#xB0C] + + [#xB0F-#xB10] + + [#xB13-#xB28] + + [#xB2A-#xB30] + + [#xB32-#xB33] + + [#xB35-#xB39] + + [#xB3D] + + [#xB5C-#xB5D] + + [#xB5F-#xB61] + + [#xB71] + + [#xB83] + + [#xB85-#xB8A] + + [#xB8E-#xB90] + + [#xB92-#xB95] + + [#xB99-#xB9A] + + [#xB9C] + + [#xB9E-#xB9F] + + [#xBA3-#xBA4] + + [#xBA8-#xBAA] + + [#xBAE-#xBB9] + + [#xBD0] + + [#xC05-#xC0C] + + [#xC0E-#xC10] + + [#xC12-#xC28] + + [#xC2A-#xC39] + + [#xC3D] + + [#xC58-#xC5A] + + [#xC5D] + + [#xC60-#xC61] + + [#xC80] + + [#xC85-#xC8C] + + [#xC8E-#xC90] + + [#xC92-#xCA8] + + [#xCAA-#xCB3] + + [#xCB5-#xCB9] + + [#xCBD] + + [#xCDD-#xCDE] + + [#xCE0-#xCE1] + + [#xCF1-#xCF2] + + [#xD04-#xD0C] + + [#xD0E-#xD10] + + [#xD12-#xD3A] + + [#xD3D] + + [#xD4E] + + [#xD54-#xD56] + + [#xD5F-#xD61] + + [#xD7A-#xD7F] + + [#xD85-#xD96] + + [#xD9A-#xDB1] + + [#xDB3-#xDBB] + + [#xDBD] + + [#xDC0-#xDC6] + + [#xE01-#xE30] + + [#xE32-#xE33] + + [#xE40-#xE45] + + [#xE81-#xE82] + + [#xE84] + + [#xE86-#xE8A] + + [#xE8C-#xEA3] + + [#xEA5] + + [#xEA7-#xEB0] + + [#xEB2-#xEB3] + + [#xEBD] + + [#xEC0-#xEC4] + + [#xEDC-#xEDF] + + [#xF00] + + [#xF40-#xF47] + + [#xF49-#xF6C] + + [#xF88-#xF8C] + + [#x1000-#x102A] + + [#x103F] + + [#x1050-#x1055] + + [#x105A-#x105D] + + [#x1061] + + [#x1065-#x1066] + + [#x106E-#x1070] + + [#x1075-#x1081] + + [#x108E] + + [#x1100-#x1248] + + [#x124A-#x124D] + + [#x1250-#x1256] + + [#x1258] + + [#x125A-#x125D] + + [#x1260-#x1288] + + [#x128A-#x128D] + + [#x1290-#x12B0] + + [#x12B2-#x12B5] + + [#x12B8-#x12BE] + + [#x12C0] + + [#x12C2-#x12C5] + + [#x12C8-#x12D6] + + [#x12D8-#x1310] + + [#x1312-#x1315] + + [#x1318-#x135A] + + [#x1380-#x138F] + + [#x1401-#x166C] + + [#x166F-#x167F] + + [#x1681-#x169A] + + [#x16A0-#x16EA] + + [#x16F1-#x16F8] + + [#x1700-#x1711] + + [#x171F-#x1731] + + [#x1740-#x1751] + + [#x1760-#x176C] + + [#x176E-#x1770] + + [#x1780-#x17B3] + + [#x17DC] + + [#x1820-#x1842] + + [#x1844-#x1878] + + [#x1880-#x1884] + + [#x1887-#x18A8] + + [#x18AA] + + [#x18B0-#x18F5] + + [#x1900-#x191E] + + [#x1950-#x196D] + + [#x1970-#x1974] + + [#x1980-#x19AB] + + [#x19B0-#x19C9] + + [#x1A00-#x1A16] + + [#x1A20-#x1A54] + + [#x1B05-#x1B33] + + [#x1B45-#x1B4C] + + [#x1B83-#x1BA0] + + [#x1BAE-#x1BAF] + + [#x1BBA-#x1BE5] + + [#x1C00-#x1C23] + + [#x1C4D-#x1C4F] + + [#x1C5A-#x1C77] + + [#x1CE9-#x1CEC] + + [#x1CEE-#x1CF3] + + [#x1CF5-#x1CF6] + + [#x1CFA] + + [#x2135-#x2138] + + [#x2D30-#x2D67] + + [#x2D80-#x2D96] + + [#x2DA0-#x2DA6] + + [#x2DA8-#x2DAE] + + [#x2DB0-#x2DB6] + + [#x2DB8-#x2DBE] + + [#x2DC0-#x2DC6] + + [#x2DC8-#x2DCE] + + [#x2DD0-#x2DD6] + + [#x2DD8-#x2DDE] + + [#x3006] + + [#x303C] + + [#x3041-#x3096] + + [#x309F] + + [#x30A1-#x30FA] + + [#x30FF] + + [#x3105-#x312F] + + [#x3131-#x318E] + + [#x31A0-#x31BF] + + [#x31F0-#x31FF] + + [#x4DBF] + + [#x9FFF-#xA014] + + [#xA016-#xA48C] + + [#xA4D0-#xA4F7] + + [#xA500-#xA60B] + + [#xA610-#xA61F] + + [#xA62A-#xA62B] + + [#xA66E] + + [#xA6A0-#xA6E5] + + [#xA78F] + + [#xA7F7] + + [#xA7FB-#xA801] + + [#xA803-#xA805] + + [#xA807-#xA80A] + + [#xA80C-#xA822] + + [#xA840-#xA873] + + [#xA882-#xA8B3] + + [#xA8F2-#xA8F7] + + [#xA8FB] + + [#xA8FD-#xA8FE] + + [#xA90A-#xA925] + + [#xA930-#xA946] + + [#xA960-#xA97C] + + [#xA984-#xA9B2] + + [#xA9E0-#xA9E4] + + [#xA9E7-#xA9EF] + + [#xA9FA-#xA9FE] + + [#xAA00-#xAA28] + + [#xAA40-#xAA42] + + [#xAA44-#xAA4B] + + [#xAA60-#xAA6F] + + [#xAA71-#xAA76] + + [#xAA7A] + + [#xAA7E-#xAAAF] + + [#xAAB1] + + [#xAAB5-#xAAB6] + + [#xAAB9-#xAABD] + + [#xAAC0] + + [#xAAC2] + + [#xAADB-#xAADC] + + [#xAAE0-#xAAEA] + + [#xAAF2] + + [#xAB01-#xAB06] + + [#xAB09-#xAB0E] + + [#xAB11-#xAB16] + + [#xAB20-#xAB26] + + [#xAB28-#xAB2E] + + [#xABC0-#xABE2] + + [#xD7A3] + + [#xD7B0-#xD7C6] + + [#xD7CB-#xD7FB] + + [#xF900-#xFA6D] + + [#xFA70-#xFAD9] + + [#xFB1D] + + [#xFB1F-#xFB28] + + [#xFB2A-#xFB36] + + [#xFB38-#xFB3C] + + [#xFB3E] + + [#xFB40-#xFB41] + + [#xFB43-#xFB44] + + [#xFB46-#xFBB1] + + [#xFBD3-#xFD3D] + + [#xFD50-#xFD8F] + + [#xFD92-#xFDC7] + + [#xFDF0-#xFDFB] + + [#xFE70-#xFE74] + + [#xFE76-#xFEFC] + + [#xFF66-#xFF6F] + + [#xFF71-#xFF9D] + + [#xFFA0-#xFFBE] + + [#xFFC2-#xFFC7] + + [#xFFCA-#xFFCF] + + [#xFFD2-#xFFD7] + + [#xFFDA-#xFFDC] + + +
    + +
    Lo       ::= [#xAA#xBA#x1BB#x1C0-#x1C3#x294#x5D0-#x5EA#x5EF-#x5F2#x620-#x63F#x641-#x64A#x66E-#x66F#x671-#x6D3#x6D5#x6EE-#x6EF#x6FA-#x6FC#x6FF#x710#x712-#x72F#x74D-#x7A5#x7B1#x7CA-#x7EA#x800-#x815#x840-#x858#x860-#x86A#x870-#x887#x889-#x88E#x8A0-#x8C8#x904-#x939#x93D#x950#x958-#x961#x972-#x980#x985-#x98C#x98F-#x990#x993-#x9A8#x9AA-#x9B0#x9B2#x9B6-#x9B9#x9BD#x9CE#x9DC-#x9DD#x9DF-#x9E1#x9F0-#x9F1#x9FC#xA05-#xA0A#xA0F-#xA10#xA13-#xA28#xA2A-#xA30#xA32-#xA33#xA35-#xA36#xA38-#xA39#xA59-#xA5C#xA5E#xA72-#xA74#xA85-#xA8D#xA8F-#xA91#xA93-#xAA8#xAAA-#xAB0#xAB2-#xAB3#xAB5-#xAB9#xABD#xAD0#xAE0-#xAE1#xAF9#xB05-#xB0C#xB0F-#xB10#xB13-#xB28#xB2A-#xB30#xB32-#xB33#xB35-#xB39#xB3D#xB5C-#xB5D#xB5F-#xB61#xB71#xB83#xB85-#xB8A#xB8E-#xB90#xB92-#xB95#xB99-#xB9A#xB9C#xB9E-#xB9F#xBA3-#xBA4#xBA8-#xBAA#xBAE-#xBB9#xBD0#xC05-#xC0C#xC0E-#xC10#xC12-#xC28#xC2A-#xC39#xC3D#xC58-#xC5A#xC5D#xC60-#xC61#xC80#xC85-#xC8C#xC8E-#xC90#xC92-#xCA8#xCAA-#xCB3#xCB5-#xCB9#xCBD#xCDD-#xCDE#xCE0-#xCE1#xCF1-#xCF2#xD04-#xD0C#xD0E-#xD10#xD12-#xD3A#xD3D#xD4E#xD54-#xD56#xD5F-#xD61#xD7A-#xD7F#xD85-#xD96#xD9A-#xDB1#xDB3-#xDBB#xDBD#xDC0-#xDC6#xE01-#xE30#xE32-#xE33#xE40-#xE45#xE81-#xE82#xE84#xE86-#xE8A#xE8C-#xEA3#xEA5#xEA7-#xEB0#xEB2-#xEB3#xEBD#xEC0-#xEC4#xEDC-#xEDF#xF00#xF40-#xF47#xF49-#xF6C#xF88-#xF8C#x1000-#x102A#x103F#x1050-#x1055#x105A-#x105D#x1061#x1065-#x1066#x106E-#x1070#x1075-#x1081#x108E#x1100-#x1248#x124A-#x124D#x1250-#x1256#x1258#x125A-#x125D#x1260-#x1288#x128A-#x128D#x1290-#x12B0#x12B2-#x12B5#x12B8-#x12BE#x12C0#x12C2-#x12C5#x12C8-#x12D6#x12D8-#x1310#x1312-#x1315#x1318-#x135A#x1380-#x138F#x1401-#x166C#x166F-#x167F#x1681-#x169A#x16A0-#x16EA#x16F1-#x16F8#x1700-#x1711#x171F-#x1731#x1740-#x1751#x1760-#x176C#x176E-#x1770#x1780-#x17B3#x17DC#x1820-#x1842#x1844-#x1878#x1880-#x1884#x1887-#x18A8#x18AA#x18B0-#x18F5#x1900-#x191E#x1950-#x196D#x1970-#x1974#x1980-#x19AB#x19B0-#x19C9#x1A00-#x1A16#x1A20-#x1A54#x1B05-#x1B33#x1B45-#x1B4C#x1B83-#x1BA0#x1BAE-#x1BAF#x1BBA-#x1BE5#x1C00-#x1C23#x1C4D-#x1C4F#x1C5A-#x1C77#x1CE9-#x1CEC#x1CEE-#x1CF3#x1CF5-#x1CF6#x1CFA#x2135-#x2138#x2D30-#x2D67#x2D80-#x2D96#x2DA0-#x2DA6#x2DA8-#x2DAE#x2DB0-#x2DB6#x2DB8-#x2DBE#x2DC0-#x2DC6#x2DC8-#x2DCE#x2DD0-#x2DD6#x2DD8-#x2DDE#x3006#x303C#x3041-#x3096#x309F#x30A1-#x30FA#x30FF#x3105-#x312F#x3131-#x318E#x31A0-#x31BF#x31F0-#x31FF#x4DBF#x9FFF-#xA014#xA016-#xA48C#xA4D0-#xA4F7#xA500-#xA60B#xA610-#xA61F#xA62A-#xA62B#xA66E#xA6A0-#xA6E5#xA78F#xA7F7#xA7FB-#xA801#xA803-#xA805#xA807-#xA80A#xA80C-#xA822#xA840-#xA873#xA882-#xA8B3#xA8F2-#xA8F7#xA8FB#xA8FD-#xA8FE#xA90A-#xA925#xA930-#xA946#xA960-#xA97C#xA984-#xA9B2#xA9E0-#xA9E4#xA9E7-#xA9EF#xA9FA-#xA9FE#xAA00-#xAA28#xAA40-#xAA42#xAA44-#xAA4B#xAA60-#xAA6F#xAA71-#xAA76#xAA7A#xAA7E-#xAAAF#xAAB1#xAAB5-#xAAB6#xAAB9-#xAABD#xAAC0#xAAC2#xAADB-#xAADC#xAAE0-#xAAEA#xAAF2#xAB01-#xAB06#xAB09-#xAB0E#xAB11-#xAB16#xAB20-#xAB26#xAB28-#xAB2E#xABC0-#xABE2#xD7A3#xD7B0-#xD7C6#xD7CB-#xD7FB#xF900-#xFA6D#xFA70-#xFAD9#xFB1D#xFB1F-#xFB28#xFB2A-#xFB36#xFB38-#xFB3C#xFB3E#xFB40-#xFB41#xFB43-#xFB44#xFB46-#xFBB1#xFBD3-#xFD3D#xFD50-#xFD8F#xFD92-#xFDC7#xFDF0-#xFDFB#xFE70-#xFE74#xFE76-#xFEFC#xFF66-#xFF6F#xFF71-#xFF9D#xFFA0-#xFFBE#xFFC2-#xFFC7#xFFCA-#xFFCF#xFFD2-#xFFD7#xFFDA-#xFFDC]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Lt +====================================================================================================================== + + +.. raw:: html + + + + + + [#x1C5] + + [#x1C8] + + [#x1CB] + + [#x1F2] + + [#x1F88-#x1F8F] + + [#x1F98-#x1F9F] + + [#x1FA8-#x1FAF] + + [#x1FBC] + + [#x1FCC] + + [#x1FFC] + + +
    + +
    Lt       ::= [#x1C5#x1C8#x1CB#x1F2#x1F88-#x1F8F#x1F98-#x1F9F#x1FA8-#x1FAF#x1FBC#x1FCC#x1FFC]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Lu +====================================================================================================================== + + +.. raw:: html + + + + + + [A-Z] + + [#xC0-#xD6] + + [#xD8-#xDE] + + [#x100] + + [#x102] + + [#x104] + + [#x106] + + [#x108] + + [#x10A] + + [#x10C] + + [#x10E] + + [#x110] + + [#x112] + + [#x114] + + [#x116] + + [#x118] + + [#x11A] + + [#x11C] + + [#x11E] + + [#x120] + + [#x122] + + [#x124] + + [#x126] + + [#x128] + + [#x12A] + + [#x12C] + + [#x12E] + + [#x130] + + [#x132] + + [#x134] + + [#x136] + + [#x139] + + [#x13B] + + [#x13D] + + [#x13F] + + [#x141] + + [#x143] + + [#x145] + + [#x147] + + [#x14A] + + [#x14C] + + [#x14E] + + [#x150] + + [#x152] + + [#x154] + + [#x156] + + [#x158] + + [#x15A] + + [#x15C] + + [#x15E] + + [#x160] + + [#x162] + + [#x164] + + [#x166] + + [#x168] + + [#x16A] + + [#x16C] + + [#x16E] + + [#x170] + + [#x172] + + [#x174] + + [#x176] + + [#x178-#x179] + + [#x17B] + + [#x17D] + + [#x181-#x182] + + [#x184] + + [#x186-#x187] + + [#x189-#x18B] + + [#x18E-#x191] + + [#x193-#x194] + + [#x196-#x198] + + [#x19C-#x19D] + + [#x19F-#x1A0] + + [#x1A2] + + [#x1A4] + + [#x1A6-#x1A7] + + [#x1A9] + + [#x1AC] + + [#x1AE-#x1AF] + + [#x1B1-#x1B3] + + [#x1B5] + + [#x1B7-#x1B8] + + [#x1BC] + + [#x1C4] + + [#x1C7] + + [#x1CA] + + [#x1CD] + + [#x1CF] + + [#x1D1] + + [#x1D3] + + [#x1D5] + + [#x1D7] + + [#x1D9] + + [#x1DB] + + [#x1DE] + + [#x1E0] + + [#x1E2] + + [#x1E4] + + [#x1E6] + + [#x1E8] + + [#x1EA] + + [#x1EC] + + [#x1EE] + + [#x1F1] + + [#x1F4] + + [#x1F6-#x1F8] + + [#x1FA] + + [#x1FC] + + [#x1FE] + + [#x200] + + [#x202] + + [#x204] + + [#x206] + + [#x208] + + [#x20A] + + [#x20C] + + [#x20E] + + [#x210] + + [#x212] + + [#x214] + + [#x216] + + [#x218] + + [#x21A] + + [#x21C] + + [#x21E] + + [#x220] + + [#x222] + + [#x224] + + [#x226] + + [#x228] + + [#x22A] + + [#x22C] + + [#x22E] + + [#x230] + + [#x232] + + [#x23A-#x23B] + + [#x23D-#x23E] + + [#x241] + + [#x243-#x246] + + [#x248] + + [#x24A] + + [#x24C] + + [#x24E] + + [#x370] + + [#x372] + + [#x376] + + [#x37F] + + [#x386] + + [#x388-#x38A] + + [#x38C] + + [#x38E-#x38F] + + [#x391-#x3A1] + + [#x3A3-#x3AB] + + [#x3CF] + + [#x3D2-#x3D4] + + [#x3D8] + + [#x3DA] + + [#x3DC] + + [#x3DE] + + [#x3E0] + + [#x3E2] + + [#x3E4] + + [#x3E6] + + [#x3E8] + + [#x3EA] + + [#x3EC] + + [#x3EE] + + [#x3F4] + + [#x3F7] + + [#x3F9-#x3FA] + + [#x3FD-#x42F] + + [#x460] + + [#x462] + + [#x464] + + [#x466] + + [#x468] + + [#x46A] + + [#x46C] + + [#x46E] + + [#x470] + + [#x472] + + [#x474] + + [#x476] + + [#x478] + + [#x47A] + + [#x47C] + + [#x47E] + + [#x480] + + [#x48A] + + [#x48C] + + [#x48E] + + [#x490] + + [#x492] + + [#x494] + + [#x496] + + [#x498] + + [#x49A] + + [#x49C] + + [#x49E] + + [#x4A0] + + [#x4A2] + + [#x4A4] + + [#x4A6] + + [#x4A8] + + [#x4AA] + + [#x4AC] + + [#x4AE] + + [#x4B0] + + [#x4B2] + + [#x4B4] + + [#x4B6] + + [#x4B8] + + [#x4BA] + + [#x4BC] + + [#x4BE] + + [#x4C0-#x4C1] + + [#x4C3] + + [#x4C5] + + [#x4C7] + + [#x4C9] + + [#x4CB] + + [#x4CD] + + [#x4D0] + + [#x4D2] + + [#x4D4] + + [#x4D6] + + [#x4D8] + + [#x4DA] + + [#x4DC] + + [#x4DE] + + [#x4E0] + + [#x4E2] + + [#x4E4] + + [#x4E6] + + [#x4E8] + + [#x4EA] + + [#x4EC] + + [#x4EE] + + [#x4F0] + + [#x4F2] + + [#x4F4] + + [#x4F6] + + [#x4F8] + + [#x4FA] + + [#x4FC] + + [#x4FE] + + [#x500] + + [#x502] + + [#x504] + + [#x506] + + [#x508] + + [#x50A] + + [#x50C] + + [#x50E] + + [#x510] + + [#x512] + + [#x514] + + [#x516] + + [#x518] + + [#x51A] + + [#x51C] + + [#x51E] + + [#x520] + + [#x522] + + [#x524] + + [#x526] + + [#x528] + + [#x52A] + + [#x52C] + + [#x52E] + + [#x531-#x556] + + [#x10A0-#x10C5] + + [#x10C7] + + [#x10CD] + + [#x13A0-#x13F5] + + [#x1C90-#x1CBA] + + [#x1CBD-#x1CBF] + + [#x1E00] + + [#x1E02] + + [#x1E04] + + [#x1E06] + + [#x1E08] + + [#x1E0A] + + [#x1E0C] + + [#x1E0E] + + [#x1E10] + + [#x1E12] + + [#x1E14] + + [#x1E16] + + [#x1E18] + + [#x1E1A] + + [#x1E1C] + + [#x1E1E] + + [#x1E20] + + [#x1E22] + + [#x1E24] + + [#x1E26] + + [#x1E28] + + [#x1E2A] + + [#x1E2C] + + [#x1E2E] + + [#x1E30] + + [#x1E32] + + [#x1E34] + + [#x1E36] + + [#x1E38] + + [#x1E3A] + + [#x1E3C] + + [#x1E3E] + + [#x1E40] + + [#x1E42] + + [#x1E44] + + [#x1E46] + + [#x1E48] + + [#x1E4A] + + [#x1E4C] + + [#x1E4E] + + [#x1E50] + + [#x1E52] + + [#x1E54] + + [#x1E56] + + [#x1E58] + + [#x1E5A] + + [#x1E5C] + + [#x1E5E] + + [#x1E60] + + [#x1E62] + + [#x1E64] + + [#x1E66] + + [#x1E68] + + [#x1E6A] + + [#x1E6C] + + [#x1E6E] + + [#x1E70] + + [#x1E72] + + [#x1E74] + + [#x1E76] + + [#x1E78] + + [#x1E7A] + + [#x1E7C] + + [#x1E7E] + + [#x1E80] + + [#x1E82] + + [#x1E84] + + [#x1E86] + + [#x1E88] + + [#x1E8A] + + [#x1E8C] + + [#x1E8E] + + [#x1E90] + + [#x1E92] + + [#x1E94] + + [#x1E9E] + + [#x1EA0] + + [#x1EA2] + + [#x1EA4] + + [#x1EA6] + + [#x1EA8] + + [#x1EAA] + + [#x1EAC] + + [#x1EAE] + + [#x1EB0] + + [#x1EB2] + + [#x1EB4] + + [#x1EB6] + + [#x1EB8] + + [#x1EBA] + + [#x1EBC] + + [#x1EBE] + + [#x1EC0] + + [#x1EC2] + + [#x1EC4] + + [#x1EC6] + + [#x1EC8] + + [#x1ECA] + + [#x1ECC] + + [#x1ECE] + + [#x1ED0] + + [#x1ED2] + + [#x1ED4] + + [#x1ED6] + + [#x1ED8] + + [#x1EDA] + + [#x1EDC] + + [#x1EDE] + + [#x1EE0] + + [#x1EE2] + + [#x1EE4] + + [#x1EE6] + + [#x1EE8] + + [#x1EEA] + + [#x1EEC] + + [#x1EEE] + + [#x1EF0] + + [#x1EF2] + + [#x1EF4] + + [#x1EF6] + + [#x1EF8] + + [#x1EFA] + + [#x1EFC] + + [#x1EFE] + + [#x1F08-#x1F0F] + + [#x1F18-#x1F1D] + + [#x1F28-#x1F2F] + + [#x1F38-#x1F3F] + + [#x1F48-#x1F4D] + + [#x1F59] + + [#x1F5B] + + [#x1F5D] + + [#x1F5F] + + [#x1F68-#x1F6F] + + [#x1FB8-#x1FBB] + + [#x1FC8-#x1FCB] + + [#x1FD8-#x1FDB] + + [#x1FE8-#x1FEC] + + [#x1FF8-#x1FFB] + + [#x2102] + + [#x2107] + + [#x210B-#x210D] + + [#x2110-#x2112] + + [#x2115] + + [#x2119-#x211D] + + [#x2124] + + [#x2126] + + [#x2128] + + [#x212A-#x212D] + + [#x2130-#x2133] + + [#x213E-#x213F] + + [#x2145] + + [#x2183] + + [#x2C00-#x2C2F] + + [#x2C60] + + [#x2C62-#x2C64] + + [#x2C67] + + [#x2C69] + + [#x2C6B] + + [#x2C6D-#x2C70] + + [#x2C72] + + [#x2C75] + + [#x2C7E-#x2C80] + + [#x2C82] + + [#x2C84] + + [#x2C86] + + [#x2C88] + + [#x2C8A] + + [#x2C8C] + + [#x2C8E] + + [#x2C90] + + [#x2C92] + + [#x2C94] + + [#x2C96] + + [#x2C98] + + [#x2C9A] + + [#x2C9C] + + [#x2C9E] + + [#x2CA0] + + [#x2CA2] + + [#x2CA4] + + [#x2CA6] + + [#x2CA8] + + [#x2CAA] + + [#x2CAC] + + [#x2CAE] + + [#x2CB0] + + [#x2CB2] + + [#x2CB4] + + [#x2CB6] + + [#x2CB8] + + [#x2CBA] + + [#x2CBC] + + [#x2CBE] + + [#x2CC0] + + [#x2CC2] + + [#x2CC4] + + [#x2CC6] + + [#x2CC8] + + [#x2CCA] + + [#x2CCC] + + [#x2CCE] + + [#x2CD0] + + [#x2CD2] + + [#x2CD4] + + [#x2CD6] + + [#x2CD8] + + [#x2CDA] + + [#x2CDC] + + [#x2CDE] + + [#x2CE0] + + [#x2CE2] + + [#x2CEB] + + [#x2CED] + + [#x2CF2] + + [#xA640] + + [#xA642] + + [#xA644] + + [#xA646] + + [#xA648] + + [#xA64A] + + [#xA64C] + + [#xA64E] + + [#xA650] + + [#xA652] + + [#xA654] + + [#xA656] + + [#xA658] + + [#xA65A] + + [#xA65C] + + [#xA65E] + + [#xA660] + + [#xA662] + + [#xA664] + + [#xA666] + + [#xA668] + + [#xA66A] + + [#xA66C] + + [#xA680] + + [#xA682] + + [#xA684] + + [#xA686] + + [#xA688] + + [#xA68A] + + [#xA68C] + + [#xA68E] + + [#xA690] + + [#xA692] + + [#xA694] + + [#xA696] + + [#xA698] + + [#xA69A] + + [#xA722] + + [#xA724] + + [#xA726] + + [#xA728] + + [#xA72A] + + [#xA72C] + + [#xA72E] + + [#xA732] + + [#xA734] + + [#xA736] + + [#xA738] + + [#xA73A] + + [#xA73C] + + [#xA73E] + + [#xA740] + + [#xA742] + + [#xA744] + + [#xA746] + + [#xA748] + + [#xA74A] + + [#xA74C] + + [#xA74E] + + [#xA750] + + [#xA752] + + [#xA754] + + [#xA756] + + [#xA758] + + [#xA75A] + + [#xA75C] + + [#xA75E] + + [#xA760] + + [#xA762] + + [#xA764] + + [#xA766] + + [#xA768] + + [#xA76A] + + [#xA76C] + + [#xA76E] + + [#xA779] + + [#xA77B] + + [#xA77D-#xA77E] + + [#xA780] + + [#xA782] + + [#xA784] + + [#xA786] + + [#xA78B] + + [#xA78D] + + [#xA790] + + [#xA792] + + [#xA796] + + [#xA798] + + [#xA79A] + + [#xA79C] + + [#xA79E] + + [#xA7A0] + + [#xA7A2] + + [#xA7A4] + + [#xA7A6] + + [#xA7A8] + + [#xA7AA-#xA7AE] + + [#xA7B0-#xA7B4] + + [#xA7B6] + + [#xA7B8] + + [#xA7BA] + + [#xA7BC] + + [#xA7BE] + + [#xA7C0] + + [#xA7C2] + + [#xA7C4-#xA7C7] + + [#xA7C9] + + [#xA7D0] + + [#xA7D6] + + [#xA7D8] + + [#xA7F5] + + [#xFF21-#xFF3A] + + +
    + +
    Lu       ::= [A-Z#xC0-#xD6#xD8-#xDE#x100#x102#x104#x106#x108#x10A#x10C#x10E#x110#x112#x114#x116#x118#x11A#x11C#x11E#x120#x122#x124#x126#x128#x12A#x12C#x12E#x130#x132#x134#x136#x139#x13B#x13D#x13F#x141#x143#x145#x147#x14A#x14C#x14E#x150#x152#x154#x156#x158#x15A#x15C#x15E#x160#x162#x164#x166#x168#x16A#x16C#x16E#x170#x172#x174#x176#x178-#x179#x17B#x17D#x181-#x182#x184#x186-#x187#x189-#x18B#x18E-#x191#x193-#x194#x196-#x198#x19C-#x19D#x19F-#x1A0#x1A2#x1A4#x1A6-#x1A7#x1A9#x1AC#x1AE-#x1AF#x1B1-#x1B3#x1B5#x1B7-#x1B8#x1BC#x1C4#x1C7#x1CA#x1CD#x1CF#x1D1#x1D3#x1D5#x1D7#x1D9#x1DB#x1DE#x1E0#x1E2#x1E4#x1E6#x1E8#x1EA#x1EC#x1EE#x1F1#x1F4#x1F6-#x1F8#x1FA#x1FC#x1FE#x200#x202#x204#x206#x208#x20A#x20C#x20E#x210#x212#x214#x216#x218#x21A#x21C#x21E#x220#x222#x224#x226#x228#x22A#x22C#x22E#x230#x232#x23A-#x23B#x23D-#x23E#x241#x243-#x246#x248#x24A#x24C#x24E#x370#x372#x376#x37F#x386#x388-#x38A#x38C#x38E-#x38F#x391-#x3A1#x3A3-#x3AB#x3CF#x3D2-#x3D4#x3D8#x3DA#x3DC#x3DE#x3E0#x3E2#x3E4#x3E6#x3E8#x3EA#x3EC#x3EE#x3F4#x3F7#x3F9-#x3FA#x3FD-#x42F#x460#x462#x464#x466#x468#x46A#x46C#x46E#x470#x472#x474#x476#x478#x47A#x47C#x47E#x480#x48A#x48C#x48E#x490#x492#x494#x496#x498#x49A#x49C#x49E#x4A0#x4A2#x4A4#x4A6#x4A8#x4AA#x4AC#x4AE#x4B0#x4B2#x4B4#x4B6#x4B8#x4BA#x4BC#x4BE#x4C0-#x4C1#x4C3#x4C5#x4C7#x4C9#x4CB#x4CD#x4D0#x4D2#x4D4#x4D6#x4D8#x4DA#x4DC#x4DE#x4E0#x4E2#x4E4#x4E6#x4E8#x4EA#x4EC#x4EE#x4F0#x4F2#x4F4#x4F6#x4F8#x4FA#x4FC#x4FE#x500#x502#x504#x506#x508#x50A#x50C#x50E#x510#x512#x514#x516#x518#x51A#x51C#x51E#x520#x522#x524#x526#x528#x52A#x52C#x52E#x531-#x556#x10A0-#x10C5#x10C7#x10CD#x13A0-#x13F5#x1C90-#x1CBA#x1CBD-#x1CBF#x1E00#x1E02#x1E04#x1E06#x1E08#x1E0A#x1E0C#x1E0E#x1E10#x1E12#x1E14#x1E16#x1E18#x1E1A#x1E1C#x1E1E#x1E20#x1E22#x1E24#x1E26#x1E28#x1E2A#x1E2C#x1E2E#x1E30#x1E32#x1E34#x1E36#x1E38#x1E3A#x1E3C#x1E3E#x1E40#x1E42#x1E44#x1E46#x1E48#x1E4A#x1E4C#x1E4E#x1E50#x1E52#x1E54#x1E56#x1E58#x1E5A#x1E5C#x1E5E#x1E60#x1E62#x1E64#x1E66#x1E68#x1E6A#x1E6C#x1E6E#x1E70#x1E72#x1E74#x1E76#x1E78#x1E7A#x1E7C#x1E7E#x1E80#x1E82#x1E84#x1E86#x1E88#x1E8A#x1E8C#x1E8E#x1E90#x1E92#x1E94#x1E9E#x1EA0#x1EA2#x1EA4#x1EA6#x1EA8#x1EAA#x1EAC#x1EAE#x1EB0#x1EB2#x1EB4#x1EB6#x1EB8#x1EBA#x1EBC#x1EBE#x1EC0#x1EC2#x1EC4#x1EC6#x1EC8#x1ECA#x1ECC#x1ECE#x1ED0#x1ED2#x1ED4#x1ED6#x1ED8#x1EDA#x1EDC#x1EDE#x1EE0#x1EE2#x1EE4#x1EE6#x1EE8#x1EEA#x1EEC#x1EEE#x1EF0#x1EF2#x1EF4#x1EF6#x1EF8#x1EFA#x1EFC#x1EFE#x1F08-#x1F0F#x1F18-#x1F1D#x1F28-#x1F2F#x1F38-#x1F3F#x1F48-#x1F4D#x1F59#x1F5B#x1F5D#x1F5F#x1F68-#x1F6F#x1FB8-#x1FBB#x1FC8-#x1FCB#x1FD8-#x1FDB#x1FE8-#x1FEC#x1FF8-#x1FFB#x2102#x2107#x210B-#x210D#x2110-#x2112#x2115#x2119-#x211D#x2124#x2126#x2128#x212A-#x212D#x2130-#x2133#x213E-#x213F#x2145#x2183#x2C00-#x2C2F#x2C60#x2C62-#x2C64#x2C67#x2C69#x2C6B#x2C6D-#x2C70#x2C72#x2C75#x2C7E-#x2C80#x2C82#x2C84#x2C86#x2C88#x2C8A#x2C8C#x2C8E#x2C90#x2C92#x2C94#x2C96#x2C98#x2C9A#x2C9C#x2C9E#x2CA0#x2CA2#x2CA4#x2CA6#x2CA8#x2CAA#x2CAC#x2CAE#x2CB0#x2CB2#x2CB4#x2CB6#x2CB8#x2CBA#x2CBC#x2CBE#x2CC0#x2CC2#x2CC4#x2CC6#x2CC8#x2CCA#x2CCC#x2CCE#x2CD0#x2CD2#x2CD4#x2CD6#x2CD8#x2CDA#x2CDC#x2CDE#x2CE0#x2CE2#x2CEB#x2CED#x2CF2#xA640#xA642#xA644#xA646#xA648#xA64A#xA64C#xA64E#xA650#xA652#xA654#xA656#xA658#xA65A#xA65C#xA65E#xA660#xA662#xA664#xA666#xA668#xA66A#xA66C#xA680#xA682#xA684#xA686#xA688#xA68A#xA68C#xA68E#xA690#xA692#xA694#xA696#xA698#xA69A#xA722#xA724#xA726#xA728#xA72A#xA72C#xA72E#xA732#xA734#xA736#xA738#xA73A#xA73C#xA73E#xA740#xA742#xA744#xA746#xA748#xA74A#xA74C#xA74E#xA750#xA752#xA754#xA756#xA758#xA75A#xA75C#xA75E#xA760#xA762#xA764#xA766#xA768#xA76A#xA76C#xA76E#xA779#xA77B#xA77D-#xA77E#xA780#xA782#xA784#xA786#xA78B#xA78D#xA790#xA792#xA796#xA798#xA79A#xA79C#xA79E#xA7A0#xA7A2#xA7A4#xA7A6#xA7A8#xA7AA-#xA7AE#xA7B0-#xA7B4#xA7B6#xA7B8#xA7BA#xA7BC#xA7BE#xA7C0#xA7C2#xA7C4-#xA7C7#xA7C9#xA7D0#xA7D6#xA7D8#xA7F5#xFF21-#xFF3A]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Nl +====================================================================================================================== + + +.. raw:: html + + + + + + [#x16EE-#x16F0] + + [#x2160-#x2182] + + [#x2185-#x2188] + + [#x3007] + + [#x3021-#x3029] + + [#x3038-#x303A] + + [#xA6E6-#xA6EF] + + +
    + +
    Nl       ::= [#x16EE-#x16F0#x2160-#x2182#x2185-#x2188#x3007#x3021-#x3029#x3038-#x303A#xA6E6-#xA6EF]
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnicodeIdentifierExtend +====================================================================================================================== + + +.. raw:: html + + + + + + Mn + + Mc + + Nd + + Pc + + Cf + + CJK + +
    + + +
             ::= Mn
    +
               | Mc
    +
               | Nd
    +
               | Pc
    +
               | Cf
    +
               | CJK
    +
    + Referenced by: +
    + + +====================================================================================================================== +Cf +====================================================================================================================== + + +.. raw:: html + + + + + + [#xAD] + + [#x600-#x605] + + [#x61C] + + [#x6DD] + + [#x70F] + + [#x890-#x891] + + [#x8E2] + + [#x180E] + + [#x200B-#x200F] + + [#x202A-#x202E] + + [#x2060-#x2064] + + [#x2066-#x206F] + + [#xFEFF] + + [#xFFF9-#xFFFB] + + +
    + +
    Cf       ::= [#xAD#x600-#x605#x61C#x6DD#x70F#x890-#x891#x8E2#x180E#x200B-#x200F#x202A-#x202E#x2060-#x2064#x2066-#x206F#xFEFF#xFFF9-#xFFFB]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Mc +====================================================================================================================== + + +.. raw:: html + + + + + + [#x903] + + [#x93B] + + [#x93E-#x940] + + [#x949-#x94C] + + [#x94E-#x94F] + + [#x982-#x983] + + [#x9BE-#x9C0] + + [#x9C7-#x9C8] + + [#x9CB-#x9CC] + + [#x9D7] + + [#xA03] + + [#xA3E-#xA40] + + [#xA83] + + [#xABE-#xAC0] + + [#xAC9] + + [#xACB-#xACC] + + [#xB02-#xB03] + + [#xB3E] + + [#xB40] + + [#xB47-#xB48] + + [#xB4B-#xB4C] + + [#xB57] + + [#xBBE-#xBBF] + + [#xBC1-#xBC2] + + [#xBC6-#xBC8] + + [#xBCA-#xBCC] + + [#xBD7] + + [#xC01-#xC03] + + [#xC41-#xC44] + + [#xC82-#xC83] + + [#xCBE] + + [#xCC0-#xCC4] + + [#xCC7-#xCC8] + + [#xCCA-#xCCB] + + [#xCD5-#xCD6] + + [#xCF3] + + [#xD02-#xD03] + + [#xD3E-#xD40] + + [#xD46-#xD48] + + [#xD4A-#xD4C] + + [#xD57] + + [#xD82-#xD83] + + [#xDCF-#xDD1] + + [#xDD8-#xDDF] + + [#xDF2-#xDF3] + + [#xF3E-#xF3F] + + [#xF7F] + + [#x102B-#x102C] + + [#x1031] + + [#x1038] + + [#x103B-#x103C] + + [#x1056-#x1057] + + [#x1062-#x1064] + + [#x1067-#x106D] + + [#x1083-#x1084] + + [#x1087-#x108C] + + [#x108F] + + [#x109A-#x109C] + + [#x1715] + + [#x1734] + + [#x17B6] + + [#x17BE-#x17C5] + + [#x17C7-#x17C8] + + [#x1923-#x1926] + + [#x1929-#x192B] + + [#x1930-#x1931] + + [#x1933-#x1938] + + [#x1A19-#x1A1A] + + [#x1A55] + + [#x1A57] + + [#x1A61] + + [#x1A63-#x1A64] + + [#x1A6D-#x1A72] + + [#x1B04] + + [#x1B35] + + [#x1B3B] + + [#x1B3D-#x1B41] + + [#x1B43-#x1B44] + + [#x1B82] + + [#x1BA1] + + [#x1BA6-#x1BA7] + + [#x1BAA] + + [#x1BE7] + + [#x1BEA-#x1BEC] + + [#x1BEE] + + [#x1BF2-#x1BF3] + + [#x1C24-#x1C2B] + + [#x1C34-#x1C35] + + [#x1CE1] + + [#x1CF7] + + [#x302E-#x302F] + + [#xA823-#xA824] + + [#xA827] + + [#xA880-#xA881] + + [#xA8B4-#xA8C3] + + [#xA952-#xA953] + + [#xA983] + + [#xA9B4-#xA9B5] + + [#xA9BA-#xA9BB] + + [#xA9BE-#xA9C0] + + [#xAA2F-#xAA30] + + [#xAA33-#xAA34] + + [#xAA4D] + + [#xAA7B] + + [#xAA7D] + + [#xAAEB] + + [#xAAEE-#xAAEF] + + [#xAAF5] + + [#xABE3-#xABE4] + + [#xABE6-#xABE7] + + [#xABE9-#xABEA] + + [#xABEC] + + +
    + +
    Mc       ::= [#x903#x93B#x93E-#x940#x949-#x94C#x94E-#x94F#x982-#x983#x9BE-#x9C0#x9C7-#x9C8#x9CB-#x9CC#x9D7#xA03#xA3E-#xA40#xA83#xABE-#xAC0#xAC9#xACB-#xACC#xB02-#xB03#xB3E#xB40#xB47-#xB48#xB4B-#xB4C#xB57#xBBE-#xBBF#xBC1-#xBC2#xBC6-#xBC8#xBCA-#xBCC#xBD7#xC01-#xC03#xC41-#xC44#xC82-#xC83#xCBE#xCC0-#xCC4#xCC7-#xCC8#xCCA-#xCCB#xCD5-#xCD6#xCF3#xD02-#xD03#xD3E-#xD40#xD46-#xD48#xD4A-#xD4C#xD57#xD82-#xD83#xDCF-#xDD1#xDD8-#xDDF#xDF2-#xDF3#xF3E-#xF3F#xF7F#x102B-#x102C#x1031#x1038#x103B-#x103C#x1056-#x1057#x1062-#x1064#x1067-#x106D#x1083-#x1084#x1087-#x108C#x108F#x109A-#x109C#x1715#x1734#x17B6#x17BE-#x17C5#x17C7-#x17C8#x1923-#x1926#x1929-#x192B#x1930-#x1931#x1933-#x1938#x1A19-#x1A1A#x1A55#x1A57#x1A61#x1A63-#x1A64#x1A6D-#x1A72#x1B04#x1B35#x1B3B#x1B3D-#x1B41#x1B43-#x1B44#x1B82#x1BA1#x1BA6-#x1BA7#x1BAA#x1BE7#x1BEA-#x1BEC#x1BEE#x1BF2-#x1BF3#x1C24-#x1C2B#x1C34-#x1C35#x1CE1#x1CF7#x302E-#x302F#xA823-#xA824#xA827#xA880-#xA881#xA8B4-#xA8C3#xA952-#xA953#xA983#xA9B4-#xA9B5#xA9BA-#xA9BB#xA9BE-#xA9C0#xAA2F-#xAA30#xAA33-#xAA34#xAA4D#xAA7B#xAA7D#xAAEB#xAAEE-#xAAEF#xAAF5#xABE3-#xABE4#xABE6-#xABE7#xABE9-#xABEA#xABEC]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Mn +====================================================================================================================== + + +.. raw:: html + + + + + + [#x300-#x36F] + + [#x483-#x487] + + [#x591-#x5BD] + + [#x5BF] + + [#x5C1-#x5C2] + + [#x5C4-#x5C5] + + [#x5C7] + + [#x610-#x61A] + + [#x64B-#x65F] + + [#x670] + + [#x6D6-#x6DC] + + [#x6DF-#x6E4] + + [#x6E7-#x6E8] + + [#x6EA-#x6ED] + + [#x711] + + [#x730-#x74A] + + [#x7A6-#x7B0] + + [#x7EB-#x7F3] + + [#x7FD] + + [#x816-#x819] + + [#x81B-#x823] + + [#x825-#x827] + + [#x829-#x82D] + + [#x859-#x85B] + + [#x898-#x89F] + + [#x8CA-#x8E1] + + [#x8E3-#x902] + + [#x93A] + + [#x93C] + + [#x941-#x948] + + [#x94D] + + [#x951-#x957] + + [#x962-#x963] + + [#x981] + + [#x9BC] + + [#x9C1-#x9C4] + + [#x9CD] + + [#x9E2-#x9E3] + + [#x9FE] + + [#xA01-#xA02] + + [#xA3C] + + [#xA41-#xA42] + + [#xA47-#xA48] + + [#xA4B-#xA4D] + + [#xA51] + + [#xA70-#xA71] + + [#xA75] + + [#xA81-#xA82] + + [#xABC] + + [#xAC1-#xAC5] + + [#xAC7-#xAC8] + + [#xACD] + + [#xAE2-#xAE3] + + [#xAFA-#xAFF] + + [#xB01] + + [#xB3C] + + [#xB3F] + + [#xB41-#xB44] + + [#xB4D] + + [#xB55-#xB56] + + [#xB62-#xB63] + + [#xB82] + + [#xBC0] + + [#xBCD] + + [#xC00] + + [#xC04] + + [#xC3C] + + [#xC3E-#xC40] + + [#xC46-#xC48] + + [#xC4A-#xC4D] + + [#xC55-#xC56] + + [#xC62-#xC63] + + [#xC81] + + [#xCBC] + + [#xCBF] + + [#xCC6] + + [#xCCC-#xCCD] + + [#xCE2-#xCE3] + + [#xD00-#xD01] + + [#xD3B-#xD3C] + + [#xD41-#xD44] + + [#xD4D] + + [#xD62-#xD63] + + [#xD81] + + [#xDCA] + + [#xDD2-#xDD4] + + [#xDD6] + + [#xE31] + + [#xE34-#xE3A] + + [#xE47-#xE4E] + + [#xEB1] + + [#xEB4-#xEBC] + + [#xEC8-#xECE] + + [#xF18-#xF19] + + [#xF35] + + [#xF37] + + [#xF39] + + [#xF71-#xF7E] + + [#xF80-#xF84] + + [#xF86-#xF87] + + [#xF8D-#xF97] + + [#xF99-#xFBC] + + [#xFC6] + + [#x102D-#x1030] + + [#x1032-#x1037] + + [#x1039-#x103A] + + [#x103D-#x103E] + + [#x1058-#x1059] + + [#x105E-#x1060] + + [#x1071-#x1074] + + [#x1082] + + [#x1085-#x1086] + + [#x108D] + + [#x109D] + + [#x135D-#x135F] + + [#x1712-#x1714] + + [#x1732-#x1733] + + [#x1752-#x1753] + + [#x1772-#x1773] + + [#x17B4-#x17B5] + + [#x17B7-#x17BD] + + [#x17C6] + + [#x17C9-#x17D3] + + [#x17DD] + + [#x180B-#x180D] + + [#x180F] + + [#x1885-#x1886] + + [#x18A9] + + [#x1920-#x1922] + + [#x1927-#x1928] + + [#x1932] + + [#x1939-#x193B] + + [#x1A17-#x1A18] + + [#x1A1B] + + [#x1A56] + + [#x1A58-#x1A5E] + + [#x1A60] + + [#x1A62] + + [#x1A65-#x1A6C] + + [#x1A73-#x1A7C] + + [#x1A7F] + + [#x1AB0-#x1ABD] + + [#x1ABF-#x1ACE] + + [#x1B00-#x1B03] + + [#x1B34] + + [#x1B36-#x1B3A] + + [#x1B3C] + + [#x1B42] + + [#x1B6B-#x1B73] + + [#x1B80-#x1B81] + + [#x1BA2-#x1BA5] + + [#x1BA8-#x1BA9] + + [#x1BAB-#x1BAD] + + [#x1BE6] + + [#x1BE8-#x1BE9] + + [#x1BED] + + [#x1BEF-#x1BF1] + + [#x1C2C-#x1C33] + + [#x1C36-#x1C37] + + [#x1CD0-#x1CD2] + + [#x1CD4-#x1CE0] + + [#x1CE2-#x1CE8] + + [#x1CED] + + [#x1CF4] + + [#x1CF8-#x1CF9] + + [#x1DC0-#x1DFF] + + [#x20D0-#x20DC] + + [#x20E1] + + [#x20E5-#x20F0] + + [#x2CEF-#x2CF1] + + [#x2D7F] + + [#x2DE0-#x2DFF] + + [#x302A-#x302D] + + [#x3099-#x309A] + + [#xA66F] + + [#xA674-#xA67D] + + [#xA69E-#xA69F] + + [#xA6F0-#xA6F1] + + [#xA802] + + [#xA806] + + [#xA80B] + + [#xA825-#xA826] + + [#xA82C] + + [#xA8C4-#xA8C5] + + [#xA8E0-#xA8F1] + + [#xA8FF] + + [#xA926-#xA92D] + + [#xA947-#xA951] + + [#xA980-#xA982] + + [#xA9B3] + + [#xA9B6-#xA9B9] + + [#xA9BC-#xA9BD] + + [#xA9E5] + + [#xAA29-#xAA2E] + + [#xAA31-#xAA32] + + [#xAA35-#xAA36] + + [#xAA43] + + [#xAA4C] + + [#xAA7C] + + [#xAAB0] + + [#xAAB2-#xAAB4] + + [#xAAB7-#xAAB8] + + [#xAABE-#xAABF] + + [#xAAC1] + + [#xAAEC-#xAAED] + + [#xAAF6] + + [#xABE5] + + [#xABE8] + + [#xABED] + + [#xFB1E] + + [#xFE00-#xFE0F] + + [#xFE20-#xFE2F] + + +
    + +
    Mn       ::= [#x300-#x36F#x483-#x487#x591-#x5BD#x5BF#x5C1-#x5C2#x5C4-#x5C5#x5C7#x610-#x61A#x64B-#x65F#x670#x6D6-#x6DC#x6DF-#x6E4#x6E7-#x6E8#x6EA-#x6ED#x711#x730-#x74A#x7A6-#x7B0#x7EB-#x7F3#x7FD#x816-#x819#x81B-#x823#x825-#x827#x829-#x82D#x859-#x85B#x898-#x89F#x8CA-#x8E1#x8E3-#x902#x93A#x93C#x941-#x948#x94D#x951-#x957#x962-#x963#x981#x9BC#x9C1-#x9C4#x9CD#x9E2-#x9E3#x9FE#xA01-#xA02#xA3C#xA41-#xA42#xA47-#xA48#xA4B-#xA4D#xA51#xA70-#xA71#xA75#xA81-#xA82#xABC#xAC1-#xAC5#xAC7-#xAC8#xACD#xAE2-#xAE3#xAFA-#xAFF#xB01#xB3C#xB3F#xB41-#xB44#xB4D#xB55-#xB56#xB62-#xB63#xB82#xBC0#xBCD#xC00#xC04#xC3C#xC3E-#xC40#xC46-#xC48#xC4A-#xC4D#xC55-#xC56#xC62-#xC63#xC81#xCBC#xCBF#xCC6#xCCC-#xCCD#xCE2-#xCE3#xD00-#xD01#xD3B-#xD3C#xD41-#xD44#xD4D#xD62-#xD63#xD81#xDCA#xDD2-#xDD4#xDD6#xE31#xE34-#xE3A#xE47-#xE4E#xEB1#xEB4-#xEBC#xEC8-#xECE#xF18-#xF19#xF35#xF37#xF39#xF71-#xF7E#xF80-#xF84#xF86-#xF87#xF8D-#xF97#xF99-#xFBC#xFC6#x102D-#x1030#x1032-#x1037#x1039-#x103A#x103D-#x103E#x1058-#x1059#x105E-#x1060#x1071-#x1074#x1082#x1085-#x1086#x108D#x109D#x135D-#x135F#x1712-#x1714#x1732-#x1733#x1752-#x1753#x1772-#x1773#x17B4-#x17B5#x17B7-#x17BD#x17C6#x17C9-#x17D3#x17DD#x180B-#x180D#x180F#x1885-#x1886#x18A9#x1920-#x1922#x1927-#x1928#x1932#x1939-#x193B#x1A17-#x1A18#x1A1B#x1A56#x1A58-#x1A5E#x1A60#x1A62#x1A65-#x1A6C#x1A73-#x1A7C#x1A7F#x1AB0-#x1ABD#x1ABF-#x1ACE#x1B00-#x1B03#x1B34#x1B36-#x1B3A#x1B3C#x1B42#x1B6B-#x1B73#x1B80-#x1B81#x1BA2-#x1BA5#x1BA8-#x1BA9#x1BAB-#x1BAD#x1BE6#x1BE8-#x1BE9#x1BED#x1BEF-#x1BF1#x1C2C-#x1C33#x1C36-#x1C37#x1CD0-#x1CD2#x1CD4-#x1CE0#x1CE2-#x1CE8#x1CED#x1CF4#x1CF8-#x1CF9#x1DC0-#x1DFF#x20D0-#x20DC#x20E1#x20E5-#x20F0#x2CEF-#x2CF1#x2D7F#x2DE0-#x2DFF#x302A-#x302D#x3099-#x309A#xA66F#xA674-#xA67D#xA69E-#xA69F#xA6F0-#xA6F1#xA802#xA806#xA80B#xA825-#xA826#xA82C#xA8C4-#xA8C5#xA8E0-#xA8F1#xA8FF#xA926-#xA92D#xA947-#xA951#xA980-#xA982#xA9B3#xA9B6-#xA9B9#xA9BC-#xA9BD#xA9E5#xAA29-#xAA2E#xAA31-#xAA32#xAA35-#xAA36#xAA43#xAA4C#xAA7C#xAAB0#xAAB2-#xAAB4#xAAB7-#xAAB8#xAABE-#xAABF#xAAC1#xAAEC-#xAAED#xAAF6#xABE5#xABE8#xABED#xFB1E#xFE00-#xFE0F#xFE20-#xFE2F]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Nd +====================================================================================================================== + + +.. raw:: html + + + + + + [0-9] + + [#x660-#x669] + + [#x6F0-#x6F9] + + [#x7C0-#x7C9] + + [#x966-#x96F] + + [#x9E6-#x9EF] + + [#xA66-#xA6F] + + [#xAE6-#xAEF] + + [#xB66-#xB6F] + + [#xBE6-#xBEF] + + [#xC66-#xC6F] + + [#xCE6-#xCEF] + + [#xD66-#xD6F] + + [#xDE6-#xDEF] + + [#xE50-#xE59] + + [#xED0-#xED9] + + [#xF20-#xF29] + + [#x1040-#x1049] + + [#x1090-#x1099] + + [#x17E0-#x17E9] + + [#x1810-#x1819] + + [#x1946-#x194F] + + [#x19D0-#x19D9] + + [#x1A80-#x1A89] + + [#x1A90-#x1A99] + + [#x1B50-#x1B59] + + [#x1BB0-#x1BB9] + + [#x1C40-#x1C49] + + [#x1C50-#x1C59] + + [#xA620-#xA629] + + [#xA8D0-#xA8D9] + + [#xA900-#xA909] + + [#xA9D0-#xA9D9] + + [#xA9F0-#xA9F9] + + [#xAA50-#xAA59] + + [#xABF0-#xABF9] + + [#xFF10-#xFF19] + + +
    + +
    Nd       ::= [0-9#x660-#x669#x6F0-#x6F9#x7C0-#x7C9#x966-#x96F#x9E6-#x9EF#xA66-#xA6F#xAE6-#xAEF#xB66-#xB6F#xBE6-#xBEF#xC66-#xC6F#xCE6-#xCEF#xD66-#xD6F#xDE6-#xDEF#xE50-#xE59#xED0-#xED9#xF20-#xF29#x1040-#x1049#x1090-#x1099#x17E0-#x17E9#x1810-#x1819#x1946-#x194F#x19D0-#x19D9#x1A80-#x1A89#x1A90-#x1A99#x1B50-#x1B59#x1BB0-#x1BB9#x1C40-#x1C49#x1C50-#x1C59#xA620-#xA629#xA8D0-#xA8D9#xA900-#xA909#xA9D0-#xA9D9#xA9F0-#xA9F9#xAA50-#xAA59#xABF0-#xABF9#xFF10-#xFF19]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Pc +====================================================================================================================== + + +.. raw:: html + + + + + + [#x203F-#x2040] + + [#x2054] + + [#xFE33-#xFE34] + + [#xFE4D-#xFE4F] + + [#xFF3F] + + +
    + +
    Pc       ::= [#x203F-#x2040#x2054#xFE33-#xFE34#xFE4D-#xFE4F#xFF3F]
    +
    + Referenced by: +
    + + +====================================================================================================================== +CJK +====================================================================================================================== + + +.. raw:: html + + + + + + [#xAC00-#xD7A3] + + [#x4E00-#x9FFF] + + +
    + +
    CJK      ::= [#xAC00-#xD7A3#x4E00-#x9FFF]
    +
    + + +====================================================================================================================== +ESC +====================================================================================================================== + + +.. raw:: html + + + + + + \ + + n + + t + + b + + r + + f + + \ + + " + + +
    + +
    ESC      ::= '\' [ntbrf\"]
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_CHAR_LITERAL +====================================================================================================================== + + +.. raw:: html + + + + + + U + + E + + N + + R + + B + + RB + + _utf8 + + q'{ + + . + + }' + + ' + + ESC + \' + + [^'\] + + '' + + [^'] + + ' + + $$ + + [^$] + + $$ + + q'( + + . + + )' + + q'[ + + . + + ]' + + q'' + + . + + '' + + +
    + + +
             ::= ( [UENRB] | 'RB' | '_utf8' )? ( "'" ( ( ESC | "\'" | [^'\] )* | ( "''" | [^'] )+ ) "'" | '$$' [^$]* '$$' | "q'{" .* "}'" | "q'(" .* ")'" | "q'[" .* "]'" | "q''" .* "''" )
    +
    + + +====================================================================================================================== +S_QUOTED_IDENTIFIER +====================================================================================================================== + + +.. raw:: html + + + + + + " + + "" + + [^"#xA#xD] + + " + + ` + + [^`#xA#xD] + + ` + + [ + + [^#x5D#xA#xD] + + ] + + +
    + + +
             ::= '"' ( '""' | [^"#xA#xD] )* '"'
    +
               | '`' [^`#xA#xD]+ '`'
    +
               | '[' [^#x5D#xA#xD]* ']'
    +
    + + +====================================================================================================================== +EOF +====================================================================================================================== + + +.. raw:: html + + + + + + $ + + +
    + +
    EOF      ::= $
    +
    + Referenced by: +
    + + \ No newline at end of file diff --git a/src/site/sphinx/syntax_stable.rst b/src/site/sphinx/syntax_stable.rst new file mode 100644 index 000000000..92839aa66 --- /dev/null +++ b/src/site/sphinx/syntax_stable.rst @@ -0,0 +1,21133 @@ + +********************************************************************* +SQL Syntax |JSQLPARSER_VERSION| +********************************************************************* + +The EBNF and Railroad Diagrams for |JSQLPARSER_VERSION|. + + +====================================================================================================================== +NonReservedWord +====================================================================================================================== + + +.. raw:: html + + + + + + ACTION + + ACTIVE + + ADD + + ADVANCE + + ADVISE + + AGAINST + + AGGREGATE + + ALGORITHM + + ALIGN + + ALTER + + ALWAYS + + ANALYZE + + APPEND_ONLY + + APPLY + + APPROXIMATE + + ARCHIVE + + ARRAY + + ASYMMETRIC + + AT + + ASC + + AUTHORIZATION + + AUTO + + AUTO_INCREMENT + + AZURE + + BASE64 + + BEFORE + + BEGIN + + BERNOULLI + + BINARY + + BIT + + BLOBSTORAGE + + BLOCK + + BOOLEAN + + BREADTH + + BRANCH + + BROWSE + + BY + + BYTES + + CACHE + + BUFFERS + + BYTE + + CALL + + CASCADE + + CASE + + CAST + + CERTIFICATE + + CHARACTER + + CHANGE + + CHANGES + + CHECKPOINT + + CHAR + + CLOSE + + CLOUD + + COALESCE + + COLLATE + + COLUMN + + COLUMNS + + COMMIT + + COMMENT + + COMMENTS + + CONFLICT + + CONSTRAINTS + + CONVERT + + CORRESPONDING + + COSTS + + COUNT + + CREATED + + CYCLE + + DATABASE + + DATA + + DECLARE + + DBA_RECYCLEBIN + + DEFAULTS + + DEPTH + + DEFERRABLE + + DELAYED + + DELETE + + DELIMIT + + DELIMITER + + DESC + + DESCRIBE + + DISABLE + + DISCARD + + DISCONNECT + + DIV + + DDL + + DML + + DO + + DOMAIN + + DRIVER + + DROP + + DUMP + + DUMPFILE + + DUPLICATE + + ELEMENTS + + ENCLOSED + + EMIT + + ENABLE + + ENCODING + + ENCRYPTION + + END + + ESCAPED + + ENFORCED + + ENGINE + + ERROR + + ESCAPE + + EXA + + EXCHANGE + + EXCLUDE + + EXCLUDING + + EXCLUSIVE + + EXEC + + EXECUTE + + EXPLAIN + + EXPLICIT + + EXTENDED + + EXTRACT + + EXPORT + + K_ISOLATION + FILTER + + FIELDS + + FIRST + + FLUSH + + FOLLOWING + + FORMAT + + FULLTEXT + + FUNCTION + + GRANT + + GROUP_CONCAT + + GUARD + + HASH + + HIGH + + HIGH_PRIORITY + + HISTORY + + HOPPING + + IDENTIFIED + + IDENTITY + + INCLUDE + + INCLUDE_NULL_VALUES + + INCLUDING + + INCREMENT + + INDEX + + INFORMATION + + INSERT + + INTERLEAVE + + INTERPRET + + INVALIDATE + + INVERSE + + INVISIBLE + + ISNULL + + JDBC + + JSON + + JSON_OBJECT + + JSON_OBJECTAGG + + JSON_ARRAY + + JSON_ARRAYAGG + + KEEP + + KEY_BLOCK_SIZE + + KEY + + KEYS + + KILL + + FN + + LAST + + LEADING + + LESS + + LEVEL + + LINES + + LOCAL + + LOCK + + LOCKED + + LINK + + LOG + + LOOP + + LOW + + LOW_PRIORITY + + LTRIM + + MATCH + + MATCH_ANY + + MATCH_ALL + + MATCH_PHRASE + + MATCH_PHRASE_PREFIX + + MATCH_REGEXP + + MATCHED + + MATERIALIZED + + MAX + + MAXVALUE + + MEMBER + + MERGE + + MIN + + MINVALUE + + MODE + + MODIFY + + MOVEMENT + + NAMES + + NAME + + NEVER + + NEXT + + K_NEXTVAL + NO + + NOCACHE + + NOKEEP + + NOLOCK + + NOMAXVALUE + + NOMINVALUE + + NONE + + NOORDER + + NOTHING + + NOTNULL + + NOVALIDATE + + NULLS + + NOWAIT + + OF + + OFF + + OPTIONALLY + + OPEN + + ORA + + ORDINALITY + + OUTFILE + + OVER + + OVERFLOW + + OVERLAPS + + OVERRIDING + + OVERWRITE + + PADDING + + PARALLEL + + PARENT + + PARSER + + PARTITION + + PARTITIONING + + PATH + + PERCENT + + PLACING + + PLAN + + PLUS + + PRECEDING + + PRIMARY + + POLICY + + PURGE + + QUERY + + QUICK + + QUIESCE + + RANGE + + RAW + + READ + + REBUILD + + RECYCLEBIN + + RECURSIVE + + REFERENCES + + REFRESH + + REGEXP + + REJECT + + RESPECT + + RLIKE + + REGEXP_LIKE + + REGISTER + + REMOTE + + REMOVE + + RENAME + + REORGANIZE + + REPAIR + + REPEATABLE + + REPLACE + + RESET + + RESTART + + RESUMABLE + + RESUME + + RESTRICT + + RESTRICTED + + RETURN + + ROLLBACK + + ROLLUP + + ROOT + + ROW + + ROWS + + RTRIM + + SAFE_CAST + + SAFE_CONVERT + + SAVEPOINT + + SCHEMA + + SEARCH + + SECURE + + SECURITY + + SEED + + SEQUENCE + + SEPARATOR + + SESSION + + SETS + + SHOW + + SHUTDOWN + + SHARE + + SIBLINGS + + SIMILAR + + SIZE + + SKIP + + SPATIAL + + STARTING + + STORED + + STREAM + + STRICT + + STRING + + STRUCT + + SUMMARIZE + + SUSPEND + + SWITCH + + SYMMETRIC + + SYNONYM + + SYSTEM + + SYSTEM_TIME + + SYSTEM_TIMESTAMP + + SYSTEM_VERSION + + TABLE + + TABLESPACE + + TERMINATED + + TRIGGER + + THEN + + TEMP + + K_TEXT_LITERAL + TEMPORARY + + THAN + + K_TIME_KEY_EXPR + TIMEOUT + + TO + + TRIM + + TRUNCATE + + TRY_CAST + + TRY_CONVERT + + TUMBLING + + TYPE + + UNLIMITED + + UNLOGGED + + UPDATE + + UPSERT + + UNQIESCE + + USER + + SIGNED + + K_STRING_FUNCTION_NAME + UNSIGNED + + VALIDATE + + VALIDATION + + VERBOSE + + VERSION + + VIEW + + VISIBLE + + VOLATILE + + CONCURRENTLY + + WAIT + + WITH TIES + + WITHIN + + WITHOUT + + WITHOUT_ARRAY_WRAPPER + + WORK + + XML + + XMLAGG + + XMLDATA + + XMLSCHEMA + + XMLTEXT + + XSINIL + + YAML + + YES + + ZONE + + +
    + + +
             ::= 'ACTION'
    +
               | 'ACTIVE'
    +
               | 'ADD'
    +
               | 'ADVANCE'
    +
               | 'ADVISE'
    +
               | 'AGAINST'
    +
               | 'AGGREGATE'
    +
               | 'ALGORITHM'
    +
               | 'ALIGN'
    +
               | 'ALTER'
    +
               | 'ALWAYS'
    +
               | 'ANALYZE'
    +
               | 'APPEND_ONLY'
    +
               | 'APPLY'
    +
               | 'APPROXIMATE'
    +
               | 'ARCHIVE'
    +
               | 'ARRAY'
    +
               | 'ASYMMETRIC'
    +
               | 'AT'
    +
               | 'ASC'
    +
               | 'AUTHORIZATION'
    +
               | 'AUTO'
    +
               | 'AUTO_INCREMENT'
    +
               | 'AZURE'
    +
               | 'BASE64'
    +
               | 'BEFORE'
    +
               | 'BEGIN'
    +
               | 'BERNOULLI'
    +
               | 'BINARY'
    +
               | 'BIT'
    +
               | 'BLOBSTORAGE'
    +
               | 'BLOCK'
    +
               | 'BOOLEAN'
    +
               | 'BREADTH'
    +
               | 'BRANCH'
    +
               | 'BROWSE'
    +
               | 'BY'
    +
               | 'BYTES'
    +
               | 'CACHE'
    +
               | 'BUFFERS'
    +
               | 'BYTE'
    +
               | 'CALL'
    +
               | 'CASCADE'
    +
               | 'CASE'
    +
               | 'CAST'
    +
               | 'CERTIFICATE'
    +
               | 'CHARACTER'
    +
               | 'CHANGE'
    +
               | 'CHANGES'
    +
               | 'CHECKPOINT'
    +
               | 'CHAR'
    +
               | 'CLOSE'
    +
               | 'CLOUD'
    +
               | 'COALESCE'
    +
               | 'COLLATE'
    +
               | 'COLUMN'
    +
               | 'COLUMNS'
    +
               | 'COMMIT'
    +
               | 'COMMENT'
    +
               | 'COMMENTS'
    +
               | 'CONFLICT'
    +
               | 'CONSTRAINTS'
    +
               | 'CONVERT'
    +
               | 'CORRESPONDING'
    +
               | 'COSTS'
    +
               | 'COUNT'
    +
               | 'CREATED'
    +
               | 'CYCLE'
    +
               | 'DATABASE'
    +
               | 'DATA'
    +
               | 'DECLARE'
    +
               | 'DBA_RECYCLEBIN'
    +
               | 'DEFAULTS'
    +
               | 'DEPTH'
    +
               | 'DEFERRABLE'
    +
               | 'DELAYED'
    +
               | 'DELETE'
    +
               | 'DELIMIT'
    +
               | 'DELIMITER'
    +
               | 'DESC'
    +
               | 'DESCRIBE'
    +
               | 'DISABLE'
    +
               | 'DISCARD'
    +
               | 'DISCONNECT'
    +
               | 'DIV'
    +
               | 'DDL'
    +
               | 'DML'
    +
               | 'DO'
    +
               | 'DOMAIN'
    +
               | 'DRIVER'
    +
               | 'DROP'
    +
               | 'DUMP'
    +
               | 'DUMPFILE'
    +
               | 'DUPLICATE'
    +
               | 'ELEMENTS'
    +
               | 'ENCLOSED'
    +
               | 'EMIT'
    +
               | 'ENABLE'
    +
               | 'ENCODING'
    +
               | 'ENCRYPTION'
    +
               | 'END'
    +
               | 'ESCAPED'
    +
               | 'ENFORCED'
    +
               | 'ENGINE'
    +
               | 'ERROR'
    +
               | 'ESCAPE'
    +
               | 'EXA'
    +
               | 'EXCHANGE'
    +
               | 'EXCLUDE'
    +
               | 'EXCLUDING'
    +
               | 'EXCLUSIVE'
    +
               | 'EXEC'
    +
               | 'EXECUTE'
    +
               | 'EXPLAIN'
    +
               | 'EXPLICIT'
    +
               | 'EXTENDED'
    +
               | 'EXTRACT'
    +
               | 'EXPORT'
    +
               | K_ISOLATION
    +
               | 'FILTER'
    +
               | 'FIELDS'
    +
               | 'FIRST'
    +
               | 'FLUSH'
    +
               | 'FOLLOWING'
    +
               | 'FORMAT'
    +
               | 'FULLTEXT'
    +
               | 'FUNCTION'
    +
               | 'GRANT'
    +
               | 'GROUP_CONCAT'
    +
               | 'GUARD'
    +
               | 'HASH'
    +
               | 'HIGH'
    +
               | 'HIGH_PRIORITY'
    +
               | 'HISTORY'
    +
               | 'HOPPING'
    +
               | 'IDENTIFIED'
    +
               | 'IDENTITY'
    +
               | 'INCLUDE'
    +
               | 'INCLUDE_NULL_VALUES'
    +
               | 'INCLUDING'
    +
               | 'INCREMENT'
    +
               | 'INDEX'
    +
               | 'INFORMATION'
    +
               | 'INSERT'
    +
               | 'INTERLEAVE'
    +
               | 'INTERPRET'
    +
               | 'INVALIDATE'
    +
               | 'INVERSE'
    +
               | 'INVISIBLE'
    +
               | 'ISNULL'
    +
               | 'JDBC'
    +
               | 'JSON'
    +
               | 'JSON_OBJECT'
    +
               | 'JSON_OBJECTAGG'
    +
               | 'JSON_ARRAY'
    +
               | 'JSON_ARRAYAGG'
    +
               | 'KEEP'
    +
               | 'KEY_BLOCK_SIZE'
    +
               | 'KEY'
    +
               | 'KEYS'
    +
               | 'KILL'
    +
               | 'FN'
    +
               | 'LAST'
    +
               | 'LEADING'
    +
               | 'LESS'
    +
               | 'LEVEL'
    +
               | 'LINES'
    +
               | 'LOCAL'
    +
               | 'LOCK'
    +
               | 'LOCKED'
    +
               | 'LINK'
    +
               | 'LOG'
    +
               | 'LOOP'
    +
               | 'LOW'
    +
               | 'LOW_PRIORITY'
    +
               | 'LTRIM'
    +
               | 'MATCH'
    +
               | 'MATCH_ANY'
    +
               | 'MATCH_ALL'
    +
               | 'MATCH_PHRASE'
    +
               | 'MATCH_PHRASE_PREFIX'
    +
               | 'MATCH_REGEXP'
    +
               | 'MATCHED'
    +
               | 'MATERIALIZED'
    +
               | 'MAX'
    +
               | 'MAXVALUE'
    +
               | 'MEMBER'
    +
               | 'MERGE'
    +
               | 'MIN'
    +
               | 'MINVALUE'
    +
               | 'MODE'
    +
               | 'MODIFY'
    +
               | 'MOVEMENT'
    +
               | 'NAMES'
    +
               | 'NAME'
    +
               | 'NEVER'
    +
               | 'NEXT'
    +
               | K_NEXTVAL
    +
               | 'NO'
    +
               | 'NOCACHE'
    +
               | 'NOKEEP'
    +
               | 'NOLOCK'
    +
               | 'NOMAXVALUE'
    +
               | 'NOMINVALUE'
    +
               | 'NONE'
    +
               | 'NOORDER'
    +
               | 'NOTHING'
    +
               | 'NOTNULL'
    +
               | 'NOVALIDATE'
    +
               | 'NULLS'
    +
               | 'NOWAIT'
    +
               | 'OF'
    +
               | 'OFF'
    +
               | 'OPTIONALLY'
    +
               | 'OPEN'
    +
               | 'ORA'
    +
               | 'ORDINALITY'
    +
               | 'OUTFILE'
    +
               | 'OVER'
    +
               | 'OVERFLOW'
    +
               | 'OVERLAPS'
    +
               | 'OVERRIDING'
    +
               | 'OVERWRITE'
    +
               | 'PADDING'
    +
               | 'PARALLEL'
    +
               | 'PARENT'
    +
               | 'PARSER'
    +
               | 'PARTITION'
    +
               | 'PARTITIONING'
    +
               | 'PATH'
    +
               | 'PERCENT'
    +
               | 'PLACING'
    +
               | 'PLAN'
    +
               | 'PLUS'
    +
               | 'PRECEDING'
    +
               | 'PRIMARY'
    +
               | 'POLICY'
    +
               | 'PURGE'
    +
               | 'QUERY'
    +
               | 'QUICK'
    +
               | 'QUIESCE'
    +
               | 'RANGE'
    +
               | 'RAW'
    +
               | 'READ'
    +
               | 'REBUILD'
    +
               | 'RECYCLEBIN'
    +
               | 'RECURSIVE'
    +
               | 'REFERENCES'
    +
               | 'REFRESH'
    +
               | 'REGEXP'
    +
               | 'REJECT'
    +
               | 'RESPECT'
    +
               | 'RLIKE'
    +
               | 'REGEXP_LIKE'
    +
               | 'REGISTER'
    +
               | 'REMOTE'
    +
               | 'REMOVE'
    +
               | 'RENAME'
    +
               | 'REORGANIZE'
    +
               | 'REPAIR'
    +
               | 'REPEATABLE'
    +
               | 'REPLACE'
    +
               | 'RESET'
    +
               | 'RESTART'
    +
               | 'RESUMABLE'
    +
               | 'RESUME'
    +
               | 'RESTRICT'
    +
               | 'RESTRICTED'
    +
               | 'RETURN'
    +
               | 'ROLLBACK'
    +
               | 'ROLLUP'
    +
               | 'ROOT'
    +
               | 'ROW'
    +
               | 'ROWS'
    +
               | 'RTRIM'
    +
               | 'SAFE_CAST'
    +
               | 'SAFE_CONVERT'
    +
               | 'SAVEPOINT'
    +
               | 'SCHEMA'
    +
               | 'SEARCH'
    +
               | 'SECURE'
    +
               | 'SECURITY'
    +
               | 'SEED'
    +
               | 'SEQUENCE'
    +
               | 'SEPARATOR'
    +
               | 'SESSION'
    +
               | 'SETS'
    +
               | 'SHOW'
    +
               | 'SHUTDOWN'
    +
               | 'SHARE'
    +
               | 'SIBLINGS'
    +
               | 'SIMILAR'
    +
               | 'SIZE'
    +
               | 'SKIP'
    +
               | 'SPATIAL'
    +
               | 'STARTING'
    +
               | 'STORED'
    +
               | 'STREAM'
    +
               | 'STRICT'
    +
               | 'STRING'
    +
               | 'STRUCT'
    +
               | 'SUMMARIZE'
    +
               | 'SUSPEND'
    +
               | 'SWITCH'
    +
               | 'SYMMETRIC'
    +
               | 'SYNONYM'
    +
               | 'SYSTEM'
    +
               | 'SYSTEM_TIME'
    +
               | 'SYSTEM_TIMESTAMP'
    +
               | 'SYSTEM_VERSION'
    +
               | 'TABLE'
    +
               | 'TABLESPACE'
    +
               | 'TERMINATED'
    +
               | 'TRIGGER'
    +
               | 'THEN'
    +
               | 'TEMP'
    +
               | K_TEXT_LITERAL
    +
               | 'TEMPORARY'
    +
               | 'THAN'
    +
               | K_TIME_KEY_EXPR
    +
               | 'TIMEOUT'
    +
               | 'TO'
    +
               | 'TRIM'
    +
               | 'TRUNCATE'
    +
               | 'TRY_CAST'
    +
               | 'TRY_CONVERT'
    +
               | 'TUMBLING'
    +
               | 'TYPE'
    +
               | 'UNLIMITED'
    +
               | 'UNLOGGED'
    +
               | 'UPDATE'
    +
               | 'UPSERT'
    +
               | 'UNQIESCE'
    +
               | 'USER'
    +
               | 'SIGNED'
    +
               | K_STRING_FUNCTION_NAME
    +
               | 'UNSIGNED'
    +
               | 'VALIDATE'
    +
               | 'VALIDATION'
    +
               | 'VERBOSE'
    +
               | 'VERSION'
    +
               | 'VIEW'
    +
               | 'VISIBLE'
    +
               | 'VOLATILE'
    +
               | 'CONCURRENTLY'
    +
               | 'WAIT'
    +
               | 'WITH TIES'
    +
               | 'WITHIN'
    +
               | 'WITHOUT'
    +
               | 'WITHOUT_ARRAY_WRAPPER'
    +
               | 'WORK'
    +
               | 'XML'
    +
               | 'XMLAGG'
    +
               | 'XMLDATA'
    +
               | 'XMLSCHEMA'
    +
               | 'XMLTEXT'
    +
               | 'XSINIL'
    +
               | 'YAML'
    +
               | 'YES'
    +
               | 'ZONE'
    +
    + Referenced by: +
    + + +====================================================================================================================== +KeywordOrIdentifier +====================================================================================================================== + + +.. raw:: html + + + + + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + NAME + + NEXT + + VALUE + + PUBLIC + + STRING + + DATA + + +
    + + +
             ::= S_IDENTIFIER
    +
               | S_QUOTED_IDENTIFIER
    +
               | 'NAME'
    +
               | 'NEXT'
    +
               | 'VALUE'
    +
               | 'PUBLIC'
    +
               | 'STRING'
    +
               | 'DATA'
    +
    + + +====================================================================================================================== +Statement +====================================================================================================================== + + +.. raw:: html + + + + + + IF + + Condition + + SingleStatement + + Block + + ST_SEMICOLON + ELSE + + SingleStatement + + Block + + ST_SEMICOLON + + SingleStatement + + Block + + ST_SEMICOLON + + EOF + + UnsupportedStatement + +
    + + +
             ::= 'IF' Condition ( SingleStatement | Block ) ST_SEMICOLON? ( 'ELSE' ( SingleStatement | Block ) ST_SEMICOLON? )?
    +
               | ( SingleStatement | Block ) ( ST_SEMICOLON | EOF )
    +
               | UnsupportedStatement
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +SingleStatement +====================================================================================================================== + + +.. raw:: html + + + + + + WithList + + SelectWithWithItems + + InsertWithWithItems + + UpdateWithWithItems + + DeleteWithWithItems + + Merge + + Select + + TableStatement + + Upsert + + Alter + + RenameTableStatement + + Create + + Drop + + Analyze + + Truncate + + Execute + + Set + + Reset + + Show + + RefreshMaterializedView + + Use + + SavepointStatement + + RollbackStatement + COMMIT + + Comment + + Describe + + Explain + + Declare + + Grant + + PurgeStatement + + SessionStatement + + LockStatement + + Import + + Export + +
    + + + +
               | Select
    +
               | TableStatement
    +
               | Upsert
    +
               | Alter
    +
               | RenameTableStatement
    +
               | Create
    +
               | Drop
    +
               | Analyze
    +
               | Truncate
    +
               | Execute
    +
               | Set
    +
               | Reset
    +
               | Show
    +
               | RefreshMaterializedView
    +
               | Use
    +
               | SavepointStatement
    +
               | RollbackStatement
    +
               | 'COMMIT'
    +
               | Comment
    +
               | Describe
    +
               | Explain
    +
               | Declare
    +
               | Grant
    +
               | PurgeStatement
    +
               | SessionStatement
    +
               | LockStatement
    +
               | Import
    +
               | Export
    +
    + Referenced by: +
    + + +====================================================================================================================== +Block +====================================================================================================================== + + +.. raw:: html + + + + + + BEGIN + + ST_SEMICOLON + + SingleStatement + + Block + + ST_SEMICOLON + END + + ST_SEMICOLON + +
    + +
    Block    ::= 'BEGIN' ST_SEMICOLON* ( ( SingleStatement | Block ) ST_SEMICOLON )+ 'END' ST_SEMICOLON?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Statements +====================================================================================================================== + + +.. raw:: html + + + + + + ST_SEMICOLON + IF + + Condition + + SingleStatement + + Block + + ST_SEMICOLON + ELSE + + SingleStatement + + Block + + ST_SEMICOLON + + SingleStatement + + Block + + ST_SEMICOLON + + EOF + + ST_SEMICOLON + IF + + Condition + + SingleStatement + + Block + + ST_SEMICOLON + ELSE + + SingleStatement + + Block + + ST_SEMICOLON + + UnsupportedStatement + + EOF + +
    + + + +
    + Not referenced by any. +
    + + +====================================================================================================================== +LockStatement +====================================================================================================================== + + +.. raw:: html + + + + + + LOCK + + TABLE + + Table + IN + + ROW + + SHARE + + EXCLUSIVE + + SHARE + + ROW + + EXCLUSIVE + + UPDATE + + EXCLUSIVE + + MODE + + NOWAIT + + WAIT + + S_LONG + +
    + + +
             ::= 'LOCK' 'TABLE' Table 'IN' ( 'ROW' ( 'SHARE' | 'EXCLUSIVE' ) | 'SHARE' ( 'ROW' 'EXCLUSIVE' | 'UPDATE' )? + | 'EXCLUSIVE' ) 'MODE' ( 'NOWAIT' | 'WAIT' S_LONG )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +LikeClause +====================================================================================================================== + + +.. raw:: html + + + + + + LIKE + + Table + ( + + ColumnSelectItemsList + ) + + INCLUDING + + EXCLUDING + + DEFAULTS + + INCLUDING + + EXCLUDING + + IDENTITY + + INCLUDING + + EXCLUDING + + COMMENTS + + +
    + + +
             ::= 'LIKE' Table ( '(' ColumnSelectItemsList ')' )? ( ( 'INCLUDING' | 'EXCLUDING' ) 'DEFAULTS' )? ( ( 'INCLUDING' | 'EXCLUDING' + ) 'IDENTITY' )? ( ( 'INCLUDING' | 'EXCLUDING' ) 'COMMENTS' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Export +====================================================================================================================== + + +.. raw:: html + + + + + + EXPORT + + Table + + ParenthesedColumnList + + ParenthesedSelect + INTO + + ExportIntoItem + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +Import +====================================================================================================================== + + +.. raw:: html + + + + + + IMPORT + + INTO + + Table + + ParenthesedColumnList + + ImportColumns + FROM + + ImportFromItem + +
    + +
    Import   ::= 'IMPORT' ( 'INTO' ( Table ParenthesedColumnList? | ImportColumns ) )? 'FROM' ImportFromItem
    +
    + Referenced by: +
    + + +====================================================================================================================== +SubImport +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + IMPORT + + INTO + + ImportColumns + FROM + + ImportFromItem + ) + + +
    + + +
             ::= '(' 'IMPORT' ( 'INTO' ImportColumns )? 'FROM' ImportFromItem ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ImportColumns +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + ColumnDefinition + + LikeClause + , + + ) + + +
    + + +
             ::= '(' ( ColumnDefinition | LikeClause ) ( ',' ( ColumnDefinition | LikeClause ) )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExportIntoItem +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSDestination + + FileDestination + + ScriptSourceDestination + + ErrorClause + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +ImportFromItem +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSSource + + FileSource + + ScriptSourceDestination + + ErrorClause + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSDestination +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSType + + ConnectionDefinition + TABLE + + Table + + ParenthesedColumnList + + DBMSTableDestinationOptionList + + ImportExportStatement + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSTableDestinationOption +====================================================================================================================== + + +.. raw:: html + + + + + + REPLACE + + TRUNCATE + + CREATED + + BY + + S_CHAR_LITERAL + +
    + + +
             ::= 'REPLACE'
    +
               | 'TRUNCATE'
    +
               | 'CREATED' 'BY' S_CHAR_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSTableDestinationOptionList +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSTableDestinationOption + +
    + + +
             ::= DBMSTableDestinationOption+
    +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSSource +====================================================================================================================== + + +.. raw:: html + + + + + + DBMSType + + ConnectionDefinition + TABLE + + Table + + ParenthesedColumnList + + ImportExportStatementsList + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +DBMSType +====================================================================================================================== + + +.. raw:: html + + + + + + EXA + + ORA + + JDBC + + DRIVER + + = + + S_CHAR_LITERAL + +
    + +
    DBMSType ::= 'EXA'
    +
               | 'ORA'
    +
               | 'JDBC' ( 'DRIVER' '=' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileType +====================================================================================================================== + + +.. raw:: html + + + + + + CSV + + FBV + + +
    + +
    FileType ::= 'CSV'
    +
               | 'FBV'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ImportExportStatement +====================================================================================================================== + + +.. raw:: html + + + + + + STATEMENT + + S_CHAR_LITERAL + +
    + + +
             ::= 'STATEMENT' S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +ImportExportStatementsList +====================================================================================================================== + + +.. raw:: html + + + + + + ImportExportStatement + +
    + + +
             ::= ImportExportStatement+
    +
    + Referenced by: +
    + + +====================================================================================================================== +File +====================================================================================================================== + + +.. raw:: html + + + + + + FILE + + S_CHAR_LITERAL + +
    + +
    File     ::= 'FILE' S_CHAR_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileList +====================================================================================================================== + + +.. raw:: html + + + + + + File + +
    + + +
    + + +====================================================================================================================== +ConnectionFileDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + ConnectionOrCloudConnectionDefinition + + FileList + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +ConnectionFileDefinitionList +====================================================================================================================== + + +.. raw:: html + + + + + + ConnectionFileDefinition + +
    + + +
             ::= ConnectionFileDefinition+
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVDestinationColumn +====================================================================================================================== + + +.. raw:: html + + + + + + S_LONG + .. + + S_LONG + FORMAT + + = + + S_CHAR_LITERAL + DELIMIT + + = + + ALWAYS + + NEVER + + AUTO + + +
    + + +
             ::= S_LONG ( '..' S_LONG | ( 'FORMAT' '=' S_CHAR_LITERAL )? ( 'DELIMIT' '=' ( 'ALWAYS' | 'NEVER' | 'AUTO' ) )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVDestinationColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + CSVDestinationColumn + , + + +
    + + +
             ::= CSVDestinationColumn ( ',' CSVDestinationColumn )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVSourceColumn +====================================================================================================================== + + +.. raw:: html + + + + + + S_LONG + .. + + S_LONG + FORMAT + + = + + S_CHAR_LITERAL + +
    + + +
             ::= S_LONG ( '..' S_LONG | 'FORMAT' '=' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVSourceColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + CSVSourceColumn + , + + +
    + + +
             ::= CSVSourceColumn ( ',' CSVSourceColumn )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +FBVDestinationColumn +====================================================================================================================== + + +.. raw:: html + + + + + + SIZE + + = + + S_LONG + FORMAT + + PADDING + + = + + S_CHAR_LITERAL + ALIGN + + = + + LEFT + + RIGHT + + +
    + + +
             ::= 'SIZE' '=' S_LONG
    +
               | ( 'FORMAT' | 'PADDING' ) '=' S_CHAR_LITERAL
    +
               | 'ALIGN' '=' ( 'LEFT' | 'RIGHT' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +FBVDestinationColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + FBVDestinationColumn + , + + +
    + + +
             ::= FBVDestinationColumn ( ','? FBVDestinationColumn )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +FBVSourceColumn +====================================================================================================================== + + +.. raw:: html + + + + + + SIZE + + START + + = + + S_LONG + FORMAT + + PADDING + + = + + S_CHAR_LITERAL + ALIGN + + = + + LEFT + + RIGHT + + +
    + + +
             ::= ( 'SIZE' | 'START' ) '=' S_LONG
    +
               | ( 'FORMAT' | 'PADDING' ) '=' S_CHAR_LITERAL
    +
               | 'ALIGN' '=' ( 'LEFT' | 'RIGHT' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +FBVSourceColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + FBVSourceColumn + , + + +
    + + +
             ::= FBVSourceColumn ( ','? FBVSourceColumn )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileDestinationOption +====================================================================================================================== + + +.. raw:: html + + + + + + REPLACE + + TRUNCATE + + WITH + + COLUMN + + NAMES + + ENCODING + + NULL + + BOOLEAN + + ROW + + SEPARATOR + + COLUMN + + SEPARATOR + + DELIMITER + + = + + S_CHAR_LITERAL + DELIMIT + + = + + ALWAYS + + NEVER + + AUTO + + +
    + + +
             ::= 'REPLACE'
    +
               | 'TRUNCATE'
    +
               | 'WITH' 'COLUMN' 'NAMES'
    +
               | ( 'ENCODING' | 'NULL' | 'BOOLEAN' | 'ROW' 'SEPARATOR' | 'COLUMN' ( 'SEPARATOR' + | 'DELIMITER' ) ) '=' S_CHAR_LITERAL
    +
               | 'DELIMIT' '=' ( 'ALWAYS' | 'NEVER' | 'AUTO' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileDestinationOptionList +====================================================================================================================== + + +.. raw:: html + + + + + + FileDestinationOption + +
    + + +
             ::= FileDestinationOption+
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileSourceOption +====================================================================================================================== + + +.. raw:: html + + + + + + TRIM + + LTRIM + + RTRIM + + ENCODING + + NULL + + COLUMN + + SEPARATOR + + DELIMITER + + = + + S_CHAR_LITERAL + SKIP + + = + + S_LONG + ROW + + SEPARATOR + + = + + S_CHAR_LITERAL + SIZE + + = + + S_LONG + +
    + + +
             ::= 'TRIM'
    +
               | 'LTRIM'
    +
               | 'RTRIM'
    +
               | ( 'ENCODING' | 'NULL' | 'COLUMN' ( 'SEPARATOR' | 'DELIMITER' ) ) '=' + S_CHAR_LITERAL
    +
               | 'SKIP' '=' S_LONG
    +
               | 'ROW' ( 'SEPARATOR' '=' S_CHAR_LITERAL | 'SIZE' '=' S_LONG )
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileSourceOptionList +====================================================================================================================== + + +.. raw:: html + + + + + + FileSourceOption + +
    + + +
             ::= FileSourceOption+
    +
    + Referenced by: +
    + + +====================================================================================================================== +FileDestination +====================================================================================================================== + + +.. raw:: html + + + + + + FileType + + ConnectionFileDefinitionList + LOCAL + + SECURE + + FileType + + FileList + ( + + CSVDestinationColumnList + + FBVDestinationColumnList + ) + + FileDestinationOptionList + + CertificateVerification + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +FileSource +====================================================================================================================== + + +.. raw:: html + + + + + + FileType + + ConnectionFileDefinitionList + LOCAL + + SECURE + + FileType + + FileList + ( + + CSVSourceColumnList + + FBVSourceColumnList + ) + + FileSourceOptionList + + CertificateVerification + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +CertificateVerification +====================================================================================================================== + + +.. raw:: html + + + + + + IGNORE + + VERIFY + + CERTIFICATE + + PUBLIC + + KEY + + S_CHAR_LITERAL + PUBLIC + + KEY + + S_CHAR_LITERAL + +
    + + +
             ::= ( 'IGNORE' | 'VERIFY' ) 'CERTIFICATE' ( 'PUBLIC' 'KEY' S_CHAR_LITERAL )?
    +
               | 'PUBLIC' 'KEY' S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +ScriptSourceDestination +====================================================================================================================== + + +.. raw:: html + + + + + + SCRIPT + + Table + + ConnectionDefinition + WITH + + RelObjectName + = + + S_CHAR_LITERAL + +
    + + +
             ::= 'SCRIPT' Table ConnectionDefinition? ( 'WITH' ( RelObjectName '=' S_CHAR_LITERAL )+ )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +UserIdentification +====================================================================================================================== + + +.. raw:: html + + + + + + USER + + S_CHAR_LITERAL + IDENTIFIED + + BY + + S_CHAR_LITERAL + +
    + + +
             ::= 'USER' S_CHAR_LITERAL 'IDENTIFIED' 'BY' S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +ConnectionDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + AT + + RelObjectName + + S_CHAR_LITERAL + + UserIdentification + + CertificateVerification + +
    + + + +
    + + +====================================================================================================================== +CloudConnectionDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + AT + + CLOUD + + NONE + + AZURE + + BLOBSTORAGE + + RelObjectName + + S_CHAR_LITERAL + + UserIdentification + +
    + + +
             ::= 'AT' 'CLOUD' ( 'NONE' | 'AZURE' 'BLOBSTORAGE' ) ( RelObjectName | S_CHAR_LITERAL ) UserIdentification?
    +
    + + +====================================================================================================================== +ConnectionOrCloudConnectionDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + CloudConnectionDefinition + + ConnectionDefinition + +
    + + +
             ::= CloudConnectionDefinition
    +
               | ConnectionDefinition
    +
    + + +====================================================================================================================== +ErrorClause +====================================================================================================================== + + +.. raw:: html + + + + + + ERRORS + + INTO + + ErrorDestination + ( + + Expression + ) + + REPLACE + + TRUNCATE + + RejectClause + + RejectClause + +
    + + +
             ::= 'ERRORS' 'INTO' ErrorDestination ( '(' Expression ')' )? ( 'REPLACE' | 'TRUNCATE' )? RejectClause?
    +
               | RejectClause
    +
    + Referenced by: +
    + + +====================================================================================================================== +RejectClause +====================================================================================================================== + + +.. raw:: html + + + + + + REJECT + + LIMIT + + S_LONG + UNLIMITED + + ERRORS + + +
    + + +
             ::= 'REJECT' 'LIMIT' ( S_LONG | 'UNLIMITED' ) 'ERRORS'?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ErrorDestination +====================================================================================================================== + + +.. raw:: html + + + + + + CSVFileDestination + + Table + +
    + + +
             ::= CSVFileDestination
    +
               | Table
    +
    + Referenced by: +
    + + +====================================================================================================================== +CSVFileDestination +====================================================================================================================== + + +.. raw:: html + + + + + + CSV + + ConnectionOrCloudConnectionDefinition + LOCAL + + SECURE + + CSV + + File + +
    + + +
             ::= ( 'CSV' ConnectionOrCloudConnectionDefinition | 'LOCAL' 'SECURE'? 'CSV' ) File
    +
    + Referenced by: +
    + + +====================================================================================================================== +Declare +====================================================================================================================== + + +.. raw:: html + + + + + + DECLARE + + UserVariable + TABLE + + ( + + ColumnDefinition + , + + ) + + AS + + RelObjectName + + ColDataType + = + + Expression + + UserVariable + , + + +
    + +
    Declare  ::= 'DECLARE' UserVariable ( 'TABLE' '(' ColumnDefinition ( ',' ColumnDefinition )* ')' | 'AS' RelObjectName | ColDataType ( '=' Expression )? ( ',' UserVariable ColDataType ( '=' Expression )? )* )
    +
    + Referenced by: +
    + + +====================================================================================================================== +SessionStatement +====================================================================================================================== + + +.. raw:: html + + + + + + SESSION + + BRANCH + + START + + APPLY + + DROP + + SHOW + + DESCRIBE + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + S_CHAR_LITERAL + + S_LONG + . + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + S_CHAR_LITERAL + + S_LONG + WITH + + S_IDENTIFIER + KEEP + + = + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + S_CHAR_LITERAL + + S_LONG + TRUE + + FALSE + + ON + + OFF + + YES + + NO + + , + + +
    + + +
             ::= ( 'SESSION' | 'BRANCH' ) ( 'START' | 'APPLY' | 'DROP' | 'SHOW' | 'DESCRIBE' + ) ( ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | S_CHAR_LITERAL | S_LONG ) ( '.' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | S_CHAR_LITERAL | S_LONG ) )? )? ( 'WITH' ( S_IDENTIFIER | 'KEEP' ) '=' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | S_CHAR_LITERAL | S_LONG | 'TRUE' | 'FALSE' | 'ON' | 'OFF' | 'YES' | 'NO' ) ( ',' ( S_IDENTIFIER | 'KEEP' ) '=' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | S_CHAR_LITERAL | S_LONG | 'TRUE' | 'FALSE' | 'ON' | 'OFF' | 'YES' | 'NO' ) )* )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Set +====================================================================================================================== + + +.. raw:: html + + + + + + SET + + LOCAL + + SESSION + + K_DATETIMELITERAL + ZONE + + UserVariable + + IdentifierChain + = + + Expression + ZONE + + K_DATETIMELITERAL + = + + RelObjectName + , + + +
    + +
    Set      ::= 'SET' ( 'LOCAL' | 'SESSION' )? ( K_DATETIMELITERAL 'ZONE' | ( UserVariable | IdentifierChain ) '='? ) Expression ( ',' ( K_DATETIMELITERAL 'ZONE' | RelObjectName '='? )? Expression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Reset +====================================================================================================================== + + +.. raw:: html + + + + + + RESET + + K_DATETIMELITERAL + ZONE + + RelObjectName + ALL + + +
    + +
    Reset    ::= 'RESET' ( K_DATETIMELITERAL 'ZONE' | RelObjectName | 'ALL' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +RenameTableStatement +====================================================================================================================== + + +.. raw:: html + + + + + + RENAME + + TABLE + + IF + + EXISTS + + Table + WAIT + + S_LONG + NOWAIT + + TO + + Table + + Table + , + + +
    + + +
             ::= 'RENAME' 'TABLE'? ( 'IF' 'EXISTS' )? Table ( 'WAIT' S_LONG | 'NOWAIT' )? 'TO' Table ( ',' Table 'TO' Table )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +PurgeStatement +====================================================================================================================== + + +.. raw:: html + + + + + + PURGE + + TABLE + + Table + INDEX + + Index + RECYCLEBIN + + DBA_RECYCLEBIN + + TABLESPACE + + S_IDENTIFIER + USER + + S_IDENTIFIER + +
    + + +
             ::= 'PURGE' ( 'TABLE' Table | 'INDEX' Index | 'RECYCLEBIN' | 'DBA_RECYCLEBIN' | 'TABLESPACE' S_IDENTIFIER ( 'USER' S_IDENTIFIER )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +Describe +====================================================================================================================== + + +.. raw:: html + + + + + + DESCRIBE + + DESC + + Table + +
    + +
    Describe ::= ( 'DESCRIBE' | 'DESC' ) Table
    +
    + Referenced by: +
    + + +====================================================================================================================== +Explain +====================================================================================================================== + + +.. raw:: html + + + + + + EXPLAIN + + SUMMARIZE + + ExplainStatementOptions + + WithList + + SelectWithWithItems + + InsertWithWithItems + + UpdateWithWithItems + + DeleteWithWithItems + + Merge + + Table + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +ExplainOptionBoolean +====================================================================================================================== + + +.. raw:: html + + + + + + TRUE + + FALSE + + ON + + OFF + + +
    + + +
             ::= ( 'TRUE' | 'FALSE' | 'ON' | 'OFF' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExplainFormatOption +====================================================================================================================== + + +.. raw:: html + + + + + + XML + + JSON + + YAML + + +
    + + +
             ::= ( 'XML' | 'JSON' | 'YAML' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExplainStatementOptions +====================================================================================================================== + + +.. raw:: html + + + + + + ANALYZE + + BUFFERS + + COSTS + + VERBOSE + + ExplainOptionBoolean + FORMAT + + PLAN + + FOR + + ExplainFormatOption + +
    + + +
             ::= ( ( 'ANALYZE' | 'BUFFERS' | 'COSTS' | 'VERBOSE' ) ExplainOptionBoolean | ( 'FORMAT' | 'PLAN' 'FOR'? ) ExplainFormatOption )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Use +====================================================================================================================== + + +.. raw:: html + + + + + + USE + + SCHEMA + + RelObjectName + +
    + +
    Use      ::= 'USE' 'SCHEMA'? RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +Show +====================================================================================================================== + + +.. raw:: html + + + + + + SHOW + + ShowColumns + + ShowIndex + + ShowTables + + captureRest + +
    + +
    Show     ::= 'SHOW' ( ShowColumns | ShowIndex | ShowTables | captureRest )
    +
    + Referenced by: +
    + + +====================================================================================================================== +ShowColumns +====================================================================================================================== + + +.. raw:: html + + + + + + COLUMNS + + FROM + + RelObjectName + +
    + + +
             ::= 'COLUMNS' 'FROM' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +ShowIndex +====================================================================================================================== + + +.. raw:: html + + + + + + INDEX + + FROM + + RelObjectName + +
    + + +
             ::= 'INDEX' 'FROM' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +RefreshMaterializedView +====================================================================================================================== + + +.. raw:: html + + + + + + REFRESH + + MATERIALIZED + + VIEW + + CONCURRENTLY + + Table + WITH + + NO + + DATA + + captureRest + +
    + + +
             ::= 'REFRESH' 'MATERIALIZED' 'VIEW' 'CONCURRENTLY'? Table ( 'WITH' 'NO'? 'DATA' )? captureRest
    +
    + Referenced by: +
    + + +====================================================================================================================== +ShowTables +====================================================================================================================== + + +.. raw:: html + + + + + + EXTENDED + + FULL + + TABLES + + FROM + + IN + + RelObjectName + LIKE + + SimpleExpression + WHERE + + Expression + +
    + + +
             ::= 'EXTENDED'? 'FULL'? 'TABLES' ( ( 'FROM' | 'IN' ) RelObjectName )? ( 'LIKE' SimpleExpression | 'WHERE' Expression )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Values +====================================================================================================================== + + +.. raw:: html + + + + + + VALUES + + VALUE + + ExpressionList + +
    + +
    Values   ::= ( 'VALUES' | 'VALUE' ) ExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReturningClause +====================================================================================================================== + + +.. raw:: html + + + + + + RETURNING + + RETURN + + ReturningOutputAliasList + + SelectItemsList + INTO + + Table + + UserVariable + , + + +
    + + +
             ::= ( 'RETURNING' | 'RETURN' ) ReturningOutputAliasList? SelectItemsList ( 'INTO' ( Table | UserVariable ) ( ',' ( Table | UserVariable ) )* )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReturningReferenceKind +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + +
    + + +
             ::= RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReturningOutputAliasDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + ReturningReferenceKind + AS + + RelObjectName + +
    + + +
             ::= ReturningReferenceKind 'AS' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReturningOutputAliasList +====================================================================================================================== + + +.. raw:: html + + + + + + WITH + + ( + + ReturningOutputAliasDefinition + , + + ) + + +
    + + +
             ::= 'WITH' '(' ReturningOutputAliasDefinition ( ',' ReturningOutputAliasDefinition )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +UpdateWithWithItems +====================================================================================================================== + + +.. raw:: html + + + + + + Update + +
    + + +
             ::= Update
    +
    + Referenced by: +
    + + +====================================================================================================================== +Update +====================================================================================================================== + + +.. raw:: html + + + + + + UPDATE + + LOW_PRIORITY + + IGNORE + + TableWithAliasAndMysqlIndexHint + + JoinsList + SET + + UpdateSets + + OutputClause + FROM + + FromItem + + JoinsList + + WhereClause + + PreferringClause + + OrderByElements + + PlainLimit + + ReturningClause + +
    + + +
    + + +====================================================================================================================== +UpdateSets +====================================================================================================================== + + +.. raw:: html + + + + + + Column + = + + Expression + + ParenthesedExpressionList + = + + ParenthesedSelect + + ParenthesedExpressionList + , + + Column + = + + Expression + + ParenthesedExpressionList + = + + ParenthesedSelect + + ParenthesedExpressionList + +
    + + + +
    + + +====================================================================================================================== +Partitions +====================================================================================================================== + + +.. raw:: html + + + + + + Column + = + + Expression + , + + +
    + + +
             ::= Column ( '=' Expression )? ( ',' Column ( '=' Expression )? )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +InsertWithWithItems +====================================================================================================================== + + +.. raw:: html + + + + + + Insert + +
    + + +
             ::= Insert
    +
    + Referenced by: +
    + + +====================================================================================================================== +Insert +====================================================================================================================== + + +.. raw:: html + + + + + + INSERT + + LOW_PRIORITY + + DELAYED + + HIGH_PRIORITY + + IGNORE + + ALL + + FIRST + + OracleMultiInsertClause + + OracleMultiInsertWhenBranch + + OracleMultiInsertElseBranch + + Select + OVERWRITE + + TABLE + + INTO + + TABLE + + Table + PARTITION + + ( + + Partitions + ) + + AS + + RelObjectName + ( + + ColumnList + ) + + OVERRIDING + + SYSTEM + + VALUE + + OutputClause + DEFAULT + + VALUES + + SET + + UpdateSets + + Select + + Alias + ON + + DUPLICATE + + KEY + + UPDATE + + InsertDuplicateAction + ON + + CONFLICT + + InsertConflictTarget + + InsertConflictAction + + ReturningClause + +
    + +
    Insert   ::= 'INSERT' ( 'LOW_PRIORITY' | 'DELAYED' | 'HIGH_PRIORITY' )? 'IGNORE'? ( ( 'ALL' + | 'FIRST' ) ( OracleMultiInsertClause+ | OracleMultiInsertWhenBranch+ OracleMultiInsertElseBranch? ) Select | ( 'OVERWRITE' 'TABLE' | 'INTO' 'TABLE'? )? Table ( 'PARTITION' '(' Partitions ')' )? ( 'AS'? RelObjectName )? ( '(' ColumnList ')' )? ( 'OVERRIDING' 'SYSTEM' 'VALUE' )? OutputClause? ( 'DEFAULT' 'VALUES' | 'SET' UpdateSets | Select ) Alias? ( 'ON' 'DUPLICATE' 'KEY' 'UPDATE' InsertDuplicateAction )? ( 'ON' 'CONFLICT' InsertConflictTarget? InsertConflictAction )? ReturningClause? )
    +
    + + +====================================================================================================================== +OracleMultiInsertClause +====================================================================================================================== + + +.. raw:: html + + + + + + INTO + + Table + ( + + ColumnList + ) + + Select + +
    + + +
             ::= 'INTO' Table ( '(' ColumnList ')' )? Select
    +
    + + +====================================================================================================================== +OracleMultiInsertWhenBranch +====================================================================================================================== + + +.. raw:: html + + + + + + WHEN + + Expression + THEN + + OracleMultiInsertClauseList + +
    + + +
             ::= 'WHEN' Expression 'THEN' OracleMultiInsertClauseList
    +
    + Referenced by: +
    + + +====================================================================================================================== +OracleMultiInsertElseBranch +====================================================================================================================== + + +.. raw:: html + + + + + + ELSE + + OracleMultiInsertClauseList + +
    + + +
             ::= 'ELSE' OracleMultiInsertClauseList
    +
    + Referenced by: +
    + + +====================================================================================================================== +OracleMultiInsertClauseList +====================================================================================================================== + + +.. raw:: html + + + + + + OracleMultiInsertClause + +
    + + +
             ::= OracleMultiInsertClause+
    +
    + + +====================================================================================================================== +InsertConflictTarget +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + RelObjectNameExt + , + + ) + + WhereClause + ON + + CONSTRAINT + + RelObjectNameExt + +
    + + +
             ::= '(' RelObjectNameExt ( ',' RelObjectNameExt )* ')' WhereClause?
    +
               | 'ON' 'CONSTRAINT' RelObjectNameExt
    +
    + Referenced by: +
    + + +====================================================================================================================== +InsertConflictAction +====================================================================================================================== + + +.. raw:: html + + + + + + DO + + NOTHING + + UPDATE + + SET + + UpdateSets + + WhereClause + +
    + + +
             ::= 'DO' ( 'NOTHING' | 'UPDATE' 'SET' UpdateSets WhereClause? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +InsertDuplicateAction +====================================================================================================================== + + +.. raw:: html + + + + + + NOTHING + + UpdateSets + + WhereClause + +
    + + +
             ::= 'NOTHING'
    +
               | UpdateSets WhereClause?
    +
    + Referenced by: +
    + + +====================================================================================================================== +OutputClause +====================================================================================================================== + + +.. raw:: html + + + + + + OUTPUT + + SelectItemsList + INTO + + UserVariable + + Table + + ColumnsNamesList + +
    + + +
             ::= 'OUTPUT' SelectItemsList ( 'INTO' ( UserVariable | Table ) ColumnsNamesList? )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Upsert +====================================================================================================================== + + +.. raw:: html + + + + + + UPSERT + + INSERT + + OR + + REPLACE + + INTO + + Table + + ParenthesedColumnList + SET + + UpdateSets + + Select + ON + + DUPLICATE + + KEY + + UPDATE + + InsertDuplicateAction + +
    + +
    Upsert   ::= ( 'UPSERT' | ( 'INSERT' 'OR' )? 'REPLACE' ) 'INTO'? Table ParenthesedColumnList? ( 'SET' UpdateSets | Select ) ( 'ON' 'DUPLICATE' 'KEY' 'UPDATE' InsertDuplicateAction )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +DeleteWithWithItems +====================================================================================================================== + + +.. raw:: html + + + + + + Delete + +
    + + +
             ::= Delete
    +
    + Referenced by: +
    + + +====================================================================================================================== +Delete +====================================================================================================================== + + +.. raw:: html + + + + + + DELETE + + LOW_PRIORITY + + QUICK + + IGNORE + + TableWithAlias + , + + OutputClause + FROM + + TableWithAlias + + JoinsList + USING + + FromItem + , + + WhereClause + + PreferringClause + + OrderByElements + + PlainLimit + + ReturningClause + +
    + +
    Delete   ::= 'DELETE' 'LOW_PRIORITY'? 'QUICK'? 'IGNORE'? ( ( TableWithAlias ( ',' TableWithAlias )* OutputClause? )? 'FROM' )? ( TableWithAlias JoinsList? )? ( 'USING' FromItem ( ',' FromItem )* )? WhereClause? PreferringClause? OrderByElements? PlainLimit? ReturningClause?
    +
    + + +====================================================================================================================== +Merge +====================================================================================================================== + + +.. raw:: html + + + + + + MERGE + + INTO + + TableWithAlias + USING + + FromItem + ON + + Expression + + MergeOperations + + OutputClause + +
    + +
    Merge    ::= 'MERGE' 'INTO' TableWithAlias 'USING' FromItem 'ON' Expression MergeOperations OutputClause?
    +
    + Referenced by: +
    + + +====================================================================================================================== +MergeOperations +====================================================================================================================== + + +.. raw:: html + + + + + + MergeWhenMatched + + MergeWhenNotMatched + +
    + + +
             ::= ( MergeWhenMatched | MergeWhenNotMatched )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +MergeWhenMatched +====================================================================================================================== + + +.. raw:: html + + + + + + WHEN + + MATCHED + + AND + + Expression + THEN + + DELETE + + MergeUpdateClause + +
    + + +
             ::= 'WHEN' 'MATCHED' ( 'AND' Expression )? 'THEN' ( 'DELETE' | MergeUpdateClause )
    +
    + Referenced by: +
    + + +====================================================================================================================== +MergeUpdateClause +====================================================================================================================== + + +.. raw:: html + + + + + + UPDATE + + SET + + UpdateSets + WHERE + + Expression + DELETE + + WHERE + + Expression + +
    + + +
             ::= 'UPDATE' 'SET' UpdateSets ( 'WHERE' Expression )? ( 'DELETE' 'WHERE' Expression )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +MergeWhenNotMatched +====================================================================================================================== + + +.. raw:: html + + + + + + WHEN + + NOT + + MATCHED + + AND + + Expression + THEN + + INSERT + + ( + + ColumnList + ) + + VALUES + + ( + + SimpleExpressionList + ) + + WHERE + + Expression + +
    + + +
             ::= 'WHEN' 'NOT' 'MATCHED' ( 'AND' Expression )? 'THEN' 'INSERT' ( '(' ColumnList ')' )? 'VALUES' '(' SimpleExpressionList ')' ( 'WHERE' Expression )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +RelObjectNames +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ... + + .. + + . + + : + + RelObjectNameExt + +
    + + +
             ::= RelObjectName ( ( '...' | '..' | '.' | ':' ) RelObjectNameExt )*
    +
    + + +====================================================================================================================== +ColumnIdentifier +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ... + + .. + + . + + RelObjectNameExt + +
    + + +
             ::= RelObjectName ( ( '...' | '..' | '.' ) RelObjectNameExt )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Column +====================================================================================================================== + + +.. raw:: html + + + + + + ColumnIdentifier + COMMENT + + S_CHAR_LITERAL + . + + K_NEXTVAL + + ArrayConstructor + +
    + + +
    + + +====================================================================================================================== +RelObjectName +====================================================================================================================== + + +.. raw:: html + + + + + + DATA_TYPE + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + K_DATETIMELITERAL + + K_DATE_LITERAL + + NonReservedWord + ALL + + ANY + + CASEWHEN + + CONNECT + + CREATE + + DEFAULT + + GLOBAL + + GROUP + + GROUPING + + IF + + IIF + + IGNORE + + IN + + INTERVAL + + LEFT + + LIMIT + + K_NEXTVAL + OFFSET + + ON + + OPTIMIZE + + ORDER + + PROCEDURE + + PUBLIC + + QUALIFY + + RIGHT + + SET + + SOME + + START + + TABLES + + TOP + + VALUE + + VALUES + + +
    + + +
             ::= DATA_TYPE
    +
               | S_IDENTIFIER
    +
               | S_QUOTED_IDENTIFIER
    +
               | K_DATETIMELITERAL
    +
               | K_DATE_LITERAL
    +
               | NonReservedWord
    +
               | 'ALL'
    +
               | 'ANY'
    +
               | 'CASEWHEN'
    +
               | 'CONNECT'
    +
               | 'CREATE'
    +
               | 'DEFAULT'
    +
               | 'GLOBAL'
    +
               | 'GROUP'
    +
               | 'GROUPING'
    +
               | 'IF'
    +
               | 'IIF'
    +
               | 'IGNORE'
    +
               | 'IN'
    +
               | 'INTERVAL'
    +
               | 'LEFT'
    +
               | 'LIMIT'
    +
               | K_NEXTVAL
    +
               | 'OFFSET'
    +
               | 'ON'
    +
               | 'OPTIMIZE'
    +
               | 'ORDER'
    +
               | 'PROCEDURE'
    +
               | 'PUBLIC'
    +
               | 'QUALIFY'
    +
               | 'RIGHT'
    +
               | 'SET'
    +
               | 'SOME'
    +
               | 'START'
    +
               | 'TABLES'
    +
               | 'TOP'
    +
               | 'VALUE'
    +
               | 'VALUES'
    +
    + + +====================================================================================================================== +RelObjectNameExt +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + FROM + + K_SELECT + CURRENT + + +
    + + +
             ::= RelObjectName
    +
               | 'FROM'
    +
               | K_SELECT
    +
               | 'CURRENT'
    +
    + + +====================================================================================================================== +Table +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNames + + TimeTravelBeforeAlias + + S_CHAR_LITERAL + +
    + + +
               | S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +TableWithAlias +====================================================================================================================== + + +.. raw:: html + + + + + + Table + + Alias + +
    + + +
             ::= Table Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +TableWithAliasAndMysqlIndexHint +====================================================================================================================== + + +.. raw:: html + + + + + + Table + + Alias + + MySQLIndexHint + +
    + + +
             ::= Table Alias? MySQLIndexHint?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Number +====================================================================================================================== + + +.. raw:: html + + + + + + S_DOUBLE + + S_LONG + +
    + +
    Number   ::= S_DOUBLE
    +
               | S_LONG
    +
    + Referenced by: +
    + + +====================================================================================================================== +SampleClause +====================================================================================================================== + + +.. raw:: html + + + + + + SAMPLE + + BLOCK + + TABLESAMPLE + + USING + + SAMPLE + + SYSTEM + + BERNOULLI + + ( + + Number + % + + PERCENT + + ROWS + + ) + + REPEATABLE + + ( + + Number + ) + + SEED + + ( + + Number + ) + + Number + OFFSET + + Number + +
    + + +
             ::= ( 'SAMPLE' 'BLOCK'? | ( 'TABLESAMPLE' | 'USING' 'SAMPLE' ) ( 'SYSTEM' + | 'BERNOULLI' ) ) ( '(' Number ( '%' | 'PERCENT' | 'ROWS' )? ')' ( 'REPEATABLE' '(' Number ')' )? ( 'SEED' '(' Number ')' )? | Number ( 'OFFSET' Number )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +SelectWithWithItems +====================================================================================================================== + + +.. raw:: html + + + + + + Select + +
    + + +
             ::= Select
    +
    + Referenced by: +
    + + +====================================================================================================================== +Select +====================================================================================================================== + + +.. raw:: html + + + + + + WithList + + FromQuery + + PlainSelect + + Values + + ParenthesedSelect + + Alias + + FromQueryFromSelect + + SetOperationList + + OrderByElements + + LimitWithOffset + + Offset + + Fetch + + WithIsolation + +
    + + +
    + + +====================================================================================================================== +FromQuery +====================================================================================================================== + + +.. raw:: html + + + + + + FROM + + FromItem + + LateralViews + + JoinsList + |> + + PipeOperator + +
    + + +
             ::= 'FROM' FromItem LateralViews? JoinsList? ( '|>' PipeOperator )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +FromQueryFromSelect +====================================================================================================================== + + +.. raw:: html + + + + + + |> + + PipeOperator + +
    + + +
             ::= ( '|>' PipeOperator )+
    +
    + Referenced by: +
    + + +====================================================================================================================== +PipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + SelectPipeOperator + + SetPipeOperator + + DropPipeOperator + + AsPipeOperator + + WherePipeOperator + + LimitPipeOperator + + AggregatePipeOperator + + OrderByPipeOperator + + SetOperationPipeOperator + + JoinPipeOperator + + CallPipeOperator + + TableSamplePipeOperator + + PivotPipeOperator + + UnPivotPipeOperator + +
    + + +
             ::= SelectPipeOperator
    +
               | SetPipeOperator
    +
               | DropPipeOperator
    +
               | AsPipeOperator
    +
               | WherePipeOperator
    +
               | LimitPipeOperator
    +
               | AggregatePipeOperator
    +
               | OrderByPipeOperator
    +
               | SetOperationPipeOperator
    +
               | JoinPipeOperator
    +
               | CallPipeOperator
    +
               | TableSamplePipeOperator
    +
               | PivotPipeOperator
    +
               | UnPivotPipeOperator
    +
    + Referenced by: +
    + + +====================================================================================================================== +SelectPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + K_SELECT + DISTINCT + + ALL + + EXTEND + + WINDOW + + RENAME + + SelectItem + , + + +
    + + +
             ::= ( K_SELECT ( 'DISTINCT' | 'ALL' )? | 'EXTEND' | 'WINDOW' | 'RENAME' ) SelectItem ( ',' SelectItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +WherePipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + WHERE + + Expression + +
    + + +
             ::= 'WHERE' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +OrderSuffix +====================================================================================================================== + + +.. raw:: html + + + + + + ASC + + DESC + + NULLS + + FIRST + + LAST + + +
    + + +
             ::= ( 'ASC' | 'DESC' ) ( 'NULLS' ( 'FIRST' | 'LAST' ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +AggregatePipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + AGGREGATE + + SelectItem + + OrderSuffix + , + + GROUP + + AND + + ORDER + + BY + + SelectItem + + OrderSuffix + , + + +
    + + +
             ::= 'AGGREGATE' SelectItem OrderSuffix? ( ',' SelectItem OrderSuffix? )* ( 'GROUP' ( 'AND' 'ORDER' )? 'BY' SelectItem OrderSuffix? ( ',' SelectItem OrderSuffix? )* )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +OrderByPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + OrderByElements + +
    + + +
             ::= OrderByElements
    +
    + Referenced by: +
    + + +====================================================================================================================== +AsPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + AS + + Alias + +
    + + +
             ::= 'AS' Alias
    +
    + Referenced by: +
    + + +====================================================================================================================== +JoinPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + JoinerExpression + +
    + + +
             ::= JoinerExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +SetPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + SET + + UpdateSets + +
    + + +
             ::= 'SET' UpdateSets
    +
    + Referenced by: +
    + + +====================================================================================================================== +DropPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + DROP + + ColumnList + +
    + + +
             ::= 'DROP' ColumnList
    +
    + Referenced by: +
    + + +====================================================================================================================== +LimitPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + LIMIT + + Expression + OFFSET + + Expression + +
    + + +
             ::= 'LIMIT' Expression ( 'OFFSET' Expression )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +SetOperationModifier +====================================================================================================================== + + +.. raw:: html + + + + + + ALL + + DISTINCT + + BY + + NAME + + MATCHING + + ( + + RelObjectName + , + + ) + + STRICT + + CORRESPONDING + + ALL + + DISTINCT + + BY + + ALL + + DISTINCT + + ( + + RelObjectName + , + + ) + + ALL + + DISTINCT + + +
    + + +
             ::= ( 'ALL' | 'DISTINCT' )? 'BY' 'NAME' ( 'MATCHING' '(' RelObjectName ( ',' RelObjectName )* ')' )?
    +
               | 'STRICT'? 'CORRESPONDING' ( 'ALL' | 'DISTINCT' )? ( 'BY' ( 'ALL' | 'DISTINCT' + )? '(' RelObjectName ( ',' RelObjectName )* ')' )?
    +
               | 'ALL'
    +
               | 'DISTINCT'
    +
    + + +====================================================================================================================== +SetOperationPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + UNION + + INTERSECT + + EXCEPT + + SetOperationModifier + + ParenthesedSelect + , + + +
    + + +
             ::= ( 'UNION' | 'INTERSECT' | 'EXCEPT' ) SetOperationModifier? ParenthesedSelect ( ',' ParenthesedSelect )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CallPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + CALL + + TableFunction + + Alias + +
    + + +
             ::= 'CALL' TableFunction Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +TableSamplePipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + TABLESAMPLE + + SYSTEM + + ( + + S_DOUBLE + + S_LONG + PERCENT + + ) + + +
    + + +
             ::= 'TABLESAMPLE' 'SYSTEM' '(' ( S_DOUBLE | S_LONG ) 'PERCENT' ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + PIVOT + + ( + + Function + FOR + + Column + IN + + ( + + SelectItemsList + ) + + ) + + Alias + +
    + + +
             ::= 'PIVOT' '(' Function 'FOR' Column 'IN' '(' SelectItemsList ')' ')' Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnPivotPipeOperator +====================================================================================================================== + + +.. raw:: html + + + + + + UNPIVOT + + ( + + Column + FOR + + Column + IN + + ( + + SelectItemsList + ) + + ) + + Alias + +
    + + +
             ::= 'UNPIVOT' '(' Column 'FOR' Column 'IN' '(' SelectItemsList ')' ')' Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +TableStatement +====================================================================================================================== + + +.. raw:: html + + + + + + TABLE + + Table + + OrderByElements + + LimitWithOffset + + Offset + +
    + + +
             ::= 'TABLE' Table OrderByElements? LimitWithOffset? Offset?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ParenthesedSelect +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Select + ) + + +
    + + +
             ::= '(' Select ')'
    +
    + + +====================================================================================================================== +ParenthesedInsert +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Insert + ) + + +
    + + +
             ::= '(' Insert ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ParenthesedUpdate +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Update + ) + + +
    + + +
             ::= '(' Update ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ParenthesedDelete +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Delete + ) + + +
    + + +
             ::= '(' Delete ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +LateralView +====================================================================================================================== + + +.. raw:: html + + + + + + LATERAL + + VIEW + + OUTER + + Function + + RelObjectName + AS + + RelObjectName + , + + RelObjectName + +
    + + +
             ::= 'LATERAL' 'VIEW' 'OUTER'? Function RelObjectName? 'AS' RelObjectName ( ',' RelObjectName )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ForClause +====================================================================================================================== + + +.. raw:: html + + + + + + FOR + + BROWSE + + XML + + RAW + + ( + + S_CHAR_LITERAL + ) + + AUTO + + , + + BINARY + + BASE64 + + TYPE + + ROOT + + XMLSCHEMA + + ( + + S_CHAR_LITERAL + ) + + XMLDATA + + ELEMENTS + + XSINIL + + ABSENT + + EXPLICIT + + , + + BINARY + + BASE64 + + TYPE + + ROOT + + ( + + S_CHAR_LITERAL + ) + + XMLDATA + + PATH + + ( + + S_CHAR_LITERAL + ) + + , + + BINARY + + BASE64 + + TYPE + + ROOT + + ( + + S_CHAR_LITERAL + ) + + ELEMENTS + + XSINIL + + ABSENT + + JSON + + AUTO + + PATH + + , + + ROOT + + ( + + S_CHAR_LITERAL + ) + + INCLUDE_NULL_VALUES + + WITHOUT_ARRAY_WRAPPER + + +
    + + +
             ::= 'FOR' ( 'BROWSE' | 'XML' ( ( 'RAW' ( '(' S_CHAR_LITERAL ')' )? | 'AUTO' ) ( ',' ( 'BINARY' 'BASE64' | 'TYPE' | ( 'ROOT' | 'XMLSCHEMA' ) ( + '(' S_CHAR_LITERAL ')' )? | 'XMLDATA' | 'ELEMENTS' ( 'XSINIL' | 'ABSENT' )? ) )* | 'EXPLICIT' ( ',' + ( 'BINARY' 'BASE64' | 'TYPE' | 'ROOT' ( '(' S_CHAR_LITERAL ')' )? | 'XMLDATA' ) )* | 'PATH' ( '(' S_CHAR_LITERAL ')' )? ( ',' ( 'BINARY' 'BASE64' | 'TYPE' | 'ROOT' ( '(' S_CHAR_LITERAL ')' )? | 'ELEMENTS' ( 'XSINIL' | 'ABSENT' )? ) )* ) | 'JSON' ( 'AUTO' | 'PATH' ) + ( ',' ( 'ROOT' ( '(' S_CHAR_LITERAL ')' )? | 'INCLUDE_NULL_VALUES' | 'WITHOUT_ARRAY_WRAPPER' ) )* )
    +
    + Referenced by: +
    + + +====================================================================================================================== +LateralViews +====================================================================================================================== + + +.. raw:: html + + + + + + LateralView + +
    + + +
             ::= LateralView+
    +
    + Referenced by: +
    + + +====================================================================================================================== +LateralSubSelect +====================================================================================================================== + + +.. raw:: html + + + + + + LATERAL + + ( + + Select + ) + + +
    + + +
             ::= 'LATERAL' '(' Select ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +PlainSelect +====================================================================================================================== + + +.. raw:: html + + + + + + K_SELECT + STRAIGHT_JOIN + + Skip + + First + + Top + ALL + + DISTINCT + + ON + + ( + + SelectItemsList + ) + + DISTINCTROW + + UNIQUE + + SQL_CALC_FOUND_ROWS + + SQL_NO_CACHE + + SQL_CACHE + + AS + + STRUCT + + VALUE + + Top + + SelectItemsList + + MySqlSelectIntoClause + + IntoClause + FROM + + FromItem + + LateralViews + + JoinsList + FROM + + ONLY + + FromItem + + LateralViews + + JoinsList + FINAL + + KSQLWindowClause + + PreWhereClause + + WhereClause + + OracleHierarchicalQueryClause + + PreferringClause + PARTITION + + BY + + ComplexExpressionList + ( + + ComplexExpressionList + ) + + Having + + GroupByColumnReferences + + Having + + Qualify + + OrderByElements + WINDOW + + RelObjectName + AS + + windowDefinition + , + + OrderByElements + + ForClause + EMIT + + CHANGES + + LimitBy + + LimitWithOffset + + Offset + + LimitWithOffset + + Fetch + + WithIsolation + FOR + + NO + + KEY + + UPDATE + + KEY + + SHARE + + READ + + FETCH + + ONLY + + OF + + Table + + Wait + NOWAIT + + SKIP + + LOCKED + + MySqlSelectIntoClause + SETTINGS + + UpdateSets + + OptimizeFor + INTO + + TEMP + + Table + WITH + + NO + + LOG + + +
    + + +
             ::= K_SELECT 'STRAIGHT_JOIN'? Skip? First? Top? ( 'ALL' | 'DISTINCT' ( 'ON' '(' SelectItemsList ')' )? | 'DISTINCTROW' | 'UNIQUE' | 'SQL_CALC_FOUND_ROWS' | 'SQL_NO_CACHE' | 'SQL_CACHE' + )? ( 'AS' ( 'STRUCT' | 'VALUE' ) )? Top? SelectItemsList MySqlSelectIntoClause? IntoClause? ( 'FROM' FromItem LateralViews? JoinsList? )? ( 'FROM' 'ONLY' FromItem LateralViews? JoinsList? )? 'FINAL'? KSQLWindowClause? PreWhereClause? WhereClause? OracleHierarchicalQueryClause? ( PreferringClause ( 'PARTITION' 'BY' ( ComplexExpressionList | '(' ComplexExpressionList ')' ) )? )? Having? GroupByColumnReferences? Having? Qualify? OrderByElements? ( 'WINDOW' RelObjectName 'AS' windowDefinition ( ',' RelObjectName 'AS' windowDefinition )* )? OrderByElements? ForClause? ( 'EMIT' 'CHANGES' )? LimitBy? LimitWithOffset? Offset? LimitWithOffset? Fetch? WithIsolation? ( 'FOR' ( ( 'NO' 'KEY' )? 'UPDATE' | 'KEY'? 'SHARE' | ( 'READ' | 'FETCH' ) 'ONLY' + ) ( 'OF' Table )? Wait? ( 'NOWAIT' | 'SKIP' 'LOCKED' )? )? MySqlSelectIntoClause? ( 'SETTINGS' UpdateSets )? OptimizeFor? ( 'INTO' 'TEMP' Table )? ( 'WITH' 'NO' 'LOG' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +SetOperationList +====================================================================================================================== + + +.. raw:: html + + + + + + UNION + + INTERSECT + + MINUS + + EXCEPT + + SetOperationModifier + + PlainSelect + + Values + + ParenthesedSelect + + OrderByElements + + LimitWithOffset + + Offset + + LimitWithOffset + + Fetch + + WithIsolation + +
    + + +
             ::= ( ( 'UNION' | 'INTERSECT' | 'MINUS' | 'EXCEPT' ) SetOperationModifier? ( PlainSelect | Values | ParenthesedSelect ) )+ OrderByElements? LimitWithOffset? Offset? LimitWithOffset? Fetch? WithIsolation?
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithList +====================================================================================================================== + + +.. raw:: html + + + + + + WITH + + WithItem + , + + +
    + +
    WithList ::= 'WITH' WithItem ( ',' WithItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithItem +====================================================================================================================== + + +.. raw:: html + + + + + + FUNCTION + + WithFunctionDeclaration + RECURSIVE + + RelObjectName + ( + + SelectItemsList + ) + + AS + + NOT + + MATERIALIZED + + ParenthesedSelect + + ParenthesedInsert + + ParenthesedUpdate + + ParenthesedDelete + + WithSearchClause + +
    + +
    WithItem ::= ( 'FUNCTION' WithFunctionDeclaration | 'RECURSIVE'? RelObjectName ( '(' SelectItemsList ')' )? 'AS' ( 'NOT'? 'MATERIALIZED' )? ( ParenthesedSelect | ParenthesedInsert | ParenthesedUpdate | ParenthesedDelete ) ) WithSearchClause?
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithSearchClause +====================================================================================================================== + + +.. raw:: html + + + + + + SEARCH + + BREADTH + + DEPTH + + FIRST + + BY + + Column + , + + SET + + RelObjectName + +
    + + +
             ::= 'SEARCH' ( 'BREADTH' | 'DEPTH' ) 'FIRST' 'BY' Column ( ',' Column )* 'SET' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithFunctionDeclaration +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ( + + WithFunctionParameter + , + + ) + + RETURNS + + RelObjectName + RETURN + + Expression + +
    + + +
             ::= RelObjectName '(' ( WithFunctionParameter ( ',' WithFunctionParameter )* )? ')' 'RETURNS' RelObjectName 'RETURN' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +WithFunctionParameter +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ARRAY + + < + + RelObjectName + > + + RelObjectName + +
    + + +
             ::= RelObjectName ( 'ARRAY' '<' RelObjectName '>' | RelObjectName )
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnSelectItemsList +====================================================================================================================== + + +.. raw:: html + + + + + + SelectItem + , + + +
    + + +
             ::= SelectItem ( ',' SelectItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +SelectItemsList +====================================================================================================================== + + +.. raw:: html + + + + + + SelectItem + , + + +
    + + +
             ::= SelectItem ( ',' SelectItem )*
    +
    + + +====================================================================================================================== +FunctionAllColumns +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Function + ) + + . + + * + + +
    + + +
             ::= '('+ Function ')'+ '.' '*'
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +SelectItem +====================================================================================================================== + + +.. raw:: html + + + + + + ConnectByPriorOperator + + XorExpression + + ConcatExpression + + Expression + + Alias + +
    + + + +
    + + +====================================================================================================================== +AllColumns +====================================================================================================================== + + +.. raw:: html + + + + + + * + + EXCEPT + + EXCLUDE + + ParenthesedColumnList + REPLACE + + ( + + SelectItemsList + ) + + +
    + + +
             ::= '*' ( ( 'EXCEPT' | 'EXCLUDE' ) ParenthesedColumnList )? ( 'REPLACE' '(' SelectItemsList ')' )?
    +
    + + +====================================================================================================================== +AllTableColumns +====================================================================================================================== + + +.. raw:: html + + + + + + Table + . + + AllColumns + +
    + + +
             ::= Table '.' AllColumns
    +
    + + +====================================================================================================================== +Alias +====================================================================================================================== + + +.. raw:: html + + + + + + AS + + RelObjectName + ( + + RelObjectName + + ColDataType + , + + ) + + AS + + RelObjectName + + S_CHAR_LITERAL + ( + + RelObjectName + + ColDataType + , + + ) + + +
    + + +
               | 'AS'? ( RelObjectName | S_CHAR_LITERAL ) ( '(' RelObjectName ColDataType? ( ',' RelObjectName ColDataType? )* ')' )?
    +
    + + +====================================================================================================================== +SQLServerHint +====================================================================================================================== + + +.. raw:: html + + + + + + INDEX + + ( + + RelObjectName + ) + + NOLOCK + + +
    + + +
             ::= 'INDEX' '(' RelObjectName ')'
    +
               | 'NOLOCK'
    +
    + Referenced by: +
    + + +====================================================================================================================== +SQLServerHints +====================================================================================================================== + + +.. raw:: html + + + + + + WITH + + ( + + SQLServerHint + , + + ) + + +
    + + +
             ::= 'WITH' '(' SQLServerHint ( ',' SQLServerHint )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +MySQLIndexHint +====================================================================================================================== + + +.. raw:: html + + + + + + USE + + SHOW + + IGNORE + + FORCE + + INDEX + + KEY + + ( + + RelObjectName + , + + ) + + +
    + + +
             ::= ( 'USE' | 'SHOW' | 'IGNORE' | 'FORCE' ) ( 'INDEX' | 'KEY' ) '(' RelObjectName ( ',' RelObjectName )* ')'
    +
    + + +====================================================================================================================== +FunctionItem +====================================================================================================================== + + +.. raw:: html + + + + + + Function + + Alias + +
    + + +
             ::= Function Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotForColumns +====================================================================================================================== + + +.. raw:: html + + + + + + ParenthesedColumnList + + Column + +
    + + +
             ::= ParenthesedColumnList
    +
               | Column
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotFunctionItems +====================================================================================================================== + + +.. raw:: html + + + + + + FunctionItem + , + + +
    + + +
             ::= FunctionItem ( ',' FunctionItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExpressionListItem +====================================================================================================================== + + +.. raw:: html + + + + + + ParenthesedExpressionList + + Alias + +
    + + +
             ::= ParenthesedExpressionList Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotMultiInItems +====================================================================================================================== + + +.. raw:: html + + + + + + ExpressionListItem + , + + +
    + + +
             ::= ExpressionListItem ( ',' ExpressionListItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Pivot +====================================================================================================================== + + +.. raw:: html + + + + + + PIVOT + + ( + + PivotFunctionItems + FOR + + PivotForColumns + IN + + ( + + SelectItemsList + + PivotMultiInItems + ) + + ) + + Alias + +
    + +
    Pivot    ::= 'PIVOT' '(' PivotFunctionItems 'FOR' PivotForColumns 'IN' '(' ( SelectItemsList | PivotMultiInItems ) ')' ')' Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +PivotXml +====================================================================================================================== + + +.. raw:: html + + + + + + PIVOT + + XML + + ( + + PivotFunctionItems + FOR + + PivotForColumns + IN + + ( + + ANY + + Select + + SelectItemsList + + PivotMultiInItems + ) + + ) + + +
    + +
    PivotXml ::= 'PIVOT' 'XML' '(' PivotFunctionItems 'FOR' PivotForColumns 'IN' '(' ( 'ANY' | Select | SelectItemsList | PivotMultiInItems ) ')' ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnPivot +====================================================================================================================== + + +.. raw:: html + + + + + + UNPIVOT + + INCLUDE + + EXCLUDE + + NULLS + + ( + + PivotForColumns + FOR + + PivotForColumns + IN + + ( + + SelectItemsList + ) + + ) + + Alias + +
    + +
    UnPivot  ::= 'UNPIVOT' ( ( 'INCLUDE' | 'EXCLUDE' ) 'NULLS' )? '(' PivotForColumns 'FOR' PivotForColumns 'IN' '(' SelectItemsList ')' ')' Alias?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IntoClause +====================================================================================================================== + + +.. raw:: html + + + + + + INTO + + Table + , + + +
    + + +
             ::= 'INTO' Table ( ',' Table )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +MySqlSelectIntoClause +====================================================================================================================== + + +.. raw:: html + + + + + + INTO + + OUTFILE + + S_CHAR_LITERAL + + MySqlSelectIntoOutfileTail + DUMPFILE + + S_CHAR_LITERAL + +
    + + +
             ::= 'INTO' ( 'OUTFILE' S_CHAR_LITERAL MySqlSelectIntoOutfileTail | 'DUMPFILE' S_CHAR_LITERAL )
    +
    + Referenced by: +
    + + +====================================================================================================================== +MySqlSelectIntoOutfileTail +====================================================================================================================== + + +.. raw:: html + + + + + + CHARACTER + + SET + + S_IDENTIFIER + BINARY + + MySqlSelectIntoFieldsClause + + MySqlSelectIntoLinesClause + +
    + + +
             ::= ( 'CHARACTER' 'SET' ( S_IDENTIFIER | 'BINARY' ) )? MySqlSelectIntoFieldsClause? MySqlSelectIntoLinesClause?
    +
    + Referenced by: +
    + + +====================================================================================================================== +MySqlSelectIntoFieldsClause +====================================================================================================================== + + +.. raw:: html + + + + + + FIELDS + + COLUMNS + + TERMINATED + + BY + + S_CHAR_LITERAL + OPTIONALLY + + ENCLOSED + + BY + + S_CHAR_LITERAL + ESCAPED + + BY + + S_CHAR_LITERAL + +
    + + +
             ::= ( 'FIELDS' | 'COLUMNS' ) ( 'TERMINATED' 'BY' S_CHAR_LITERAL )? ( 'OPTIONALLY'? 'ENCLOSED' 'BY' S_CHAR_LITERAL )? ( 'ESCAPED' 'BY' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +MySqlSelectIntoLinesClause +====================================================================================================================== + + +.. raw:: html + + + + + + LINES + + STARTING + + BY + + S_CHAR_LITERAL + TERMINATED + + BY + + S_CHAR_LITERAL + +
    + + +
             ::= 'LINES' ( 'STARTING' 'BY' S_CHAR_LITERAL )? ( 'TERMINATED' 'BY' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ParenthesedFromItem +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + FromItem + + JoinsList + ) + + +
    + + +
             ::= '(' FromItem JoinsList? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +FromItem +====================================================================================================================== + + +.. raw:: html + + + + + + Values + + TableFunction + + Table + + ParenthesedFromItem + + ParenthesedSelect + + Pivot + + UnPivot + + LateralSubSelect + + SubImport + + Select + + Alias + + TimeTravelAfterAlias + + SampleClause + + UnPivot + + PivotXml + + Pivot + + MySQLIndexHint + + SQLServerHints + +
    + + +
    + + +====================================================================================================================== +JoinsList +====================================================================================================================== + + +.. raw:: html + + + + + + JoinerExpression + +
    + + +
             ::= JoinerExpression+
    +
    + + +====================================================================================================================== +JoinHint +====================================================================================================================== + + +.. raw:: html + + + + + + LOOP + + HASH + + MERGE + + REMOTE + + +
    + +
    JoinHint ::= 'LOOP'
    +
               | 'HASH'
    +
               | 'MERGE'
    +
               | 'REMOTE'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JoinerExpression +====================================================================================================================== + + +.. raw:: html + + + + + + GLOBAL + + ANY + + ALL + + NATURAL + + LEFT + + SEMI + + OUTER + + ANY + + ALL + + RIGHT + + FULL + + OUTER + + ANY + + ALL + + INNER + + CROSS + + OUTER + + JoinHint + JOIN + + FETCH + + , + + OUTER + + STRAIGHT_JOIN + + APPLY + + FromItem + WITHIN + + ( + + JoinWindow + ) + + ON + + Expression + USING + + ( + + Column + , + + ) + + +
    + + +
             ::= 'GLOBAL'? ( 'ANY' | 'ALL' )? 'NATURAL'? ( 'LEFT' ( 'SEMI' | 'OUTER' | + 'ANY' | 'ALL' )? | ( 'RIGHT' | 'FULL' ) ( 'OUTER' | 'ANY' | 'ALL' )? | 'INNER' | 'CROSS' + | 'OUTER' )? ( JoinHint? 'JOIN' 'FETCH'? | ',' 'OUTER'? | 'STRAIGHT_JOIN' | 'APPLY' ) FromItem ( ( 'WITHIN' '(' JoinWindow ')' )? ( 'ON' Expression )+ | 'USING' '(' Column ( ',' Column )* ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JoinWindow +====================================================================================================================== + + +.. raw:: html + + + + + + S_LONG + + S_IDENTIFIER + + K_DATE_LITERAL + , + + S_LONG + + S_IDENTIFIER + + K_DATE_LITERAL + +
    + + +
             ::= S_LONG ( S_IDENTIFIER | K_DATE_LITERAL ) ( ',' S_LONG ( S_IDENTIFIER | K_DATE_LITERAL ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +KSQLWindowClause +====================================================================================================================== + + +.. raw:: html + + + + + + WINDOW + + HOPPING + + ( + + SIZE + + S_LONG + + S_IDENTIFIER + , + + ADVANCE + + BY + + SESSION + + ( + + TUMBLING + + ( + + SIZE + + S_LONG + + S_IDENTIFIER + ) + + +
    + + +
             ::= 'WINDOW' ( 'HOPPING' '(' 'SIZE' S_LONG S_IDENTIFIER ',' 'ADVANCE' 'BY' | 'SESSION' '(' | 'TUMBLING' '(' 'SIZE' ) S_LONG S_IDENTIFIER ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +WhereClause +====================================================================================================================== + + +.. raw:: html + + + + + + WHERE + + Expression + +
    + + +
             ::= 'WHERE' Expression
    +
    + + +====================================================================================================================== +PreWhereClause +====================================================================================================================== + + +.. raw:: html + + + + + + PREWHERE + + Expression + +
    + + +
             ::= 'PREWHERE' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +OracleHierarchicalQueryClause +====================================================================================================================== + + +.. raw:: html + + + + + + START + + WITH + + XorExpression + CONNECT + + BY + + NOCYCLE + + CONNECT + + BY + + NOCYCLE + + XorExpression + START + + WITH + + XorExpression + +
    + + +
             ::= ( 'START' 'WITH' XorExpression 'CONNECT' 'BY' 'NOCYCLE'? | 'CONNECT' 'BY' 'NOCYCLE'? ( XorExpression 'START' 'WITH' )? ) XorExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +PreferringClause +====================================================================================================================== + + +.. raw:: html + + + + + + PREFERRING + + PreferenceTerm + +
    + + +
             ::= 'PREFERRING' PreferenceTerm
    +
    + Referenced by: +
    + + +====================================================================================================================== +PreferenceTerm +====================================================================================================================== + + +.. raw:: html + + + + + + Plus + +
    + + +
             ::= Plus
    +
    + Referenced by: +
    + + +====================================================================================================================== +Plus +====================================================================================================================== + + +.. raw:: html + + + + + + PriorTo + PLUS + + +
    + +
    Plus     ::= PriorTo ( 'PLUS' PriorTo )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +PriorTo +====================================================================================================================== + + +.. raw:: html + + + + + + PreferenceTermTerminal + ( + + PreferenceTerm + ) + + TO + + PRIOR + + +
    + +
    PriorTo  ::= ( PreferenceTermTerminal | '(' PreferenceTerm ')' ) ( 'PRIOR' 'TO' ( PreferenceTermTerminal | '(' PreferenceTerm ')' ) )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +PreferenceTermTerminal +====================================================================================================================== + + +.. raw:: html + + + + + + HighExpression + + LowExpression + + Inverse + + Condition + +
    + + +
             ::= HighExpression
    +
               | LowExpression
    +
               | Inverse
    +
               | Condition
    +
    + Referenced by: +
    + + +====================================================================================================================== +HighExpression +====================================================================================================================== + + +.. raw:: html + + + + + + HIGH + + Expression + +
    + + +
             ::= 'HIGH' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +LowExpression +====================================================================================================================== + + +.. raw:: html + + + + + + LOW + + Expression + +
    + + +
             ::= 'LOW' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +Inverse +====================================================================================================================== + + +.. raw:: html + + + + + + INVERSE + + ( + + PreferenceTerm + ) + + +
    + +
    Inverse  ::= 'INVERSE' '(' PreferenceTerm ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +GroupByColumnReferences +====================================================================================================================== + + +.. raw:: html + + + + + + GROUP + + BY + + GROUPING + + SETS + + ( + + GroupingSet + , + + ) + + ExpressionList + GROUPING + + SETS + + ( + + GroupingSet + , + + ) + + WITH + + ROLLUP + + +
    + + +
             ::= 'GROUP' 'BY' ( 'GROUPING' 'SETS' '(' GroupingSet ( ',' GroupingSet )* ')' | ExpressionList ( 'GROUPING' 'SETS' '(' GroupingSet ( ',' GroupingSet )* ')' )? ( 'WITH' 'ROLLUP' )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +GroupingSet +====================================================================================================================== + + +.. raw:: html + + + + + + ParenthesedExpressionList + + SimpleExpression + +
    + + +
             ::= ParenthesedExpressionList
    +
               | SimpleExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +Having +====================================================================================================================== + + +.. raw:: html + + + + + + HAVING + + Expression + +
    + +
    Having   ::= 'HAVING' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +Qualify +====================================================================================================================== + + +.. raw:: html + + + + + + QUALIFY + + Expression + +
    + +
    Qualify  ::= 'QUALIFY' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +OrderByElements +====================================================================================================================== + + +.. raw:: html + + + + + + ORDER + + SIBLINGS + + BY + + OrderByElement + , + + +
    + + +
             ::= 'ORDER' 'SIBLINGS'? 'BY' OrderByElement ( ',' OrderByElement )*
    +
    + + +====================================================================================================================== +OrderByElement +====================================================================================================================== + + +.. raw:: html + + + + + + Expression + COLLATE + + S_CHAR_LITERAL + + S_QUOTED_IDENTIFIER + ASC + + DESC + + NULLS + + FIRST + + LAST + + WITH + + ROLLUP + + +
    + + +
             ::= Expression ( 'COLLATE' ( S_CHAR_LITERAL | S_QUOTED_IDENTIFIER ) )? ( 'ASC' | 'DESC' )? ( 'NULLS' ( 'FIRST' | 'LAST' )? )? ( 'WITH' 'ROLLUP' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JdbcParameter +====================================================================================================================== + + +.. raw:: html + + + + + + ? + + S_PARAMETER + + S_LONG + +
    + + +
             ::= ( '?' | S_PARAMETER ) S_LONG?
    +
    + Referenced by: +
    + + +====================================================================================================================== +LimitWithOffset +====================================================================================================================== + + +.. raw:: html + + + + + + LIMIT + + ParenthesedSelect + + Expression + , + + Expression + +
    + + +
             ::= 'LIMIT' ( ParenthesedSelect | Expression ) ( ',' Expression )?
    +
    + + +====================================================================================================================== +PlainLimit +====================================================================================================================== + + +.. raw:: html + + + + + + LIMIT + + ParenthesedSelect + + Expression + +
    + + +
             ::= 'LIMIT' ( ParenthesedSelect | Expression )
    +
    + Referenced by: +
    + + +====================================================================================================================== +LimitBy +====================================================================================================================== + + +.. raw:: html + + + + + + LimitWithOffset + BY + + ExpressionList + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +Offset +====================================================================================================================== + + +.. raw:: html + + + + + + OFFSET + + Expression + ROWS + + ROW + + +
    + +
    Offset   ::= 'OFFSET' Expression ( 'ROWS' | 'ROW' )?
    +
    + + +====================================================================================================================== +Fetch +====================================================================================================================== + + +.. raw:: html + + + + + + FETCH + + FIRST + + NEXT + + Expression + PERCENT + + ROWS + + ROW + + ONLY + + WITH TIES + + +
    + +
    Fetch    ::= 'FETCH' ( 'FIRST' | 'NEXT' ) ( Expression 'PERCENT'? )? ( 'ROWS' | 'ROW' ) ( 'ONLY' | 'WITH TIES' )
    +
    + + +====================================================================================================================== +WithIsolation +====================================================================================================================== + + +.. raw:: html + + + + + + WITH + + K_ISOLATION + +
    + + +
             ::= 'WITH' K_ISOLATION
    +
    + + +====================================================================================================================== +OptimizeFor +====================================================================================================================== + + +.. raw:: html + + + + + + OPTIMIZE + + FOR + + S_LONG + ROWS + + +
    + + +
             ::= 'OPTIMIZE' 'FOR' S_LONG 'ROWS'
    +
    + Referenced by: +
    + + +====================================================================================================================== +Top +====================================================================================================================== + + +.. raw:: html + + + + + + TOP + + S_LONG + + JdbcParameter + : + + S_IDENTIFIER + ( + + AdditiveExpression + ) + + PERCENT + + WITH TIES + + +
    + +
    Top      ::= 'TOP' ( S_LONG | JdbcParameter | ':' S_IDENTIFIER? | '(' AdditiveExpression ')' ) 'PERCENT'? 'WITH TIES'?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Skip +====================================================================================================================== + + +.. raw:: html + + + + + + SKIP + + S_LONG + + S_IDENTIFIER + + JdbcParameter + +
    + +
    Skip     ::= 'SKIP' ( S_LONG | S_IDENTIFIER | JdbcParameter )
    +
    + Referenced by: +
    + + +====================================================================================================================== +First +====================================================================================================================== + + +.. raw:: html + + + + + + FIRST + + LIMIT + + S_LONG + + S_IDENTIFIER + + JdbcParameter + +
    + +
    First    ::= ( 'FIRST' | 'LIMIT' ) ( S_LONG | S_IDENTIFIER | JdbcParameter )
    +
    + Referenced by: +
    + + +====================================================================================================================== +Expression +====================================================================================================================== + + +.. raw:: html + + + + + + XorExpression + +
    + + +
             ::= XorExpression
    +
    + + +====================================================================================================================== +XorExpression +====================================================================================================================== + + +.. raw:: html + + + + + + OrExpression + XOR + + +
    + + +
             ::= OrExpression ( 'XOR' OrExpression )*
    +
    + + +====================================================================================================================== +OrExpression +====================================================================================================================== + + +.. raw:: html + + + + + + AndExpression + OR + + +
    + + +
             ::= AndExpression ( 'OR' AndExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +AndExpression +====================================================================================================================== + + +.. raw:: html + + + + + + Condition + AND + + && + + +
    + + +
             ::= Condition ( ( 'AND' | '&&' ) Condition )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Condition +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + ! + + ExistsExpression + PRIOR + + SimpleExpression + ( + + + + + ) + + RegularConditionRHS + + OverlapsCondition + + InExpression + + ExcludesExpression + + IncludesExpression + + Between + + MemberOfExpression + + IsNullExpression + + IsBooleanExpression + + IsUnknownExpression + + LikeExpression + + IsDistinctExpression + + SimilarToExpression + +
    + + + +
    + + +====================================================================================================================== +RegularConditionRHS +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + + + + ) + + > + + < + + = + + OP_GREATERTHANEQUALS + + OP_MINORTHANEQUALS + + OP_NOTEQUALSSTANDARD + + OP_NOTEQUALSBANG + + OP_NOTEQUALSHAT + *= + + =* + + && + + &> + + <& + + @@ + + ~ + + ~* + + !~ + + !~* + + @> + + <@ + + ? + + ?| + + ?& + + OP_CONCAT + - + + -# + + <-> + + <#> + + <=> + + PRIOR + + ComparisonItem + ( + + + + + ) + + +
    + + +
             ::= ( '(' '+' ')' )? ( '>' | '<' | '=' | OP_GREATERTHANEQUALS | OP_MINORTHANEQUALS | OP_NOTEQUALSSTANDARD | OP_NOTEQUALSBANG | OP_NOTEQUALSHAT | '*=' | '=*' | '&&' | '&>' | '<&' | '@@' | '~' | '~*' | '!~' | '!~*' | '@>' | '<@' + | '?' | '?|' | '?&' | OP_CONCAT | '-' | '-#' | '<->' | '<#>' | '<=>' ) 'PRIOR'? ComparisonItem ( '(' '+' ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +OverlapsCondition +====================================================================================================================== + + +.. raw:: html + + + + + + OVERLAPS + + ParenthesedExpressionList + +
    + + +
             ::= 'OVERLAPS' ParenthesedExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +SQLCondition +====================================================================================================================== + + +.. raw:: html + + + + + + ExistsExpression + + SimpleExpression + + OverlapsCondition + + InExpression + + ExcludesExpression + + IncludesExpression + + Between + + MemberOfExpression + + IsNullExpression + + IsBooleanExpression + + IsUnknownExpression + + LikeExpression + + IsDistinctExpression + + SimilarToExpression + +
    + + +
             ::= ExistsExpression
    +
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +InExpression +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + + + + ) + + GLOBAL + + NOT + + IN + + S_CHAR_LITERAL + + PrimaryExpression + +
    + + +
             ::= ( '(' '+' ')' )? 'GLOBAL'? 'NOT'? 'IN' ( S_CHAR_LITERAL | PrimaryExpression )
    +
    + Referenced by: +
    + + +====================================================================================================================== +IncludesExpression +====================================================================================================================== + + +.. raw:: html + + + + + + INCLUDES + + ParenthesedExpressionList + +
    + + +
             ::= 'INCLUDES' ParenthesedExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExcludesExpression +====================================================================================================================== + + +.. raw:: html + + + + + + EXCLUDES + + ParenthesedExpressionList + +
    + + +
             ::= 'EXCLUDES' ParenthesedExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +Between +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + BETWEEN + + SYMMETRIC + + ASYMMETRIC + + ParenthesedSelect + + SimpleExpression + + RegularConditionRHS + AND + + ParenthesedSelect + + SimpleExpression + + RegularConditionRHS + +
    + +
    Between  ::= 'NOT'? 'BETWEEN' ( 'SYMMETRIC' | 'ASYMMETRIC' )? ( ParenthesedSelect | SimpleExpression RegularConditionRHS? ) 'AND' ( ParenthesedSelect | SimpleExpression RegularConditionRHS? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +LikeExpression +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + LIKE + + ILIKE + + RLIKE + + REGEXP_LIKE + + REGEXP + + K_SIMILAR_TO + MATCH_ANY + + MATCH_ALL + + MATCH_PHRASE + + MATCH_PHRASE_PREFIX + + MATCH_REGEXP + + BINARY + + SimpleExpression + ESCAPE + + S_CHAR_LITERAL + + Expression + +
    + + +
             ::= 'NOT'? ( 'LIKE' | 'ILIKE' | 'RLIKE' | 'REGEXP_LIKE' | 'REGEXP' | K_SIMILAR_TO | 'MATCH_ANY' | 'MATCH_ALL' | 'MATCH_PHRASE' | 'MATCH_PHRASE_PREFIX' | 'MATCH_REGEXP' + ) 'BINARY'? SimpleExpression ( 'ESCAPE' ( S_CHAR_LITERAL | Expression ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +SimilarToExpression +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + SIMILAR + + TO + + SimpleExpression + ESCAPE + + S_CHAR_LITERAL + +
    + + +
             ::= 'NOT'? 'SIMILAR' 'TO' SimpleExpression ( 'ESCAPE' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IsDistinctExpression +====================================================================================================================== + + +.. raw:: html + + + + + + IS + + NOT + + DISTINCT + + FROM + + SimpleExpression + +
    + + +
             ::= 'IS' 'NOT'? 'DISTINCT' 'FROM' SimpleExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +IsNullExpression +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + ISNULL + + NOTNULL + + IS + + NOT + + NULL + + +
    + + +
             ::= 'NOT'? 'ISNULL'
    +
               | 'NOTNULL'
    +
               | 'IS' 'NOT'? 'NULL'
    +
    + Referenced by: +
    + + +====================================================================================================================== +IsBooleanExpression +====================================================================================================================== + + +.. raw:: html + + + + + + IS + + NOT + + TRUE + + FALSE + + +
    + + +
             ::= 'IS' 'NOT'? ( 'TRUE' | 'FALSE' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +IsUnknownExpression +====================================================================================================================== + + +.. raw:: html + + + + + + IS + + NOT + + UNKNOWN + + +
    + + +
             ::= 'IS' 'NOT'? 'UNKNOWN'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExistsExpression +====================================================================================================================== + + +.. raw:: html + + + + + + EXISTS + + SimpleExpression + +
    + + +
             ::= 'EXISTS' SimpleExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +MemberOfExpression +====================================================================================================================== + + +.. raw:: html + + + + + + MEMBER + + OF + + Expression + +
    + + +
             ::= 'MEMBER' 'OF' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExpressionList +====================================================================================================================== + + +.. raw:: html + + + + + + ComplexExpressionList + + SimpleExpressionList + + ParenthesedExpressionList + +
    + + +
             ::= ComplexExpressionList
    +
               | SimpleExpressionList
    +
               | ParenthesedExpressionList
    +
    + + +====================================================================================================================== +ParenthesedExpressionList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + ComplexExpressionList + + SimpleExpressionList + ) + + +
    + + +
             ::= '(' ( ComplexExpressionList | SimpleExpressionList )? ')'
    +
    + + +====================================================================================================================== +SimpleExpressionList +====================================================================================================================== + + +.. raw:: html + + + + + + SimpleExpression + , + + LambdaExpression + + SimpleExpression + +
    + + +
             ::= SimpleExpression ( ',' ( LambdaExpression | SimpleExpression ) )*
    +
    + + +====================================================================================================================== +ColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + Column + , + + +
    + + +
             ::= Column ( ',' Column )*
    +
    + + +====================================================================================================================== +ParenthesedColumnList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + ColumnList + ) + + +
    + + +
             ::= '(' ColumnList ')'
    +
    + + +====================================================================================================================== +ComplexExpressionList +====================================================================================================================== + + +.. raw:: html + + + + + + OracleNamedFunctionParameter + + PostgresNamedFunctionParameter + + Expression + , + + OracleNamedFunctionParameter + + PostgresNamedFunctionParameter + + LambdaExpression + + Expression + +
    + + + +
    + + +====================================================================================================================== +NamedExpressionListExprFirst +====================================================================================================================== + + +.. raw:: html + + + + + + SimpleExpression + FROM + + IN + + PLACING + + SimpleExpression + FOR + + FROM + + SimpleExpression + FOR + + SimpleExpression + +
    + + +
             ::= SimpleExpression ( 'FROM' | 'IN' | 'PLACING' ) SimpleExpression ( ( 'FOR' | 'FROM' ) SimpleExpression ( 'FOR' SimpleExpression )? )?
    +
    + + +====================================================================================================================== +ComparisonItem +====================================================================================================================== + + +.. raw:: html + + + + + + AnyComparisonExpression + + SimpleExpression + + ParenthesedExpressionList + + RowConstructor + + PrimaryExpression + +
    + + +
             ::= AnyComparisonExpression
    +
               | SimpleExpression
    +
               | ParenthesedExpressionList
    +
               | RowConstructor
    +
               | PrimaryExpression
    +
    + Referenced by: +
    + + +====================================================================================================================== +AnyComparisonExpression +====================================================================================================================== + + +.. raw:: html + + + + + + ANY + + SOME + + ALL + + ParenthesedSelect + +
    + + +
             ::= ( 'ANY' | 'SOME' | 'ALL' ) ParenthesedSelect
    +
    + Referenced by: +
    + + +====================================================================================================================== +SimpleExpression +====================================================================================================================== + + +.. raw:: html + + + + + + UserVariable + = + + := + + ConcatExpression + +
    + + +
             ::= ( UserVariable ( '=' | ':=' ) )? ConcatExpression
    +
    + + +====================================================================================================================== +ConcatExpression +====================================================================================================================== + + +.. raw:: html + + + + + + BitwiseAndOr + + OP_CONCAT + +
    + + +
             ::= BitwiseAndOr ( OP_CONCAT BitwiseAndOr )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +BitwiseAndOr +====================================================================================================================== + + +.. raw:: html + + + + + + AdditiveExpression + | + + & + + << + + >> + + +
    + + +
             ::= AdditiveExpression ( ( '|' | '&' | '<<' | '>>' ) AdditiveExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +AdditiveExpression +====================================================================================================================== + + +.. raw:: html + + + + + + MultiplicativeExpression + + + + - + + +
    + + +
             ::= MultiplicativeExpression ( ( '+' | '-' ) MultiplicativeExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +MultiplicativeExpression +====================================================================================================================== + + +.. raw:: html + + + + + + BitwiseXor + * + + / + + DIV + + % + + +
    + + +
             ::= BitwiseXor ( ( '*' | '/' | 'DIV' | '%' ) BitwiseXor )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +BitwiseXor +====================================================================================================================== + + +.. raw:: html + + + + + + PrimaryExpression + ^ + + +
    + + +
             ::= PrimaryExpression ( '^' PrimaryExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +ArrayExpression +====================================================================================================================== + + +.. raw:: html + + + + + + [ + + SimpleExpression + : + + SimpleExpression + ] + + +
    + + +
             ::= ( '[' SimpleExpression? ( ':' SimpleExpression? )? ']' )+
    +
    + Referenced by: +
    + + +====================================================================================================================== +PrimaryExpression +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + ! + + + + + - + + ~ + + NULL + + CaseWhenExpression + + CharacterPrimary + + ImplicitCast + + JdbcParameter + + JdbcNamedParameter + + UserVariable + + NumericBind + + ExtractExpression + + XMLSerializeExpr + + JsonFunction + + JsonAggregateFunction + + FullTextSearch + + CastExpression + + Function + + AnalyticExpression + + DateUnitExpression + + IntervalExpression + + S_DOUBLE + + S_LONG + + S_HEX + + AllColumns + + AllTableColumns + + K_TIME_KEY_EXPR + CURRENT + + DateTimeLiteralExpression + + StructType + ARRAY + + < + + ColDataType + > + + ArrayConstructor + + NextValExpression + + ConnectByRootOperator + + ConnectByPriorOperator + + KeyExpression + ALL + + Column + ( + + + + + ) + + TRUE + + FALSE + + S_CHAR_LITERAL + {d + + {t + + {ts + + S_CHAR_LITERAL + } + + Select + + ParenthesedSelect + + ParenthesedExpressionList + -> + + Expression + . + + RelObjectName + COLLATE + + S_CHAR_LITERAL + + S_QUOTED_IDENTIFIER + + S_IDENTIFIER + + IntervalExpressionWithoutInterval + + ArrayExpression + :: + + ColDataType + -> + + : + + ->> + + #> + + #>> + + Expression + + SimpleExpression + + JsonExpression + AT + + K_DATETIMELITERAL + ZONE + + PrimaryExpression + +
    + + +
             ::= ( 'NOT' | '!' )? ( '+' | '-' | '~' )? ( 'NULL' | CaseWhenExpression | CharacterPrimary | ImplicitCast | JdbcParameter | JdbcNamedParameter | UserVariable | NumericBind | ExtractExpression | XMLSerializeExpr | JsonFunction | JsonAggregateFunction | FullTextSearch | CastExpression | Function AnalyticExpression? | DateUnitExpression | IntervalExpression | S_DOUBLE | S_LONG | S_HEX | AllColumns | AllTableColumns | K_TIME_KEY_EXPR | 'CURRENT' | DateTimeLiteralExpression | StructType | ( 'ARRAY' ( '<' ColDataType '>' )? )? ArrayConstructor | NextValExpression | ConnectByRootOperator | ConnectByPriorOperator | KeyExpression | 'ALL' | Column ( '(' '+' ')' )? | 'TRUE' | 'FALSE' | S_CHAR_LITERAL | ( '{d' | '{t' | '{ts' ) S_CHAR_LITERAL '}' | Select | ParenthesedSelect | ParenthesedExpressionList ( '->' Expression )? ( '.' RelObjectName )* ) ( 'COLLATE' ( S_CHAR_LITERAL | S_QUOTED_IDENTIFIER | S_IDENTIFIER ) )? IntervalExpressionWithoutInterval? ArrayExpression? ( '::' ColDataType )* ( ( ( '->' | ':' | '->>' | '#>' | '#>>' ) ( Expression | SimpleExpression ) )+ JsonExpression )? ( 'AT' K_DATETIMELITERAL 'ZONE' PrimaryExpression )*
    +
    + + +====================================================================================================================== +ConnectByRootOperator +====================================================================================================================== + + +.. raw:: html + + + + + + CONNECT_BY_ROOT + + Expression + +
    + + +
             ::= 'CONNECT_BY_ROOT' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +ConnectByPriorOperator +====================================================================================================================== + + +.. raw:: html + + + + + + PRIOR + + Expression + +
    + + +
             ::= 'PRIOR' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +KeyExpression +====================================================================================================================== + + +.. raw:: html + + + + + + KEY + + Expression + +
    + + +
             ::= 'KEY' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +NextValExpression +====================================================================================================================== + + +.. raw:: html + + + + + + K_NEXTVAL + + RelObjectNames + +
    + + +
             ::= K_NEXTVAL RelObjectNames
    +
    + Referenced by: +
    + + +====================================================================================================================== +JdbcNamedParameter +====================================================================================================================== + + +.. raw:: html + + + + + + : + + & + + IdentifierChain + +
    + + +
             ::= ( ':' | '&' ) IdentifierChain
    +
    + Referenced by: +
    + + +====================================================================================================================== +OracleNamedFunctionParameter +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNameExt + OUTER + + => + + Expression + +
    + + +
             ::= ( RelObjectNameExt | 'OUTER' ) '=>' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +PostgresNamedFunctionParameter +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNameExt + OUTER + + := + + Expression + +
    + + +
             ::= ( RelObjectNameExt | 'OUTER' ) ':=' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +UserVariable +====================================================================================================================== + + +.. raw:: html + + + + + + S_AT_IDENTIFIER + + IdentifierChain2 + +
    + + +
             ::= S_AT_IDENTIFIER IdentifierChain2
    +
    + + +====================================================================================================================== +NumericBind +====================================================================================================================== + + +.. raw:: html + + + + + + : + + S_LONG + +
    + + +
             ::= ':' S_LONG
    +
    + Referenced by: +
    + + +====================================================================================================================== +DateTimeLiteralExpression +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATETIMELITERAL + + S_CHAR_LITERAL + + S_QUOTED_IDENTIFIER + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +DateUnitExpression +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATE_LITERAL + +
    + + +
             ::= K_DATE_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +RangeExpression +====================================================================================================================== + + +.. raw:: html + + + + + + : + + Expression + +
    + + +
             ::= ':' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +ArrayConstructor +====================================================================================================================== + + +.. raw:: html + + + + + + [ + + Expression + + RangeExpression + + ArrayConstructor + , + + ] + + +
    + + +
             ::= '[' ( ( Expression RangeExpression? | ArrayConstructor ) ( ',' ( Expression RangeExpression? | ArrayConstructor ) )* )? ']'
    +
    + + +====================================================================================================================== +StructParameters +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + + ColDataType + , + + +
    + + +
             ::= RelObjectName? ColDataType ( ',' RelObjectName? ColDataType )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +StructType +====================================================================================================================== + + +.. raw:: html + + + + + + STRUCT + + < + + StructParameters + > + + ( + + SelectItemsList + ) + + { + + RelObjectNameExt + + S_CHAR_LITERAL + : + + Expression + , + + } + + :: + + STRUCT + + ( + + StructParameters + ) + + +
    + + +
             ::= 'STRUCT' ( '<' StructParameters '>' )? '(' SelectItemsList ')'
    +
               | '{' ( RelObjectNameExt | S_CHAR_LITERAL ) ':' Expression ( ',' ( RelObjectNameExt | S_CHAR_LITERAL ) ':' Expression )* '}' ( '::' 'STRUCT' '(' StructParameters ')' )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonExpression +====================================================================================================================== + + +.. raw:: html + + + + + + :: + + ColDataType + -> + + : + + ->> + + #> + + #>> + + Expression + + SimpleExpression + +
    + + +
             ::= ( ( '::' ColDataType )+ ( ( '->' | ':' | '->>' | '#>' | '#>>' ) ( Expression | SimpleExpression ) )* )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonKeyValuePair +====================================================================================================================== + + +.. raw:: html + + + + + + KEY + + S_CHAR_LITERAL + + Column + + AllTableColumns + + AllColumns + + Expression + VALUE + + : + + , + + Expression + FORMAT + + JSON + + ENCODING + + JsonEncoding + +
    + + +
             ::= ( 'KEY'? ( S_CHAR_LITERAL | Column ) | AllTableColumns | AllColumns | Expression ) ( ( 'VALUE' | ':' | ',' ) Expression )? ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonObjectBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonKeyValuePair + , + + NULL + + ABSENT + + ON + + NULL + + STRICT + + WITH + + WITHOUT + + UNIQUE + + KEYS + + RETURNING + + ColDataType + FORMAT + + JSON + + ENCODING + + JsonEncoding + ) + + +
    + + +
             ::= '(' ( JsonKeyValuePair ( ',' JsonKeyValuePair )* )? ( ( 'NULL' | 'ABSENT' ) 'ON' 'NULL' )? 'STRICT'? ( ( 'WITH' | 'WITHOUT' ) 'UNIQUE' + 'KEYS' )? ( 'RETURNING' ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonArrayBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + NULL + + ON + + NULL + + Expression + FORMAT + + JSON + + ENCODING + + JsonEncoding + , + + ABSENT + + ON + + NULL + + RETURNING + + ColDataType + FORMAT + + JSON + + ENCODING + + JsonEncoding + ) + + +
    + + +
             ::= '(' ( 'NULL' 'ON' 'NULL' | Expression ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? ( ',' Expression ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )* )* ( 'ABSENT' 'ON' 'NULL' )? ( 'RETURNING' ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonKeyword +====================================================================================================================== + + +.. raw:: html + + + + + + S_IDENTIFIER + +
    + + +
             ::= S_IDENTIFIER
    +
    + + +====================================================================================================================== +JsonEncoding +====================================================================================================================== + + +.. raw:: html + + + + + + S_IDENTIFIER + +
    + + +
             ::= S_IDENTIFIER
    +
    + + +====================================================================================================================== +JsonValueOrQueryInputExpression +====================================================================================================================== + + +.. raw:: html + + + + + + Expression + FORMAT + + JSON + + ENCODING + + JsonEncoding + +
    + + +
             ::= Expression ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )?
    +
    + + +====================================================================================================================== +JsonValueOnResponseBehavior +====================================================================================================================== + + +.. raw:: html + + + + + + ERROR + + NULL + + DEFAULT + + Expression + +
    + + +
             ::= 'ERROR'
    +
               | 'NULL'
    +
               | 'DEFAULT' Expression
    +
    + + +====================================================================================================================== +JsonQueryOnResponseBehavior +====================================================================================================================== + + +.. raw:: html + + + + + + ERROR + + NULL + + S_IDENTIFIER + ARRAY + + JsonKeyword + +
    + + +
             ::= 'ERROR'
    +
               | 'NULL'
    +
               | S_IDENTIFIER ( 'ARRAY' | JsonKeyword )
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonExistsOnResponseBehavior +====================================================================================================================== + + +.. raw:: html + + + + + + TRUE + + FALSE + + UNKNOWN + + ERROR + + +
    + + +
             ::= 'TRUE'
    +
               | 'FALSE'
    +
               | 'UNKNOWN'
    +
               | 'ERROR'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonExistsBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonValueOrQueryInputExpression + , + + Expression + + JsonKeyword + + Expression + , + + JsonExistsOnResponseBehavior + ON + + ERROR + + ) + + +
    + + +
             ::= '(' JsonValueOrQueryInputExpression ',' Expression ( JsonKeyword Expression ( ',' Expression )* )? ( JsonExistsOnResponseBehavior 'ON' 'ERROR' )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonValueBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonValueOrQueryInputExpression + , + + Expression + + JsonKeyword + + Expression + , + + RETURNING + + ColDataType + + JsonValueOnResponseBehavior + ON + + JsonKeyword + + JsonValueOnResponseBehavior + ON + + ERROR + + ) + + +
    + + +
             ::= '(' JsonValueOrQueryInputExpression ',' Expression ( JsonKeyword Expression ( ',' Expression )* )? ( 'RETURNING' ColDataType )? ( JsonValueOnResponseBehavior 'ON' JsonKeyword )? ( JsonValueOnResponseBehavior 'ON' 'ERROR' )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonQueryBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonValueOrQueryInputExpression + , + + Expression + + JsonKeyword + + Expression + , + + RETURNING + + ColDataType + FORMAT + + JSON + + ENCODING + + JsonEncoding + WITHOUT + + WITH + + S_IDENTIFIER + ARRAY + + JsonKeyword + KEEP + + JsonKeyword + + JsonKeyword + ON + + JsonKeyword + STRING + + JsonQueryOnResponseBehavior + ON + + JsonKeyword + + JsonQueryOnResponseBehavior + ON + + ERROR + + Expression + , + + ) + + +
    + + +
             ::= '(' JsonValueOrQueryInputExpression ',' Expression ( JsonKeyword Expression ( ',' Expression )* )? ( 'RETURNING' ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )? ( ( 'WITHOUT' | 'WITH' S_IDENTIFIER? ) 'ARRAY'? JsonKeyword )? ( ( 'KEEP' | JsonKeyword ) JsonKeyword ( 'ON' JsonKeyword 'STRING' )? )? ( JsonQueryOnResponseBehavior 'ON' JsonKeyword )? ( JsonQueryOnResponseBehavior 'ON' 'ERROR' )? ( ',' Expression ( 'RETURNING' ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? )? ( ( 'WITHOUT' | 'WITH' S_IDENTIFIER? ) 'ARRAY'? JsonKeyword )? ( ( 'KEEP' | JsonKeyword ) JsonKeyword ( 'ON' JsonKeyword 'STRING' )? )? ( JsonQueryOnResponseBehavior 'ON' JsonKeyword )? ( JsonQueryOnResponseBehavior 'ON' 'ERROR' )? )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonFunction +====================================================================================================================== + + +.. raw:: html + + + + + + JSON_OBJECT + + JsonObjectBody + JSON_ARRAY + + JsonArrayBody + + JsonKeyword + + JsonValueBody + + JsonQueryBody + + JsonExistsBody + +
    + + +
             ::= 'JSON_OBJECT' JsonObjectBody
    +
               | 'JSON_ARRAY' JsonArrayBody
    +
               | JsonKeyword ( JsonValueBody | JsonQueryBody | JsonExistsBody )
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonAggregateFunction +====================================================================================================================== + + +.. raw:: html + + + + + + JSON_OBJECTAGG + + ( + + KEY + + DT_ZONE + + S_DOUBLE + + S_LONG + + S_HEX + + S_CHAR_LITERAL + + Column + : + + , + + VALUE + + Expression + FORMAT + + JSON + + NULL + + ABSENT + + ON + + NULL + + WITH + + WITHOUT + + UNIQUE + + KEYS + + JSON_ARRAYAGG + + ( + + Expression + FORMAT + + JSON + + OrderByElements + NULL + + ABSENT + + ON + + NULL + + ) + + FILTER + + ( + + WHERE + + Expression + ) + + OVER + + ( + + PARTITION + + BY + + ComplexExpressionList + ( + + ComplexExpressionList + ) + + OrderByElements + + WindowElement + ) + + +
    + + +
             ::= ( 'JSON_OBJECTAGG' '(' 'KEY'? ( DT_ZONE | S_DOUBLE | S_LONG | S_HEX | S_CHAR_LITERAL | Column ) ( ':' | ',' | 'VALUE' ) Expression ( 'FORMAT' 'JSON' )? ( ( 'NULL' | 'ABSENT' ) 'ON' 'NULL' )? ( ( 'WITH' | 'WITHOUT' + ) 'UNIQUE' 'KEYS' )? | 'JSON_ARRAYAGG' '(' Expression ( 'FORMAT' 'JSON' )? OrderByElements? ( ( 'NULL' | 'ABSENT' ) 'ON' 'NULL' )? ) ')' ( 'FILTER' '(' 'WHERE' Expression ')' )? ( 'OVER' '(' ( 'PARTITION' 'BY' ( ComplexExpressionList | '(' ComplexExpressionList ')' ) )? OrderByElements? WindowElement? ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IntervalExpression +====================================================================================================================== + + +.. raw:: html + + + + + + INTERVAL + + - + + S_LONG + + S_DOUBLE + + S_CHAR_LITERAL + + Expression + + S_IDENTIFIER + + K_DATE_LITERAL + +
    + + +
             ::= 'INTERVAL' ( '-'? ( S_LONG | S_DOUBLE ) | S_CHAR_LITERAL | Expression ) ( S_IDENTIFIER | K_DATE_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IntervalExpressionWithoutInterval +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATE_LITERAL + +
    + + +
             ::= K_DATE_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +KeepExpression +====================================================================================================================== + + +.. raw:: html + + + + + + KEEP + + ( + + S_IDENTIFIER + FIRST + + LAST + + OrderByElements + ) + + +
    + + +
             ::= 'KEEP' '(' S_IDENTIFIER ( 'FIRST' | 'LAST' ) OrderByElements ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +windowFun +====================================================================================================================== + + +.. raw:: html + + + + + + OVER + + WITHIN + + GROUP + + RelObjectName + + windowDefinition + OVER + + ( + + PARTITION + + BY + + ComplexExpressionList + ( + + ComplexExpressionList + ) + + ) + + +
    + + +
             ::= ( 'OVER' | 'WITHIN' 'GROUP' ) ( RelObjectName | windowDefinition ( 'OVER' '(' ( 'PARTITION' 'BY' ( ComplexExpressionList | '(' ComplexExpressionList ')' ) )? ')' )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +windowDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + PARTITION + + BY + + ComplexExpressionList + ( + + ComplexExpressionList + ) + + OrderByElements + + WindowElement + ) + + +
    + + +
             ::= '(' ( 'PARTITION' 'BY' ( ComplexExpressionList | '(' ComplexExpressionList ')' ) )? OrderByElements? WindowElement? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AnalyticExpression +====================================================================================================================== + + +.. raw:: html + + + + + + FILTER + + ( + + WHERE + + Expression + ) + + windowFun + + windowFun + +
    + + +
             ::= 'FILTER' '(' 'WHERE' Expression ')' windowFun?
    +
               | windowFun
    +
    + Referenced by: +
    + + +====================================================================================================================== +WindowElement +====================================================================================================================== + + +.. raw:: html + + + + + + ROWS + + RANGE + + BETWEEN + + WindowOffset + AND + + WindowOffset + +
    + + +
             ::= ( 'ROWS' | 'RANGE' ) ( 'BETWEEN' WindowOffset 'AND' )? WindowOffset
    +
    + + +====================================================================================================================== +WindowOffset +====================================================================================================================== + + +.. raw:: html + + + + + + UNBOUNDED + + SimpleExpression + PRECEDING + + FOLLOWING + + CURRENT + + ROW + + +
    + + +
             ::= ( 'UNBOUNDED' | SimpleExpression ) ( 'PRECEDING' | 'FOLLOWING' )
    +
               | 'CURRENT' 'ROW'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ExtractExpression +====================================================================================================================== + + +.. raw:: html + + + + + + EXTRACT + + ( + + RelObjectName + + S_CHAR_LITERAL + FROM + + SimpleExpression + ) + + +
    + + +
             ::= 'EXTRACT' '(' ( RelObjectName | S_CHAR_LITERAL ) 'FROM' SimpleExpression ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ImplicitCast +====================================================================================================================== + + +.. raw:: html + + + + + + DataType + + S_CHAR_LITERAL + + S_LONG + + S_DOUBLE + +
    + + +
             ::= DataType ( S_CHAR_LITERAL | S_LONG | S_DOUBLE )
    +
    + Referenced by: +
    + + +====================================================================================================================== +CastExpression +====================================================================================================================== + + +.. raw:: html + + + + + + CAST + + SAFE_CAST + + TRY_CAST + + INTERPRET + + ( + + SimpleExpression + AS + + ROW + + ( + + ColumnDefinition + , + + ) + + ColDataType + FORMAT + + S_CHAR_LITERAL + ) + + +
    + + +
             ::= ( 'CAST' | 'SAFE_CAST' | 'TRY_CAST' | 'INTERPRET' ) '(' SimpleExpression 'AS' ( 'ROW' '(' ColumnDefinition ( ',' ColumnDefinition )* ')' | ColDataType ) ( 'FORMAT' S_CHAR_LITERAL )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +CaseWhenExpression +====================================================================================================================== + + +.. raw:: html + + + + + + CASE + + Expression + + WhenThenSearchCondition + ELSE + + Expression + + SimpleExpression + END + + +
    + + +
             ::= 'CASE' Expression? WhenThenSearchCondition+ ( 'ELSE' ( Expression | SimpleExpression ) )? 'END'
    +
    + Referenced by: +
    + + +====================================================================================================================== +WhenThenSearchCondition +====================================================================================================================== + + +.. raw:: html + + + + + + WHEN + + Expression + THEN + + Expression + + SimpleExpression + +
    + + +
             ::= 'WHEN' Expression 'THEN' ( Expression | SimpleExpression )
    +
    + Referenced by: +
    + + +====================================================================================================================== +RowConstructor +====================================================================================================================== + + +.. raw:: html + + + + + + ROW + + ParenthesedExpressionList + +
    + + +
             ::= 'ROW' ParenthesedExpressionList
    +
    + Referenced by: +
    + + +====================================================================================================================== +VariableExpression +====================================================================================================================== + + +.. raw:: html + + + + + + UserVariable + = + + SimpleExpression + +
    + + +
             ::= UserVariable '=' SimpleExpression
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +Execute +====================================================================================================================== + + +.. raw:: html + + + + + + EXEC + + EXECUTE + + CALL + + RelObjectNames + + ExpressionList + +
    + +
    Execute  ::= ( 'EXEC' | 'EXECUTE' | 'CALL' ) RelObjectNames ExpressionList?
    +
    + Referenced by: +
    + + +====================================================================================================================== +FullTextSearch +====================================================================================================================== + + +.. raw:: html + + + + + + MATCH + + ( + + ColumnList + ) + + AGAINST + + ( + + SimpleExpression + IN NATURAL LANGUAGE MODE + + IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION + + IN BOOLEAN MODE + + WITH QUERY EXPANSION + + ) + + +
    + + +
             ::= 'MATCH' '(' ColumnList ')' 'AGAINST' '(' SimpleExpression ( 'IN NATURAL LANGUAGE MODE' | 'IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION' | + 'IN BOOLEAN MODE' | 'WITH QUERY EXPANSION' )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +LambdaExpression +====================================================================================================================== + + +.. raw:: html + + + + + + ParenthesedColumnList + + RelObjectName + -> + + Expression + +
    + + +
             ::= ( ParenthesedColumnList | RelObjectName ) '->' Expression
    +
    + + +====================================================================================================================== +Function +====================================================================================================================== + + +.. raw:: html + + + + + + { + + FN + + InternalFunction + } + + SpecialStringFunctionWithNamedParameters + + InternalFunction + +
    + +
    Function ::= '{' 'FN' InternalFunction '}'
    + +
               | InternalFunction
    +
    + + +====================================================================================================================== +SpecialStringFunctionWithNamedParameters +====================================================================================================================== + + +.. raw:: html + + + + + + K_STRING_FUNCTION_NAME + ( + + NamedExpressionListExprFirst + + ExpressionList + ) + + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +InternalFunction +====================================================================================================================== + + +.. raw:: html + + + + + + APPROXIMATE + + RelObjectNames + ( + + DISTINCT + + ALL + + UNIQUE + + TABLE + + ExpressionList + + OrderByElements + ON + + OVERFLOW + + TRUNCATE + + ERROR + + S_CHAR_LITERAL + WITH + + WITHOUT + + COUNT + + Select + HAVING + + MIN + + MAX + + Expression + IGNORE + + RESPECT + + NULLS + + PlainLimit + ) + + ( + + ExpressionList + ) + + . + + Function + + Column + IGNORE + + RESPECT + + NULLS + + KeepExpression + +
    + + +
             ::= 'APPROXIMATE'? RelObjectNames '(' ( ( 'DISTINCT' | 'ALL' | 'UNIQUE' )? ( 'TABLE'? ExpressionList OrderByElements? ( 'ON' 'OVERFLOW' ( 'TRUNCATE' | 'ERROR' ) ( S_CHAR_LITERAL ( ( 'WITH' | 'WITHOUT' ) 'COUNT' )? )? )? | Select ) )? ( 'HAVING' ( 'MIN' | 'MAX' ) Expression )? ( ( 'IGNORE' | 'RESPECT' ) 'NULLS' )? PlainLimit? ')' ( '(' ExpressionList ')' )? ( '.' ( Function | Column ) )? ( ( 'IGNORE' | 'RESPECT' ) 'NULLS' )? KeepExpression?
    +
    + Referenced by: +
    + + +====================================================================================================================== +XMLSerializeExpr +====================================================================================================================== + + +.. raw:: html + + + + + + XMLSERIALIZE + + ( + + XMLAGG + + ( + + XMLTEXT + + ( + + SimpleExpression + ) + + OrderByElements + ) + + AS + + ColDataType + ) + + +
    + + +
             ::= 'XMLSERIALIZE' '(' 'XMLAGG' '(' 'XMLTEXT' '(' SimpleExpression ')' OrderByElements? ')' 'AS' ColDataType ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTablePassingClause +====================================================================================================================== + + +.. raw:: html + + + + + + Expression + AS + + RelObjectName + +
    + + +
             ::= Expression 'AS' RelObjectName
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableOnEmptyBehavior +====================================================================================================================== + + +.. raw:: html + + + + + + ERROR + + NULL + + DEFAULT + + Expression + + S_IDENTIFIER + + JsonKeyword + ARRAY + + +
    + + +
             ::= 'ERROR'
    +
               | 'NULL'
    +
               | 'DEFAULT' Expression
    +
               | S_IDENTIFIER ( JsonKeyword | 'ARRAY' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableWrapperClause +====================================================================================================================== + + +.. raw:: html + + + + + + WITHOUT + + WITH + + S_IDENTIFIER + ARRAY + + JsonKeyword + +
    + + +
             ::= ( 'WITHOUT' | 'WITH' S_IDENTIFIER? ) 'ARRAY'? JsonKeyword
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableQuotesClause +====================================================================================================================== + + +.. raw:: html + + + + + + KEEP + + JsonKeyword + + JsonKeyword + ON + + JsonKeyword + STRING + + +
    + + +
             ::= ( 'KEEP' | JsonKeyword ) JsonKeyword ( 'ON' JsonKeyword 'STRING' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableColumnDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + JsonKeyword + PATH + + Expression + AS + + RelObjectName + + JsonTableColumnsClause + + RelObjectName + FOR + + JsonKeyword + + ColDataType + FORMAT + + JSON + + ENCODING + + JsonEncoding + PATH + + Expression + + JsonTableWrapperClause + + JsonTableQuotesClause + + JsonTableOnEmptyBehavior + ON + + JsonKeyword + + JsonValueOnResponseBehavior + ON + + ERROR + + +
    + + +
             ::= JsonKeyword 'PATH'? Expression ( 'AS' RelObjectName )? JsonTableColumnsClause
    +
               | RelObjectName ( 'FOR' JsonKeyword | ColDataType ( 'FORMAT' 'JSON' ( 'ENCODING' JsonEncoding )? )? ( 'PATH' Expression )? JsonTableWrapperClause? JsonTableQuotesClause? ( JsonTableOnEmptyBehavior 'ON' JsonKeyword )? ( JsonValueOnResponseBehavior 'ON' 'ERROR' )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableColumnsClause +====================================================================================================================== + + +.. raw:: html + + + + + + COLUMNS + + ( + + JsonTableColumnDefinition + , + + ) + + +
    + + +
             ::= 'COLUMNS' '(' ( JsonTableColumnDefinition ( ',' JsonTableColumnDefinition )* )? ')'
    +
    + + +====================================================================================================================== +JsonTablePlanTerm +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + JsonTablePlanExpression + ) + + RelObjectName + + Expression + +
    + + +
             ::= '(' JsonTablePlanExpression ')'
    +
               | RelObjectName
    +
               | Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTablePlanExpression +====================================================================================================================== + + +.. raw:: html + + + + + + JsonTablePlanTerm + , + + INNER + + OUTER + + CROSS + + UNION + + +
    + + +
             ::= JsonTablePlanTerm ( ( ',' | 'INNER' | 'OUTER' | 'CROSS' | 'UNION' ) JsonTablePlanTerm )*
    +
    + + +====================================================================================================================== +JsonTablePlanClause +====================================================================================================================== + + +.. raw:: html + + + + + + PLAN + + DEFAULT + + ( + + JsonTablePlanExpression + ) + + +
    + + +
             ::= 'PLAN' 'DEFAULT'? '(' JsonTablePlanExpression ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableOnErrorClause +====================================================================================================================== + + +.. raw:: html + + + + + + ERROR + + S_IDENTIFIER + ON + + ERROR + + +
    + + +
             ::= ( 'ERROR' | S_IDENTIFIER ) 'ON' 'ERROR'
    +
    + Referenced by: +
    + + +====================================================================================================================== +JsonTableBody +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Expression + , + + Expression + AS + + RelObjectName + + JsonKeyword + + JsonTablePassingClause + , + + JsonTableColumnsClause + + JsonTablePlanClause + + JsonTableOnErrorClause + ) + + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +TableFunction +====================================================================================================================== + + +.. raw:: html + + + + + + LATERAL + + JsonKeyword + + JsonTableBody + + Function + WITH + + OFFSET + + ORDINALITY + + +
    + + +
             ::= 'LATERAL'? ( JsonKeyword JsonTableBody | Function ) ( 'WITH' ( 'OFFSET' | 'ORDINALITY' ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnNamesWithParamsList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + RelObjectName + + CreateParameter + , + + ) + + +
    + + +
             ::= '(' RelObjectName CreateParameter? ( ',' RelObjectName CreateParameter? )* ')'
    +
    + + +====================================================================================================================== +IndexColumnWithParams +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ( + + Expression + ) + + CreateParameter + +
    + + +
             ::= ( RelObjectName | '(' Expression ')' ) CreateParameter?
    +
    + Referenced by: +
    + + +====================================================================================================================== +IndexColumnsWithParamsList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + IndexColumnWithParams + , + + ) + + +
    + + +
             ::= '(' IndexColumnWithParams ( ',' IndexColumnWithParams )* ')'
    +
    + + +====================================================================================================================== +Index +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNames + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +CreateIndex +====================================================================================================================== + + +.. raw:: html + + + + + + CreateParameter + INDEX + + IF + + NOT + + EXISTS + + Index + ON + + Table + + UsingIndexType + + UsingIndexType + ON + + Table + + IndexColumnsWithParamsList + + CreateParameter + +
    + + +
             ::= CreateParameter? 'INDEX' ( 'IF' 'NOT' 'EXISTS' )? Index ( 'ON' Table UsingIndexType? | UsingIndexType? 'ON' Table ) IndexColumnsWithParamsList CreateParameter*
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnDefinition +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + + ColDataType + + CreateParameter + +
    + + + +
    + + +====================================================================================================================== +CreateSchema +====================================================================================================================== + + +.. raw:: html + + + + + + SCHEMA + + IF + + NOT + + EXISTS + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + . + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + AUTHORIZATION + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + PathSpecification + CREATE + + CreateTable + + CreateView + +
    + + +
             ::= 'SCHEMA' ( 'IF' 'NOT' 'EXISTS' )? ( ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ( '.' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) )? )? ( 'AUTHORIZATION' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) )? PathSpecification? ( 'CREATE' CreateTable | CreateView )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +PathSpecification +====================================================================================================================== + + +.. raw:: html + + + + + + PATH + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + , + + +
    + + +
             ::= 'PATH' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ( ',' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateTableConstraint +====================================================================================================================== + + +.. raw:: html + + + + + + INDEX + + UNIQUE + + FULLTEXT + + SPATIAL + + KEY + + RelObjectName + + IndexColumnsWithParamsList + + CreateParameter + CONSTRAINT + + RelObjectName + PRIMARY + + KEY + + UNIQUE + + KEY + + ColumnNamesWithParamsList + + CreateParameter + + ForeignKeySpec + + CheckConstraintSpec + EXCLUDE + + WHERE + + ( + + Expression + ) + + +
    + + +
             ::= ( 'INDEX' | 'UNIQUE'? ( 'FULLTEXT' | 'SPATIAL' )? 'KEY' ) RelObjectName IndexColumnsWithParamsList CreateParameter*
    +
               | ( 'CONSTRAINT' RelObjectName )? ( ( 'PRIMARY' 'KEY' | 'UNIQUE' 'KEY'? ) ColumnNamesWithParamsList CreateParameter* | ForeignKeySpec | CheckConstraintSpec )
    +
               | 'EXCLUDE' 'WHERE' ( '(' Expression ')' )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateTable +====================================================================================================================== + + +.. raw:: html + + + + + + UNLOGGED + + GLOBAL + + CreateParameter + TABLE + + IF + + NOT + + EXISTS + + Table + ( + + RelObjectName + , + + ColumnDefinition + , + + CreateTableConstraint + + ColumnDefinition + ) + + CreateParameter + + RowMovement + AS + + Select + LIKE + + ( + + Table + ) + + Table + , + + SpannerInterleaveIn + +
    + + +
             ::= 'UNLOGGED'? 'GLOBAL'? CreateParameter* 'TABLE' ( 'IF' 'NOT' 'EXISTS' )? Table ( '(' ( RelObjectName ( ',' RelObjectName )* | ColumnDefinition ( ',' ( CreateTableConstraint | ColumnDefinition ) )* ) ')' )? CreateParameter* RowMovement? ( 'AS' Select )? ( 'LIKE' ( '(' Table ')' | Table ) )? ( ',' SpannerInterleaveIn )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +SpannerInterleaveIn +====================================================================================================================== + + +.. raw:: html + + + + + + INTERLEAVE + + IN + + PARENT + + Table + ON + + DELETE + + NO + + ACTION + + CASCADE + + +
    + + +
             ::= 'INTERLEAVE' 'IN' 'PARENT' Table ( 'ON' 'DELETE' ( 'NO' 'ACTION' | 'CASCADE' ) )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +DataType +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATETIMELITERAL + + DT_ZONE + + DATA_TYPE + SIGNED + + UNSIGNED + + CHARACTER + + BIT + + BYTES + + BINARY + + BOOLEAN + + CHAR + + JSON + + STRING + + DATA_TYPE + SIGNED + + UNSIGNED + + CHARACTER + + BIT + + BYTES + + BINARY + + BOOLEAN + + CHAR + + JSON + + STRING + + ( + + S_LONG + MAX + + , + + S_LONG + ) + + K_TEXT_LITERAL + ARRAY + + < + + ColDataType + > + + +
    + + +
               | 'ARRAY' '<' ColDataType '>'
    +
               | ( K_DATETIMELITERAL | DT_ZONE | DATA_TYPE | 'SIGNED' | 'UNSIGNED' | 'CHARACTER' | 'BIT' | 'BYTES' | 'BINARY' | 'BOOLEAN' | + 'CHAR' | 'JSON' | 'STRING' ) ( DATA_TYPE | 'SIGNED' | 'UNSIGNED' | 'CHARACTER' | 'BIT' | 'BYTES' | 'BINARY' | 'BOOLEAN' | + 'CHAR' | 'JSON' | 'STRING' )* ( '(' ( S_LONG | 'MAX' ) ( ',' S_LONG )? ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColDataType +====================================================================================================================== + + +.. raw:: html + + + + + + STRUCT + + ( + + RelObjectNameExt + + ColDataType + , + + ) + + DataType + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + K_DATETIMELITERAL + + K_DATE_LITERAL + XML + + INTERVAL + + DT_ZONE + CHAR + + SET + + BINARY + + JSON + + STRING + + PUBLIC + + DATA + + NAME + + . + + ColDataType + ( + + S_LONG + MAX + + BYTE + + CHAR + + S_CHAR_LITERAL + + S_IDENTIFIER + CHAR + + , + + ) + + [ + + S_LONG + ] + + CHARACTER + + SET + + S_IDENTIFIER + BINARY + + +
    + + +
             ::= ( 'STRUCT' '(' RelObjectNameExt ColDataType ( ',' RelObjectNameExt ColDataType )* ')' | DataType | ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | K_DATETIMELITERAL | K_DATE_LITERAL | 'XML' | 'INTERVAL' | DT_ZONE | 'CHAR' | 'SET' | 'BINARY' | 'JSON' | 'STRING' | 'PUBLIC' | 'DATA' | 'NAME' ) ( + '.' ColDataType )? ) ( '(' ( ( ( S_LONG | 'MAX' ) ( 'BYTE' | 'CHAR' )? | S_CHAR_LITERAL | S_IDENTIFIER | 'CHAR' ) ','? )* ')' )? ( '[' S_LONG? ']' )* ( 'CHARACTER' 'SET' ( S_IDENTIFIER | 'BINARY' ) )?
    +
    + + +====================================================================================================================== +Analyze +====================================================================================================================== + + +.. raw:: html + + + + + + ANALYZE + + Table + +
    + +
    Analyze  ::= 'ANALYZE' Table
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnWithCommentList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + Column + , + + ) + + +
    + + +
             ::= '(' Column ( ',' Column )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateView +====================================================================================================================== + + +.. raw:: html + + + + + + NO + + FORCE + + SECURE + + TEMP + + TEMPORARY + + VOLATILE + + MATERIALIZED + + VIEW + + Table + AUTO + + REFRESH + + YES + + NO + + IF + + NOT + + EXISTS + + ColumnWithCommentList + + CreateViewTailComment + AS + + Select + WITH + + READ + + ONLY + + +
    + + +
             ::= ( 'NO'? 'FORCE' )? 'SECURE'? ( 'TEMP' | 'TEMPORARY' | 'VOLATILE' )? 'MATERIALIZED'? + 'VIEW' Table ( 'AUTO' 'REFRESH' ( 'YES' | 'NO' ) )? ( 'IF' 'NOT' 'EXISTS' )? ColumnWithCommentList? CreateViewTailComment? 'AS' Select ( 'WITH' 'READ' 'ONLY' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateViewTailComment +====================================================================================================================== + + +.. raw:: html + + + + + + COMMENT + + = + + S_CHAR_LITERAL + +
    + + +
             ::= 'COMMENT' '='? S_CHAR_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +Action +====================================================================================================================== + + +.. raw:: html + + + + + + CASCADE + + RESTRICT + + NO + + ACTION + + SET + + NULL + + DEFAULT + + +
    + +
    Action   ::= 'CASCADE'
    +
               | 'RESTRICT'
    +
               | 'NO' 'ACTION'
    +
               | 'SET' ( 'NULL' | 'DEFAULT' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +ReferentialActionsOnIndex +====================================================================================================================== + + +.. raw:: html + + + + + + ON + + DELETE + + UPDATE + + Action + ON + + DELETE + + UPDATE + + Action + +
    + + +
             ::= ( 'ON' ( 'DELETE' | 'UPDATE' ) Action )? ( 'ON' ( 'DELETE' | 'UPDATE' ) Action )?
    +
    + + +====================================================================================================================== +CheckConstraintSpec +====================================================================================================================== + + +.. raw:: html + + + + + + CHECK + + ( + + Expression + ) + + +
    + + +
             ::= 'CHECK' ( '(' Expression ')' )*
    +
    + + +====================================================================================================================== +ForeignKeySpec +====================================================================================================================== + + +.. raw:: html + + + + + + FOREIGN + + KEY + + ColumnNamesWithParamsList + REFERENCES + + Table + + ColumnsNamesList + + ReferentialActionsOnIndex + +
    + + +
             ::= 'FOREIGN' 'KEY' ColumnNamesWithParamsList 'REFERENCES' Table ColumnsNamesList? ReferentialActionsOnIndex
    +
    + + +====================================================================================================================== +AlterExpressionUsingIndex +====================================================================================================================== + + +.. raw:: html + + + + + + USING + + INDEX + + RelObjectName + +
    + + +
             ::= 'USING' 'INDEX'? RelObjectName
    +
    + + +====================================================================================================================== +AlterExpressionConstraintTail +====================================================================================================================== + + +.. raw:: html + + + + + + AlterExpressionConstraintState + + AlterExpressionUsingIndex + + IndexWithComment + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +AlterView +====================================================================================================================== + + +.. raw:: html + + + + + + VIEW + + Table + + ColumnsNamesList + AS + + Select + +
    + + +
             ::= 'VIEW' Table ColumnsNamesList? 'AS' Select
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateParameter +====================================================================================================================== + + +.. raw:: html + + + + + + K_NEXTVAL + ( + + S_CHAR_LITERAL + :: + + ColDataType + ) + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + NAME + + . + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + NAME + + USING + + INDEX + + TABLESPACE + + RelObjectName + + S_CHAR_LITERAL + NULL + + NOT + + AUTO_INCREMENT + + PRIMARY + + FOREIGN + + REFERENCES + + KEY + + STORED + + ON + + COMMIT + + DROP + + ROWS + + UNIQUE + + CASCADE + + DELETE + + UPDATE + + CONSTRAINT + + WITH + + EXCLUDE + + WHERE + + TEMP + + TEMPORARY + + PARTITION + + BY + + IN + + TYPE + + COMMENT + + USING + + COLLATE + + ASC + + DESC + + TRUE + + FALSE + + PARALLEL + + BINARY + + START + + ORDER + + K_TIME_KEY_EXPR + RAW + + HASH + + FIRST + + LAST + + SIGNED + + UNSIGNED + + ENGINE + + IDENTITY + + MATERIALIZED + + SAMPLE + + ALWAYS + + = + + DEFAULT + + AS + + CHECK + + ( + + Expression + ) + + + + + - + + S_LONG + + S_DOUBLE + + AList + CHARACTER + + SET + + ARRAY + + ArrayConstructor + :: + + ColDataType + +
    + + +
             ::= K_NEXTVAL '(' S_CHAR_LITERAL '::' ColDataType ')'
    +
               | ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | 'NAME' ) ( '.' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER | 'NAME' ) )?
    +
               | ( 'USING' 'INDEX' )? 'TABLESPACE' RelObjectName
    +
               | S_CHAR_LITERAL
    +
               | 'NULL'
    +
               | 'NOT'
    +
               | 'AUTO_INCREMENT'
    +
               | 'PRIMARY'
    +
               | 'FOREIGN'
    +
               | 'REFERENCES'
    +
               | 'KEY'
    +
               | 'STORED'
    +
               | 'ON'
    +
               | 'COMMIT'
    +
               | 'DROP'
    +
               | 'ROWS'
    +
               | 'UNIQUE'
    +
               | 'CASCADE'
    +
               | 'DELETE'
    +
               | 'UPDATE'
    +
               | 'CONSTRAINT'
    +
               | 'WITH'
    +
               | 'EXCLUDE'
    +
               | 'WHERE'
    +
               | 'TEMP'
    +
               | 'TEMPORARY'
    +
               | 'PARTITION'
    +
               | 'BY'
    +
               | 'IN'
    +
               | 'TYPE'
    +
               | 'COMMENT'
    +
               | 'USING'
    +
               | 'COLLATE'
    +
               | 'ASC'
    +
               | 'DESC'
    +
               | 'TRUE'
    +
               | 'FALSE'
    +
               | 'PARALLEL'
    +
               | 'BINARY'
    +
               | 'START'
    +
               | 'ORDER'
    +
               | K_TIME_KEY_EXPR
    +
               | 'RAW'
    +
               | 'HASH'
    +
               | 'FIRST'
    +
               | 'LAST'
    +
               | 'SIGNED'
    +
               | 'UNSIGNED'
    +
               | 'ENGINE'
    +
               | 'IDENTITY'
    +
               | 'MATERIALIZED'
    +
               | 'SAMPLE'
    +
               | 'ALWAYS'
    +
               | '='
    +
               | ( 'DEFAULT' | 'AS' | 'CHECK' ) ( '(' Expression ')' )?
    +
               | ( '+' | '-' )? S_LONG
    +
               | S_DOUBLE
    +
               | AList
    +
               | 'CHARACTER' 'SET'
    +
               | 'ARRAY' ArrayConstructor
    +
               | '::' ColDataType
    +
    + + +====================================================================================================================== +RowMovement +====================================================================================================================== + + +.. raw:: html + + + + + + ENABLE + + DISABLE + + ROW + + MOVEMENT + + +
    + + +
             ::= ( 'ENABLE' | 'DISABLE' ) 'ROW' 'MOVEMENT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + S_LONG + + S_DOUBLE + + S_CHAR_LITERAL + TRUE + + FALSE + + RelObjectName + , + + = + + ) + + +
    + +
    AList    ::= '(' ( ( S_LONG | S_DOUBLE | S_CHAR_LITERAL | 'TRUE' | 'FALSE' | RelObjectName ) ( ',' | '=' )? )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnsNamesListItem +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + ( + + S_LONG + ) + + ASC + + DESC + + +
    + + +
             ::= RelObjectName ( '(' S_LONG ')' )? ( 'ASC' | 'DESC' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +ColumnsNamesList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + ColumnsNamesListItem + , + + ) + + +
    + + +
             ::= '(' ColumnsNamesListItem ( ',' ColumnsNamesListItem )* ')'
    +
    + + +====================================================================================================================== +FuncArgsListItem +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + + RelObjectName + ( + + S_LONG + ) + + +
    + + +
             ::= RelObjectName RelObjectName? ( '(' S_LONG ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +FuncArgsList +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + FuncArgsListItem + , + + ) + + +
    + + +
             ::= '(' ( FuncArgsListItem ( ',' FuncArgsListItem )* )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +Drop +====================================================================================================================== + + +.. raw:: html + + + + + + DROP + + MATERIALIZED + + S_IDENTIFIER + TEMPORARY + + TABLE + + INDEX + + VIEW + + SCHEMA + + SEQUENCE + + FUNCTION + + IF + + EXISTS + + Table + + FuncArgsList + + S_IDENTIFIER + CASCADE + + RESTRICT + + ON + + Table + +
    + +
    Drop     ::= 'DROP' 'MATERIALIZED'? ( S_IDENTIFIER | 'TEMPORARY'? 'TABLE' | 'INDEX' | 'VIEW' | 'SCHEMA' | 'SEQUENCE' | 'FUNCTION' ) + ( 'IF' 'EXISTS' )? Table FuncArgsList? ( S_IDENTIFIER | 'CASCADE' | 'RESTRICT' | 'ON' Table )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +Truncate +====================================================================================================================== + + +.. raw:: html + + + + + + TRUNCATE + + TABLE + + ONLY + + Table + , + + CASCADE + + +
    + +
    Truncate ::= 'TRUNCATE' 'TABLE'? 'ONLY'? Table ( ',' Table )* 'CASCADE'?
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnChanges +====================================================================================================================== + + +.. raw:: html + + + + + + AlterExpressionColumnDropDefault + + AlterExpressionColumnSetDefault + + AlterExpressionColumnSetVisibility + ( + + AlterExpressionColumnDataType + , + + ) + + +
    + + +
             ::= AlterExpressionColumnDropDefault
    +
               | AlterExpressionColumnSetDefault
    +
               | AlterExpressionColumnSetVisibility
    +
               | '(' AlterExpressionColumnDataType ( ',' AlterExpressionColumnDataType )* ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnDataType +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + TYPE + + ColDataType + + CreateParameter + +
    + + +
             ::= RelObjectName 'TYPE'? ColDataType? CreateParameter*
    +
    + + +====================================================================================================================== +AlterExpressionColumnDropNotNull +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + DROP + + NOT + + NULL + + +
    + + +
             ::= RelObjectName 'DROP' 'NOT'? 'NULL'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnDropDefault +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + DROP + + DEFAULT + + +
    + + +
             ::= RelObjectName 'DROP' 'DEFAULT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnSetDefault +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + SET + + DEFAULT + + Expression + +
    + + +
             ::= RelObjectName 'SET' 'DEFAULT' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionColumnSetVisibility +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + SET + + VISIBLE + + INVISIBLE + + +
    + + +
             ::= RelObjectName 'SET' ( 'VISIBLE' | 'INVISIBLE' )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionConstraintState +====================================================================================================================== + + +.. raw:: html + + + + + + NOT + + DEFERRABLE + + VALIDATE + + NOVALIDATE + + ENABLE + + DISABLE + + +
    + + +
             ::= ( 'NOT'? 'DEFERRABLE' | 'VALIDATE' | 'NOVALIDATE' | 'ENABLE' | 'DISABLE' + )*
    +
    + + +====================================================================================================================== +IndexWithComment +====================================================================================================================== + + +.. raw:: html + + + + + + COMMENT + + S_CHAR_LITERAL + +
    + + +
             ::= 'COMMENT' S_CHAR_LITERAL
    +
    + + +====================================================================================================================== +IndexOptionList +====================================================================================================================== + + +.. raw:: html + + + + + + IndexOption + +
    + + +
             ::= IndexOption*
    +
    + Referenced by: +
    + + +====================================================================================================================== +UsingIndexType +====================================================================================================================== + + +.. raw:: html + + + + + + USING + + RelObjectName + +
    + + +
             ::= 'USING' RelObjectName
    +
    + + +====================================================================================================================== +IndexOption +====================================================================================================================== + + +.. raw:: html + + + + + + KEY_BLOCK_SIZE + + = + + S_LONG + WITH + + PARSER + + S_IDENTIFIER + COMMENT + + S_CHAR_LITERAL + VISIBLE + + INVISIBLE + + UsingIndexType + +
    + + +
             ::= 'KEY_BLOCK_SIZE' '='? S_LONG
    +
               | 'WITH' 'PARSER' S_IDENTIFIER
    +
               | 'COMMENT' S_CHAR_LITERAL
    +
               | 'VISIBLE'
    +
               | 'INVISIBLE'
    +
               | UsingIndexType
    +
    + Referenced by: +
    + + +====================================================================================================================== +PartitionDefinitions +====================================================================================================================== + + +.. raw:: html + + + + + + ( + + PARTITION + + RelObjectName + VALUES + + LESS + + THAN + + ( + + Expression + ) + + MAXVALUE + + ENGINE + + = + + S_IDENTIFIER + , + + ) + + +
    + + +
             ::= '(' ( 'PARTITION' RelObjectName 'VALUES' 'LESS' 'THAN' ( '(' Expression ')' | 'MAXVALUE' ) ( 'ENGINE' '=' S_IDENTIFIER )? ','? )* ')'
    +
    + + +====================================================================================================================== +PartitionNamesList +====================================================================================================================== + + +.. raw:: html + + + + + + ALL + + S_IDENTIFIER + , + + +
    + + +
             ::= 'ALL'
    +
               | S_IDENTIFIER ( ',' S_IDENTIFIER )*
    +
    + + +====================================================================================================================== +AlterExpressionDiscardOrImport +====================================================================================================================== + + +.. raw:: html + + + + + + DISCARD + + IMPORT + + PARTITION + + PartitionNamesList + TABLESPACE + + +
    + + +
             ::= ( 'DISCARD' | 'IMPORT' ) ( 'PARTITION' PartitionNamesList )? 'TABLESPACE'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionAddConstraint +====================================================================================================================== + + +.. raw:: html + + + + + + CONSTRAINT + + UNIQUE + + KEY + + INDEX + + RelObjectName + + ColumnsNamesList + + RelObjectName + FOREIGN + + KEY + + ColumnsNamesList + REFERENCES + + Table + + ColumnsNamesList + + ReferentialActionsOnIndex + KEY + + ColumnsNamesList + + AlterExpressionConstraintState + PRIMARY + + KEY + + UNIQUE + + KEY + + INDEX + + ColumnsNamesList + + AlterExpressionConstraintTail + NOT + + ENFORCED + + CheckConstraintSpec + +
    + + +
             ::= 'CONSTRAINT' ( 'UNIQUE' ( 'KEY' | 'INDEX' )? RelObjectName ColumnsNamesList | RelObjectName ( ( 'FOREIGN' 'KEY' ColumnsNamesList 'REFERENCES' Table ColumnsNamesList? ReferentialActionsOnIndex | 'KEY' ColumnsNamesList ) AlterExpressionConstraintState | ( 'PRIMARY' 'KEY' | 'UNIQUE' ( 'KEY' | 'INDEX' )? ) ColumnsNamesList AlterExpressionConstraintTail | 'NOT'? 'ENFORCED' | CheckConstraintSpec ) )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionDrop +====================================================================================================================== + + +.. raw:: html + + + + + + DROP + + PARTITION + + PartitionNamesList + + ColumnsNamesList + COLUMN + + IF + + EXISTS + + KeywordOrIdentifier + INVALIDATE + + CASCADE + + CONSTRAINTS + + INDEX + + KEY + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + UNIQUE + + FOREIGN + + KEY + + ColumnsNamesList + PRIMARY + + KEY + + CONSTRAINT + + IF + + EXISTS + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + CASCADE + + RESTRICT + + +
    + + +
             ::= 'DROP' ( 'PARTITION' PartitionNamesList | ( ColumnsNamesList | 'COLUMN'? ( 'IF' 'EXISTS' )? KeywordOrIdentifier ) 'INVALIDATE'? ( 'CASCADE' 'CONSTRAINTS'? )? | ( 'INDEX' | 'KEY' ) ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) | ( ( 'UNIQUE' | 'FOREIGN' 'KEY' ) ColumnsNamesList | 'PRIMARY' 'KEY' | 'CONSTRAINT' ( 'IF' 'EXISTS' )? ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ) ( 'CASCADE' | 'RESTRICT' )? )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionPartitionOp +====================================================================================================================== + + +.. raw:: html + + + + + + TRUNCATE + + ANALYZE + + CHECK + + OPTIMIZE + + REBUILD + + REPAIR + + PARTITION + + PartitionNamesList + COALESCE + + PARTITION + + S_LONG + REORGANIZE + + PARTITION + + PartitionNamesList + INTO + + PARTITION + + BY + + RANGE + + ( + + Expression + ) + + COLUMNS + + ColumnsNamesList + + PartitionDefinitions + EXCHANGE + + PARTITION + + PartitionNamesList + WITH + + TABLE + + S_IDENTIFIER + WITH + + WITHOUT + + VALIDATION + + REMOVE + + PARTITIONING + + +
    + + +
             ::= ( 'TRUNCATE' | 'ANALYZE' | 'CHECK' | 'OPTIMIZE' | 'REBUILD' | 'REPAIR' + ) 'PARTITION' PartitionNamesList
    +
               | 'COALESCE' 'PARTITION' S_LONG
    +
               | ( 'REORGANIZE' 'PARTITION' PartitionNamesList 'INTO' | 'PARTITION' 'BY' 'RANGE' ( '(' Expression ')' | 'COLUMNS' ColumnsNamesList ) ) PartitionDefinitions
    +
               | 'EXCHANGE' 'PARTITION' PartitionNamesList 'WITH' 'TABLE' S_IDENTIFIER ( ( 'WITH' | 'WITHOUT' ) 'VALIDATION' )?
    +
               | 'REMOVE' 'PARTITIONING'
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionAddAlterModify +====================================================================================================================== + + +.. raw:: html + + + + + + ADD + + ALTER + + MODIFY + + PRIMARY + + KEY + + ColumnsNamesList + + AlterExpressionConstraintState + + AlterExpressionUsingIndex + KEY + + INDEX + + RelObjectName + + UsingIndexType + + IndexColumnsWithParamsList + + IndexOptionList + + AlterExpressionConstraintState + SPATIAL + + FULLTEXT + + INDEX + + KEY + + RelObjectName + + ColumnsNamesList + + IndexOptionList + + RelObjectName + COMMENT + + S_CHAR_LITERAL + PARTITION + + PartitionDefinitions + COLUMN + + COLUMNS + + IF + + NOT + + EXISTS + + AlterExpressionColumnChanges + + AlterExpressionColumnDataType + + AlterExpressionColumnDropNotNull + + AlterExpressionColumnChanges + UNIQUE + + KEY + + INDEX + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + + ColumnsNamesList + + AlterExpressionUsingIndex + + IndexWithComment + + ForeignKeySpec + CHECK + + RelObjectName + NOT + + ENFORCED + + AlterExpressionAddConstraint + +
    + + +
             ::= ( 'ADD' | 'ALTER' | 'MODIFY' ) ( 'PRIMARY' 'KEY' ColumnsNamesList AlterExpressionConstraintState AlterExpressionUsingIndex? | ( 'KEY' | 'INDEX' ) RelObjectName? UsingIndexType? IndexColumnsWithParamsList? IndexOptionList AlterExpressionConstraintState | ( 'SPATIAL' | 'FULLTEXT' ) ( 'INDEX' | 'KEY' )? RelObjectName? ColumnsNamesList IndexOptionList | RelObjectName 'COMMENT' S_CHAR_LITERAL | 'PARTITION' PartitionDefinitions | ( 'COLUMN' | 'COLUMNS' )? ( 'IF' 'NOT' 'EXISTS' )? ( AlterExpressionColumnChanges | AlterExpressionColumnDataType | AlterExpressionColumnDropNotNull ) | AlterExpressionColumnChanges | 'UNIQUE' ( 'KEY' | 'INDEX' )? ( S_IDENTIFIER | S_QUOTED_IDENTIFIER )? ColumnsNamesList AlterExpressionUsingIndex? IndexWithComment? | ForeignKeySpec | 'CHECK' RelObjectName 'NOT'? 'ENFORCED' | AlterExpressionAddConstraint )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpressionRenameOp +====================================================================================================================== + + +.. raw:: html + + + + + + RENAME + + INDEX + + KEY + + CONSTRAINT + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + TO + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + COLUMN + + KeywordOrIdentifier + TO + + KeywordOrIdentifier + +
    + + +
             ::= 'RENAME' ( ( ( 'INDEX' | 'KEY' | 'CONSTRAINT' ) ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) )? 'TO' ( S_IDENTIFIER | S_QUOTED_IDENTIFIER ) | 'COLUMN'? KeywordOrIdentifier 'TO' KeywordOrIdentifier )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterExpression +====================================================================================================================== + + +.. raw:: html + + + + + + AlterExpressionAddAlterModify + CHANGE + + COLUMN + + KeywordOrIdentifier + + AlterExpressionColumnDataType + + AlterExpressionDrop + FORCE + + ROW + + LEVEL + + SECURITY + + NO + + FORCE + + ROW + + LEVEL + + SECURITY + + ALGORITHM + + LOCK + + ENGINE + + = + + RelObjectName + KEY_BLOCK_SIZE + + AUTO_INCREMENT + + = + + S_LONG + + AlterExpressionRenameOp + CONVERT + + TO + + CHARACTER + + SET + + S_IDENTIFIER + COLLATE + + DEFAULT + + CHARACTER + + SET + + = + + S_IDENTIFIER + COLLATE + + COLLATE + + = + + S_IDENTIFIER + COMMENT + + ENCRYPTION + + = + + S_CHAR_LITERAL + + AlterExpressionDiscardOrImport + DISABLE + + ENABLE + + ROW + + LEVEL + + SECURITY + + KEYS + + AlterExpressionPartitionOp + + captureRest + +
    + + +
             ::= AlterExpressionAddAlterModify
    +
               | 'CHANGE' 'COLUMN'? KeywordOrIdentifier AlterExpressionColumnDataType
    +
               | AlterExpressionDrop
    +
               | 'FORCE' ( 'ROW' 'LEVEL' 'SECURITY' )?
    +
               | 'NO' 'FORCE' 'ROW' 'LEVEL' 'SECURITY'
    +
               | ( 'ALGORITHM' | 'LOCK' | 'ENGINE' ) '='? RelObjectName
    +
               | ( 'KEY_BLOCK_SIZE' | 'AUTO_INCREMENT' ) '='? S_LONG
    +
               | AlterExpressionRenameOp
    +
               | ( 'CONVERT' 'TO' 'CHARACTER' 'SET' ( S_IDENTIFIER 'COLLATE' )? | 'DEFAULT'? ( 'CHARACTER' 'SET' ( '='? S_IDENTIFIER 'COLLATE' )? | 'COLLATE' ) '='? ) S_IDENTIFIER
    +
               | ( 'COMMENT' | 'ENCRYPTION' ) '='? S_CHAR_LITERAL
    +
               | AlterExpressionDiscardOrImport
    +
               | ( 'DISABLE' | 'ENABLE' ) ( 'ROW' 'LEVEL' 'SECURITY' | 'KEYS' )
    +
               | AlterExpressionPartitionOp
    +
               | captureRest
    +
    + Referenced by: +
    + + +====================================================================================================================== +Alter +====================================================================================================================== + + +.. raw:: html + + + + + + ALTER + + AlterTable + + AlterSession + + AlterView + + AlterSystemStatement + + AlterSequence + + captureRest + REPLACE + + AlterView + + captureRest + +
    + + +
               | 'REPLACE' ( AlterView | captureRest )
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterTable +====================================================================================================================== + + +.. raw:: html + + + + + + TABLE + + ONLY + + IF + + EXISTS + + Table + + AlterExpression + , + + +
    + + +
             ::= 'TABLE' 'ONLY'? ( 'IF' 'EXISTS' )? Table AlterExpression ( ',' AlterExpression )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterSession +====================================================================================================================== + + +.. raw:: html + + + + + + SESSION + + ADVISE + + COMMIT + + ROLLBACK + + NOTHING + + CLOSE + + DATABASE + + LINK + + ENABLE + + DISABLE + + COMMIT + + IN + + PROCEDURE + + GUARD + + PARALLEL + + DML + + DDL + + QUERY + + RESUMABLE + + FORCE + + PARALLEL + + DML + + DDL + + QUERY + + SET + + S_CHAR_LITERAL + + S_IDENTIFIER + = + + S_LONG + PARALLEL + + +
    + + +
             ::= 'SESSION' ( 'ADVISE' ( 'COMMIT' | 'ROLLBACK' | 'NOTHING' ) | 'CLOSE' + 'DATABASE' 'LINK' | ( 'ENABLE' | 'DISABLE' ) ( 'COMMIT' 'IN' 'PROCEDURE' | 'GUARD' + | 'PARALLEL' ( 'DML' | 'DDL' | 'QUERY' ) | 'RESUMABLE' ) | 'FORCE' 'PARALLEL' ( 'DML' + | 'DDL' | 'QUERY' ) | 'SET' ) ( S_CHAR_LITERAL | S_IDENTIFIER | '=' | S_LONG | 'PARALLEL' )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterSystemStatement +====================================================================================================================== + + +.. raw:: html + + + + + + SYSTEM + + ARCHIVE + + LOG + + CHECKPOINT + + DUMP + + ACTIVE + + SESSION + + HISTORY + + ENABLE + + DISABLE + + DISTRIBUTED + + RECOVERY + + RESTRICTED + + SESSION + + FLUSH + + DISCONNECT + + KILL + + SESSION + + SWITCH + + SUSPEND + + RESUME + + QUIESCE + + RESTRICTED + + UNQIESCE + + SHUTDOWN + + REGISTER + + SET + + RESET + + captureRest + +
    + + +
             ::= 'SYSTEM' ( 'ARCHIVE' 'LOG' | 'CHECKPOINT' | 'DUMP' 'ACTIVE' 'SESSION' + 'HISTORY' | ( 'ENABLE' | 'DISABLE' ) ( 'DISTRIBUTED' 'RECOVERY' | 'RESTRICTED' 'SESSION' + ) | 'FLUSH' | ( 'DISCONNECT' | 'KILL' ) 'SESSION' | 'SWITCH' | 'SUSPEND' | 'RESUME' + | 'QUIESCE' 'RESTRICTED' | 'UNQIESCE' | 'SHUTDOWN' | 'REGISTER' | 'SET' | 'RESET' + ) captureRest
    +
    + Referenced by: +
    + + +====================================================================================================================== +Wait +====================================================================================================================== + + +.. raw:: html + + + + + + WAIT + + S_LONG + +
    + +
    Wait     ::= 'WAIT' S_LONG
    +
    + Referenced by: +
    + + +====================================================================================================================== +SavepointStatement +====================================================================================================================== + + +.. raw:: html + + + + + + SAVEPOINT + + S_IDENTIFIER + +
    + + +
             ::= 'SAVEPOINT' S_IDENTIFIER
    +
    + Referenced by: +
    + + +====================================================================================================================== +RollbackStatement +====================================================================================================================== + + +.. raw:: html + + + + + + ROLLBACK + + WORK + + TO + + SAVEPOINT + + S_IDENTIFIER + FORCE + + S_CHAR_LITERAL + +
    + + +
             ::= 'ROLLBACK' 'WORK'? ( 'TO' 'SAVEPOINT'? S_IDENTIFIER | 'FORCE' S_CHAR_LITERAL )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +Comment +====================================================================================================================== + + +.. raw:: html + + + + + + COMMENT + + ON + + TABLE + + VIEW + + Table + COLUMN + + Column + IS + + S_CHAR_LITERAL + +
    + +
    Comment  ::= 'COMMENT' 'ON' ( ( 'TABLE' | 'VIEW' ) Table | 'COLUMN' Column ) 'IS' S_CHAR_LITERAL
    +
    + Referenced by: +
    + + +====================================================================================================================== +Grant +====================================================================================================================== + + +.. raw:: html + + + + + + GRANT + + readGrantTypes + , + + ON + + RelObjectNames + + S_IDENTIFIER + TO + + UsersList + +
    + +
    Grant    ::= 'GRANT' ( ( readGrantTypes ( ',' readGrantTypes )* )? 'ON' RelObjectNames | S_IDENTIFIER ) 'TO' UsersList
    +
    + Referenced by: +
    + + +====================================================================================================================== +UsersList +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectName + , + + ColumnsNamesListItem + +
    + + +
             ::= RelObjectName ( ',' ColumnsNamesListItem )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +readGrantTypes +====================================================================================================================== + + +.. raw:: html + + + + + + K_SELECT + INSERT + + UPDATE + + DELETE + + EXECUTE + + ALTER + + DROP + + +
    + + +
             ::= K_SELECT
    +
               | 'INSERT'
    +
               | 'UPDATE'
    +
               | 'DELETE'
    +
               | 'EXECUTE'
    +
               | 'ALTER'
    +
               | 'DROP'
    +
    + Referenced by: +
    + + +====================================================================================================================== +Sequence +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNames + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +SequenceParameters +====================================================================================================================== + + +.. raw:: html + + + + + + INCREMENT + + BY + + START + + WITH + + MAXVALUE + + MINVALUE + + CACHE + + S_LONG + RESTART + + WITH + + S_LONG + NOMAXVALUE + + NOMINVALUE + + NOCYCLE + + CYCLE + + NOCACHE + + ORDER + + NOORDER + + KEEP + + NOKEEP + + SESSION + + GLOBAL + + +
    + + +
             ::= ( ( 'INCREMENT' 'BY'? | 'START' 'WITH'? | 'MAXVALUE' | 'MINVALUE' | 'CACHE' + ) S_LONG | 'RESTART' ( 'WITH' S_LONG )? | 'NOMAXVALUE' | 'NOMINVALUE' | 'NOCYCLE' | 'CYCLE' | 'NOCACHE' | 'ORDER' | 'NOORDER' + | 'KEEP' | 'NOKEEP' | 'SESSION' | 'GLOBAL' )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateSequence +====================================================================================================================== + + +.. raw:: html + + + + + + SEQUENCE + + Sequence + AS + + S_IDENTIFIER + + DATA_TYPE + + SequenceParameters + +
    + + +
             ::= 'SEQUENCE' Sequence ( 'AS' ( S_IDENTIFIER | DATA_TYPE ) )? SequenceParameters
    +
    + Referenced by: +
    + + +====================================================================================================================== +AlterSequence +====================================================================================================================== + + +.. raw:: html + + + + + + SEQUENCE + + Sequence + + SequenceParameters + +
    + + +
             ::= 'SEQUENCE' Sequence SequenceParameters
    +
    + Referenced by: +
    + + +====================================================================================================================== +Create +====================================================================================================================== + + +.. raw:: html + + + + + + CREATE + + OR + + REPLACE + + CreateFunctionStatement + + CreateSchema + + CreateSequence + + CreateSynonym + + CreateTable + + CreateView + + CreatePolicy + TRIGGER + + DOMAIN + + captureRest + + CreateIndex + +
    + +
    Create   ::= 'CREATE' ( 'OR' 'REPLACE' )? ( CreateFunctionStatement | CreateSchema | CreateSequence | CreateSynonym | CreateTable | CreateView | CreatePolicy | ( 'TRIGGER' | 'DOMAIN' )? captureRest | CreateIndex )
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateFunctionStatement +====================================================================================================================== + + +.. raw:: html + + + + + + FUNCTION + + PROCEDURE + + captureFunctionBody + +
    + + +
             ::= ( 'FUNCTION' | 'PROCEDURE' ) captureFunctionBody
    +
    + Referenced by: +
    + + +====================================================================================================================== +CreateSynonym +====================================================================================================================== + + +.. raw:: html + + + + + + PUBLIC + + SYNONYM + + Synonym + FOR + + RelObjectNames + +
    + + +
             ::= 'PUBLIC'? 'SYNONYM' Synonym 'FOR' RelObjectNames
    +
    + Referenced by: +
    + + +====================================================================================================================== +Synonym +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNames + +
    + + +
    + Referenced by: +
    + + +====================================================================================================================== +CreatePolicy +====================================================================================================================== + + +.. raw:: html + + + + + + POLICY + + RelObjectName + ON + + Table + FOR + + ALL + + K_SELECT + INSERT + + UPDATE + + DELETE + + TO + + RelObjectName + , + + USING + + ( + + Expression + ) + + WITH + + CHECK + + ( + + Expression + ) + + +
    + + +
             ::= 'POLICY' RelObjectName 'ON' Table ( 'FOR' ( 'ALL' | K_SELECT | 'INSERT' | 'UPDATE' | 'DELETE' ) )? ( 'TO' RelObjectName ( ',' RelObjectName )* )? ( 'USING' '(' Expression ')' )? ( 'WITH' 'CHECK' '(' Expression ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnsupportedStatement +====================================================================================================================== + + +.. raw:: html + + + + + + captureUnsupportedStatementDeclaration + +
    + + + +
    + Referenced by: +
    + + +====================================================================================================================== +IdentifierChain +====================================================================================================================== + + +.. raw:: html + + + + + + RelObjectNameExt + . + + +
    + + +
             ::= RelObjectNameExt ( '.' RelObjectNameExt )*
    +
    + + +====================================================================================================================== +IdentifierChain2 +====================================================================================================================== + + +.. raw:: html + + + + + + . + + RelObjectNameExt + +
    + + +
             ::= ( '.' RelObjectNameExt )*
    +
    + Referenced by: +
    + + +====================================================================================================================== +CharacterPrimary +====================================================================================================================== + + +.. raw:: html + + + + + + TranscodingFunction + + TrimFunction + +
    + + +
             ::= TranscodingFunction
    +
               | TrimFunction
    +
    + Referenced by: +
    + + +====================================================================================================================== +TranscodingFunction +====================================================================================================================== + + +.. raw:: html + + + + + + TRY_CONVERT + + SAFE_CONVERT + + CONVERT + + ( + + ColDataType + , + + Expression + , + + S_LONG + + Expression + USING + + IdentifierChain + ) + + +
    + + +
             ::= ( 'TRY_CONVERT' | 'SAFE_CONVERT' | 'CONVERT' ) '(' ( ColDataType ',' Expression ( ',' S_LONG )? | Expression 'USING' IdentifierChain ) ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TrimFunction +====================================================================================================================== + + +.. raw:: html + + + + + + TRIM + + ( + + LEADING + + TRAILING + + BOTH + + Expression + , + + FROM + + Expression + ) + + +
    + + +
             ::= 'TRIM' '(' ( 'LEADING' | 'TRAILING' | 'BOTH' )? Expression? ( ( ',' | 'FROM' ) Expression )? ')'
    +
    + Referenced by: +
    + + +====================================================================================================================== +SnowflakeTimeTravelAt +====================================================================================================================== + + +.. raw:: html + + + + + + AT + + ( + + K_DATETIMELITERAL + OFFSET + + => + + Expression + STATEMENT + + => + + S_CHAR_LITERAL + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + STREAM + + => + + S_CHAR_LITERAL + ) + + +
    + + +
             ::= 'AT' '(' ( ( K_DATETIMELITERAL | 'OFFSET' ) '=>' Expression | 'STATEMENT' '=>' ( S_CHAR_LITERAL | S_IDENTIFIER | S_QUOTED_IDENTIFIER ) | 'STREAM' '=>' S_CHAR_LITERAL ) ')'
    +
    + + +====================================================================================================================== +SnowflakeTimeTravelBefore +====================================================================================================================== + + +.. raw:: html + + + + + + BEFORE + + ( + + STATEMENT + + => + + S_CHAR_LITERAL + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + ) + + +
    + + +
             ::= 'BEFORE' '(' 'STATEMENT' '=>' ( S_CHAR_LITERAL | S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ')'
    +
    + + +====================================================================================================================== +SnowflakeTimeTravelChange +====================================================================================================================== + + +.. raw:: html + + + + + + CHANGES + + ( + + INFORMATION + + => + + DEFAULT + + APPEND_ONLY + + ) + + SnowflakeTimeTravelAt + + SnowflakeTimeTravelBefore + END + + ( + + K_DATETIMELITERAL + OFFSET + + => + + Expression + STATEMENT + + => + + S_CHAR_LITERAL + + S_IDENTIFIER + + S_QUOTED_IDENTIFIER + ) + + +
    + + +
             ::= 'CHANGES' '(' 'INFORMATION' '=>' ( 'DEFAULT' | 'APPEND_ONLY' ) ')' ( + SnowflakeTimeTravelAt | SnowflakeTimeTravelBefore ) ( 'END' '(' ( ( K_DATETIMELITERAL | 'OFFSET' ) '=>' Expression | 'STATEMENT' '=>' ( S_CHAR_LITERAL | S_IDENTIFIER | S_QUOTED_IDENTIFIER ) ) ')' )?
    +
    + Referenced by: +
    + + +====================================================================================================================== +DataBricksTemporalSpec +====================================================================================================================== + + +.. raw:: html + + + + + + @ + + @V + + S_CHAR_LITERAL + + S_LONG + FOR + + SYSTEM_TIMESTAMP + + K_DATETIMELITERAL + AS + + OF + + Expression + SYSTEM_VERSION + + VERSION + + AS + + OF + + S_LONG + + S_CHAR_LITERAL + +
    + + +
             ::= ( '@' | '@V' ) ( S_CHAR_LITERAL | S_LONG )
    +
               | 'FOR'? ( 'SYSTEM_TIMESTAMP' | K_DATETIMELITERAL ) 'AS' 'OF' Expression
    +
               | ( 'SYSTEM_VERSION' | 'VERSION' ) 'AS' 'OF' ( S_LONG | S_CHAR_LITERAL )
    +
    + Referenced by: +
    + + +====================================================================================================================== +BigQueryHistoricalVersion +====================================================================================================================== + + +.. raw:: html + + + + + + FOR + + SYSTEM_TIME + + AS + + OF + + Expression + +
    + + +
             ::= 'FOR' 'SYSTEM_TIME' 'AS' 'OF' Expression
    +
    + Referenced by: +
    + + +====================================================================================================================== +TimeTravelBeforeAlias +====================================================================================================================== + + +.. raw:: html + + + + + + SnowflakeTimeTravelAt + + SnowflakeTimeTravelBefore + + SnowflakeTimeTravelChange + + DataBricksTemporalSpec + +
    + + +
             ::= SnowflakeTimeTravelAt
    +
               | SnowflakeTimeTravelBefore
    +
               | SnowflakeTimeTravelChange
    +
               | DataBricksTemporalSpec
    +
    + Referenced by: +
    + + +====================================================================================================================== +TimeTravelAfterAlias +====================================================================================================================== + + +.. raw:: html + + + + + + BigQueryHistoricalVersion + +
    + + +
             ::= BigQueryHistoricalVersion
    +
    + Referenced by: +
    + + +====================================================================================================================== +WHITESPACE +====================================================================================================================== + + +.. raw:: html + + + + + + + + [#x9] + + [#xD] + + [#xA] + + +
    + + +
             ::= [ #x9#xD#xA]
    +
    + + +====================================================================================================================== +K_ISOLATION +====================================================================================================================== + + +.. raw:: html + + + + + + UR + + RS + + RR + + CS + + +
    + + +
             ::= 'UR'
    +
               | 'RS'
    +
               | 'RR'
    +
               | 'CS'
    +
    + Referenced by: +
    + + +====================================================================================================================== +K_NEXTVAL +====================================================================================================================== + + +.. raw:: html + + + + + + NEXTVAL + + + + FOR + + NEXT + + + + VALUE + + + + FOR + + +
    + + +
             ::= 'NEXTVAL' ( ' '+ 'FOR' )?
    +
               | 'NEXT' ' '+ 'VALUE' ' '+ 'FOR'
    +
    + + +====================================================================================================================== +K_TEXT_LITERAL +====================================================================================================================== + + +.. raw:: html + + + + + + TEXT + + TINYTEXT + + MEDIUMTEXT + + LONGTEXT + + +
    + + +
             ::= 'TEXT'
    +
               | 'TINYTEXT'
    +
               | 'MEDIUMTEXT'
    +
               | 'LONGTEXT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +K_TIME_KEY_EXPR +====================================================================================================================== + + +.. raw:: html + + + + + + CURRENT + + _ + + + + TIMESTAMP + + TIME + + DATE + + TIMEZONE + + () + + +
    + + +
             ::= 'CURRENT' ( '_' | ' '+ ) ( 'TIMESTAMP' | 'TIME' | 'DATE' | 'TIMEZONE' + ) '()'?
    +
    + + +====================================================================================================================== +K_STRING_FUNCTION_NAME +====================================================================================================================== + + +.. raw:: html + + + + + + SUBSTR + + SUBSTRING + + TRIM + + POSITION + + OVERLAY + + +
    + + +
             ::= 'SUBSTR'
    +
               | 'SUBSTRING'
    +
               | 'TRIM'
    +
               | 'POSITION'
    +
               | 'OVERLAY'
    +
    + + +====================================================================================================================== +K_DATETIMELITERAL +====================================================================================================================== + + +.. raw:: html + + + + + + DATE + + DATETIME + + TIME + + TIMESTAMP + + TIMESTAMPTZ + + +
    + + +
             ::= 'DATE'
    +
               | 'DATETIME'
    +
               | 'TIME'
    +
               | 'TIMESTAMP'
    +
               | 'TIMESTAMPTZ'
    +
    + + +====================================================================================================================== +K_DATE_LITERAL +====================================================================================================================== + + +.. raw:: html + + + + + + YEAR + + MONTH + + DAY + + HOUR + + MINUTE + + SECOND + + +
    + + +
             ::= 'YEAR'
    +
               | 'MONTH'
    +
               | 'DAY'
    +
               | 'HOUR'
    +
               | 'MINUTE'
    +
               | 'SECOND'
    +
    + + +====================================================================================================================== +K_SELECT +====================================================================================================================== + + +.. raw:: html + + + + + + SELECT + + SEL + + +
    + +
    K_SELECT ::= 'SELECT'
    +
               | 'SEL'
    +
    + + +====================================================================================================================== +K_SIMILAR_TO +====================================================================================================================== + + +.. raw:: html + + + + + + SIMILAR + + + + TO + + +
    + + +
             ::= 'SIMILAR' ' '+ 'TO'
    +
    + Referenced by: +
    + + +====================================================================================================================== +ST_SEMICOLON +====================================================================================================================== + + +.. raw:: html + + + + + + ; + + [#xA] + + / + + [#xA] + + go + + [#xA] + + +
    + + +
             ::= ';'
    +
               | #xA ( [/#xA] | 'go' ) #xA
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_GREATERTHANEQUALS +====================================================================================================================== + + +.. raw:: html + + + + + + > + + WHITESPACE + = + + +
    + + +
             ::= '>' WHITESPACE* '='
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_MINORTHANEQUALS +====================================================================================================================== + + +.. raw:: html + + + + + + < + + WHITESPACE + = + + +
    + + +
             ::= '<' WHITESPACE* '='
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_NOTEQUALSSTANDARD +====================================================================================================================== + + +.. raw:: html + + + + + + < + + WHITESPACE + > + + +
    + + +
             ::= '<' WHITESPACE* '>'
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_NOTEQUALSBANG +====================================================================================================================== + + +.. raw:: html + + + + + + ! + + WHITESPACE + = + + +
    + + +
             ::= '!' WHITESPACE* '='
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_NOTEQUALSHAT +====================================================================================================================== + + +.. raw:: html + + + + + + ^ + + WHITESPACE + = + + +
    + + +
             ::= '^' WHITESPACE* '='
    +
    + Referenced by: +
    + + +====================================================================================================================== +OP_CONCAT +====================================================================================================================== + + +.. raw:: html + + + + + + | + + WHITESPACE + | + + +
    + + +
             ::= '|' WHITESPACE* '|'
    +
    + + +====================================================================================================================== +DT_ZONE +====================================================================================================================== + + +.. raw:: html + + + + + + K_DATETIMELITERAL + + WHITESPACE + ( + + S_LONG + ) + + WHITESPACE + WITH + + WITHOUT + + WHITESPACE + LOCAL + + WHITESPACE + TIME + + WHITESPACE + ZONE + + +
    + +
    DT_ZONE  ::= K_DATETIMELITERAL WHITESPACE* ( '(' S_LONG ')' )? WHITESPACE* ( 'WITH' | 'WITHOUT' ) WHITESPACE+ ( 'LOCAL' WHITESPACE+ )? 'TIME' WHITESPACE+ 'ZONE'
    +
    + + +====================================================================================================================== +DATA_TYPE +====================================================================================================================== + + +.. raw:: html + + + + + + BISTRING + + TYPE_BLOB + + TYPE_BOOLEAN + ENUM + + TYPE_REAL + + TYPE_DOUBLE + UUID + + MAP + + TYPE_TINYINT + + TYPE_SMALLINT + + TYPE_INTEGER + + TYPE_BIGINT + HUGEINT + + UTINYINT + + USMALLINT + + UINTEGER + + UBIGINT + + UHUGEINT + + TYPE_DECIMAL + + TYPE_VARCHAR + TIMETZ + + TYPE_TIMESTAMP + +
    + + +
             ::= 'BISTRING'
    +
               | TYPE_BLOB
    +
               | TYPE_BOOLEAN
    +
               | 'ENUM'
    +
               | TYPE_REAL
    +
               | TYPE_DOUBLE
    +
               | 'UUID'
    +
               | 'MAP'
    +
               | TYPE_TINYINT
    +
               | TYPE_SMALLINT
    +
               | TYPE_INTEGER
    +
               | TYPE_BIGINT
    +
               | 'HUGEINT'
    +
               | 'UTINYINT'
    +
               | 'USMALLINT'
    +
               | 'UINTEGER'
    +
               | 'UBIGINT'
    +
               | 'UHUGEINT'
    +
               | TYPE_DECIMAL
    +
               | TYPE_VARCHAR
    +
               | 'TIMETZ'
    +
               | TYPE_TIMESTAMP
    +
    + + +====================================================================================================================== +TYPE_BLOB +====================================================================================================================== + + +.. raw:: html + + + + + + BLOB + + BYTEA + + BINARY + + VARBINARY + + BYTES + + +
    + + +
             ::= 'BLOB'
    +
               | 'BYTEA'
    +
               | 'BINARY'
    +
               | 'VARBINARY'
    +
               | 'BYTES'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_BOOLEAN +====================================================================================================================== + + +.. raw:: html + + + + + + BOOLEAN + + BOOL + + +
    + + +
             ::= 'BOOLEAN'
    +
               | 'BOOL'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_DECIMAL +====================================================================================================================== + + +.. raw:: html + + + + + + DECIMAL + + NUMBER + + NUMERIC + + +
    + + +
             ::= 'DECIMAL'
    +
               | 'NUMBER'
    +
               | 'NUMERIC'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_TINYINT +====================================================================================================================== + + +.. raw:: html + + + + + + TINYINT + + INT1 + + +
    + + +
             ::= 'TINYINT'
    +
               | 'INT1'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_SMALLINT +====================================================================================================================== + + +.. raw:: html + + + + + + SMALLINT + + INT2 + + SHORT + + +
    + + +
             ::= 'SMALLINT'
    +
               | 'INT2'
    +
               | 'SHORT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_INTEGER +====================================================================================================================== + + +.. raw:: html + + + + + + INTEGER + + INT + + INT4 + + SIGNED + + UNSIGNED + + +
    + + +
             ::= 'INTEGER'
    +
               | 'INT'
    +
               | 'INT4'
    +
               | 'SIGNED'
    +
               | 'UNSIGNED'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_BIGINT +====================================================================================================================== + + +.. raw:: html + + + + + + BIGINT + + INT8 + + LONG + + +
    + + +
             ::= 'BIGINT'
    +
               | 'INT8'
    +
               | 'LONG'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_REAL +====================================================================================================================== + + +.. raw:: html + + + + + + REAL + + FLOAT4 + + FLOAT + + +
    + + +
             ::= 'REAL'
    +
               | 'FLOAT4'
    +
               | 'FLOAT'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_DOUBLE +====================================================================================================================== + + +.. raw:: html + + + + + + DOUBLE + + PRECISION + + FLOAT8 + + FLOAT64 + + +
    + + +
             ::= 'DOUBLE'
    +
               | 'PRECISION'
    +
               | 'FLOAT8'
    +
               | 'FLOAT64'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_VARCHAR +====================================================================================================================== + + +.. raw:: html + + + + + + NVARCHAR + + VARCHAR + + NCHAR + + CHAR + + BPCHAR + + TEXT + + STRING + + CHARACTER + + VARYING + + +
    + + +
             ::= 'NVARCHAR'
    +
               | 'VARCHAR'
    +
               | 'NCHAR'
    +
               | 'CHAR'
    +
               | 'BPCHAR'
    +
               | 'TEXT'
    +
               | 'STRING'
    +
               | 'CHARACTER'
    +
               | 'VARYING'
    +
    + Referenced by: +
    + + +====================================================================================================================== +TYPE_TIMESTAMP +====================================================================================================================== + + +.. raw:: html + + + + + + TIMESTAMP_NS + + TIMESTAMP_MS + + TIMESTAMP_S + + +
    + + +
             ::= 'TIMESTAMP_NS'
    +
               | 'TIMESTAMP_MS'
    +
               | 'TIMESTAMP_S'
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_DOUBLE +====================================================================================================================== + + +.. raw:: html + + + + + + S_LONG + . + + S_LONG + e + + E + + + + + [#x2D] + + S_LONG + + S_LONG + . + + e + + E + + + + + [#x2D] + + S_LONG + e + + E + + + + + [#x2D] + + S_LONG + +
    + +
    S_DOUBLE ::= S_LONG? '.' S_LONG ( [eE] [+#x2D]? S_LONG )?
    +
               | S_LONG ( '.' ( [eE] [+#x2D]? S_LONG )? | [eE] [+#x2D]? S_LONG )
    +
    + + +====================================================================================================================== +S_LONG +====================================================================================================================== + + +.. raw:: html + + + + + + DIGIT + +
    + +
    S_LONG   ::= DIGIT+
    +
    + + +====================================================================================================================== +DIGIT +====================================================================================================================== + + +.. raw:: html + + + + + + [0-9] + + +
    + +
    DIGIT    ::= [0-9]
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_HEX +====================================================================================================================== + + +.. raw:: html + + + + + + X + + ' + + HEX_VALUE + ' + + + + 0x + + HEX_VALUE + +
    + +
    S_HEX    ::= 'X' ( "'" HEX_VALUE* "'" ' '* )+
    +
               | '0x' HEX_VALUE+
    +
    + + +====================================================================================================================== +HEX_VALUE +====================================================================================================================== + + +.. raw:: html + + + + + + [0-9] + + [A-F] + + + + +
    + + +
             ::= [0-9A-F ]
    +
    + Referenced by: +
    + + +====================================================================================================================== +LINE_COMMENT +====================================================================================================================== + + +.. raw:: html + + + + + + -- + + // + + [^#xD#xA] + + +
    + + +
             ::= ( '--' | '//' ) [^#xD#xA]*
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +MULTI_LINE_COMMENT +====================================================================================================================== + + +.. raw:: html + + + + + + . + + +
    + + +
             ::= .
    +
    + Not referenced by any. +
    + + +====================================================================================================================== +S_PARAMETER +====================================================================================================================== + + +.. raw:: html + + + + + + $ + + [0-9] + + +
    + + +
             ::= '$' [0-9]+
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_IDENTIFIER +====================================================================================================================== + + +.. raw:: html + + + + + + LETTER + + PART_LETTER + $ + + PART_LETTER_NO_DOLLAR + + PART_LETTER + +
    + + +
             ::= LETTER PART_LETTER*
    +
               | '$' ( PART_LETTER_NO_DOLLAR PART_LETTER* )?
    +
    + + +====================================================================================================================== +LETTER +====================================================================================================================== + + +.. raw:: html + + + + + + UnicodeIdentifierStart + + Nd + _ + + [#x23] + + +
    + + +
               | Nd
    +
               | [_#x23]
    +
    + Referenced by: +
    + + +====================================================================================================================== +PART_LETTER_NO_DOLLAR +====================================================================================================================== + + +.. raw:: html + + + + + + UnicodeIdentifierStart + + UnicodeIdentifierExtend + _ + + @ + + [#x23] + + +
    + + +
             ::= UnicodeIdentifierStart
    +
               | UnicodeIdentifierExtend
    +
               | [_@#x23]
    +
    + Referenced by: +
    + + +====================================================================================================================== +PART_LETTER +====================================================================================================================== + + +.. raw:: html + + + + + + UnicodeIdentifierStart + + UnicodeIdentifierExtend + $ + + _ + + @ + + [#x23] + + +
    + + +
             ::= UnicodeIdentifierStart
    +
               | UnicodeIdentifierExtend
    +
               | [$_@#x23]
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_AT_IDENTIFIER +====================================================================================================================== + + +.. raw:: html + + + + + + @ + + @ + + S_IDENTIFIER + +
    + + +
             ::= '@' '@'? S_IDENTIFIER
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnicodeIdentifierStart +====================================================================================================================== + + +.. raw:: html + + + + + + [#xB7] + + Ll + + Lm + + Lo + + Lt + + Lu + + Nl + + CJK + +
    + + +
             ::= #xB7
    +
               | Ll
    +
               | Lm
    +
               | Lo
    +
               | Lt
    +
               | Lu
    +
               | Nl
    +
               | CJK
    +
    + + +====================================================================================================================== +Ll +====================================================================================================================== + + +.. raw:: html + + + + + + [a-z] + + [#xB5] + + [#xDF-#xF6] + + [#xF8-#xFF] + + [#x101] + + [#x103] + + [#x105] + + [#x107] + + [#x109] + + [#x10B] + + [#x10D] + + [#x10F] + + [#x111] + + [#x113] + + [#x115] + + [#x117] + + [#x119] + + [#x11B] + + [#x11D] + + [#x11F] + + [#x121] + + [#x123] + + [#x125] + + [#x127] + + [#x129] + + [#x12B] + + [#x12D] + + [#x12F] + + [#x131] + + [#x133] + + [#x135] + + [#x137-#x138] + + [#x13A] + + [#x13C] + + [#x13E] + + [#x140] + + [#x142] + + [#x144] + + [#x146] + + [#x148-#x149] + + [#x14B] + + [#x14D] + + [#x14F] + + [#x151] + + [#x153] + + [#x155] + + [#x157] + + [#x159] + + [#x15B] + + [#x15D] + + [#x15F] + + [#x161] + + [#x163] + + [#x165] + + [#x167] + + [#x169] + + [#x16B] + + [#x16D] + + [#x16F] + + [#x171] + + [#x173] + + [#x175] + + [#x177] + + [#x17A] + + [#x17C] + + [#x17E-#x180] + + [#x183] + + [#x185] + + [#x188] + + [#x18C-#x18D] + + [#x192] + + [#x195] + + [#x199-#x19B] + + [#x19E] + + [#x1A1] + + [#x1A3] + + [#x1A5] + + [#x1A8] + + [#x1AA-#x1AB] + + [#x1AD] + + [#x1B0] + + [#x1B4] + + [#x1B6] + + [#x1B9-#x1BA] + + [#x1BD-#x1BF] + + [#x1C6] + + [#x1C9] + + [#x1CC] + + [#x1CE] + + [#x1D0] + + [#x1D2] + + [#x1D4] + + [#x1D6] + + [#x1D8] + + [#x1DA] + + [#x1DC-#x1DD] + + [#x1DF] + + [#x1E1] + + [#x1E3] + + [#x1E5] + + [#x1E7] + + [#x1E9] + + [#x1EB] + + [#x1ED] + + [#x1EF-#x1F0] + + [#x1F3] + + [#x1F5] + + [#x1F9] + + [#x1FB] + + [#x1FD] + + [#x1FF] + + [#x201] + + [#x203] + + [#x205] + + [#x207] + + [#x209] + + [#x20B] + + [#x20D] + + [#x20F] + + [#x211] + + [#x213] + + [#x215] + + [#x217] + + [#x219] + + [#x21B] + + [#x21D] + + [#x21F] + + [#x221] + + [#x223] + + [#x225] + + [#x227] + + [#x229] + + [#x22B] + + [#x22D] + + [#x22F] + + [#x231] + + [#x233-#x239] + + [#x23C] + + [#x23F-#x240] + + [#x242] + + [#x247] + + [#x249] + + [#x24B] + + [#x24D] + + [#x24F-#x293] + + [#x295-#x2AF] + + [#x371] + + [#x373] + + [#x377] + + [#x37B-#x37D] + + [#x390] + + [#x3AC-#x3CE] + + [#x3D0-#x3D1] + + [#x3D5-#x3D7] + + [#x3D9] + + [#x3DB] + + [#x3DD] + + [#x3DF] + + [#x3E1] + + [#x3E3] + + [#x3E5] + + [#x3E7] + + [#x3E9] + + [#x3EB] + + [#x3ED] + + [#x3EF-#x3F3] + + [#x3F5] + + [#x3F8] + + [#x3FB-#x3FC] + + [#x430-#x45F] + + [#x461] + + [#x463] + + [#x465] + + [#x467] + + [#x469] + + [#x46B] + + [#x46D] + + [#x46F] + + [#x471] + + [#x473] + + [#x475] + + [#x477] + + [#x479] + + [#x47B] + + [#x47D] + + [#x47F] + + [#x481] + + [#x48B] + + [#x48D] + + [#x48F] + + [#x491] + + [#x493] + + [#x495] + + [#x497] + + [#x499] + + [#x49B] + + [#x49D] + + [#x49F] + + [#x4A1] + + [#x4A3] + + [#x4A5] + + [#x4A7] + + [#x4A9] + + [#x4AB] + + [#x4AD] + + [#x4AF] + + [#x4B1] + + [#x4B3] + + [#x4B5] + + [#x4B7] + + [#x4B9] + + [#x4BB] + + [#x4BD] + + [#x4BF] + + [#x4C2] + + [#x4C4] + + [#x4C6] + + [#x4C8] + + [#x4CA] + + [#x4CC] + + [#x4CE-#x4CF] + + [#x4D1] + + [#x4D3] + + [#x4D5] + + [#x4D7] + + [#x4D9] + + [#x4DB] + + [#x4DD] + + [#x4DF] + + [#x4E1] + + [#x4E3] + + [#x4E5] + + [#x4E7] + + [#x4E9] + + [#x4EB] + + [#x4ED] + + [#x4EF] + + [#x4F1] + + [#x4F3] + + [#x4F5] + + [#x4F7] + + [#x4F9] + + [#x4FB] + + [#x4FD] + + [#x4FF] + + [#x501] + + [#x503] + + [#x505] + + [#x507] + + [#x509] + + [#x50B] + + [#x50D] + + [#x50F] + + [#x511] + + [#x513] + + [#x515] + + [#x517] + + [#x519] + + [#x51B] + + [#x51D] + + [#x51F] + + [#x521] + + [#x523] + + [#x525] + + [#x527] + + [#x529] + + [#x52B] + + [#x52D] + + [#x52F] + + [#x560-#x588] + + [#x10D0-#x10FA] + + [#x10FD-#x10FF] + + [#x13F8-#x13FD] + + [#x1C80-#x1C88] + + [#x1D00-#x1D2B] + + [#x1D6B-#x1D77] + + [#x1D79-#x1D9A] + + [#x1E01] + + [#x1E03] + + [#x1E05] + + [#x1E07] + + [#x1E09] + + [#x1E0B] + + [#x1E0D] + + [#x1E0F] + + [#x1E11] + + [#x1E13] + + [#x1E15] + + [#x1E17] + + [#x1E19] + + [#x1E1B] + + [#x1E1D] + + [#x1E1F] + + [#x1E21] + + [#x1E23] + + [#x1E25] + + [#x1E27] + + [#x1E29] + + [#x1E2B] + + [#x1E2D] + + [#x1E2F] + + [#x1E31] + + [#x1E33] + + [#x1E35] + + [#x1E37] + + [#x1E39] + + [#x1E3B] + + [#x1E3D] + + [#x1E3F] + + [#x1E41] + + [#x1E43] + + [#x1E45] + + [#x1E47] + + [#x1E49] + + [#x1E4B] + + [#x1E4D] + + [#x1E4F] + + [#x1E51] + + [#x1E53] + + [#x1E55] + + [#x1E57] + + [#x1E59] + + [#x1E5B] + + [#x1E5D] + + [#x1E5F] + + [#x1E61] + + [#x1E63] + + [#x1E65] + + [#x1E67] + + [#x1E69] + + [#x1E6B] + + [#x1E6D] + + [#x1E6F] + + [#x1E71] + + [#x1E73] + + [#x1E75] + + [#x1E77] + + [#x1E79] + + [#x1E7B] + + [#x1E7D] + + [#x1E7F] + + [#x1E81] + + [#x1E83] + + [#x1E85] + + [#x1E87] + + [#x1E89] + + [#x1E8B] + + [#x1E8D] + + [#x1E8F] + + [#x1E91] + + [#x1E93] + + [#x1E95-#x1E9D] + + [#x1E9F] + + [#x1EA1] + + [#x1EA3] + + [#x1EA5] + + [#x1EA7] + + [#x1EA9] + + [#x1EAB] + + [#x1EAD] + + [#x1EAF] + + [#x1EB1] + + [#x1EB3] + + [#x1EB5] + + [#x1EB7] + + [#x1EB9] + + [#x1EBB] + + [#x1EBD] + + [#x1EBF] + + [#x1EC1] + + [#x1EC3] + + [#x1EC5] + + [#x1EC7] + + [#x1EC9] + + [#x1ECB] + + [#x1ECD] + + [#x1ECF] + + [#x1ED1] + + [#x1ED3] + + [#x1ED5] + + [#x1ED7] + + [#x1ED9] + + [#x1EDB] + + [#x1EDD] + + [#x1EDF] + + [#x1EE1] + + [#x1EE3] + + [#x1EE5] + + [#x1EE7] + + [#x1EE9] + + [#x1EEB] + + [#x1EED] + + [#x1EEF] + + [#x1EF1] + + [#x1EF3] + + [#x1EF5] + + [#x1EF7] + + [#x1EF9] + + [#x1EFB] + + [#x1EFD] + + [#x1EFF-#x1F07] + + [#x1F10-#x1F15] + + [#x1F20-#x1F27] + + [#x1F30-#x1F37] + + [#x1F40-#x1F45] + + [#x1F50-#x1F57] + + [#x1F60-#x1F67] + + [#x1F70-#x1F7D] + + [#x1F80-#x1F87] + + [#x1F90-#x1F97] + + [#x1FA0-#x1FA7] + + [#x1FB0-#x1FB4] + + [#x1FB6-#x1FB7] + + [#x1FBE] + + [#x1FC2-#x1FC4] + + [#x1FC6-#x1FC7] + + [#x1FD0-#x1FD3] + + [#x1FD6-#x1FD7] + + [#x1FE0-#x1FE7] + + [#x1FF2-#x1FF4] + + [#x1FF6-#x1FF7] + + [#x210A] + + [#x210E-#x210F] + + [#x2113] + + [#x212F] + + [#x2134] + + [#x2139] + + [#x213C-#x213D] + + [#x2146-#x2149] + + [#x214E] + + [#x2184] + + [#x2C30-#x2C5F] + + [#x2C61] + + [#x2C65-#x2C66] + + [#x2C68] + + [#x2C6A] + + [#x2C6C] + + [#x2C71] + + [#x2C73-#x2C74] + + [#x2C76-#x2C7B] + + [#x2C81] + + [#x2C83] + + [#x2C85] + + [#x2C87] + + [#x2C89] + + [#x2C8B] + + [#x2C8D] + + [#x2C8F] + + [#x2C91] + + [#x2C93] + + [#x2C95] + + [#x2C97] + + [#x2C99] + + [#x2C9B] + + [#x2C9D] + + [#x2C9F] + + [#x2CA1] + + [#x2CA3] + + [#x2CA5] + + [#x2CA7] + + [#x2CA9] + + [#x2CAB] + + [#x2CAD] + + [#x2CAF] + + [#x2CB1] + + [#x2CB3] + + [#x2CB5] + + [#x2CB7] + + [#x2CB9] + + [#x2CBB] + + [#x2CBD] + + [#x2CBF] + + [#x2CC1] + + [#x2CC3] + + [#x2CC5] + + [#x2CC7] + + [#x2CC9] + + [#x2CCB] + + [#x2CCD] + + [#x2CCF] + + [#x2CD1] + + [#x2CD3] + + [#x2CD5] + + [#x2CD7] + + [#x2CD9] + + [#x2CDB] + + [#x2CDD] + + [#x2CDF] + + [#x2CE1] + + [#x2CE3-#x2CE4] + + [#x2CEC] + + [#x2CEE] + + [#x2CF3] + + [#x2D00-#x2D25] + + [#x2D27] + + [#x2D2D] + + [#xA641] + + [#xA643] + + [#xA645] + + [#xA647] + + [#xA649] + + [#xA64B] + + [#xA64D] + + [#xA64F] + + [#xA651] + + [#xA653] + + [#xA655] + + [#xA657] + + [#xA659] + + [#xA65B] + + [#xA65D] + + [#xA65F] + + [#xA661] + + [#xA663] + + [#xA665] + + [#xA667] + + [#xA669] + + [#xA66B] + + [#xA66D] + + [#xA681] + + [#xA683] + + [#xA685] + + [#xA687] + + [#xA689] + + [#xA68B] + + [#xA68D] + + [#xA68F] + + [#xA691] + + [#xA693] + + [#xA695] + + [#xA697] + + [#xA699] + + [#xA69B] + + [#xA723] + + [#xA725] + + [#xA727] + + [#xA729] + + [#xA72B] + + [#xA72D] + + [#xA72F-#xA731] + + [#xA733] + + [#xA735] + + [#xA737] + + [#xA739] + + [#xA73B] + + [#xA73D] + + [#xA73F] + + [#xA741] + + [#xA743] + + [#xA745] + + [#xA747] + + [#xA749] + + [#xA74B] + + [#xA74D] + + [#xA74F] + + [#xA751] + + [#xA753] + + [#xA755] + + [#xA757] + + [#xA759] + + [#xA75B] + + [#xA75D] + + [#xA75F] + + [#xA761] + + [#xA763] + + [#xA765] + + [#xA767] + + [#xA769] + + [#xA76B] + + [#xA76D] + + [#xA76F] + + [#xA771-#xA778] + + [#xA77A] + + [#xA77C] + + [#xA77F] + + [#xA781] + + [#xA783] + + [#xA785] + + [#xA787] + + [#xA78C] + + [#xA78E] + + [#xA791] + + [#xA793-#xA795] + + [#xA797] + + [#xA799] + + [#xA79B] + + [#xA79D] + + [#xA79F] + + [#xA7A1] + + [#xA7A3] + + [#xA7A5] + + [#xA7A7] + + [#xA7A9] + + [#xA7AF] + + [#xA7B5] + + [#xA7B7] + + [#xA7B9] + + [#xA7BB] + + [#xA7BD] + + [#xA7BF] + + [#xA7C1] + + [#xA7C3] + + [#xA7C8] + + [#xA7CA] + + [#xA7D1] + + [#xA7D3] + + [#xA7D5] + + [#xA7D7] + + [#xA7D9] + + [#xA7F6] + + [#xA7FA] + + [#xAB30-#xAB5A] + + [#xAB60-#xAB68] + + [#xAB70-#xABBF] + + [#xFB00-#xFB06] + + [#xFB13-#xFB17] + + [#xFF41-#xFF5A] + + +
    + +
    Ll       ::= [a-z#xB5#xDF-#xF6#xF8-#xFF#x101#x103#x105#x107#x109#x10B#x10D#x10F#x111#x113#x115#x117#x119#x11B#x11D#x11F#x121#x123#x125#x127#x129#x12B#x12D#x12F#x131#x133#x135#x137-#x138#x13A#x13C#x13E#x140#x142#x144#x146#x148-#x149#x14B#x14D#x14F#x151#x153#x155#x157#x159#x15B#x15D#x15F#x161#x163#x165#x167#x169#x16B#x16D#x16F#x171#x173#x175#x177#x17A#x17C#x17E-#x180#x183#x185#x188#x18C-#x18D#x192#x195#x199-#x19B#x19E#x1A1#x1A3#x1A5#x1A8#x1AA-#x1AB#x1AD#x1B0#x1B4#x1B6#x1B9-#x1BA#x1BD-#x1BF#x1C6#x1C9#x1CC#x1CE#x1D0#x1D2#x1D4#x1D6#x1D8#x1DA#x1DC-#x1DD#x1DF#x1E1#x1E3#x1E5#x1E7#x1E9#x1EB#x1ED#x1EF-#x1F0#x1F3#x1F5#x1F9#x1FB#x1FD#x1FF#x201#x203#x205#x207#x209#x20B#x20D#x20F#x211#x213#x215#x217#x219#x21B#x21D#x21F#x221#x223#x225#x227#x229#x22B#x22D#x22F#x231#x233-#x239#x23C#x23F-#x240#x242#x247#x249#x24B#x24D#x24F-#x293#x295-#x2AF#x371#x373#x377#x37B-#x37D#x390#x3AC-#x3CE#x3D0-#x3D1#x3D5-#x3D7#x3D9#x3DB#x3DD#x3DF#x3E1#x3E3#x3E5#x3E7#x3E9#x3EB#x3ED#x3EF-#x3F3#x3F5#x3F8#x3FB-#x3FC#x430-#x45F#x461#x463#x465#x467#x469#x46B#x46D#x46F#x471#x473#x475#x477#x479#x47B#x47D#x47F#x481#x48B#x48D#x48F#x491#x493#x495#x497#x499#x49B#x49D#x49F#x4A1#x4A3#x4A5#x4A7#x4A9#x4AB#x4AD#x4AF#x4B1#x4B3#x4B5#x4B7#x4B9#x4BB#x4BD#x4BF#x4C2#x4C4#x4C6#x4C8#x4CA#x4CC#x4CE-#x4CF#x4D1#x4D3#x4D5#x4D7#x4D9#x4DB#x4DD#x4DF#x4E1#x4E3#x4E5#x4E7#x4E9#x4EB#x4ED#x4EF#x4F1#x4F3#x4F5#x4F7#x4F9#x4FB#x4FD#x4FF#x501#x503#x505#x507#x509#x50B#x50D#x50F#x511#x513#x515#x517#x519#x51B#x51D#x51F#x521#x523#x525#x527#x529#x52B#x52D#x52F#x560-#x588#x10D0-#x10FA#x10FD-#x10FF#x13F8-#x13FD#x1C80-#x1C88#x1D00-#x1D2B#x1D6B-#x1D77#x1D79-#x1D9A#x1E01#x1E03#x1E05#x1E07#x1E09#x1E0B#x1E0D#x1E0F#x1E11#x1E13#x1E15#x1E17#x1E19#x1E1B#x1E1D#x1E1F#x1E21#x1E23#x1E25#x1E27#x1E29#x1E2B#x1E2D#x1E2F#x1E31#x1E33#x1E35#x1E37#x1E39#x1E3B#x1E3D#x1E3F#x1E41#x1E43#x1E45#x1E47#x1E49#x1E4B#x1E4D#x1E4F#x1E51#x1E53#x1E55#x1E57#x1E59#x1E5B#x1E5D#x1E5F#x1E61#x1E63#x1E65#x1E67#x1E69#x1E6B#x1E6D#x1E6F#x1E71#x1E73#x1E75#x1E77#x1E79#x1E7B#x1E7D#x1E7F#x1E81#x1E83#x1E85#x1E87#x1E89#x1E8B#x1E8D#x1E8F#x1E91#x1E93#x1E95-#x1E9D#x1E9F#x1EA1#x1EA3#x1EA5#x1EA7#x1EA9#x1EAB#x1EAD#x1EAF#x1EB1#x1EB3#x1EB5#x1EB7#x1EB9#x1EBB#x1EBD#x1EBF#x1EC1#x1EC3#x1EC5#x1EC7#x1EC9#x1ECB#x1ECD#x1ECF#x1ED1#x1ED3#x1ED5#x1ED7#x1ED9#x1EDB#x1EDD#x1EDF#x1EE1#x1EE3#x1EE5#x1EE7#x1EE9#x1EEB#x1EED#x1EEF#x1EF1#x1EF3#x1EF5#x1EF7#x1EF9#x1EFB#x1EFD#x1EFF-#x1F07#x1F10-#x1F15#x1F20-#x1F27#x1F30-#x1F37#x1F40-#x1F45#x1F50-#x1F57#x1F60-#x1F67#x1F70-#x1F7D#x1F80-#x1F87#x1F90-#x1F97#x1FA0-#x1FA7#x1FB0-#x1FB4#x1FB6-#x1FB7#x1FBE#x1FC2-#x1FC4#x1FC6-#x1FC7#x1FD0-#x1FD3#x1FD6-#x1FD7#x1FE0-#x1FE7#x1FF2-#x1FF4#x1FF6-#x1FF7#x210A#x210E-#x210F#x2113#x212F#x2134#x2139#x213C-#x213D#x2146-#x2149#x214E#x2184#x2C30-#x2C5F#x2C61#x2C65-#x2C66#x2C68#x2C6A#x2C6C#x2C71#x2C73-#x2C74#x2C76-#x2C7B#x2C81#x2C83#x2C85#x2C87#x2C89#x2C8B#x2C8D#x2C8F#x2C91#x2C93#x2C95#x2C97#x2C99#x2C9B#x2C9D#x2C9F#x2CA1#x2CA3#x2CA5#x2CA7#x2CA9#x2CAB#x2CAD#x2CAF#x2CB1#x2CB3#x2CB5#x2CB7#x2CB9#x2CBB#x2CBD#x2CBF#x2CC1#x2CC3#x2CC5#x2CC7#x2CC9#x2CCB#x2CCD#x2CCF#x2CD1#x2CD3#x2CD5#x2CD7#x2CD9#x2CDB#x2CDD#x2CDF#x2CE1#x2CE3-#x2CE4#x2CEC#x2CEE#x2CF3#x2D00-#x2D25#x2D27#x2D2D#xA641#xA643#xA645#xA647#xA649#xA64B#xA64D#xA64F#xA651#xA653#xA655#xA657#xA659#xA65B#xA65D#xA65F#xA661#xA663#xA665#xA667#xA669#xA66B#xA66D#xA681#xA683#xA685#xA687#xA689#xA68B#xA68D#xA68F#xA691#xA693#xA695#xA697#xA699#xA69B#xA723#xA725#xA727#xA729#xA72B#xA72D#xA72F-#xA731#xA733#xA735#xA737#xA739#xA73B#xA73D#xA73F#xA741#xA743#xA745#xA747#xA749#xA74B#xA74D#xA74F#xA751#xA753#xA755#xA757#xA759#xA75B#xA75D#xA75F#xA761#xA763#xA765#xA767#xA769#xA76B#xA76D#xA76F#xA771-#xA778#xA77A#xA77C#xA77F#xA781#xA783#xA785#xA787#xA78C#xA78E#xA791#xA793-#xA795#xA797#xA799#xA79B#xA79D#xA79F#xA7A1#xA7A3#xA7A5#xA7A7#xA7A9#xA7AF#xA7B5#xA7B7#xA7B9#xA7BB#xA7BD#xA7BF#xA7C1#xA7C3#xA7C8#xA7CA#xA7D1#xA7D3#xA7D5#xA7D7#xA7D9#xA7F6#xA7FA#xAB30-#xAB5A#xAB60-#xAB68#xAB70-#xABBF#xFB00-#xFB06#xFB13-#xFB17#xFF41-#xFF5A]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Lm +====================================================================================================================== + + +.. raw:: html + + + + + + [#x2B0-#x2C1] + + [#x2C6-#x2D1] + + [#x2E0-#x2E4] + + [#x2EC] + + [#x2EE] + + [#x374] + + [#x37A] + + [#x559] + + [#x640] + + [#x6E5-#x6E6] + + [#x7F4-#x7F5] + + [#x7FA] + + [#x81A] + + [#x824] + + [#x828] + + [#x8C9] + + [#x971] + + [#xE46] + + [#xEC6] + + [#x10FC] + + [#x17D7] + + [#x1843] + + [#x1AA7] + + [#x1C78-#x1C7D] + + [#x1D2C-#x1D6A] + + [#x1D78] + + [#x1D9B-#x1DBF] + + [#x2071] + + [#x207F] + + [#x2090-#x209C] + + [#x2C7C-#x2C7D] + + [#x2D6F] + + [#x2E2F] + + [#x3005] + + [#x3031-#x3035] + + [#x303B] + + [#x309D-#x309E] + + [#x30FC-#x30FE] + + [#xA015] + + [#xA4F8-#xA4FD] + + [#xA60C] + + [#xA67F] + + [#xA69C-#xA69D] + + [#xA717-#xA71F] + + [#xA770] + + [#xA788] + + [#xA7F2-#xA7F4] + + [#xA7F8-#xA7F9] + + [#xA9CF] + + [#xA9E6] + + [#xAA70] + + [#xAADD] + + [#xAAF3-#xAAF4] + + [#xAB5C-#xAB5F] + + [#xAB69] + + [#xFF70] + + [#xFF9E-#xFF9F] + + +
    + +
    Lm       ::= [#x2B0-#x2C1#x2C6-#x2D1#x2E0-#x2E4#x2EC#x2EE#x374#x37A#x559#x640#x6E5-#x6E6#x7F4-#x7F5#x7FA#x81A#x824#x828#x8C9#x971#xE46#xEC6#x10FC#x17D7#x1843#x1AA7#x1C78-#x1C7D#x1D2C-#x1D6A#x1D78#x1D9B-#x1DBF#x2071#x207F#x2090-#x209C#x2C7C-#x2C7D#x2D6F#x2E2F#x3005#x3031-#x3035#x303B#x309D-#x309E#x30FC-#x30FE#xA015#xA4F8-#xA4FD#xA60C#xA67F#xA69C-#xA69D#xA717-#xA71F#xA770#xA788#xA7F2-#xA7F4#xA7F8-#xA7F9#xA9CF#xA9E6#xAA70#xAADD#xAAF3-#xAAF4#xAB5C-#xAB5F#xAB69#xFF70#xFF9E-#xFF9F]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Lo +====================================================================================================================== + + +.. raw:: html + + + + + + [#xAA] + + [#xBA] + + [#x1BB] + + [#x1C0-#x1C3] + + [#x294] + + [#x5D0-#x5EA] + + [#x5EF-#x5F2] + + [#x620-#x63F] + + [#x641-#x64A] + + [#x66E-#x66F] + + [#x671-#x6D3] + + [#x6D5] + + [#x6EE-#x6EF] + + [#x6FA-#x6FC] + + [#x6FF] + + [#x710] + + [#x712-#x72F] + + [#x74D-#x7A5] + + [#x7B1] + + [#x7CA-#x7EA] + + [#x800-#x815] + + [#x840-#x858] + + [#x860-#x86A] + + [#x870-#x887] + + [#x889-#x88E] + + [#x8A0-#x8C8] + + [#x904-#x939] + + [#x93D] + + [#x950] + + [#x958-#x961] + + [#x972-#x980] + + [#x985-#x98C] + + [#x98F-#x990] + + [#x993-#x9A8] + + [#x9AA-#x9B0] + + [#x9B2] + + [#x9B6-#x9B9] + + [#x9BD] + + [#x9CE] + + [#x9DC-#x9DD] + + [#x9DF-#x9E1] + + [#x9F0-#x9F1] + + [#x9FC] + + [#xA05-#xA0A] + + [#xA0F-#xA10] + + [#xA13-#xA28] + + [#xA2A-#xA30] + + [#xA32-#xA33] + + [#xA35-#xA36] + + [#xA38-#xA39] + + [#xA59-#xA5C] + + [#xA5E] + + [#xA72-#xA74] + + [#xA85-#xA8D] + + [#xA8F-#xA91] + + [#xA93-#xAA8] + + [#xAAA-#xAB0] + + [#xAB2-#xAB3] + + [#xAB5-#xAB9] + + [#xABD] + + [#xAD0] + + [#xAE0-#xAE1] + + [#xAF9] + + [#xB05-#xB0C] + + [#xB0F-#xB10] + + [#xB13-#xB28] + + [#xB2A-#xB30] + + [#xB32-#xB33] + + [#xB35-#xB39] + + [#xB3D] + + [#xB5C-#xB5D] + + [#xB5F-#xB61] + + [#xB71] + + [#xB83] + + [#xB85-#xB8A] + + [#xB8E-#xB90] + + [#xB92-#xB95] + + [#xB99-#xB9A] + + [#xB9C] + + [#xB9E-#xB9F] + + [#xBA3-#xBA4] + + [#xBA8-#xBAA] + + [#xBAE-#xBB9] + + [#xBD0] + + [#xC05-#xC0C] + + [#xC0E-#xC10] + + [#xC12-#xC28] + + [#xC2A-#xC39] + + [#xC3D] + + [#xC58-#xC5A] + + [#xC5D] + + [#xC60-#xC61] + + [#xC80] + + [#xC85-#xC8C] + + [#xC8E-#xC90] + + [#xC92-#xCA8] + + [#xCAA-#xCB3] + + [#xCB5-#xCB9] + + [#xCBD] + + [#xCDD-#xCDE] + + [#xCE0-#xCE1] + + [#xCF1-#xCF2] + + [#xD04-#xD0C] + + [#xD0E-#xD10] + + [#xD12-#xD3A] + + [#xD3D] + + [#xD4E] + + [#xD54-#xD56] + + [#xD5F-#xD61] + + [#xD7A-#xD7F] + + [#xD85-#xD96] + + [#xD9A-#xDB1] + + [#xDB3-#xDBB] + + [#xDBD] + + [#xDC0-#xDC6] + + [#xE01-#xE30] + + [#xE32-#xE33] + + [#xE40-#xE45] + + [#xE81-#xE82] + + [#xE84] + + [#xE86-#xE8A] + + [#xE8C-#xEA3] + + [#xEA5] + + [#xEA7-#xEB0] + + [#xEB2-#xEB3] + + [#xEBD] + + [#xEC0-#xEC4] + + [#xEDC-#xEDF] + + [#xF00] + + [#xF40-#xF47] + + [#xF49-#xF6C] + + [#xF88-#xF8C] + + [#x1000-#x102A] + + [#x103F] + + [#x1050-#x1055] + + [#x105A-#x105D] + + [#x1061] + + [#x1065-#x1066] + + [#x106E-#x1070] + + [#x1075-#x1081] + + [#x108E] + + [#x1100-#x1248] + + [#x124A-#x124D] + + [#x1250-#x1256] + + [#x1258] + + [#x125A-#x125D] + + [#x1260-#x1288] + + [#x128A-#x128D] + + [#x1290-#x12B0] + + [#x12B2-#x12B5] + + [#x12B8-#x12BE] + + [#x12C0] + + [#x12C2-#x12C5] + + [#x12C8-#x12D6] + + [#x12D8-#x1310] + + [#x1312-#x1315] + + [#x1318-#x135A] + + [#x1380-#x138F] + + [#x1401-#x166C] + + [#x166F-#x167F] + + [#x1681-#x169A] + + [#x16A0-#x16EA] + + [#x16F1-#x16F8] + + [#x1700-#x1711] + + [#x171F-#x1731] + + [#x1740-#x1751] + + [#x1760-#x176C] + + [#x176E-#x1770] + + [#x1780-#x17B3] + + [#x17DC] + + [#x1820-#x1842] + + [#x1844-#x1878] + + [#x1880-#x1884] + + [#x1887-#x18A8] + + [#x18AA] + + [#x18B0-#x18F5] + + [#x1900-#x191E] + + [#x1950-#x196D] + + [#x1970-#x1974] + + [#x1980-#x19AB] + + [#x19B0-#x19C9] + + [#x1A00-#x1A16] + + [#x1A20-#x1A54] + + [#x1B05-#x1B33] + + [#x1B45-#x1B4C] + + [#x1B83-#x1BA0] + + [#x1BAE-#x1BAF] + + [#x1BBA-#x1BE5] + + [#x1C00-#x1C23] + + [#x1C4D-#x1C4F] + + [#x1C5A-#x1C77] + + [#x1CE9-#x1CEC] + + [#x1CEE-#x1CF3] + + [#x1CF5-#x1CF6] + + [#x1CFA] + + [#x2135-#x2138] + + [#x2D30-#x2D67] + + [#x2D80-#x2D96] + + [#x2DA0-#x2DA6] + + [#x2DA8-#x2DAE] + + [#x2DB0-#x2DB6] + + [#x2DB8-#x2DBE] + + [#x2DC0-#x2DC6] + + [#x2DC8-#x2DCE] + + [#x2DD0-#x2DD6] + + [#x2DD8-#x2DDE] + + [#x3006] + + [#x303C] + + [#x3041-#x3096] + + [#x309F] + + [#x30A1-#x30FA] + + [#x30FF] + + [#x3105-#x312F] + + [#x3131-#x318E] + + [#x31A0-#x31BF] + + [#x31F0-#x31FF] + + [#x4DBF] + + [#x9FFF-#xA014] + + [#xA016-#xA48C] + + [#xA4D0-#xA4F7] + + [#xA500-#xA60B] + + [#xA610-#xA61F] + + [#xA62A-#xA62B] + + [#xA66E] + + [#xA6A0-#xA6E5] + + [#xA78F] + + [#xA7F7] + + [#xA7FB-#xA801] + + [#xA803-#xA805] + + [#xA807-#xA80A] + + [#xA80C-#xA822] + + [#xA840-#xA873] + + [#xA882-#xA8B3] + + [#xA8F2-#xA8F7] + + [#xA8FB] + + [#xA8FD-#xA8FE] + + [#xA90A-#xA925] + + [#xA930-#xA946] + + [#xA960-#xA97C] + + [#xA984-#xA9B2] + + [#xA9E0-#xA9E4] + + [#xA9E7-#xA9EF] + + [#xA9FA-#xA9FE] + + [#xAA00-#xAA28] + + [#xAA40-#xAA42] + + [#xAA44-#xAA4B] + + [#xAA60-#xAA6F] + + [#xAA71-#xAA76] + + [#xAA7A] + + [#xAA7E-#xAAAF] + + [#xAAB1] + + [#xAAB5-#xAAB6] + + [#xAAB9-#xAABD] + + [#xAAC0] + + [#xAAC2] + + [#xAADB-#xAADC] + + [#xAAE0-#xAAEA] + + [#xAAF2] + + [#xAB01-#xAB06] + + [#xAB09-#xAB0E] + + [#xAB11-#xAB16] + + [#xAB20-#xAB26] + + [#xAB28-#xAB2E] + + [#xABC0-#xABE2] + + [#xD7A3] + + [#xD7B0-#xD7C6] + + [#xD7CB-#xD7FB] + + [#xF900-#xFA6D] + + [#xFA70-#xFAD9] + + [#xFB1D] + + [#xFB1F-#xFB28] + + [#xFB2A-#xFB36] + + [#xFB38-#xFB3C] + + [#xFB3E] + + [#xFB40-#xFB41] + + [#xFB43-#xFB44] + + [#xFB46-#xFBB1] + + [#xFBD3-#xFD3D] + + [#xFD50-#xFD8F] + + [#xFD92-#xFDC7] + + [#xFDF0-#xFDFB] + + [#xFE70-#xFE74] + + [#xFE76-#xFEFC] + + [#xFF66-#xFF6F] + + [#xFF71-#xFF9D] + + [#xFFA0-#xFFBE] + + [#xFFC2-#xFFC7] + + [#xFFCA-#xFFCF] + + [#xFFD2-#xFFD7] + + [#xFFDA-#xFFDC] + + +
    + +
    Lo       ::= [#xAA#xBA#x1BB#x1C0-#x1C3#x294#x5D0-#x5EA#x5EF-#x5F2#x620-#x63F#x641-#x64A#x66E-#x66F#x671-#x6D3#x6D5#x6EE-#x6EF#x6FA-#x6FC#x6FF#x710#x712-#x72F#x74D-#x7A5#x7B1#x7CA-#x7EA#x800-#x815#x840-#x858#x860-#x86A#x870-#x887#x889-#x88E#x8A0-#x8C8#x904-#x939#x93D#x950#x958-#x961#x972-#x980#x985-#x98C#x98F-#x990#x993-#x9A8#x9AA-#x9B0#x9B2#x9B6-#x9B9#x9BD#x9CE#x9DC-#x9DD#x9DF-#x9E1#x9F0-#x9F1#x9FC#xA05-#xA0A#xA0F-#xA10#xA13-#xA28#xA2A-#xA30#xA32-#xA33#xA35-#xA36#xA38-#xA39#xA59-#xA5C#xA5E#xA72-#xA74#xA85-#xA8D#xA8F-#xA91#xA93-#xAA8#xAAA-#xAB0#xAB2-#xAB3#xAB5-#xAB9#xABD#xAD0#xAE0-#xAE1#xAF9#xB05-#xB0C#xB0F-#xB10#xB13-#xB28#xB2A-#xB30#xB32-#xB33#xB35-#xB39#xB3D#xB5C-#xB5D#xB5F-#xB61#xB71#xB83#xB85-#xB8A#xB8E-#xB90#xB92-#xB95#xB99-#xB9A#xB9C#xB9E-#xB9F#xBA3-#xBA4#xBA8-#xBAA#xBAE-#xBB9#xBD0#xC05-#xC0C#xC0E-#xC10#xC12-#xC28#xC2A-#xC39#xC3D#xC58-#xC5A#xC5D#xC60-#xC61#xC80#xC85-#xC8C#xC8E-#xC90#xC92-#xCA8#xCAA-#xCB3#xCB5-#xCB9#xCBD#xCDD-#xCDE#xCE0-#xCE1#xCF1-#xCF2#xD04-#xD0C#xD0E-#xD10#xD12-#xD3A#xD3D#xD4E#xD54-#xD56#xD5F-#xD61#xD7A-#xD7F#xD85-#xD96#xD9A-#xDB1#xDB3-#xDBB#xDBD#xDC0-#xDC6#xE01-#xE30#xE32-#xE33#xE40-#xE45#xE81-#xE82#xE84#xE86-#xE8A#xE8C-#xEA3#xEA5#xEA7-#xEB0#xEB2-#xEB3#xEBD#xEC0-#xEC4#xEDC-#xEDF#xF00#xF40-#xF47#xF49-#xF6C#xF88-#xF8C#x1000-#x102A#x103F#x1050-#x1055#x105A-#x105D#x1061#x1065-#x1066#x106E-#x1070#x1075-#x1081#x108E#x1100-#x1248#x124A-#x124D#x1250-#x1256#x1258#x125A-#x125D#x1260-#x1288#x128A-#x128D#x1290-#x12B0#x12B2-#x12B5#x12B8-#x12BE#x12C0#x12C2-#x12C5#x12C8-#x12D6#x12D8-#x1310#x1312-#x1315#x1318-#x135A#x1380-#x138F#x1401-#x166C#x166F-#x167F#x1681-#x169A#x16A0-#x16EA#x16F1-#x16F8#x1700-#x1711#x171F-#x1731#x1740-#x1751#x1760-#x176C#x176E-#x1770#x1780-#x17B3#x17DC#x1820-#x1842#x1844-#x1878#x1880-#x1884#x1887-#x18A8#x18AA#x18B0-#x18F5#x1900-#x191E#x1950-#x196D#x1970-#x1974#x1980-#x19AB#x19B0-#x19C9#x1A00-#x1A16#x1A20-#x1A54#x1B05-#x1B33#x1B45-#x1B4C#x1B83-#x1BA0#x1BAE-#x1BAF#x1BBA-#x1BE5#x1C00-#x1C23#x1C4D-#x1C4F#x1C5A-#x1C77#x1CE9-#x1CEC#x1CEE-#x1CF3#x1CF5-#x1CF6#x1CFA#x2135-#x2138#x2D30-#x2D67#x2D80-#x2D96#x2DA0-#x2DA6#x2DA8-#x2DAE#x2DB0-#x2DB6#x2DB8-#x2DBE#x2DC0-#x2DC6#x2DC8-#x2DCE#x2DD0-#x2DD6#x2DD8-#x2DDE#x3006#x303C#x3041-#x3096#x309F#x30A1-#x30FA#x30FF#x3105-#x312F#x3131-#x318E#x31A0-#x31BF#x31F0-#x31FF#x4DBF#x9FFF-#xA014#xA016-#xA48C#xA4D0-#xA4F7#xA500-#xA60B#xA610-#xA61F#xA62A-#xA62B#xA66E#xA6A0-#xA6E5#xA78F#xA7F7#xA7FB-#xA801#xA803-#xA805#xA807-#xA80A#xA80C-#xA822#xA840-#xA873#xA882-#xA8B3#xA8F2-#xA8F7#xA8FB#xA8FD-#xA8FE#xA90A-#xA925#xA930-#xA946#xA960-#xA97C#xA984-#xA9B2#xA9E0-#xA9E4#xA9E7-#xA9EF#xA9FA-#xA9FE#xAA00-#xAA28#xAA40-#xAA42#xAA44-#xAA4B#xAA60-#xAA6F#xAA71-#xAA76#xAA7A#xAA7E-#xAAAF#xAAB1#xAAB5-#xAAB6#xAAB9-#xAABD#xAAC0#xAAC2#xAADB-#xAADC#xAAE0-#xAAEA#xAAF2#xAB01-#xAB06#xAB09-#xAB0E#xAB11-#xAB16#xAB20-#xAB26#xAB28-#xAB2E#xABC0-#xABE2#xD7A3#xD7B0-#xD7C6#xD7CB-#xD7FB#xF900-#xFA6D#xFA70-#xFAD9#xFB1D#xFB1F-#xFB28#xFB2A-#xFB36#xFB38-#xFB3C#xFB3E#xFB40-#xFB41#xFB43-#xFB44#xFB46-#xFBB1#xFBD3-#xFD3D#xFD50-#xFD8F#xFD92-#xFDC7#xFDF0-#xFDFB#xFE70-#xFE74#xFE76-#xFEFC#xFF66-#xFF6F#xFF71-#xFF9D#xFFA0-#xFFBE#xFFC2-#xFFC7#xFFCA-#xFFCF#xFFD2-#xFFD7#xFFDA-#xFFDC]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Lt +====================================================================================================================== + + +.. raw:: html + + + + + + [#x1C5] + + [#x1C8] + + [#x1CB] + + [#x1F2] + + [#x1F88-#x1F8F] + + [#x1F98-#x1F9F] + + [#x1FA8-#x1FAF] + + [#x1FBC] + + [#x1FCC] + + [#x1FFC] + + +
    + +
    Lt       ::= [#x1C5#x1C8#x1CB#x1F2#x1F88-#x1F8F#x1F98-#x1F9F#x1FA8-#x1FAF#x1FBC#x1FCC#x1FFC]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Lu +====================================================================================================================== + + +.. raw:: html + + + + + + [A-Z] + + [#xC0-#xD6] + + [#xD8-#xDE] + + [#x100] + + [#x102] + + [#x104] + + [#x106] + + [#x108] + + [#x10A] + + [#x10C] + + [#x10E] + + [#x110] + + [#x112] + + [#x114] + + [#x116] + + [#x118] + + [#x11A] + + [#x11C] + + [#x11E] + + [#x120] + + [#x122] + + [#x124] + + [#x126] + + [#x128] + + [#x12A] + + [#x12C] + + [#x12E] + + [#x130] + + [#x132] + + [#x134] + + [#x136] + + [#x139] + + [#x13B] + + [#x13D] + + [#x13F] + + [#x141] + + [#x143] + + [#x145] + + [#x147] + + [#x14A] + + [#x14C] + + [#x14E] + + [#x150] + + [#x152] + + [#x154] + + [#x156] + + [#x158] + + [#x15A] + + [#x15C] + + [#x15E] + + [#x160] + + [#x162] + + [#x164] + + [#x166] + + [#x168] + + [#x16A] + + [#x16C] + + [#x16E] + + [#x170] + + [#x172] + + [#x174] + + [#x176] + + [#x178-#x179] + + [#x17B] + + [#x17D] + + [#x181-#x182] + + [#x184] + + [#x186-#x187] + + [#x189-#x18B] + + [#x18E-#x191] + + [#x193-#x194] + + [#x196-#x198] + + [#x19C-#x19D] + + [#x19F-#x1A0] + + [#x1A2] + + [#x1A4] + + [#x1A6-#x1A7] + + [#x1A9] + + [#x1AC] + + [#x1AE-#x1AF] + + [#x1B1-#x1B3] + + [#x1B5] + + [#x1B7-#x1B8] + + [#x1BC] + + [#x1C4] + + [#x1C7] + + [#x1CA] + + [#x1CD] + + [#x1CF] + + [#x1D1] + + [#x1D3] + + [#x1D5] + + [#x1D7] + + [#x1D9] + + [#x1DB] + + [#x1DE] + + [#x1E0] + + [#x1E2] + + [#x1E4] + + [#x1E6] + + [#x1E8] + + [#x1EA] + + [#x1EC] + + [#x1EE] + + [#x1F1] + + [#x1F4] + + [#x1F6-#x1F8] + + [#x1FA] + + [#x1FC] + + [#x1FE] + + [#x200] + + [#x202] + + [#x204] + + [#x206] + + [#x208] + + [#x20A] + + [#x20C] + + [#x20E] + + [#x210] + + [#x212] + + [#x214] + + [#x216] + + [#x218] + + [#x21A] + + [#x21C] + + [#x21E] + + [#x220] + + [#x222] + + [#x224] + + [#x226] + + [#x228] + + [#x22A] + + [#x22C] + + [#x22E] + + [#x230] + + [#x232] + + [#x23A-#x23B] + + [#x23D-#x23E] + + [#x241] + + [#x243-#x246] + + [#x248] + + [#x24A] + + [#x24C] + + [#x24E] + + [#x370] + + [#x372] + + [#x376] + + [#x37F] + + [#x386] + + [#x388-#x38A] + + [#x38C] + + [#x38E-#x38F] + + [#x391-#x3A1] + + [#x3A3-#x3AB] + + [#x3CF] + + [#x3D2-#x3D4] + + [#x3D8] + + [#x3DA] + + [#x3DC] + + [#x3DE] + + [#x3E0] + + [#x3E2] + + [#x3E4] + + [#x3E6] + + [#x3E8] + + [#x3EA] + + [#x3EC] + + [#x3EE] + + [#x3F4] + + [#x3F7] + + [#x3F9-#x3FA] + + [#x3FD-#x42F] + + [#x460] + + [#x462] + + [#x464] + + [#x466] + + [#x468] + + [#x46A] + + [#x46C] + + [#x46E] + + [#x470] + + [#x472] + + [#x474] + + [#x476] + + [#x478] + + [#x47A] + + [#x47C] + + [#x47E] + + [#x480] + + [#x48A] + + [#x48C] + + [#x48E] + + [#x490] + + [#x492] + + [#x494] + + [#x496] + + [#x498] + + [#x49A] + + [#x49C] + + [#x49E] + + [#x4A0] + + [#x4A2] + + [#x4A4] + + [#x4A6] + + [#x4A8] + + [#x4AA] + + [#x4AC] + + [#x4AE] + + [#x4B0] + + [#x4B2] + + [#x4B4] + + [#x4B6] + + [#x4B8] + + [#x4BA] + + [#x4BC] + + [#x4BE] + + [#x4C0-#x4C1] + + [#x4C3] + + [#x4C5] + + [#x4C7] + + [#x4C9] + + [#x4CB] + + [#x4CD] + + [#x4D0] + + [#x4D2] + + [#x4D4] + + [#x4D6] + + [#x4D8] + + [#x4DA] + + [#x4DC] + + [#x4DE] + + [#x4E0] + + [#x4E2] + + [#x4E4] + + [#x4E6] + + [#x4E8] + + [#x4EA] + + [#x4EC] + + [#x4EE] + + [#x4F0] + + [#x4F2] + + [#x4F4] + + [#x4F6] + + [#x4F8] + + [#x4FA] + + [#x4FC] + + [#x4FE] + + [#x500] + + [#x502] + + [#x504] + + [#x506] + + [#x508] + + [#x50A] + + [#x50C] + + [#x50E] + + [#x510] + + [#x512] + + [#x514] + + [#x516] + + [#x518] + + [#x51A] + + [#x51C] + + [#x51E] + + [#x520] + + [#x522] + + [#x524] + + [#x526] + + [#x528] + + [#x52A] + + [#x52C] + + [#x52E] + + [#x531-#x556] + + [#x10A0-#x10C5] + + [#x10C7] + + [#x10CD] + + [#x13A0-#x13F5] + + [#x1C90-#x1CBA] + + [#x1CBD-#x1CBF] + + [#x1E00] + + [#x1E02] + + [#x1E04] + + [#x1E06] + + [#x1E08] + + [#x1E0A] + + [#x1E0C] + + [#x1E0E] + + [#x1E10] + + [#x1E12] + + [#x1E14] + + [#x1E16] + + [#x1E18] + + [#x1E1A] + + [#x1E1C] + + [#x1E1E] + + [#x1E20] + + [#x1E22] + + [#x1E24] + + [#x1E26] + + [#x1E28] + + [#x1E2A] + + [#x1E2C] + + [#x1E2E] + + [#x1E30] + + [#x1E32] + + [#x1E34] + + [#x1E36] + + [#x1E38] + + [#x1E3A] + + [#x1E3C] + + [#x1E3E] + + [#x1E40] + + [#x1E42] + + [#x1E44] + + [#x1E46] + + [#x1E48] + + [#x1E4A] + + [#x1E4C] + + [#x1E4E] + + [#x1E50] + + [#x1E52] + + [#x1E54] + + [#x1E56] + + [#x1E58] + + [#x1E5A] + + [#x1E5C] + + [#x1E5E] + + [#x1E60] + + [#x1E62] + + [#x1E64] + + [#x1E66] + + [#x1E68] + + [#x1E6A] + + [#x1E6C] + + [#x1E6E] + + [#x1E70] + + [#x1E72] + + [#x1E74] + + [#x1E76] + + [#x1E78] + + [#x1E7A] + + [#x1E7C] + + [#x1E7E] + + [#x1E80] + + [#x1E82] + + [#x1E84] + + [#x1E86] + + [#x1E88] + + [#x1E8A] + + [#x1E8C] + + [#x1E8E] + + [#x1E90] + + [#x1E92] + + [#x1E94] + + [#x1E9E] + + [#x1EA0] + + [#x1EA2] + + [#x1EA4] + + [#x1EA6] + + [#x1EA8] + + [#x1EAA] + + [#x1EAC] + + [#x1EAE] + + [#x1EB0] + + [#x1EB2] + + [#x1EB4] + + [#x1EB6] + + [#x1EB8] + + [#x1EBA] + + [#x1EBC] + + [#x1EBE] + + [#x1EC0] + + [#x1EC2] + + [#x1EC4] + + [#x1EC6] + + [#x1EC8] + + [#x1ECA] + + [#x1ECC] + + [#x1ECE] + + [#x1ED0] + + [#x1ED2] + + [#x1ED4] + + [#x1ED6] + + [#x1ED8] + + [#x1EDA] + + [#x1EDC] + + [#x1EDE] + + [#x1EE0] + + [#x1EE2] + + [#x1EE4] + + [#x1EE6] + + [#x1EE8] + + [#x1EEA] + + [#x1EEC] + + [#x1EEE] + + [#x1EF0] + + [#x1EF2] + + [#x1EF4] + + [#x1EF6] + + [#x1EF8] + + [#x1EFA] + + [#x1EFC] + + [#x1EFE] + + [#x1F08-#x1F0F] + + [#x1F18-#x1F1D] + + [#x1F28-#x1F2F] + + [#x1F38-#x1F3F] + + [#x1F48-#x1F4D] + + [#x1F59] + + [#x1F5B] + + [#x1F5D] + + [#x1F5F] + + [#x1F68-#x1F6F] + + [#x1FB8-#x1FBB] + + [#x1FC8-#x1FCB] + + [#x1FD8-#x1FDB] + + [#x1FE8-#x1FEC] + + [#x1FF8-#x1FFB] + + [#x2102] + + [#x2107] + + [#x210B-#x210D] + + [#x2110-#x2112] + + [#x2115] + + [#x2119-#x211D] + + [#x2124] + + [#x2126] + + [#x2128] + + [#x212A-#x212D] + + [#x2130-#x2133] + + [#x213E-#x213F] + + [#x2145] + + [#x2183] + + [#x2C00-#x2C2F] + + [#x2C60] + + [#x2C62-#x2C64] + + [#x2C67] + + [#x2C69] + + [#x2C6B] + + [#x2C6D-#x2C70] + + [#x2C72] + + [#x2C75] + + [#x2C7E-#x2C80] + + [#x2C82] + + [#x2C84] + + [#x2C86] + + [#x2C88] + + [#x2C8A] + + [#x2C8C] + + [#x2C8E] + + [#x2C90] + + [#x2C92] + + [#x2C94] + + [#x2C96] + + [#x2C98] + + [#x2C9A] + + [#x2C9C] + + [#x2C9E] + + [#x2CA0] + + [#x2CA2] + + [#x2CA4] + + [#x2CA6] + + [#x2CA8] + + [#x2CAA] + + [#x2CAC] + + [#x2CAE] + + [#x2CB0] + + [#x2CB2] + + [#x2CB4] + + [#x2CB6] + + [#x2CB8] + + [#x2CBA] + + [#x2CBC] + + [#x2CBE] + + [#x2CC0] + + [#x2CC2] + + [#x2CC4] + + [#x2CC6] + + [#x2CC8] + + [#x2CCA] + + [#x2CCC] + + [#x2CCE] + + [#x2CD0] + + [#x2CD2] + + [#x2CD4] + + [#x2CD6] + + [#x2CD8] + + [#x2CDA] + + [#x2CDC] + + [#x2CDE] + + [#x2CE0] + + [#x2CE2] + + [#x2CEB] + + [#x2CED] + + [#x2CF2] + + [#xA640] + + [#xA642] + + [#xA644] + + [#xA646] + + [#xA648] + + [#xA64A] + + [#xA64C] + + [#xA64E] + + [#xA650] + + [#xA652] + + [#xA654] + + [#xA656] + + [#xA658] + + [#xA65A] + + [#xA65C] + + [#xA65E] + + [#xA660] + + [#xA662] + + [#xA664] + + [#xA666] + + [#xA668] + + [#xA66A] + + [#xA66C] + + [#xA680] + + [#xA682] + + [#xA684] + + [#xA686] + + [#xA688] + + [#xA68A] + + [#xA68C] + + [#xA68E] + + [#xA690] + + [#xA692] + + [#xA694] + + [#xA696] + + [#xA698] + + [#xA69A] + + [#xA722] + + [#xA724] + + [#xA726] + + [#xA728] + + [#xA72A] + + [#xA72C] + + [#xA72E] + + [#xA732] + + [#xA734] + + [#xA736] + + [#xA738] + + [#xA73A] + + [#xA73C] + + [#xA73E] + + [#xA740] + + [#xA742] + + [#xA744] + + [#xA746] + + [#xA748] + + [#xA74A] + + [#xA74C] + + [#xA74E] + + [#xA750] + + [#xA752] + + [#xA754] + + [#xA756] + + [#xA758] + + [#xA75A] + + [#xA75C] + + [#xA75E] + + [#xA760] + + [#xA762] + + [#xA764] + + [#xA766] + + [#xA768] + + [#xA76A] + + [#xA76C] + + [#xA76E] + + [#xA779] + + [#xA77B] + + [#xA77D-#xA77E] + + [#xA780] + + [#xA782] + + [#xA784] + + [#xA786] + + [#xA78B] + + [#xA78D] + + [#xA790] + + [#xA792] + + [#xA796] + + [#xA798] + + [#xA79A] + + [#xA79C] + + [#xA79E] + + [#xA7A0] + + [#xA7A2] + + [#xA7A4] + + [#xA7A6] + + [#xA7A8] + + [#xA7AA-#xA7AE] + + [#xA7B0-#xA7B4] + + [#xA7B6] + + [#xA7B8] + + [#xA7BA] + + [#xA7BC] + + [#xA7BE] + + [#xA7C0] + + [#xA7C2] + + [#xA7C4-#xA7C7] + + [#xA7C9] + + [#xA7D0] + + [#xA7D6] + + [#xA7D8] + + [#xA7F5] + + [#xFF21-#xFF3A] + + +
    + +
    Lu       ::= [A-Z#xC0-#xD6#xD8-#xDE#x100#x102#x104#x106#x108#x10A#x10C#x10E#x110#x112#x114#x116#x118#x11A#x11C#x11E#x120#x122#x124#x126#x128#x12A#x12C#x12E#x130#x132#x134#x136#x139#x13B#x13D#x13F#x141#x143#x145#x147#x14A#x14C#x14E#x150#x152#x154#x156#x158#x15A#x15C#x15E#x160#x162#x164#x166#x168#x16A#x16C#x16E#x170#x172#x174#x176#x178-#x179#x17B#x17D#x181-#x182#x184#x186-#x187#x189-#x18B#x18E-#x191#x193-#x194#x196-#x198#x19C-#x19D#x19F-#x1A0#x1A2#x1A4#x1A6-#x1A7#x1A9#x1AC#x1AE-#x1AF#x1B1-#x1B3#x1B5#x1B7-#x1B8#x1BC#x1C4#x1C7#x1CA#x1CD#x1CF#x1D1#x1D3#x1D5#x1D7#x1D9#x1DB#x1DE#x1E0#x1E2#x1E4#x1E6#x1E8#x1EA#x1EC#x1EE#x1F1#x1F4#x1F6-#x1F8#x1FA#x1FC#x1FE#x200#x202#x204#x206#x208#x20A#x20C#x20E#x210#x212#x214#x216#x218#x21A#x21C#x21E#x220#x222#x224#x226#x228#x22A#x22C#x22E#x230#x232#x23A-#x23B#x23D-#x23E#x241#x243-#x246#x248#x24A#x24C#x24E#x370#x372#x376#x37F#x386#x388-#x38A#x38C#x38E-#x38F#x391-#x3A1#x3A3-#x3AB#x3CF#x3D2-#x3D4#x3D8#x3DA#x3DC#x3DE#x3E0#x3E2#x3E4#x3E6#x3E8#x3EA#x3EC#x3EE#x3F4#x3F7#x3F9-#x3FA#x3FD-#x42F#x460#x462#x464#x466#x468#x46A#x46C#x46E#x470#x472#x474#x476#x478#x47A#x47C#x47E#x480#x48A#x48C#x48E#x490#x492#x494#x496#x498#x49A#x49C#x49E#x4A0#x4A2#x4A4#x4A6#x4A8#x4AA#x4AC#x4AE#x4B0#x4B2#x4B4#x4B6#x4B8#x4BA#x4BC#x4BE#x4C0-#x4C1#x4C3#x4C5#x4C7#x4C9#x4CB#x4CD#x4D0#x4D2#x4D4#x4D6#x4D8#x4DA#x4DC#x4DE#x4E0#x4E2#x4E4#x4E6#x4E8#x4EA#x4EC#x4EE#x4F0#x4F2#x4F4#x4F6#x4F8#x4FA#x4FC#x4FE#x500#x502#x504#x506#x508#x50A#x50C#x50E#x510#x512#x514#x516#x518#x51A#x51C#x51E#x520#x522#x524#x526#x528#x52A#x52C#x52E#x531-#x556#x10A0-#x10C5#x10C7#x10CD#x13A0-#x13F5#x1C90-#x1CBA#x1CBD-#x1CBF#x1E00#x1E02#x1E04#x1E06#x1E08#x1E0A#x1E0C#x1E0E#x1E10#x1E12#x1E14#x1E16#x1E18#x1E1A#x1E1C#x1E1E#x1E20#x1E22#x1E24#x1E26#x1E28#x1E2A#x1E2C#x1E2E#x1E30#x1E32#x1E34#x1E36#x1E38#x1E3A#x1E3C#x1E3E#x1E40#x1E42#x1E44#x1E46#x1E48#x1E4A#x1E4C#x1E4E#x1E50#x1E52#x1E54#x1E56#x1E58#x1E5A#x1E5C#x1E5E#x1E60#x1E62#x1E64#x1E66#x1E68#x1E6A#x1E6C#x1E6E#x1E70#x1E72#x1E74#x1E76#x1E78#x1E7A#x1E7C#x1E7E#x1E80#x1E82#x1E84#x1E86#x1E88#x1E8A#x1E8C#x1E8E#x1E90#x1E92#x1E94#x1E9E#x1EA0#x1EA2#x1EA4#x1EA6#x1EA8#x1EAA#x1EAC#x1EAE#x1EB0#x1EB2#x1EB4#x1EB6#x1EB8#x1EBA#x1EBC#x1EBE#x1EC0#x1EC2#x1EC4#x1EC6#x1EC8#x1ECA#x1ECC#x1ECE#x1ED0#x1ED2#x1ED4#x1ED6#x1ED8#x1EDA#x1EDC#x1EDE#x1EE0#x1EE2#x1EE4#x1EE6#x1EE8#x1EEA#x1EEC#x1EEE#x1EF0#x1EF2#x1EF4#x1EF6#x1EF8#x1EFA#x1EFC#x1EFE#x1F08-#x1F0F#x1F18-#x1F1D#x1F28-#x1F2F#x1F38-#x1F3F#x1F48-#x1F4D#x1F59#x1F5B#x1F5D#x1F5F#x1F68-#x1F6F#x1FB8-#x1FBB#x1FC8-#x1FCB#x1FD8-#x1FDB#x1FE8-#x1FEC#x1FF8-#x1FFB#x2102#x2107#x210B-#x210D#x2110-#x2112#x2115#x2119-#x211D#x2124#x2126#x2128#x212A-#x212D#x2130-#x2133#x213E-#x213F#x2145#x2183#x2C00-#x2C2F#x2C60#x2C62-#x2C64#x2C67#x2C69#x2C6B#x2C6D-#x2C70#x2C72#x2C75#x2C7E-#x2C80#x2C82#x2C84#x2C86#x2C88#x2C8A#x2C8C#x2C8E#x2C90#x2C92#x2C94#x2C96#x2C98#x2C9A#x2C9C#x2C9E#x2CA0#x2CA2#x2CA4#x2CA6#x2CA8#x2CAA#x2CAC#x2CAE#x2CB0#x2CB2#x2CB4#x2CB6#x2CB8#x2CBA#x2CBC#x2CBE#x2CC0#x2CC2#x2CC4#x2CC6#x2CC8#x2CCA#x2CCC#x2CCE#x2CD0#x2CD2#x2CD4#x2CD6#x2CD8#x2CDA#x2CDC#x2CDE#x2CE0#x2CE2#x2CEB#x2CED#x2CF2#xA640#xA642#xA644#xA646#xA648#xA64A#xA64C#xA64E#xA650#xA652#xA654#xA656#xA658#xA65A#xA65C#xA65E#xA660#xA662#xA664#xA666#xA668#xA66A#xA66C#xA680#xA682#xA684#xA686#xA688#xA68A#xA68C#xA68E#xA690#xA692#xA694#xA696#xA698#xA69A#xA722#xA724#xA726#xA728#xA72A#xA72C#xA72E#xA732#xA734#xA736#xA738#xA73A#xA73C#xA73E#xA740#xA742#xA744#xA746#xA748#xA74A#xA74C#xA74E#xA750#xA752#xA754#xA756#xA758#xA75A#xA75C#xA75E#xA760#xA762#xA764#xA766#xA768#xA76A#xA76C#xA76E#xA779#xA77B#xA77D-#xA77E#xA780#xA782#xA784#xA786#xA78B#xA78D#xA790#xA792#xA796#xA798#xA79A#xA79C#xA79E#xA7A0#xA7A2#xA7A4#xA7A6#xA7A8#xA7AA-#xA7AE#xA7B0-#xA7B4#xA7B6#xA7B8#xA7BA#xA7BC#xA7BE#xA7C0#xA7C2#xA7C4-#xA7C7#xA7C9#xA7D0#xA7D6#xA7D8#xA7F5#xFF21-#xFF3A]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Nl +====================================================================================================================== + + +.. raw:: html + + + + + + [#x16EE-#x16F0] + + [#x2160-#x2182] + + [#x2185-#x2188] + + [#x3007] + + [#x3021-#x3029] + + [#x3038-#x303A] + + [#xA6E6-#xA6EF] + + +
    + +
    Nl       ::= [#x16EE-#x16F0#x2160-#x2182#x2185-#x2188#x3007#x3021-#x3029#x3038-#x303A#xA6E6-#xA6EF]
    +
    + Referenced by: +
    + + +====================================================================================================================== +UnicodeIdentifierExtend +====================================================================================================================== + + +.. raw:: html + + + + + + Mn + + Mc + + Nd + + Pc + + Cf + + CJK + +
    + + +
             ::= Mn
    +
               | Mc
    +
               | Nd
    +
               | Pc
    +
               | Cf
    +
               | CJK
    +
    + + +====================================================================================================================== +Cf +====================================================================================================================== + + +.. raw:: html + + + + + + [#xAD] + + [#x600-#x605] + + [#x61C] + + [#x6DD] + + [#x70F] + + [#x890-#x891] + + [#x8E2] + + [#x180E] + + [#x200B-#x200F] + + [#x202A-#x202E] + + [#x2060-#x2064] + + [#x2066-#x206F] + + [#xFEFF] + + [#xFFF9-#xFFFB] + + +
    + +
    Cf       ::= [#xAD#x600-#x605#x61C#x6DD#x70F#x890-#x891#x8E2#x180E#x200B-#x200F#x202A-#x202E#x2060-#x2064#x2066-#x206F#xFEFF#xFFF9-#xFFFB]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Mc +====================================================================================================================== + + +.. raw:: html + + + + + + [#x903] + + [#x93B] + + [#x93E-#x940] + + [#x949-#x94C] + + [#x94E-#x94F] + + [#x982-#x983] + + [#x9BE-#x9C0] + + [#x9C7-#x9C8] + + [#x9CB-#x9CC] + + [#x9D7] + + [#xA03] + + [#xA3E-#xA40] + + [#xA83] + + [#xABE-#xAC0] + + [#xAC9] + + [#xACB-#xACC] + + [#xB02-#xB03] + + [#xB3E] + + [#xB40] + + [#xB47-#xB48] + + [#xB4B-#xB4C] + + [#xB57] + + [#xBBE-#xBBF] + + [#xBC1-#xBC2] + + [#xBC6-#xBC8] + + [#xBCA-#xBCC] + + [#xBD7] + + [#xC01-#xC03] + + [#xC41-#xC44] + + [#xC82-#xC83] + + [#xCBE] + + [#xCC0-#xCC4] + + [#xCC7-#xCC8] + + [#xCCA-#xCCB] + + [#xCD5-#xCD6] + + [#xCF3] + + [#xD02-#xD03] + + [#xD3E-#xD40] + + [#xD46-#xD48] + + [#xD4A-#xD4C] + + [#xD57] + + [#xD82-#xD83] + + [#xDCF-#xDD1] + + [#xDD8-#xDDF] + + [#xDF2-#xDF3] + + [#xF3E-#xF3F] + + [#xF7F] + + [#x102B-#x102C] + + [#x1031] + + [#x1038] + + [#x103B-#x103C] + + [#x1056-#x1057] + + [#x1062-#x1064] + + [#x1067-#x106D] + + [#x1083-#x1084] + + [#x1087-#x108C] + + [#x108F] + + [#x109A-#x109C] + + [#x1715] + + [#x1734] + + [#x17B6] + + [#x17BE-#x17C5] + + [#x17C7-#x17C8] + + [#x1923-#x1926] + + [#x1929-#x192B] + + [#x1930-#x1931] + + [#x1933-#x1938] + + [#x1A19-#x1A1A] + + [#x1A55] + + [#x1A57] + + [#x1A61] + + [#x1A63-#x1A64] + + [#x1A6D-#x1A72] + + [#x1B04] + + [#x1B35] + + [#x1B3B] + + [#x1B3D-#x1B41] + + [#x1B43-#x1B44] + + [#x1B82] + + [#x1BA1] + + [#x1BA6-#x1BA7] + + [#x1BAA] + + [#x1BE7] + + [#x1BEA-#x1BEC] + + [#x1BEE] + + [#x1BF2-#x1BF3] + + [#x1C24-#x1C2B] + + [#x1C34-#x1C35] + + [#x1CE1] + + [#x1CF7] + + [#x302E-#x302F] + + [#xA823-#xA824] + + [#xA827] + + [#xA880-#xA881] + + [#xA8B4-#xA8C3] + + [#xA952-#xA953] + + [#xA983] + + [#xA9B4-#xA9B5] + + [#xA9BA-#xA9BB] + + [#xA9BE-#xA9C0] + + [#xAA2F-#xAA30] + + [#xAA33-#xAA34] + + [#xAA4D] + + [#xAA7B] + + [#xAA7D] + + [#xAAEB] + + [#xAAEE-#xAAEF] + + [#xAAF5] + + [#xABE3-#xABE4] + + [#xABE6-#xABE7] + + [#xABE9-#xABEA] + + [#xABEC] + + +
    + +
    Mc       ::= [#x903#x93B#x93E-#x940#x949-#x94C#x94E-#x94F#x982-#x983#x9BE-#x9C0#x9C7-#x9C8#x9CB-#x9CC#x9D7#xA03#xA3E-#xA40#xA83#xABE-#xAC0#xAC9#xACB-#xACC#xB02-#xB03#xB3E#xB40#xB47-#xB48#xB4B-#xB4C#xB57#xBBE-#xBBF#xBC1-#xBC2#xBC6-#xBC8#xBCA-#xBCC#xBD7#xC01-#xC03#xC41-#xC44#xC82-#xC83#xCBE#xCC0-#xCC4#xCC7-#xCC8#xCCA-#xCCB#xCD5-#xCD6#xCF3#xD02-#xD03#xD3E-#xD40#xD46-#xD48#xD4A-#xD4C#xD57#xD82-#xD83#xDCF-#xDD1#xDD8-#xDDF#xDF2-#xDF3#xF3E-#xF3F#xF7F#x102B-#x102C#x1031#x1038#x103B-#x103C#x1056-#x1057#x1062-#x1064#x1067-#x106D#x1083-#x1084#x1087-#x108C#x108F#x109A-#x109C#x1715#x1734#x17B6#x17BE-#x17C5#x17C7-#x17C8#x1923-#x1926#x1929-#x192B#x1930-#x1931#x1933-#x1938#x1A19-#x1A1A#x1A55#x1A57#x1A61#x1A63-#x1A64#x1A6D-#x1A72#x1B04#x1B35#x1B3B#x1B3D-#x1B41#x1B43-#x1B44#x1B82#x1BA1#x1BA6-#x1BA7#x1BAA#x1BE7#x1BEA-#x1BEC#x1BEE#x1BF2-#x1BF3#x1C24-#x1C2B#x1C34-#x1C35#x1CE1#x1CF7#x302E-#x302F#xA823-#xA824#xA827#xA880-#xA881#xA8B4-#xA8C3#xA952-#xA953#xA983#xA9B4-#xA9B5#xA9BA-#xA9BB#xA9BE-#xA9C0#xAA2F-#xAA30#xAA33-#xAA34#xAA4D#xAA7B#xAA7D#xAAEB#xAAEE-#xAAEF#xAAF5#xABE3-#xABE4#xABE6-#xABE7#xABE9-#xABEA#xABEC]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Mn +====================================================================================================================== + + +.. raw:: html + + + + + + [#x300-#x36F] + + [#x483-#x487] + + [#x591-#x5BD] + + [#x5BF] + + [#x5C1-#x5C2] + + [#x5C4-#x5C5] + + [#x5C7] + + [#x610-#x61A] + + [#x64B-#x65F] + + [#x670] + + [#x6D6-#x6DC] + + [#x6DF-#x6E4] + + [#x6E7-#x6E8] + + [#x6EA-#x6ED] + + [#x711] + + [#x730-#x74A] + + [#x7A6-#x7B0] + + [#x7EB-#x7F3] + + [#x7FD] + + [#x816-#x819] + + [#x81B-#x823] + + [#x825-#x827] + + [#x829-#x82D] + + [#x859-#x85B] + + [#x898-#x89F] + + [#x8CA-#x8E1] + + [#x8E3-#x902] + + [#x93A] + + [#x93C] + + [#x941-#x948] + + [#x94D] + + [#x951-#x957] + + [#x962-#x963] + + [#x981] + + [#x9BC] + + [#x9C1-#x9C4] + + [#x9CD] + + [#x9E2-#x9E3] + + [#x9FE] + + [#xA01-#xA02] + + [#xA3C] + + [#xA41-#xA42] + + [#xA47-#xA48] + + [#xA4B-#xA4D] + + [#xA51] + + [#xA70-#xA71] + + [#xA75] + + [#xA81-#xA82] + + [#xABC] + + [#xAC1-#xAC5] + + [#xAC7-#xAC8] + + [#xACD] + + [#xAE2-#xAE3] + + [#xAFA-#xAFF] + + [#xB01] + + [#xB3C] + + [#xB3F] + + [#xB41-#xB44] + + [#xB4D] + + [#xB55-#xB56] + + [#xB62-#xB63] + + [#xB82] + + [#xBC0] + + [#xBCD] + + [#xC00] + + [#xC04] + + [#xC3C] + + [#xC3E-#xC40] + + [#xC46-#xC48] + + [#xC4A-#xC4D] + + [#xC55-#xC56] + + [#xC62-#xC63] + + [#xC81] + + [#xCBC] + + [#xCBF] + + [#xCC6] + + [#xCCC-#xCCD] + + [#xCE2-#xCE3] + + [#xD00-#xD01] + + [#xD3B-#xD3C] + + [#xD41-#xD44] + + [#xD4D] + + [#xD62-#xD63] + + [#xD81] + + [#xDCA] + + [#xDD2-#xDD4] + + [#xDD6] + + [#xE31] + + [#xE34-#xE3A] + + [#xE47-#xE4E] + + [#xEB1] + + [#xEB4-#xEBC] + + [#xEC8-#xECE] + + [#xF18-#xF19] + + [#xF35] + + [#xF37] + + [#xF39] + + [#xF71-#xF7E] + + [#xF80-#xF84] + + [#xF86-#xF87] + + [#xF8D-#xF97] + + [#xF99-#xFBC] + + [#xFC6] + + [#x102D-#x1030] + + [#x1032-#x1037] + + [#x1039-#x103A] + + [#x103D-#x103E] + + [#x1058-#x1059] + + [#x105E-#x1060] + + [#x1071-#x1074] + + [#x1082] + + [#x1085-#x1086] + + [#x108D] + + [#x109D] + + [#x135D-#x135F] + + [#x1712-#x1714] + + [#x1732-#x1733] + + [#x1752-#x1753] + + [#x1772-#x1773] + + [#x17B4-#x17B5] + + [#x17B7-#x17BD] + + [#x17C6] + + [#x17C9-#x17D3] + + [#x17DD] + + [#x180B-#x180D] + + [#x180F] + + [#x1885-#x1886] + + [#x18A9] + + [#x1920-#x1922] + + [#x1927-#x1928] + + [#x1932] + + [#x1939-#x193B] + + [#x1A17-#x1A18] + + [#x1A1B] + + [#x1A56] + + [#x1A58-#x1A5E] + + [#x1A60] + + [#x1A62] + + [#x1A65-#x1A6C] + + [#x1A73-#x1A7C] + + [#x1A7F] + + [#x1AB0-#x1ABD] + + [#x1ABF-#x1ACE] + + [#x1B00-#x1B03] + + [#x1B34] + + [#x1B36-#x1B3A] + + [#x1B3C] + + [#x1B42] + + [#x1B6B-#x1B73] + + [#x1B80-#x1B81] + + [#x1BA2-#x1BA5] + + [#x1BA8-#x1BA9] + + [#x1BAB-#x1BAD] + + [#x1BE6] + + [#x1BE8-#x1BE9] + + [#x1BED] + + [#x1BEF-#x1BF1] + + [#x1C2C-#x1C33] + + [#x1C36-#x1C37] + + [#x1CD0-#x1CD2] + + [#x1CD4-#x1CE0] + + [#x1CE2-#x1CE8] + + [#x1CED] + + [#x1CF4] + + [#x1CF8-#x1CF9] + + [#x1DC0-#x1DFF] + + [#x20D0-#x20DC] + + [#x20E1] + + [#x20E5-#x20F0] + + [#x2CEF-#x2CF1] + + [#x2D7F] + + [#x2DE0-#x2DFF] + + [#x302A-#x302D] + + [#x3099-#x309A] + + [#xA66F] + + [#xA674-#xA67D] + + [#xA69E-#xA69F] + + [#xA6F0-#xA6F1] + + [#xA802] + + [#xA806] + + [#xA80B] + + [#xA825-#xA826] + + [#xA82C] + + [#xA8C4-#xA8C5] + + [#xA8E0-#xA8F1] + + [#xA8FF] + + [#xA926-#xA92D] + + [#xA947-#xA951] + + [#xA980-#xA982] + + [#xA9B3] + + [#xA9B6-#xA9B9] + + [#xA9BC-#xA9BD] + + [#xA9E5] + + [#xAA29-#xAA2E] + + [#xAA31-#xAA32] + + [#xAA35-#xAA36] + + [#xAA43] + + [#xAA4C] + + [#xAA7C] + + [#xAAB0] + + [#xAAB2-#xAAB4] + + [#xAAB7-#xAAB8] + + [#xAABE-#xAABF] + + [#xAAC1] + + [#xAAEC-#xAAED] + + [#xAAF6] + + [#xABE5] + + [#xABE8] + + [#xABED] + + [#xFB1E] + + [#xFE00-#xFE0F] + + [#xFE20-#xFE2F] + + +
    + +
    Mn       ::= [#x300-#x36F#x483-#x487#x591-#x5BD#x5BF#x5C1-#x5C2#x5C4-#x5C5#x5C7#x610-#x61A#x64B-#x65F#x670#x6D6-#x6DC#x6DF-#x6E4#x6E7-#x6E8#x6EA-#x6ED#x711#x730-#x74A#x7A6-#x7B0#x7EB-#x7F3#x7FD#x816-#x819#x81B-#x823#x825-#x827#x829-#x82D#x859-#x85B#x898-#x89F#x8CA-#x8E1#x8E3-#x902#x93A#x93C#x941-#x948#x94D#x951-#x957#x962-#x963#x981#x9BC#x9C1-#x9C4#x9CD#x9E2-#x9E3#x9FE#xA01-#xA02#xA3C#xA41-#xA42#xA47-#xA48#xA4B-#xA4D#xA51#xA70-#xA71#xA75#xA81-#xA82#xABC#xAC1-#xAC5#xAC7-#xAC8#xACD#xAE2-#xAE3#xAFA-#xAFF#xB01#xB3C#xB3F#xB41-#xB44#xB4D#xB55-#xB56#xB62-#xB63#xB82#xBC0#xBCD#xC00#xC04#xC3C#xC3E-#xC40#xC46-#xC48#xC4A-#xC4D#xC55-#xC56#xC62-#xC63#xC81#xCBC#xCBF#xCC6#xCCC-#xCCD#xCE2-#xCE3#xD00-#xD01#xD3B-#xD3C#xD41-#xD44#xD4D#xD62-#xD63#xD81#xDCA#xDD2-#xDD4#xDD6#xE31#xE34-#xE3A#xE47-#xE4E#xEB1#xEB4-#xEBC#xEC8-#xECE#xF18-#xF19#xF35#xF37#xF39#xF71-#xF7E#xF80-#xF84#xF86-#xF87#xF8D-#xF97#xF99-#xFBC#xFC6#x102D-#x1030#x1032-#x1037#x1039-#x103A#x103D-#x103E#x1058-#x1059#x105E-#x1060#x1071-#x1074#x1082#x1085-#x1086#x108D#x109D#x135D-#x135F#x1712-#x1714#x1732-#x1733#x1752-#x1753#x1772-#x1773#x17B4-#x17B5#x17B7-#x17BD#x17C6#x17C9-#x17D3#x17DD#x180B-#x180D#x180F#x1885-#x1886#x18A9#x1920-#x1922#x1927-#x1928#x1932#x1939-#x193B#x1A17-#x1A18#x1A1B#x1A56#x1A58-#x1A5E#x1A60#x1A62#x1A65-#x1A6C#x1A73-#x1A7C#x1A7F#x1AB0-#x1ABD#x1ABF-#x1ACE#x1B00-#x1B03#x1B34#x1B36-#x1B3A#x1B3C#x1B42#x1B6B-#x1B73#x1B80-#x1B81#x1BA2-#x1BA5#x1BA8-#x1BA9#x1BAB-#x1BAD#x1BE6#x1BE8-#x1BE9#x1BED#x1BEF-#x1BF1#x1C2C-#x1C33#x1C36-#x1C37#x1CD0-#x1CD2#x1CD4-#x1CE0#x1CE2-#x1CE8#x1CED#x1CF4#x1CF8-#x1CF9#x1DC0-#x1DFF#x20D0-#x20DC#x20E1#x20E5-#x20F0#x2CEF-#x2CF1#x2D7F#x2DE0-#x2DFF#x302A-#x302D#x3099-#x309A#xA66F#xA674-#xA67D#xA69E-#xA69F#xA6F0-#xA6F1#xA802#xA806#xA80B#xA825-#xA826#xA82C#xA8C4-#xA8C5#xA8E0-#xA8F1#xA8FF#xA926-#xA92D#xA947-#xA951#xA980-#xA982#xA9B3#xA9B6-#xA9B9#xA9BC-#xA9BD#xA9E5#xAA29-#xAA2E#xAA31-#xAA32#xAA35-#xAA36#xAA43#xAA4C#xAA7C#xAAB0#xAAB2-#xAAB4#xAAB7-#xAAB8#xAABE-#xAABF#xAAC1#xAAEC-#xAAED#xAAF6#xABE5#xABE8#xABED#xFB1E#xFE00-#xFE0F#xFE20-#xFE2F]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Nd +====================================================================================================================== + + +.. raw:: html + + + + + + [0-9] + + [#x660-#x669] + + [#x6F0-#x6F9] + + [#x7C0-#x7C9] + + [#x966-#x96F] + + [#x9E6-#x9EF] + + [#xA66-#xA6F] + + [#xAE6-#xAEF] + + [#xB66-#xB6F] + + [#xBE6-#xBEF] + + [#xC66-#xC6F] + + [#xCE6-#xCEF] + + [#xD66-#xD6F] + + [#xDE6-#xDEF] + + [#xE50-#xE59] + + [#xED0-#xED9] + + [#xF20-#xF29] + + [#x1040-#x1049] + + [#x1090-#x1099] + + [#x17E0-#x17E9] + + [#x1810-#x1819] + + [#x1946-#x194F] + + [#x19D0-#x19D9] + + [#x1A80-#x1A89] + + [#x1A90-#x1A99] + + [#x1B50-#x1B59] + + [#x1BB0-#x1BB9] + + [#x1C40-#x1C49] + + [#x1C50-#x1C59] + + [#xA620-#xA629] + + [#xA8D0-#xA8D9] + + [#xA900-#xA909] + + [#xA9D0-#xA9D9] + + [#xA9F0-#xA9F9] + + [#xAA50-#xAA59] + + [#xABF0-#xABF9] + + [#xFF10-#xFF19] + + +
    + +
    Nd       ::= [0-9#x660-#x669#x6F0-#x6F9#x7C0-#x7C9#x966-#x96F#x9E6-#x9EF#xA66-#xA6F#xAE6-#xAEF#xB66-#xB6F#xBE6-#xBEF#xC66-#xC6F#xCE6-#xCEF#xD66-#xD6F#xDE6-#xDEF#xE50-#xE59#xED0-#xED9#xF20-#xF29#x1040-#x1049#x1090-#x1099#x17E0-#x17E9#x1810-#x1819#x1946-#x194F#x19D0-#x19D9#x1A80-#x1A89#x1A90-#x1A99#x1B50-#x1B59#x1BB0-#x1BB9#x1C40-#x1C49#x1C50-#x1C59#xA620-#xA629#xA8D0-#xA8D9#xA900-#xA909#xA9D0-#xA9D9#xA9F0-#xA9F9#xAA50-#xAA59#xABF0-#xABF9#xFF10-#xFF19]
    +
    + Referenced by: +
    + + +====================================================================================================================== +Pc +====================================================================================================================== + + +.. raw:: html + + + + + + [#x203F-#x2040] + + [#x2054] + + [#xFE33-#xFE34] + + [#xFE4D-#xFE4F] + + [#xFF3F] + + +
    + +
    Pc       ::= [#x203F-#x2040#x2054#xFE33-#xFE34#xFE4D-#xFE4F#xFF3F]
    +
    + Referenced by: +
    + + +====================================================================================================================== +CJK +====================================================================================================================== + + +.. raw:: html + + + + + + [#xAC00-#xD7A3] + + [#x4E00-#x9FFF] + + +
    + +
    CJK      ::= [#xAC00-#xD7A3#x4E00-#x9FFF]
    +
    + + +====================================================================================================================== +ESC +====================================================================================================================== + + +.. raw:: html + + + + + + \ + + n + + t + + b + + r + + f + + \ + + " + + +
    + +
    ESC      ::= '\' [ntbrf\"]
    +
    + Referenced by: +
    + + +====================================================================================================================== +S_CHAR_LITERAL +====================================================================================================================== + + +.. raw:: html + + + + + + U + + E + + N + + R + + B + + RB + + _utf8 + + q'{ + + . + + }' + + ' + + ESC + \' + + [^'\] + + '' + + [^'] + + ' + + q'( + + . + + )' + + q'[ + + . + + ]' + + q'' + + . + + '' + + +
    + + +
             ::= ( [UENRB] | 'RB' | '_utf8' )? ( "'" ( ( ESC | "\'" | [^'\] )* | ( "''" | [^'] )+ ) "'" | "q'{" .* "}'" | "q'(" .* ")'" | "q'[" .* "]'" | "q''" .* "''" )
    +
    + + +====================================================================================================================== +S_QUOTED_IDENTIFIER +====================================================================================================================== + + +.. raw:: html + + + + + + " + + "" + + [^"#xA#xD] + + " + + ` + + [^`#xA#xD] + + ` + + [ + + [^#x5D#xA#xD] + + ] + + +
    + + +
             ::= '"' ( '""' | [^"#xA#xD] )* '"'
    +
               | '`' [^`#xA#xD]+ '`'
    +
               | '[' [^#x5D#xA#xD]* ']'
    +
    + + +====================================================================================================================== +EOF +====================================================================================================================== + + +.. raw:: html + + + + + + $ + + +
    + +
    EOF      ::= $
    +
    + Referenced by: +
    + + \ No newline at end of file diff --git a/src/site/sphinx/unsupported.rst b/src/site/sphinx/unsupported.rst index b6489a84a..c231dbe81 100644 --- a/src/site/sphinx/unsupported.rst +++ b/src/site/sphinx/unsupported.rst @@ -5,14 +5,6 @@ Unsupported Grammar of various RDBMS *JSQLParser* is a RDBMS agnostic parser with a certain focus on SQL:2016 Standard compliant Queries and the "Big Four" (Oracle, MS SQL Server, Postgres, MySQL/MariaDB). We would like to recommend writing portable, standard compliant SQL in general. -- Postgres Implicit cast is not supported. - - .. code-block:: java - - SELECT date '2022-12-31'; - SELECT double precision 1; - - - Oracle PL/SQL blocks are not support. .. code-block:: sql @@ -24,26 +16,10 @@ We would like to recommend writing portable, standard compliant SQL in general. dbms_output.put_line('The number is ' || num); END; - - -- Oracle `INSERT ALL ...` is not supported - - .. code-block:: sql - - INSERT ALL - INTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n) - INTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n) - INTO mytable (column1, column2, column_n) VALUES (expr1, expr2, expr_n) - SELECT * FROM dual; - - DDL statements While *JSQLParser* provides a lot of generic support for DDL statements, it is possible that certain RDBMS specific syntax (especially about indices, encodings, compression) won't be supported. -- `JSON` or `XML` specific syntax and functions - - While *JSQLParser* provides a lot of generic support for `JSON` or `XML` processing, it is possible that certain RDBMS specific syntax or functions won't be supported. - - Interval Operators Anything like `DAY HOUR MINUTE SECOND [TO HOUR MINUTE SECOND]` is not supported.: @@ -54,4 +30,3 @@ We would like to recommend writing portable, standard compliant SQL in general. - diff --git a/src/site/sphinx/usage.rst b/src/site/sphinx/usage.rst index 74a9fc6d5..c0bcdac88 100644 --- a/src/site/sphinx/usage.rst +++ b/src/site/sphinx/usage.rst @@ -18,22 +18,22 @@ How to use it Compile from Source Code ============================== -You will need to have ``JDK 8`` or ``JDK 11`` installed. Please note that JSQLParser-4.9 is the last ``JDK 8`` compatible release and all development after will depend on ``JDK 11``. +You will need to have ``JDK 8`` or ``JDK 11`` installed. Please note that JSQLParser-4.9 is the last ``JDK 8`` compatible release and all development after will depend on ``JDK 11``. Building JSQLParser-5.1 and newer with Gradle will depend on a JDK17 toolchain due to the used plugins. .. tab:: Maven .. code-block:: shell - git clone https://github.com/JSQLParser/JSqlParser.git - cd jsqlformatter + git clone --depth 1 https://github.com/JSQLParser/JSqlParser.git + cd JSqlParser mvn install .. tab:: Gradle .. code-block:: shell - git clone https://github.com/JSQLParser/JSqlParser.git - cd jsqlformatter + git clone --depth 1 https://github.com/JSQLParser/JSqlParser.git + cd JSqlParser gradle publishToMavenLocal @@ -192,36 +192,38 @@ Traverse the Java Object Tree using the Visitor Patterns: // Define an Expression Visitor reacting on any Expression // Overwrite the visit() methods for each Expression Class - ExpressionVisitorAdapter expressionVisitorAdapter = new ExpressionVisitorAdapter() { - public void visit(EqualsTo equalsTo) { - equalsTo.getLeftExpression().accept(this); - equalsTo.getRightExpression().accept(this); + ExpressionVisitorAdapter expressionVisitorAdapter = new ExpressionVisitorAdapter<>() { + public Void visit(EqualsTo equalsTo, S context) { + equalsTo.getLeftExpression().accept(this, context); + equalsTo.getRightExpression().accept(this, context); + return null; } - public void visit(Column column) { + public Void visit(Column column, S context) { System.out.println("Found a Column " + column.getColumnName()); + return null; } }; // Define a Select Visitor reacting on a Plain Select invoking the Expression Visitor on the Where Clause - SelectVisitorAdapter selectVisitorAdapter = new SelectVisitorAdapter() { + SelectVisitorAdapter selectVisitorAdapter = new SelectVisitorAdapter<>() { @Override - public void visit(PlainSelect plainSelect) { - plainSelect.getWhere().accept(expressionVisitorAdapter); + public Void visit(PlainSelect plainSelect, S context) { + return plainSelect.getWhere().accept(expressionVisitorAdapter, context); } }; // Define a Statement Visitor for dispatching the Statements - StatementVisitorAdapter statementVisitor = new StatementVisitorAdapter() { - public void visit(Select select) { - select.getSelectBody().accept(selectVisitorAdapter); + StatementVisitorAdapter statementVisitor = new StatementVisitorAdapter<>() { + public Void visit(Select select, S context) { + return select.getSelectBody().accept(selectVisitorAdapter, context); } }; String sqlStr="select 1 from dual where a=b"; Statement stmt = CCJSqlParserUtil.parse(sqlStr); - // Invoke the Statement Visitor - stmt.accept(statementVisitor); + // Invoke the Statement Visitor without a context + stmt.accept(statementVisitor, null); Find Table Names ============================== @@ -315,4 +317,4 @@ Additionally there are Features to control the Parser's effort at the cost of th sqlStr , parser -> parser .withBackslashEscapeCharacter(true) - ); + ); \ No newline at end of file diff --git a/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java new file mode 100644 index 000000000..f87acd119 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/DynamicParserRunner.java @@ -0,0 +1,40 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.lang.reflect.Method; +import java.net.URLClassLoader; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public class DynamicParserRunner implements SqlParserRunner { + private final Method parseStatementsMethod; + + public DynamicParserRunner(URLClassLoader loader) throws Exception { + Class utilClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParserUtil"); + Class ccjClass = loader.loadClass("net.sf.jsqlparser.parser.CCJSqlParser"); + Class consumerClass = Class.forName("java.util.function.Consumer"); // interface OK + parseStatementsMethod = utilClass.getMethod( + "parseStatements", + String.class, + ExecutorService.class, + consumerClass); + } + + @Override + public Statements parseStatements(String sql, + ExecutorService executorService, + Consumer consumer) throws Exception { + return (Statements) parseStatementsMethod.invoke(null, sql, executorService, null); + } +} diff --git a/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java new file mode 100644 index 000000000..abe61a804 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/JSQLParserBenchmark.java @@ -0,0 +1,101 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.concurrent.*; +import java.util.function.Consumer; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +public class JSQLParserBenchmark { + + private String sqlContent; + private ExecutorService executorService; + + SqlParserRunner runner; + + // @Param({ "latest", "5.2", "5.1", "5.0", "4.9", "4.8", "4.7", "4.6", "4.5" }) + @Param({"latest", "5.3", "5.1"}) + public String version; + + @Setup(Level.Trial) + public void setup() throws Exception { + if ("latest".equals(version)) { + runner = new LatestClasspathRunner(); // direct call, no reflection + } else { + Path jarPath = downloadJsqlparserJar(version); + URLClassLoader loader = new URLClassLoader(new URL[] {jarPath.toUri().toURL()}, null); + runner = new DynamicParserRunner(loader); + } + + // Adjust path as necessary based on where source root is during test execution + Path path = Paths.get("src/test/resources/net/sf/jsqlparser/performance.sql"); + sqlContent = Files.readString(path, StandardCharsets.UTF_8); + executorService = Executors.newSingleThreadExecutor(); + } + + private Path downloadJsqlparserJar(String version) throws IOException { + String jarUrl = String.format( + "https://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/%s/jsqlparser-%s.jar", + version, version); + + Path cacheDir = Paths.get("build/libs/downloaded-jars"); + Files.createDirectories(cacheDir); + Path jarFile = cacheDir.resolve("jsqlparser-" + version + ".jar"); + + if (!Files.exists(jarFile)) { + System.out.println("Downloading " + version); + try (InputStream in = new URL(jarUrl).openStream()) { + Files.copy(in, jarFile); + } + } + + return jarFile; + } + + @Benchmark + public void parseSQLStatements(Blackhole blackhole) throws Exception { + final Statements statements = runner.parseStatements( + sqlContent, + executorService, + (Consumer) parser -> parser.withAllowComplexParsing(false)); + blackhole.consume(statements); + } + + // @Benchmark + public void parseQuotedText(Blackhole blackhole) throws Exception { + String sqlStr = "SELECT ('\\'', 'a');\n" + + "INSERT INTO recycle_record (a,f) VALUES ('\\'anything', 'abc');\n" + + "INSERT INTO recycle_record (a,f) VALUES ('\\'','83653692186728700711687663398101');\n"; + + final Statements statements = runner.parseStatements( + sqlStr, + executorService, + (Consumer) parser -> parser.withBackslashEscapeCharacter(true)); + blackhole.consume(statements); + } + + @TearDown(Level.Trial) + public void tearDown() { + executorService.shutdown(); + } +} diff --git a/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java new file mode 100644 index 000000000..5f70cf878 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/LatestClasspathRunner.java @@ -0,0 +1,28 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public class LatestClasspathRunner implements SqlParserRunner { + + @Override + public Statements parseStatements(String sql, + ExecutorService executorService, + Consumer consumer) throws Exception { + return net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(sql, executorService, + consumer); + } +} + diff --git a/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java new file mode 100644 index 000000000..00496ad68 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/benchmark/SqlParserRunner.java @@ -0,0 +1,21 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.benchmark; + +import net.sf.jsqlparser.parser.CCJSqlParser; +import net.sf.jsqlparser.statement.Statements; + +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; + +public interface SqlParserRunner { + Statements parseStatements(String sql, ExecutorService executorService, + Consumer consumer) throws Exception; +} diff --git a/src/test/java/net/sf/jsqlparser/expression/AliasTest.java b/src/test/java/net/sf/jsqlparser/expression/AliasTest.java index 809aed3dd..6c65bc8a3 100644 --- a/src/test/java/net/sf/jsqlparser/expression/AliasTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/AliasTest.java @@ -20,4 +20,12 @@ void testUDTF() throws JSQLParserException { String sqlStr = "select udtf_1(words) as (a1, a2) from tab"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testLateralViewMultipleColumns() throws JSQLParserException { + String sqlStr = "SELECT k, v \n" + + "FROM table \n" + + "LATERAL VIEW EXPLODE(a) exploded_data AS k, v;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/AnalyticExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/AnalyticExpressionTest.java index 48e4fe44d..df4ef1eba 100644 --- a/src/test/java/net/sf/jsqlparser/expression/AnalyticExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/AnalyticExpressionTest.java @@ -32,4 +32,15 @@ void testRedshiftApproximate() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testDatabricks() throws JSQLParserException { + String sqlStr = "SELECT any_value(col) IGNORE NULLS FROM test;"; + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + sqlStr = "SELECT any_value(col) IGNORE NULLS FROM VALUES (NULL), (5), (20) AS tab(col);"; + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/ArrayExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/ArrayExpressionTest.java new file mode 100644 index 000000000..dd9644100 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/ArrayExpressionTest.java @@ -0,0 +1,33 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SelectItem; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ArrayExpressionTest { + + @Test + void testColumnArrayExpression() throws JSQLParserException { + String sqlStr = "SELECT a[2+1] AS a"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + SelectItem selectItem = select.getSelectItem(0); + + Column column = selectItem.getExpression(Column.class); + assertInstanceOf(ArrayConstructor.class, column.getArrayConstructor()); + } + +} diff --git a/src/test/java/net/sf/jsqlparser/expression/BooleanValueTest.java b/src/test/java/net/sf/jsqlparser/expression/BooleanValueTest.java new file mode 100644 index 000000000..93c936188 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/BooleanValueTest.java @@ -0,0 +1,49 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author tw + */ +public class BooleanValueTest { + + @Test + public void testTrueValue() { + BooleanValue value = new BooleanValue("true"); + + assertTrue(value.getValue()); + } + + @Test + public void testFalseValue() { + BooleanValue value = new BooleanValue("false"); + + assertFalse(value.getValue()); + } + + @Test + public void testWrongValueAsFalseLargeNumber() { + BooleanValue value = new BooleanValue("test"); + + assertFalse(value.getValue()); + } + + @Test + public void testNullStringValue() { + BooleanValue value = new BooleanValue(null); + + assertFalse(value.getValue()); + } +} diff --git a/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java index 806b6764a..81c2ae58a 100644 --- a/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java @@ -9,14 +9,15 @@ */ package net.sf.jsqlparser.expression; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; + import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; - /** * * @author Andreas Reichel @@ -104,4 +105,39 @@ void testParenthesisCastIssue1997() throws JSQLParserException { sqlStr = "SELECT ((foo)::text = ANY((((ARRAY['bar'])))::text[]))"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testDateTimeCast() throws JSQLParserException { + String sqlStr = "SELECT\n" + + " TIME(15, 30, 00) as time_hms,\n" + + " TIME(DATETIME '2008-12-25 15:30:00') AS time_dt,\n" + + " TIME(TIMESTAMP '2008-12-25 15:30:00+08', 'America/Los_Angeles')\n" + + "as time_tstz;"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testNestedCompositeTypeCastIssue2341() throws JSQLParserException { + String sqlStr = "SELECT\n" + + " (product_data::product_info_similarity).info.category AS category,\n" + + " COUNT(*) AS num_products\n" + + "FROM products\n" + + "GROUP BY (product_data::product_info_similarity).info.category;"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + RowGetExpression categoryAccess = + Assertions.assertInstanceOf(RowGetExpression.class, + select.getSelectItem(0).getExpression()); + Assertions.assertEquals("category", categoryAccess.getColumnName()); + + RowGetExpression infoAccess = Assertions.assertInstanceOf(RowGetExpression.class, + categoryAccess.getExpression()); + Assertions.assertEquals("info", infoAccess.getColumnName()); + + ParenthesedExpressionList parenthesedCast = + Assertions.assertInstanceOf(ParenthesedExpressionList.class, + infoAccess.getExpression()); + Assertions.assertEquals(1, parenthesedCast.size()); + Assertions.assertInstanceOf(CastExpression.class, parenthesedCast.get(0)); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java b/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java new file mode 100644 index 000000000..23f4f2d1b --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/ConnectByRootOperatorTest.java @@ -0,0 +1,32 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + + +class ConnectByRootOperatorTest { + + @Test + void testCondition() throws JSQLParserException { + //@formatter:off + String sqlStr= + "SELECT EMP_ID, EMP_NAME,\n" + + " \t CONNECT_BY_ROOT (EMP_NAME || '_' || EMP_ID) AS ROOT_MANAGER,\n" + + " \t SYS_CONNECT_BY_PATH(EMP_NAME, ' -> ') AS PATH\n" + + " FROM EMPLOYEES\n" + + " START WITH MANAGER_ID IS NULL\n" + + " CONNECT BY PRIOR EMP_ID = MANAGER_ID"; + //@formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java new file mode 100644 index 000000000..164c9e112 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/DateUnitExpressionTest.java @@ -0,0 +1,30 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.test.TestUtils; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + + +class DateUnitExpressionTest { + + @Test + void testParsing() throws JSQLParserException { + String sqlStr = "SELECT Last_Day( DATE '2024-12-31', month ) as month"; + + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Function f = select.getSelectItem(0).getExpression(Function.class); + Assertions.assertThat(f.getParameters().get(1)).isInstanceOf(DateUnitExpression.class); + } +} diff --git a/src/test/java/net/sf/jsqlparser/expression/DoubleValueTest.java b/src/test/java/net/sf/jsqlparser/expression/DoubleValueTest.java index 1ef676c6d..43150d261 100644 --- a/src/test/java/net/sf/jsqlparser/expression/DoubleValueTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/DoubleValueTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; public class DoubleValueTest { @@ -28,4 +29,14 @@ public void testEmptyValue() { new DoubleValue(""); }); } + + @Test + public void shouldSetStringValue() { + final DoubleValue doubleValue = new DoubleValue("42"); + + doubleValue.setValue(43D); + + assertEquals(43D, doubleValue.getValue()); + assertEquals("43.0", doubleValue.toString()); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/ExpressionPrecedenceTest.java b/src/test/java/net/sf/jsqlparser/expression/ExpressionPrecedenceTest.java index cbe161c43..a601f6e0a 100644 --- a/src/test/java/net/sf/jsqlparser/expression/ExpressionPrecedenceTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/ExpressionPrecedenceTest.java @@ -13,7 +13,8 @@ import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd; import net.sf.jsqlparser.expression.operators.arithmetic.Concat; import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** @@ -25,8 +26,8 @@ public class ExpressionPrecedenceTest { @Test public void testGetSign() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseExpression("1&2||3"); - assertTrue(expr instanceof Concat); - assertTrue(((Concat) expr).getLeftExpression() instanceof BitwiseAnd); - assertTrue(((Concat) expr).getRightExpression() instanceof LongValue); + Assertions.assertInstanceOf(Concat.class, expr); + Assertions.assertInstanceOf(BitwiseAnd.class, ((Concat) expr).getLeftExpression()); + Assertions.assertInstanceOf(LongValue.class, ((Concat) expr).getRightExpression()); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapterTest.java b/src/test/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapterTest.java index f7ad3994f..0654480da 100644 --- a/src/test/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapterTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapterTest.java @@ -28,8 +28,8 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; /** @@ -43,18 +43,19 @@ public void testInExpressionProblem() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil.parse("select * from foo where x in (?,?,?)"); Expression where = plainSelect.getWhere(); - where.accept(new ExpressionVisitorAdapter() { + where.accept(new ExpressionVisitorAdapter() { @Override - public void visit(InExpression expr) { - super.visit(expr); + public Void visit(InExpression expr, S parameters) { + super.visit(expr, parameters); exprList.add(expr.getLeftExpression()); exprList.add(expr.getRightExpression()); + return null; } - }); + }, null); - assertTrue(exprList.get(0) instanceof Column); - assertTrue(exprList.get(1) instanceof ExpressionList); + assertInstanceOf(Column.class, exprList.get(0)); + assertInstanceOf(ExpressionList.class, exprList.get(1)); } @Test @@ -63,18 +64,19 @@ public void testInExpression() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil .parse("select * from foo where (a,b) in (select a,b from foo2)"); Expression where = plainSelect.getWhere(); - where.accept(new ExpressionVisitorAdapter() { + where.accept(new ExpressionVisitorAdapter() { @Override - public void visit(InExpression expr) { - super.visit(expr); + public Void visit(InExpression expr, S parameters) { + super.visit(expr, parameters); exprList.add(expr.getLeftExpression()); exprList.add(expr.getRightExpression()); + return null; } - }); + }, null); - assertTrue(exprList.get(0) instanceof ExpressionList); - assertTrue(exprList.get(1) instanceof Select); + assertInstanceOf(ExpressionList.class, exprList.get(0)); + assertInstanceOf(Select.class, exprList.get(1)); } @Test @@ -83,20 +85,21 @@ public void testXorExpression() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil.parse("SELECT * FROM table WHERE foo XOR bar"); Expression where = plainSelect.getWhere(); - where.accept(new ExpressionVisitorAdapter() { + where.accept(new ExpressionVisitorAdapter() { @Override - public void visit(XorExpression expr) { - super.visit(expr); + public Void visit(XorExpression expr, S parameters) { + super.visit(expr, parameters); exprList.add(expr.getLeftExpression()); exprList.add(expr.getRightExpression()); + return null; } - }); + }, null); assertEquals(2, exprList.size()); - assertTrue(exprList.get(0) instanceof Column); + assertInstanceOf(Column.class, exprList.get(0)); assertEquals("foo", ((Column) exprList.get(0)).getColumnName()); - assertTrue(exprList.get(1) instanceof Column); + assertInstanceOf(Column.class, exprList.get(1)); assertEquals("bar", ((Column) exprList.get(1)).getColumnName()); } @@ -111,14 +114,15 @@ public static void testOracleHintExpression(String sql, String hint, boolean sin PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil.parse(sql); final OracleHint[] holder = new OracleHint[1]; assertNotNull(plainSelect.getOracleHint()); - plainSelect.getOracleHint().accept(new ExpressionVisitorAdapter() { + plainSelect.getOracleHint().accept(new ExpressionVisitorAdapter() { @Override - public void visit(OracleHint hint) { - super.visit(hint); + public Void visit(OracleHint hint, S parameters) { + super.visit(hint, parameters); holder[0] = hint; + return null; } - }); + }, null); assertNotNull(holder[0]); assertEquals(singleLine, holder[0].isSingleLine()); @@ -131,14 +135,15 @@ public void testCurrentTimestampExpression() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil .parse("select * from foo where bar < CURRENT_TIMESTAMP"); Expression where = plainSelect.getWhere(); - where.accept(new ExpressionVisitorAdapter() { + where.accept(new ExpressionVisitorAdapter() { @Override - public void visit(Column column) { - super.visit(column); + public Void visit(Column column, S parameters) { + super.visit(column, parameters); columnList.add(column.getColumnName()); + return null; } - }); + }, null); assertEquals(1, columnList.size()); assertEquals("bar", columnList.get(0)); @@ -150,14 +155,15 @@ public void testCurrentDateExpression() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil.parse("select * from foo where bar < CURRENT_DATE"); Expression where = plainSelect.getWhere(); - where.accept(new ExpressionVisitorAdapter() { + where.accept(new ExpressionVisitorAdapter() { @Override - public void visit(Column column) { - super.visit(column); + public Void visit(Column column, S parameters) { + super.visit(column, parameters); columnList.add(column.getColumnName()); + return null; } - }); + }, null); assertEquals(1, columnList.size()); assertEquals("bar", columnList.get(0)); @@ -168,10 +174,10 @@ public void testSubSelectExpressionProblem() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil .parse("SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t2.col2 = t1.col1)"); Expression where = plainSelect.getWhere(); - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); - adapter.setSelectVisitor(new SelectVisitorAdapter()); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); + adapter.setSelectVisitor(new SelectVisitorAdapter<>()); try { - where.accept(adapter); + where.accept(adapter, null); } catch (NullPointerException npe) { fail(); } @@ -180,70 +186,71 @@ public void testSubSelectExpressionProblem() throws JSQLParserException { @Test public void testCaseWithoutElse() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseExpression("CASE WHEN 1 then 0 END"); - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); - expr.accept(adapter); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); + expr.accept(adapter, null); } @Test public void testCaseWithoutElse2() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseExpression("CASE WHEN 1 then 0 ELSE -1 END"); - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); - expr.accept(adapter); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); + expr.accept(adapter, null); } @Test public void testCaseWithoutElse3() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseExpression("CASE 3+4 WHEN 1 then 0 END"); - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); - expr.accept(adapter); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); + expr.accept(adapter, null); } @Test public void testAnalyticFunctionWithoutExpression502() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseExpression("row_number() over (order by c)"); - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); - expr.accept(adapter); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); + expr.accept(adapter, null); } @Test public void testAtTimeZoneExpression() throws JSQLParserException { Expression expr = CCJSqlParserUtil .parseExpression("DATE(date1 AT TIME ZONE 'UTC' AT TIME ZONE 'australia/sydney')"); - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); - expr.accept(adapter); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); + expr.accept(adapter, null); } @Test public void testJsonFunction() throws JSQLParserException { - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); CCJSqlParserUtil.parseExpression("JSON_OBJECT( KEY 'foo' VALUE bar, KEY 'foo' VALUE bar)") - .accept(adapter); - CCJSqlParserUtil.parseExpression("JSON_ARRAY( (SELECT * from dual) )").accept(adapter); + .accept(adapter, null); + CCJSqlParserUtil.parseExpression("JSON_ARRAY( (SELECT * from dual) )").accept(adapter, + null); } @Test public void testJsonAggregateFunction() throws JSQLParserException { - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); CCJSqlParserUtil.parseExpression( "JSON_OBJECTAGG( KEY foo VALUE bar NULL ON NULL WITH UNIQUE KEYS ) FILTER( WHERE name = 'Raj' ) OVER( PARTITION BY name )") - .accept(adapter); + .accept(adapter, null); CCJSqlParserUtil.parseExpression( "JSON_ARRAYAGG( a FORMAT JSON ABSENT ON NULL ) FILTER( WHERE name = 'Raj' ) OVER( PARTITION BY name )") - .accept(adapter); + .accept(adapter, null); } @Test public void testConnectedByRootExpression() throws JSQLParserException { - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); - CCJSqlParserUtil.parseExpression("CONNECT_BY_ROOT last_name as name").accept(adapter); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); + CCJSqlParserUtil.parseExpression("CONNECT_BY_ROOT last_name as name").accept(adapter, null); } @Test public void testRowConstructor() throws JSQLParserException { - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); CCJSqlParserUtil.parseExpression( "CAST(ROW(dataid, value, calcMark) AS ROW(datapointid CHAR, value CHAR, calcMark CHAR))") - .accept(adapter); + .accept(adapter, null); } @Test @@ -251,13 +258,14 @@ public void testAllTableColumns() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil.parse("select a.* from foo a"); final AllTableColumns[] holder = new AllTableColumns[1]; Expression from = plainSelect.getSelectItems().get(0).getExpression(); - from.accept(new ExpressionVisitorAdapter() { + from.accept(new ExpressionVisitorAdapter() { @Override - public void visit(AllTableColumns all) { + public Void visit(AllTableColumns all, S parameters) { holder[0] = all; + return null; } - }); + }, null); assertNotNull(holder[0]); assertEquals("a.*", holder[0].toString()); @@ -265,11 +273,11 @@ public void visit(AllTableColumns all) { @Test public void testAnalyticExpressionWithPartialWindowElement() throws JSQLParserException { - ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter(); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); Expression expression = CCJSqlParserUtil.parseExpression( "SUM(\"Spent\") OVER (PARTITION BY \"ID\" ORDER BY \"Name\" ASC ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)"); - expression.accept(adapter); + expression.accept(adapter, null); } @Test @@ -278,18 +286,19 @@ public void testIncludesExpression() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil .parse("select id from foo where b includes ('A', 'B')"); Expression where = plainSelect.getWhere(); - where.accept(new ExpressionVisitorAdapter() { + where.accept(new ExpressionVisitorAdapter() { @Override - public void visit(IncludesExpression expr) { - super.visit(expr); + public Void visit(IncludesExpression expr, S parameters) { + super.visit(expr, parameters); exprList.add(expr.getLeftExpression()); exprList.add(expr.getRightExpression()); + return null; } - }); + }, null); - assertTrue(exprList.get(0) instanceof Column); - assertTrue(exprList.get(1) instanceof ParenthesedExpressionList); + assertInstanceOf(Column.class, exprList.get(0)); + assertInstanceOf(ParenthesedExpressionList.class, exprList.get(1)); } @Test @@ -298,17 +307,25 @@ public void testExcludesExpression() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) CCJSqlParserUtil .parse("select id from foo where b Excludes ('A', 'B')"); Expression where = plainSelect.getWhere(); - where.accept(new ExpressionVisitorAdapter() { + where.accept(new ExpressionVisitorAdapter() { @Override - public void visit(ExcludesExpression expr) { - super.visit(expr); + public Void visit(ExcludesExpression expr, S parameters) { + super.visit(expr, parameters); exprList.add(expr.getLeftExpression()); exprList.add(expr.getRightExpression()); + return null; } - }); + }, null); - assertTrue(exprList.get(0) instanceof Column); - assertTrue(exprList.get(1) instanceof ParenthesedExpressionList); + assertInstanceOf(Column.class, exprList.get(0)); + assertInstanceOf(ParenthesedExpressionList.class, exprList.get(1)); + } + + @Test + public void testIntervalWithNoExpression() throws JSQLParserException { + Expression expr = CCJSqlParserUtil.parseExpression("INTERVAL 1 DAY"); + ExpressionVisitorAdapter adapter = new ExpressionVisitorAdapter<>(); + expr.accept(adapter, null); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/FunctionKeywordArgumentTest.java b/src/test/java/net/sf/jsqlparser/expression/FunctionKeywordArgumentTest.java new file mode 100644 index 000000000..8621d4cee --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/FunctionKeywordArgumentTest.java @@ -0,0 +1,584 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for the generic keyword-argument support inside {@link Function} and the removal of the + * dedicated {@code MySQLGroupConcat} production. + *

    + * The {@code (KEYWORD expr)*} tail in InternalFunction generically captures dialect-specific + * keyword-expression pairs like {@code SEPARATOR ','} or {@code USING utf8} without requiring a + * dedicated grammar branch per keyword. + *

    + * GROUP_CONCAT is no longer a special production - it routes through InternalFunction like any + * other function, with SEPARATOR handled as a keyword argument. + */ +class FunctionKeywordArgumentTest { + + // ==================================================================== + // Roundtrip parse tests - parameterised + // ==================================================================== + + static Stream roundtripSqlProvider() { + return Stream.of( + + // -- GROUP_CONCAT: basic SEPARATOR (was MySQLGroupConcat) ---- + // + // These previously required the dedicated MySQLGroupConcat + // production. Now handled by InternalFunction + keyword args. + + Arguments.of( + "GROUP_CONCAT with SEPARATOR string literal", + "SELECT GROUP_CONCAT(col SEPARATOR ',') FROM t"), + + Arguments.of( + "GROUP_CONCAT with DISTINCT and SEPARATOR", + "SELECT GROUP_CONCAT(DISTINCT col SEPARATOR ',') FROM t"), + + Arguments.of( + "GROUP_CONCAT with ORDER BY and SEPARATOR", + "SELECT GROUP_CONCAT(col ORDER BY col SEPARATOR ',') FROM t"), + + Arguments.of( + "GROUP_CONCAT with DISTINCT, ORDER BY and SEPARATOR", + "SELECT GROUP_CONCAT(DISTINCT col ORDER BY col ASC SEPARATOR ';') FROM t"), + + Arguments.of( + "GROUP_CONCAT multiple expressions with SEPARATOR", + "SELECT GROUP_CONCAT(a, b SEPARATOR ',') FROM t"), + + // -- Original bug: SEPARATOR with expression, not just literal + + Arguments.of( + "GROUP_CONCAT SEPARATOR CHR(10) - the original bug", + "SELECT GROUP_CONCAT(description SEPARATOR CHR(10)) FROM t"), + + Arguments.of( + "GROUP_CONCAT SEPARATOR CONCAT expression", + "SELECT GROUP_CONCAT(col SEPARATOR CONCAT(',', ' ')) FROM t"), + + Arguments.of( + "GROUP_CONCAT SEPARATOR with hex literal", + "SELECT GROUP_CONCAT(col SEPARATOR 0x0A) FROM t"), + + Arguments.of( + "GROUP_CONCAT SEPARATOR with empty string", + "SELECT GROUP_CONCAT(col SEPARATOR '') FROM t"), + + Arguments.of( + "GROUP_CONCAT SEPARATOR with column reference", + "SELECT GROUP_CONCAT(col SEPARATOR sep_col) FROM t"), + + // -- GitHub Issue #688: CONVERT(expr USING charset) ---------- + // https://github.com/JSQLParser/JSqlParser/issues/688 + // "select * from a order by convert(a.name using gbk) desc" + // Failed: ParseException at "(" + + Arguments.of( + "Issue #688: CONVERT with USING charset", + "SELECT CONVERT(a.name USING gbk) FROM t"), + + Arguments.of( + "Issue #688: CONVERT USING in ORDER BY", + "SELECT * FROM a ORDER BY CONVERT(a.name USING gbk) DESC"), + + Arguments.of( + "Issue #688: CONVERT USING utf8mb4", + "SELECT CONVERT(col USING utf8mb4) FROM t"), + + // -- GitHub Issue #1257: CONVERT(name USING GBK) ------------- + // https://github.com/JSQLParser/JSqlParser/issues/1257 + // Same root cause as #688, different reporter. + + Arguments.of( + "Issue #1257: CONVERT USING GBK with WHERE clause", + "SELECT id, name FROM tbl_template WHERE name LIKE ? ORDER BY CONVERT(name USING GBK) ASC"), + + // -- Generic SEPARATOR on non-GROUP_CONCAT functions --------- + + Arguments.of( + "SEPARATOR with string literal on generic function", + "SELECT list_agg(col SEPARATOR ',') FROM t"), + + Arguments.of( + "SEPARATOR with CHR() on generic function", + "SELECT list_agg(col SEPARATOR CHR(10)) FROM t"), + + Arguments.of( + "ORDER BY then SEPARATOR on generic function", + "SELECT my_agg(col ORDER BY col SEPARATOR ',') FROM t"), + + Arguments.of( + "ORDER BY DESC then SEPARATOR with function expr", + "SELECT my_agg(col ORDER BY col DESC SEPARATOR CHR(10)) FROM t"), + + Arguments.of( + "ORDER BY multiple columns then SEPARATOR", + "SELECT my_agg(col ORDER BY a ASC, b DESC SEPARATOR '|') FROM t"), + + // -- DISTINCT / UNIQUE + SEPARATOR --------------------------- + + Arguments.of( + "DISTINCT with SEPARATOR", + "SELECT my_agg(DISTINCT col SEPARATOR ',') FROM t"), + + Arguments.of( + "UNIQUE with SEPARATOR", + "SELECT my_agg(UNIQUE col SEPARATOR ';') FROM t"), + + Arguments.of( + "DISTINCT + ORDER BY + SEPARATOR", + "SELECT my_agg(DISTINCT col ORDER BY col SEPARATOR ',') FROM t"), + + // -- Multiple expression-list args + keyword arg ------------- + + Arguments.of( + "Two args then SEPARATOR", + "SELECT my_agg(col, ',' SEPARATOR CHR(10)) FROM t"), + + Arguments.of( + "Three args then DELIMITER", + "SELECT custom_agg(a, b, c DELIMITER '|') FROM t"), + + // -- USING on other functions -------------------------------- + + Arguments.of( + "USING with identifier", + "SELECT transcode(expr USING utf8mb4) FROM t"), + + Arguments.of( + "USING with quoted identifier", + "SELECT transcode('hello' USING utf8) FROM t"), + + Arguments.of( + "TRANSLATE with USING", + "SELECT translate_func(col USING unicode_to_latin) FROM t"), + + // -- FORMAT keyword (SQL Server, Snowflake, BigQuery) -------- + + Arguments.of( + "FORMAT with string literal", + "SELECT to_json(col FORMAT 'json') FROM t"), + + Arguments.of( + "FORMAT with identifier", + "SELECT fmt_func(col FORMAT json) FROM t"), + + // -- ENCODING keyword ---------------------------------------- + + Arguments.of( + "ENCODING with string literal", + "SELECT encode_func(col ENCODING 'UTF-8') FROM t"), + + // -- DELIMITER keyword (Redshift, Vertica) ------------------- + + Arguments.of( + "DELIMITER with pipe", + "SELECT str_agg(col DELIMITER '|') FROM t"), + + Arguments.of( + "DELIMITER with CHR", + "SELECT str_agg(col DELIMITER CHR(9)) FROM t"), + + Arguments.of( + "ORDER BY then DELIMITER", + "SELECT str_agg(col ORDER BY col DELIMITER '|') FROM t"), + + // -- Multiple keyword arguments ------------------------------ + + Arguments.of( + "Two keyword args: SEPARATOR + ENCODING", + "SELECT custom_func(col SEPARATOR ',' ENCODING 'utf8') FROM t"), + + Arguments.of( + "Three keyword args", + "SELECT custom_func(col FORMAT 'json' ENCODING 'utf8' MODE 'strict') FROM t"), + + // -- Complex separator expressions --------------------------- + + Arguments.of( + "SEPARATOR with nested function call", + "SELECT agg_func(col SEPARATOR REPLACE(CHR(10), CHR(13), '')) FROM t"), + + Arguments.of( + "SEPARATOR with CASE expression", + "SELECT agg_func(col SEPARATOR CASE WHEN x = 1 THEN ',' ELSE ';' END) FROM t"), + + Arguments.of( + "SEPARATOR with arithmetic expression", + "SELECT agg_func(col SEPARATOR 1 + 2) FROM t"), + + // -- Schema-qualified function names ------------------------- + + Arguments.of( + "Schema-qualified function with SEPARATOR", + "SELECT myschema.agg_func(col SEPARATOR ',') FROM t"), + + Arguments.of( + "Two-level schema with SEPARATOR", + "SELECT cat.myschema.agg_func(col SEPARATOR ',') FROM t"), + + // -- Integration with other InternalFunction clauses --------- + + Arguments.of( + "ALL + ORDER BY + SEPARATOR", + "SELECT my_agg(ALL col ORDER BY col SEPARATOR ',') FROM t"), + + // -- Multi-value keyword arguments (USING col1, col2, ...) --- + // Oracle Data Mining functions use USING followed by a + // comma-separated column list. + + Arguments.of( + "Oracle PREDICTION with USING column list", + "SELECT PREDICTION(dt_sh_clas_sample USING cust_marital_status, education, household_size) FROM t"), + + Arguments.of( + "Oracle PREDICTION in WHERE clause", + "SELECT cust_gender, COUNT(*) AS cnt FROM mining_data_apply_v WHERE PREDICTION(dt_sh_clas_sample USING cust_marital_status, education, household_size) = 1 GROUP BY cust_gender ORDER BY cust_gender"), + + Arguments.of( + "Oracle PREDICTION_PROBABILITY with USING", + "SELECT PREDICTION_PROBABILITY(my_model USING col1, col2, col3) FROM t"), + + Arguments.of( + "Oracle CLUSTER_ID with USING", + "SELECT CLUSTER_ID(my_model USING col1, col2) FROM t"), + + Arguments.of( + "USING with single column", + "SELECT my_func(model USING col1) FROM t"), + + Arguments.of( + "USING with many columns", + "SELECT my_func(model USING a, b, c, d, e) FROM t"), + + // -- Keyword arg in different SQL contexts ------------------- + + Arguments.of( + "Keyword arg function in WHERE", + "SELECT * FROM t WHERE my_agg(col SEPARATOR ',') = 'a,b,c'"), + + Arguments.of( + "Keyword arg function in SELECT + alias", + "SELECT my_agg(col SEPARATOR ',') AS concatenated FROM t"), + + // -- Edge cases ---------------------------------------------- + + Arguments.of( + "SEPARATOR with parenthesised expression", + "SELECT agg_func(col SEPARATOR (CHR(10))) FROM t"), + + Arguments.of( + "Keyword arg in function with chained call", + "SELECT quantile_agg(col SEPARATOR ',')(cost) FROM t")); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("roundtripSqlProvider") + void testRoundtrip(String label, String sql) throws JSQLParserException { + // First parse + Statement stmt = CCJSqlParserUtil.parse(sql); + assertNotNull(stmt, "Parse returned null for: " + sql); + + // Deparse + String deparsed = stmt.toString(); + assertNotNull(deparsed, "toString returned null for: " + sql); + + // Second parse of deparsed output + Statement stmt2 = CCJSqlParserUtil.parse(deparsed); + assertNotNull(stmt2, "Re-parse returned null for deparsed: " + deparsed); + + // Structural equivalence + assertEquals(deparsed, stmt2.toString(), + "Roundtrip mismatch for [" + label + "]:\n" + + " original: " + sql + "\n" + + " deparsed: " + deparsed + "\n" + + " reparsed: " + stmt2); + } + + // ==================================================================== + // GitHub Issue #688 / #1257 - CONVERT(expr USING charset) + // These were ParseExceptions before the generic keyword-arg tail. + // ==================================================================== + + @Test + void testIssue688_ConvertUsingGbk() throws JSQLParserException { + // Exact SQL from issue #688 — was a ParseException before + String sql = "SELECT * FROM a ORDER BY CONVERT(a.name USING gbk) DESC"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertNotNull(stmt); + // Roundtrip + String deparsed = stmt.toString(); + assertEquals(deparsed, CCJSqlParserUtil.parse(deparsed).toString()); + } + + @Test + void testIssue1257_ConvertUsingGBK() throws JSQLParserException { + // Exact SQL from issue #1257 + String sql = + "SELECT id, name FROM tbl_template WHERE name LIKE ? ORDER BY CONVERT(name USING GBK) ASC"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertNotNull(stmt); + } + + // ==================================================================== + // GROUP_CONCAT migration - now parsed as Function, not MySQLGroupConcat + // ==================================================================== + + @Test + void testGroupConcatParsedAsFunction() throws JSQLParserException { + String sql = "SELECT GROUP_CONCAT(col SEPARATOR ',') FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + + assertNotNull(func, "GROUP_CONCAT should parse as Function"); + assertEquals("GROUP_CONCAT", func.getName()); + + // SEPARATOR should be a keyword argument + List kwArgs = func.getKeywordArguments(); + assertNotNull(kwArgs); + assertEquals(1, kwArgs.size()); + assertEquals("SEPARATOR", kwArgs.get(0).getKeyword().toUpperCase()); + assertEquals("','", kwArgs.get(0).getExpression().toString()); + } + + @Test + void testGroupConcatDistinctOrderBySeparator() throws JSQLParserException { + String sql = "SELECT GROUP_CONCAT(DISTINCT col ORDER BY col ASC SEPARATOR ';') FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + + assertNotNull(func); + assertTrue(func.isDistinct(), "DISTINCT should be set"); + assertNotNull(func.getOrderByElements(), "ORDER BY should be present"); + + List kwArgs = func.getKeywordArguments(); + assertNotNull(kwArgs); + assertEquals("SEPARATOR", kwArgs.get(0).getKeyword().toUpperCase()); + } + + @Test + void testGroupConcatSeparatorExpression() throws JSQLParserException { + // The original bug: SEPARATOR with a function call, not just a string literal + String sql = "SELECT GROUP_CONCAT(description SEPARATOR CHR(10)) FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + + assertNotNull(func); + List kwArgs = func.getKeywordArguments(); + assertNotNull(kwArgs); + assertEquals(1, kwArgs.size()); + + Expression separatorExpr = kwArgs.get(0).getExpression(); + assertInstanceOf(Function.class, separatorExpr, + "SEPARATOR expression should be a Function call (CHR)"); + assertEquals("CHR", ((Function) separatorExpr).getName()); + } + + // ==================================================================== + // AST structure assertions + // ==================================================================== + + @Test + void testKeywordArgumentsPresentInAST() throws JSQLParserException { + String sql = "SELECT my_agg(col ORDER BY col SEPARATOR ',') FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + + assertNotNull(func); + assertEquals("my_agg", func.getName()); + + // ORDER BY should be captured by the explicit clause + assertNotNull(func.getOrderByElements()); + assertFalse(func.getOrderByElements().isEmpty()); + + // SEPARATOR should be captured as a generic keyword argument + List kwArgs = func.getKeywordArguments(); + assertNotNull(kwArgs); + assertEquals(1, kwArgs.size()); + assertEquals("SEPARATOR", kwArgs.get(0).getKeyword().toUpperCase()); + assertEquals("','", kwArgs.get(0).getExpression().toString()); + } + + @Test + void testMultipleKeywordArguments() throws JSQLParserException { + String sql = "SELECT custom_func(col FORMAT 'json' ENCODING 'utf8') FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + + assertNotNull(func); + List kwArgs = func.getKeywordArguments(); + assertNotNull(kwArgs); + assertEquals(2, kwArgs.size()); + + assertEquals("FORMAT", kwArgs.get(0).getKeyword().toUpperCase()); + assertEquals("'json'", kwArgs.get(0).getExpression().toString()); + + assertEquals("ENCODING", kwArgs.get(1).getKeyword().toUpperCase()); + assertEquals("'utf8'", kwArgs.get(1).getExpression().toString()); + } + + @Test + void testMultiValueKeywordArgument_OraclePrediction() throws JSQLParserException { + String sql = "SELECT PREDICTION(my_model USING col1, col2, col3) FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + + assertNotNull(func); + assertEquals("PREDICTION", func.getName()); + + List kwArgs = func.getKeywordArguments(); + assertNotNull(kwArgs); + assertEquals(1, kwArgs.size()); + + // USING col1, col2, col3 — multi-value, kept as ExpressionList + assertEquals("USING", kwArgs.get(0).getKeyword().toUpperCase()); + Expression usingExpr = kwArgs.get(0).getExpression(); + assertInstanceOf(ExpressionList.class, + usingExpr, "Multi-value keyword arg should be an ExpressionList"); + assertEquals("col1, col2, col3", usingExpr.toString()); + } + + @Test + void testGetKeywordArgumentValue() throws JSQLParserException { + String sql = "SELECT my_agg(col SEPARATOR ',' ENCODING 'utf8') FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + + assertNotNull(func); + Expression sep = func.getKeywordArgumentValue("SEPARATOR"); + assertNotNull(sep, "Should find SEPARATOR by name"); + assertEquals("','", sep.toString()); + + Expression enc = func.getKeywordArgumentValue("ENCODING"); + assertNotNull(enc, "Should find ENCODING by name"); + + Expression missing = func.getKeywordArgumentValue("NONEXISTENT"); + assertNull(missing, "Non-existent keyword should return null"); + } + + @Test + void testKeywordArgumentPreservedInAnalyticExpression() throws JSQLParserException { + String sql = "SELECT my_agg(col SEPARATOR ',') OVER (PARTITION BY grp) FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + + PlainSelect select = getPlainSelect(stmt); + Expression expr = select.getSelectItems().get(0).getExpression(); + + assertInstanceOf(AnalyticExpression.class, expr); + AnalyticExpression analytic = (AnalyticExpression) expr; + + List kwArgs = analytic.getKeywordArguments(); + assertNotNull(kwArgs, + "Keyword arguments should be copied from Function to AnalyticExpression"); + assertEquals(1, kwArgs.size()); + assertEquals("SEPARATOR", kwArgs.get(0).getKeyword().toUpperCase()); + } + + // ==================================================================== + // Negative / regression tests - must NOT break existing clauses + // ==================================================================== + + @Test + void testExplicitClausesStillWork() throws JSQLParserException { + String sql = + "SELECT LISTAGG(col, ',' ON OVERFLOW TRUNCATE '...' WITH COUNT) FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertNotNull(stmt); + assertEquals(stmt.toString(), CCJSqlParserUtil.parse(stmt.toString()).toString()); + } + + @Test + void testOrderByStillWorks() throws JSQLParserException { + String sql = "SELECT my_func(col ORDER BY col ASC) FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + assertNotNull(func); + assertNotNull(func.getOrderByElements()); + assertNull(func.getKeywordArguments(), + "No keyword args - ORDER BY should be handled by explicit clause"); + } + + @Test + void testIgnoreNullsStillWorks() throws JSQLParserException { + String sql = "SELECT my_func(col IGNORE NULLS) FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + assertNotNull(func); + assertEquals(Function.NullHandling.IGNORE_NULLS, func.getNullHandling()); + assertNull(func.getKeywordArguments()); + } + + @Test + void testNoKeywordArguments() throws JSQLParserException { + String sql = "SELECT MAX(col) FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + Function func = extractFirstFunction(stmt); + assertNotNull(func); + assertNull(func.getKeywordArguments(), + "Normal function should have null keywordArguments"); + } + + @Test + void testOperatorsNotSwallowed() throws JSQLParserException { + // Regression: f1(a1=1) must NOT treat "=" as a keyword arg + String sql = "SELECT f1(a1 = 1).f2 = 1 FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertNotNull(stmt); + assertEquals(stmt.toString(), CCJSqlParserUtil.parse(stmt.toString()).toString()); + } + + @Test + void testCaseEndNotSwallowed() throws JSQLParserException { + // Regression: CASE...END='pastdue' must not lose the = comparison + String sql = "SELECT CASE WHEN a = 1 THEN 'x' ELSE 'y' END = 'x' FROM t"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertNotNull(stmt); + assertEquals(stmt.toString(), CCJSqlParserUtil.parse(stmt.toString()).toString()); + } + + // ==================================================================== + // Helpers + // ==================================================================== + + private static PlainSelect getPlainSelect(Statement stmt) { + assertInstanceOf(Select.class, stmt); + Select select = (Select) stmt; + assertInstanceOf(PlainSelect.class, select); + return (PlainSelect) select; + } + + private static Function extractFirstFunction(Statement stmt) { + PlainSelect select = getPlainSelect(stmt); + Expression expr = select.getSelectItems().get(0).getExpression(); + if (expr instanceof Function) { + return (Function) expr; + } + return null; + } + +} diff --git a/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java index cd0f17278..deb508c19 100644 --- a/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java @@ -9,10 +9,16 @@ */ package net.sf.jsqlparser.expression; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class FunctionTest { @Test @@ -75,4 +81,80 @@ void testSubSelectArrayWithoutKeywordParameter() throws JSQLParserException { " UNNEST(addresses) AS email"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testSubSelectParameterWithoutParentheses() throws JSQLParserException { + String sqlStr = "SELECT COALESCE(SELECT mycolumn FROM mytable, 0)"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withUnparenthesizedSubSelects(true)); + } + + @Test + void testSimpleFunctionIssue2059() throws JSQLParserException { + String sqlStr = "select count(*) from zzz"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, parser -> { + parser.withAllowComplexParsing(false); + }); + } + + @ParameterizedTest + @ValueSource(strings = { + "select LISTAGG(field, ',' on overflow truncate '...') from dual", + "select LISTAGG(field, ',' on overflow truncate '...' with count) from dual", + "select LISTAGG(field, ',' on overflow truncate '...' without count) from dual", + "select LISTAGG(field, ',' on overflow error) from dual", "SELECT department, \n" + + " LISTAGG(name, ', ' ON OVERFLOW TRUNCATE '... (truncated)' WITH COUNT) WITHIN GROUP (ORDER BY name)\n" + + + " AS employee_names\n" + + "FROM employees\n" + + "GROUP BY department;" + }) + void testListAggOnOverflow(String sqlStr) throws Exception { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "select RTRIM('string')", + "select LTRIM('string')", + "select RTRIM(field) from dual", + "select LTRIM(field) from dual" + }) + void testTrimFunctions(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void TestIntervalParameterIssue2272() throws JSQLParserException { + String sqlStr = + "SELECT DATE_SUB('2025-06-19', INTERVAL QUARTER(STR_TO_DATE('20250619', '%Y%m%d')) - 1 QUARTER) from dual"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testAesDecryptWithKeyExpressionParameter() throws JSQLParserException { + String expression = "aes_decrypt(from_base64(entity), KEY chain.entity)"; + TestUtils.assertExpressionCanBeParsedAndDeparsed(expression, true); + + Function function = (Function) CCJSqlParserUtil.parseExpression(expression); + KeyExpression keyExpression = + assertInstanceOf(KeyExpression.class, function.getParameters().get(1)); + assertEquals("chain.entity", keyExpression.getExpression().toString()); + + function.accept(new ExpressionVisitorAdapter<>(), null); + } + + @Test + void testAesDecryptWithKeyExpressionInSelect() throws JSQLParserException { + String sqlStr = "SELECT t1.entity, SUM(t2.balance) AS total_balance\n" + + "FROM (\n" + + " SELECT DISTINCT address, aes_decrypt(from_base64(entity), KEY chain.entity) AS entity\n" + + " FROM bch_entity\n" + + ") t1\n" + + "JOIN bch_address_token_statis t2\n" + + "ON t1.address = t2.address\n" + + "GROUP BY t1.entity"; + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/FunctionWithBooleanParameterTest.java b/src/test/java/net/sf/jsqlparser/expression/FunctionWithBooleanParameterTest.java index 87b9982b9..3c726619c 100644 --- a/src/test/java/net/sf/jsqlparser/expression/FunctionWithBooleanParameterTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/FunctionWithBooleanParameterTest.java @@ -21,8 +21,7 @@ */ public class FunctionWithBooleanParameterTest { - public FunctionWithBooleanParameterTest() { - } + public FunctionWithBooleanParameterTest() {} @Test public void testParseOpLowerTotally() throws Exception { diff --git a/src/test/java/net/sf/jsqlparser/expression/IntervalExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/IntervalExpressionTest.java new file mode 100644 index 000000000..30645789f --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/IntervalExpressionTest.java @@ -0,0 +1,27 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + + +class IntervalExpressionTest { + + @Test + void testExtractExpressionIssue2172() throws JSQLParserException { + String sqlStr = "select INTERVAL Extract( DAY from Now()) - 1 DAY"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + sqlStr = "SELECT UNIX_TIMESTAMP(date_sub(date_sub(date_format(now(),'%y-%m-%d'),interval extract(day from now())-1 day),interval 1 month))*1000"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java index 860a69382..5fc72bea8 100644 --- a/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java @@ -10,14 +10,18 @@ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.PlainSelect; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; class JsonExpressionTest { @Test - void testIssue1792() throws JSQLParserException, InterruptedException { + void testIssue1792() throws JSQLParserException { String sqlStr = "SELECT ''::JSON -> 'obj'::TEXT"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); @@ -35,6 +39,22 @@ void testIssue1792() throws JSQLParserException, InterruptedException { assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @Test + void testSnowflakeGetOperator() throws JSQLParserException { + // https://docs.snowflake.com/en/user-guide/querying-semistructured + String sqlStr = "SELECT v:'attr[0].name' FROM vartab;"; + PlainSelect st = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertInstanceOf(JsonExpression.class, st.getSelectItem(0).getExpression()); + } + + @Test + void testDataBricksExtractPathOperator() throws JSQLParserException { + // https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-json-path-expression + String sqlStr = "SELECT C1:PRICE J FROM VALUES('{\"price\":5}')AS T(C1)"; + PlainSelect st = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertInstanceOf(JsonExpression.class, st.getSelectItem(0).getExpression()); + } + @Test void testParenthesedJsonExpressionsIssue1792() throws JSQLParserException { String sqlStr = @@ -108,4 +128,56 @@ void testParenthesedJsonExpressionsIssue1792() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT ( JSONB_AGG(variables) " + + " FILTER (WHERE variables IS NOT NULL) " + + " OVER (PARTITION BY deviceid ORDER BY time)->>-1 )::JSONB AS variables\n" + + "FROM devices\n" + + ";", + "SELECT ( JSONB_AGG(variables) " + + " FILTER (WHERE variables IS NOT NULL) " + + " OVER (PARTITION BY deviceid ORDER BY time)->>(0-1) )::JSONB AS variables\n" + + + "FROM devices\n" + + ";", + "SELECT ( JSONB_AGG(variables) " + + " FILTER (WHERE variables IS NOT NULL) " + + " OVER (PARTITION BY deviceid ORDER BY time)->>(jsonb_array_length(JSONB_AGG(variables) FILTER (WHERE variables IS NOT NULL) OVER (PARTITION BY deviceid ORDER BY time))-1) )::JSONB AS variables\n" + + + "FROM devices\n" + + ";"}) + void testIssue2054(String sqlStr) throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testIssue2181() throws JSQLParserException { + String sqlStr = + "SELECT\n" + + " 1\n" + + "FROM\n" + + " public.tbl\n" + + "WHERE\n" + + " fieldd ->> 'att1' = 1\n" + + " OR fieldd ->> 'att1' = 1\n" + + " OR fieldd ->> 'att1' = 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + " OR fieldd::jsonb -> 'att2' @> 1\n" + + "ORDER BY\n" + + " att ASC\n" + + "LIMIT\n" + + " 1"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java index d27378658..03a6e486b 100644 --- a/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java @@ -11,9 +11,20 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.parser.feature.Feature; +import net.sf.jsqlparser.parser.feature.FeatureConfiguration; +import net.sf.jsqlparser.statement.select.AllColumns; +import net.sf.jsqlparser.statement.select.AllTableColumns; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.TableFunction; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; /** * @@ -25,7 +36,8 @@ public class JsonFunctionTest { public void testObjectAgg() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed( "SELECT JSON_OBJECTAGG( KEY foo VALUE bar) FROM dual ", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT JSON_OBJECTAGG( foo:bar) FROM dual ", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT JSON_OBJECTAGG( foo:bar) FROM dual ", + true); TestUtils.assertSqlCanBeParsedAndDeparsed( "SELECT JSON_OBJECTAGG( foo:bar FORMAT JSON) FROM dual ", true); TestUtils.assertSqlCanBeParsedAndDeparsed( @@ -61,17 +73,19 @@ public void testObjectBuilder() throws JSQLParserException { keyValuePair1.setUsingValueKeyword(true); f.add(keyValuePair1.withUsingFormatJson(true)); - JsonKeyValuePair keyValuePair2 = new JsonKeyValuePair("foo", "bar", false, false).withUsingKeyKeyword(true).withUsingValueKeyword(true).withUsingFormatJson(false); + JsonKeyValuePair keyValuePair2 = new JsonKeyValuePair("foo", "bar", false, false) + .withUsingKeyKeyword(true).withUsingValueKeyword(true).withUsingFormatJson(false); // this should work because we compare based on KEY only - Assertions.assertEquals(keyValuePair1, keyValuePair2); + assertEquals(keyValuePair1, keyValuePair2); // this must fail because all the properties are considered Assertions.assertNotEquals(keyValuePair1.toString(), keyValuePair2.toString()); - JsonKeyValuePair keyValuePair3 = new JsonKeyValuePair("foo", "bar", false, false).withUsingKeyKeyword(false).withUsingValueKeyword(false).withUsingFormatJson(false); - Assertions.assertNotNull(keyValuePair3); - Assertions.assertEquals(keyValuePair3, keyValuePair3); + JsonKeyValuePair keyValuePair3 = new JsonKeyValuePair("foo", "bar", false, false) + .withUsingKeyKeyword(false).withUsingValueKeyword(false).withUsingFormatJson(false); + assertNotNull(keyValuePair3); + assertEquals(keyValuePair3, keyValuePair3); Assertions.assertNotEquals(keyValuePair3, f); Assertions.assertTrue(keyValuePair3.hashCode() != 0); @@ -87,10 +101,11 @@ public void testArrayBuilder() throws JSQLParserException { JsonFunctionExpression expression1 = new JsonFunctionExpression(new NullValue()); expression1.setUsingFormatJson(true); - JsonFunctionExpression expression2 = new JsonFunctionExpression(new NullValue()).withUsingFormatJson( - true); + JsonFunctionExpression expression2 = + new JsonFunctionExpression(new NullValue()).withUsingFormatJson( + true); - Assertions.assertEquals(expression1.toString(), expression2.toString()); + assertEquals(expression1.toString(), expression2.toString()); f.add(expression1); f.add(expression2); @@ -101,9 +116,11 @@ public void testArrayAgg() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT JSON_ARRAYAGG( a ) FROM dual ", true); TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT JSON_ARRAYAGG( a ORDER BY a ) FROM dual ", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT JSON_ARRAYAGG( a NULL ON NULL ) FROM dual ", + TestUtils.assertSqlCanBeParsedAndDeparsed( + "SELECT JSON_ARRAYAGG( a NULL ON NULL ) FROM dual ", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT JSON_ARRAYAGG( a FORMAT JSON ) FROM dual ", + TestUtils.assertSqlCanBeParsedAndDeparsed( + "SELECT JSON_ARRAYAGG( a FORMAT JSON ) FROM dual ", true); TestUtils.assertSqlCanBeParsedAndDeparsed( "SELECT JSON_ARRAYAGG( a FORMAT JSON NULL ON NULL ) FROM dual ", true); @@ -125,9 +142,14 @@ public void testArrayAgg() throws JSQLParserException { @Test public void testObject() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "WITH Items AS (SELECT 'hello' AS key, 'world' AS value)\n" + + "SELECT JSON_OBJECT(key, value) AS json_data FROM Items", + true); TestUtils.assertSqlCanBeParsedAndDeparsed( "SELECT JSON_OBJECT( KEY 'foo' VALUE bar, KEY 'foo' VALUE bar) FROM dual ", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT JSON_OBJECT( 'foo' : bar, 'foo' : bar) FROM dual ", + TestUtils.assertSqlCanBeParsedAndDeparsed( + "SELECT JSON_OBJECT( 'foo' : bar, 'foo' : bar) FROM dual ", true); TestUtils.assertSqlCanBeParsedAndDeparsed( "SELECT JSON_OBJECT( 'foo':bar, 'foo':bar FORMAT JSON) FROM dual ", true); @@ -153,13 +175,71 @@ public void testObject() throws JSQLParserException { TestUtils.assertExpressionCanBeParsedAndDeparsed("json_object()", true); } + @Test + public void nestedObjects() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "WITH Items AS (SELECT 'hello' AS key, 'world' AS value), \n" + + " SubItems AS (SELECT 'nestedValue' AS 'nestedKey', 'nestedWorld' AS nestedValue)\n" + + + "SELECT JSON_OBJECT(key: value, nested : (SELECT JSON_OBJECT(nestedKey, nestedValue) FROM SubItems)) AS json_data FROM Items", + true); + } + + @ParameterizedTest + @ValueSource(strings = { + // AllColumns + "SELECT JSON_OBJECT(*) FROM employees", + "SELECT JSON_OBJECT(* ABSENT ON NULL) FROM employees", + + // AllTableColumns + "SELECT JSON_OBJECT(e.*) FROM employees e", + "SELECT JSON_OBJECT(e.*, d.* NULL ON NULL) FROM employees e, departments d", + "SELECT JSON_OBJECT(e.* WITH UNIQUE KEYS) FROM employees e", + + // Single Column as entry + "SELECT JSON_OBJECT(first_name, last_name, address) FROM employees t1", + "SELECT JSON_OBJECT(t1.first_name, t1.last_name, t1.address) FROM employees t1", + "SELECT JSON_OBJECT(first_name, last_name FORMAT JSON, address) FROM employees t1", + "SELECT JSON_OBJECT(t1.first_name, t1.last_name FORMAT JSON, t1.address FORMAT JSON) FROM employees t1", + + // STRICT Keyword + "SELECT JSON_OBJECT( 'foo':bar, 'fob':baz FORMAT JSON STRICT ) FROM dual", + "SELECT JSON_OBJECT( 'foo':bar FORMAT JSON, 'fob':baz STRICT ) FROM dual", + "SELECT JSON_OBJECT( 'foo':bar, 'fob':baz NULL ON NULL STRICT WITH UNIQUE KEYS) FROM dual" + }) + void testObjectOracle(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + // BigQuery EXCEPT/REPLACE are not allowed here + "SELECT JSON_OBJECT(* EXCEPT(first_name)) FROM employees", + "SELECT JSON_OBJECT(* EXCLUDE(first_name)) FROM employees", + "SELECT JSON_OBJECT(* REPLACE(\"first_name\" AS first_name)) FROM employees", + + // FORMAT JSON is not allowed on wildcards + "SELECT JSON_OBJECT(* FORMAT JSON) FROM employees", + "SELECT JSON_OBJECT(e.* FORMAT JSON) FROM employees e", + + // Value is not allowed on wildcards + "SELECT JSON_OBJECT(* : bar) FROM employees", + "SELECT JSON_OBJECT(e.* VALUE bar) FROM employees e", + "SELECT JSON_OBJECT(KEY e.* VALUE bar) FROM employees e", + }) + void testInvalidObjectOracle(String sqlStr) { + assertThrows(JSQLParserException.class, () -> CCJSqlParserUtil.parse(sqlStr)); + } + @Test public void testObjectWithExpression() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed( - "SELECT JSON_OBJECT( KEY 'foo' VALUE cast( bar AS VARCHAR(40)), KEY 'foo' VALUE bar) FROM dual ", true); + "SELECT JSON_OBJECT( KEY 'foo' VALUE cast( bar AS VARCHAR(40)), KEY 'foo' VALUE bar) FROM dual ", + true); TestUtils.assertSqlCanBeParsedAndDeparsed( - "SELECT JSON_ARRAYAGG(obj) FROM (SELECT trt.relevance_id,JSON_OBJECT('id',CAST(trt.id AS CHAR),'taskName',trt.task_name,'openStatus',trt.open_status,'taskSort',trt.task_sort) as obj FROM tb_review_task trt ORDER BY trt.task_sort ASC)", true); + "SELECT JSON_ARRAYAGG(obj) FROM (SELECT trt.relevance_id,JSON_OBJECT('id',CAST(trt.id AS CHAR),'taskName',trt.task_name,'openStatus',trt.open_status,'taskSort',trt.task_sort) as obj FROM tb_review_task trt ORDER BY trt.task_sort ASC)", + true); } @Test @@ -168,7 +248,8 @@ public void testObjectIssue1504() throws JSQLParserException { "SELECT JSON_OBJECT(key 'person' value tp.account) obj", true); TestUtils.assertSqlCanBeParsedAndDeparsed( - "SELECT JSON_OBJECT(key 'person' value tp.account, key 'person' value tp.account) obj", true); + "SELECT JSON_OBJECT(key 'person' value tp.account, key 'person' value tp.account) obj", + true); TestUtils.assertSqlCanBeParsedAndDeparsed( "SELECT JSON_OBJECT( 'person' : tp.account) obj", true); @@ -180,7 +261,8 @@ public void testObjectIssue1504() throws JSQLParserException { "SELECT JSON_OBJECT( 'person' : '1', 'person' : '2') obj", true); TestUtils.assertSqlCanBeParsedAndDeparsed( - "SELECT JSON_OBJECT( 'person' VALUE tp.person, 'account' VALUE tp.account) obj", true); + "SELECT JSON_OBJECT( 'person' VALUE tp.person, 'account' VALUE tp.account) obj", + true); } @Test @@ -202,19 +284,201 @@ public void testArrayWithNullExpressions() throws JSQLParserException { TestUtils.assertExpressionCanBeParsedAndDeparsed("JSON_ARRAY( 1, 2, 3 )", true); TestUtils.assertExpressionCanBeParsedAndDeparsed("json_array(null on null)", true); TestUtils.assertExpressionCanBeParsedAndDeparsed("json_array(null null on null)", true); - TestUtils.assertExpressionCanBeParsedAndDeparsed("json_array(null, null null on null)", true); + TestUtils.assertExpressionCanBeParsedAndDeparsed("json_array(null, null null on null)", + true); TestUtils.assertExpressionCanBeParsedAndDeparsed("json_array()", true); } + @Test + public void testJsonValue() throws JSQLParserException { + String expressionStr = + "JSON_VALUE(payload FORMAT JSON ENCODING UTF8, '$.customer.id' PASSING customer_id RETURNING VARCHAR(32) DEFAULT 'missing' ON EMPTY NULL ON ERROR)"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertEquals(JsonFunctionType.VALUE, jsonFunction.getType()); + assertNotNull(jsonFunction.getInputExpression()); + assertEquals("UTF8", jsonFunction.getInputExpression().getEncoding()); + assertEquals(1, jsonFunction.getPassingExpressions().size()); + assertNotNull(jsonFunction.getOnEmptyBehavior()); + assertEquals(JsonFunction.JsonOnResponseBehaviorType.DEFAULT, + jsonFunction.getOnEmptyBehavior().getType()); + assertNotNull(jsonFunction.getOnErrorBehavior()); + assertEquals(JsonFunction.JsonOnResponseBehaviorType.NULL, + jsonFunction.getOnErrorBehavior().getType()); + + TestUtils.assertExpressionCanBeParsedAndDeparsed(expressionStr, true); + } + + @Test + public void testJsonQuery() throws JSQLParserException { + String expressionStr = + "JSON_QUERY(payload FORMAT JSON ENCODING UTF16, '$.items[*]' PASSING item_filter RETURNING VARCHAR(200) FORMAT JSON ENCODING UTF32 WITH CONDITIONAL ARRAY WRAPPER OMIT QUOTES ON SCALAR STRING EMPTY ARRAY ON EMPTY ERROR ON ERROR)"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertEquals(JsonFunctionType.QUERY, jsonFunction.getType()); + assertNotNull(jsonFunction.getInputExpression()); + assertEquals("UTF16", jsonFunction.getInputExpression().getEncoding()); + assertEquals("UTF32", jsonFunction.getReturningEncoding()); + assertEquals(JsonFunction.JsonWrapperType.WITH, jsonFunction.getWrapperType()); + assertEquals(JsonFunction.JsonWrapperMode.CONDITIONAL, jsonFunction.getWrapperMode()); + assertTrue(jsonFunction.isWrapperArray()); + assertEquals(JsonFunction.JsonQuotesType.OMIT, jsonFunction.getQuotesType()); + assertTrue(jsonFunction.isQuotesOnScalarString()); + assertNotNull(jsonFunction.getOnEmptyBehavior()); + assertEquals(JsonFunction.JsonOnResponseBehaviorType.EMPTY_ARRAY, + jsonFunction.getOnEmptyBehavior().getType()); + assertNotNull(jsonFunction.getOnErrorBehavior()); + assertEquals(JsonFunction.JsonOnResponseBehaviorType.ERROR, + jsonFunction.getOnErrorBehavior().getType()); + + TestUtils.assertExpressionCanBeParsedAndDeparsed(expressionStr, true); + TestUtils.assertExpressionCanBeParsedAndDeparsed( + "JSON_QUERY(payload, '$' WITHOUT WRAPPER KEEP QUOTES EMPTY OBJECT ON ERROR)", true); + } + + @Test + public void testJsonQueryLegacyAdditionalPathArguments() throws JSQLParserException { + String sql = + "select json_query('{\"customer\" : 100, \"region\" : \"AFRICA\"}', 'strict $.keyvalue()' WITH ARRAY WRAPPER, '$.region') from tbl"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sql, true); + + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select json_query('{\"a\":1}', '$' ERROR ON ERROR, '$.x' RETURNING VARCHAR(10), '$.z' WITH ARRAY WRAPPER) from tbl", + true); + } + + @Test + public void testJsonExists() throws JSQLParserException { + String expressionStr = + "JSON_EXISTS(payload FORMAT JSON ENCODING UTF8, '$.children[2]' PASSING child_idx UNKNOWN ON ERROR)"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertEquals(JsonFunctionType.EXISTS, jsonFunction.getType()); + assertNotNull(jsonFunction.getInputExpression()); + assertEquals("UTF8", jsonFunction.getInputExpression().getEncoding()); + assertNotNull(jsonFunction.getOnErrorBehavior()); + assertEquals(JsonFunction.JsonOnResponseBehaviorType.UNKNOWN, + jsonFunction.getOnErrorBehavior().getType()); + + TestUtils.assertExpressionCanBeParsedAndDeparsed(expressionStr, true); + } + + @Test + public void testJsonArrayAndObjectReturning() throws JSQLParserException { + TestUtils.assertExpressionCanBeParsedAndDeparsed( + "JSON_ARRAY(true, 1 RETURNING VARBINARY FORMAT JSON ENCODING UTF16)", true); + TestUtils.assertExpressionCanBeParsedAndDeparsed( + "JSON_OBJECT('x' : 1 RETURNING VARBINARY FORMAT JSON ENCODING UTF32)", true); + TestUtils.assertExpressionCanBeParsedAndDeparsed( + "JSON_OBJECT('x' : X'5B0035005D00' FORMAT JSON ENCODING UTF16)", true); + } + + @Test + public void testJsonTableAstParity() throws JSQLParserException { + String sqlStr = + "SELECT * FROM JSON_TABLE(payload, 'lax $' AS \"root_path\" " + + "PASSING filter_expr AS filter " + + "COLUMNS (" + + "a VARCHAR(10) FORMAT JSON ENCODING UTF8 PATH 'lax $.a' " + + "WITH CONDITIONAL ARRAY WRAPPER KEEP QUOTES ON SCALAR STRING " + + "DEFAULT 'missing' ON EMPTY NULL ON ERROR, " + + "NESTED PATH 'lax $[*]' AS \"nested_path\" " + + "COLUMNS (b INTEGER PATH 'lax $.b')" + + ") " + + "PLAN DEFAULT (\"root_path\" OUTER \"nested_path\") EMPTY ON ERROR)"; + + Select select = (Select) CCJSqlParserUtil.parse(sqlStr, + parser -> parser.withAllowComplexParsing(false)); + PlainSelect plainSelect = select.getPlainSelect(); + assertNotNull(plainSelect); + assertInstanceOf(TableFunction.class, plainSelect.getFromItem()); + + TableFunction tableFunction = (TableFunction) plainSelect.getFromItem(); + assertInstanceOf(JsonTableFunction.class, tableFunction.getFunction()); + JsonTableFunction jsonTableFunction = (JsonTableFunction) tableFunction.getFunction(); + + assertEquals("payload", jsonTableFunction.getJsonInputExpression().toString()); + assertEquals("'lax $'", jsonTableFunction.getJsonPathExpression().toString()); + assertEquals("\"root_path\"", jsonTableFunction.getPathName()); + assertEquals(1, jsonTableFunction.getPassingClauses().size()); + assertEquals("filter_expr", + jsonTableFunction.getPassingClauses().get(0).getValueExpression().toString()); + assertEquals("filter", jsonTableFunction.getPassingClauses().get(0).getParameterName()); + + JsonTableFunction.JsonTableColumnsClause columnsClause = + jsonTableFunction.getColumnsClause(); + assertNotNull(columnsClause); + assertEquals(2, columnsClause.getColumnDefinitions().size()); + assertInstanceOf(JsonTableFunction.JsonTableValueColumnDefinition.class, + columnsClause.getColumnDefinitions().get(0)); + assertInstanceOf(JsonTableFunction.JsonTableNestedColumnDefinition.class, + columnsClause.getColumnDefinitions().get(1)); + + JsonTableFunction.JsonTableValueColumnDefinition firstColumn = + (JsonTableFunction.JsonTableValueColumnDefinition) columnsClause + .getColumnDefinitions().get(0); + assertEquals("a", firstColumn.getColumnName()); + assertEquals("UTF8", firstColumn.getEncoding()); + assertTrue(firstColumn.isFormatJson()); + assertEquals("'lax $.a'", firstColumn.getPathExpression().toString()); + assertEquals(JsonFunction.JsonWrapperType.WITH, + firstColumn.getWrapperClause().getWrapperType()); + assertEquals(JsonFunction.JsonWrapperMode.CONDITIONAL, + firstColumn.getWrapperClause().getWrapperMode()); + assertTrue(firstColumn.getWrapperClause().isArray()); + assertEquals(JsonFunction.JsonQuotesType.KEEP, + firstColumn.getQuotesClause().getQuotesType()); + assertTrue(firstColumn.getQuotesClause().isOnScalarString()); + assertEquals(JsonFunction.JsonOnResponseBehaviorType.DEFAULT, + firstColumn.getOnEmptyBehavior().getType()); + assertEquals("'missing'", firstColumn.getOnEmptyBehavior().getExpression().toString()); + assertEquals(JsonFunction.JsonOnResponseBehaviorType.NULL, + firstColumn.getOnErrorBehavior().getType()); + + JsonTableFunction.JsonTableNestedColumnDefinition nestedColumn = + (JsonTableFunction.JsonTableNestedColumnDefinition) columnsClause + .getColumnDefinitions().get(1); + assertTrue(nestedColumn.isPathKeyword()); + assertEquals("'lax $[*]'", nestedColumn.getPathExpression().toString()); + assertEquals("\"nested_path\"", nestedColumn.getPathName()); + assertNotNull(nestedColumn.getColumnsClause()); + assertEquals(1, nestedColumn.getColumnsClause().getColumnDefinitions().size()); + + JsonTableFunction.JsonTableValueColumnDefinition nestedValueColumn = + (JsonTableFunction.JsonTableValueColumnDefinition) nestedColumn.getColumnsClause() + .getColumnDefinitions().get(0); + assertEquals("b", nestedValueColumn.getColumnName()); + assertEquals("'lax $.b'", nestedValueColumn.getPathExpression().toString()); + + assertNotNull(jsonTableFunction.getPlanClause()); + assertTrue(jsonTableFunction.getPlanClause().isDefaultPlan()); + assertEquals(2, jsonTableFunction.getPlanClause().getPlanExpression().getTerms().size()); + assertEquals(1, + jsonTableFunction.getPlanClause().getPlanExpression().getOperators().size()); + assertEquals(JsonTableFunction.JsonTablePlanOperator.OUTER, + jsonTableFunction.getPlanClause().getPlanExpression().getOperators().get(0)); + + assertNotNull(jsonTableFunction.getOnErrorClause()); + assertEquals(JsonTableFunction.JsonTableOnErrorType.EMPTY, + jsonTableFunction.getOnErrorClause().getType()); + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withAllowComplexParsing(false)); + } + @Test public void testIssue1260() throws JSQLParserException { - TestUtils.assertSqlCanBeParsedAndDeparsed("select \n" + " cast((\n" + " select coalesce(\n" - + " json_arrayagg(json_array(\"v0\") order by \"t\".\"v0\"),\n" - + " json_array(null on null)\n" + " )\n" + " from (\n" - + " select 2 \"v0\"\n" + " union\n" + " select 4 \"ID\"\n" + " ) \"t\"\n" - + " ) as text)", true); + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select \n" + " cast((\n" + " select coalesce(\n" + + " json_arrayagg(json_array(\"v0\") order by \"t\".\"v0\"),\n" + + " json_array(null on null)\n" + " )\n" + " from (\n" + + " select 2 \"v0\"\n" + " union\n" + " select 4 \"ID\"\n" + + " ) \"t\"\n" + + " ) as text)", + true); - TestUtils.assertExpressionCanBeParsedAndDeparsed("listagg( json_object(key 'v0' value \"v0\"), ',' )", true); + TestUtils.assertExpressionCanBeParsedAndDeparsed( + "listagg( json_object(key 'v0' value \"v0\"), ',' )", true); TestUtils.assertSqlCanBeParsedAndDeparsed("select (\n" + " select coalesce(\n" @@ -242,21 +506,134 @@ public void testIssue1371() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT json_object('{a, b}', '{1,2 }')", true); } + @ParameterizedTest + @ValueSource(strings = { + "JSON_OBJECT( KEY 'foo' VALUE bar, 'fob' : baz)", + + "JSON_OBJECT( t1.*, t2.* )", + "JSON_OBJECT( 'foo' VALUE bar, t1.*)", + "JSON_OBJECT( t1.*, 'foo' VALUE bar)", + + // The FORMAT JSON forces the parser to correctly identify the entries as single entries + "JSON_OBJECT(first_name FORMAT JSON, last_name)", + "JSON_OBJECT(t1.first_name FORMAT JSON, t1.last_name FORMAT JSON)", + + // MySQL syntax + "JSON_OBJECT( 'foo', bar, 'fob', baz)", + }) + void testEntriesAreParsedCorrectly(String expressionStr) throws JSQLParserException { + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + assertEquals(2, jsonFunction.getKeyValuePairs().size()); + } + + @ParameterizedTest + @ValueSource(strings = { + "JSON_OBJECT( t1.*, t2.*, t3.* )", + "JSON_OBJECT( 'foo' VALUE bar, t1.*, t2.single_column)", + "JSON_OBJECT( t1.*, 'foo' VALUE bar, KEY fob : baz)", + + // MySQL syntax + "JSON_OBJECT( 'foo', bar, 'fob', baz, 'for', buz)", + }) + void testEntriesAreParsedCorrectly3Entries(String expressionStr) throws JSQLParserException { + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + assertEquals(3, jsonFunction.getKeyValuePairs().size()); + } + + @ParameterizedTest + @ValueSource(strings = { + "JSON_OBJECT(first_name, last_name, address)", + "JSON_OBJECT(t1.first_name, t1.last_name, t1.address)", + "JSON_OBJECT(first_name, last_name FORMAT JSON, address)", + "JSON_OBJECT(first_name FORMAT JSON, last_name FORMAT JSON, address)", + "JSON_OBJECT(t1.first_name, t1.last_name FORMAT JSON, t1.address FORMAT JSON)", + }) + void testSingleEntriesAreParsedCorrectlyWithouCommaAsKeyValueSeparator(String expressionStr) + throws JSQLParserException { + FeatureConfiguration fc = + new FeatureConfiguration().setValue(Feature.allowCommaAsKeyValueSeparator, false); + + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr, + true, parser -> parser.withConfiguration(fc)); + assertEquals(3, jsonFunction.getKeyValuePairs().size()); + } + @Test public void testJavaMethods() throws JSQLParserException { - String expressionStr = "JSON_OBJECT( KEY 'foo' VALUE bar FORMAT JSON, 'foo':bar, 'foo':bar ABSENT ON NULL WITHOUT UNIQUE KEYS)"; + String expressionStr = + "JSON_OBJECT( KEY 'foo' VALUE bar FORMAT JSON, 'fob':baz, 'fod':bag ABSENT ON NULL WITHOUT UNIQUE KEYS)"; JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); - Assertions.assertEquals(JsonFunctionType.OBJECT, jsonFunction.getType()); - Assertions.assertNotEquals(jsonFunction.withType(JsonFunctionType.POSTGRES_OBJECT), jsonFunction.getType()); + assertEquals(JsonFunctionType.OBJECT, jsonFunction.getType()); + Assertions.assertNotEquals(jsonFunction.withType(JsonFunctionType.POSTGRES_OBJECT), + jsonFunction.getType()); - Assertions.assertEquals(3, jsonFunction.getKeyValuePairs().size()); - Assertions.assertEquals(new JsonKeyValuePair("'foo'", "bar", true, true), jsonFunction.getKeyValuePair(0)); + assertEquals(3, jsonFunction.getKeyValuePairs().size()); + assertEquals(new JsonKeyValuePair("'foo'", "bar", true, true), + jsonFunction.getKeyValuePair(0)); jsonFunction.setOnNullType(JsonAggregateOnNullType.NULL); - Assertions.assertEquals(JsonAggregateOnNullType.ABSENT, jsonFunction.withOnNullType(JsonAggregateOnNullType.ABSENT).getOnNullType()); + assertEquals(JsonAggregateOnNullType.ABSENT, + jsonFunction.withOnNullType(JsonAggregateOnNullType.ABSENT).getOnNullType()); jsonFunction.setUniqueKeysType(JsonAggregateUniqueKeysType.WITH); - Assertions.assertEquals(JsonAggregateUniqueKeysType.WITH, jsonFunction.withUniqueKeysType(JsonAggregateUniqueKeysType.WITH).getUniqueKeysType()); + assertEquals(JsonAggregateUniqueKeysType.WITH, jsonFunction + .withUniqueKeysType(JsonAggregateUniqueKeysType.WITH).getUniqueKeysType()); + } + + @Test + void testJavaMethodsStrict() throws JSQLParserException { + String expressionStr = "JSON_OBJECT( 'foo':bar, 'fob':baz FORMAT JSON STRICT )"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertTrue(jsonFunction.isStrict()); + + jsonFunction.withStrict(false); + + assertEquals( + TestUtils.buildSqlString("JSON_OBJECT( 'foo':bar, 'fob':baz FORMAT JSON ) ", true), + TestUtils.buildSqlString(jsonFunction.toString(), true)); + + } + + @Test + void testJavaMethodsAllColumns() throws JSQLParserException { + String expressionStr = "JSON_OBJECT(* NULL ON NULL)"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertEquals(1, jsonFunction.getKeyValuePairs().size()); + JsonKeyValuePair kv = jsonFunction.getKeyValuePair(0); + assertNotNull(kv); + + assertNull(kv.getValue()); + assertInstanceOf(AllColumns.class, kv.getKey()); + } + + @Test + void testJavaMethodsAllTableColumns() throws JSQLParserException { + String expressionStr = "JSON_OBJECT(a.*, b.* NULL ON NULL)"; + JsonFunction jsonFunction = (JsonFunction) CCJSqlParserUtil.parseExpression(expressionStr); + + assertEquals(2, jsonFunction.getKeyValuePairs().size()); + + JsonKeyValuePair kv1 = jsonFunction.getKeyValuePair(0); + assertNotNull(kv1); + assertInstanceOf(AllTableColumns.class, kv1.getKey()); + assertNull(kv1.getValue()); + + JsonKeyValuePair kv2 = jsonFunction.getKeyValuePair(1); + assertNotNull(kv2); + assertInstanceOf(AllTableColumns.class, kv2.getKey()); + assertNull(kv2.getValue()); + + } + + @Test + void testIssue1753JSonObjectAggWithColumns() throws JSQLParserException { + String sqlStr = "SELECT JSON_OBJECTAGG( KEY q.foo VALUE q.bar) FROM dual"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr); + + sqlStr = "SELECT JSON_OBJECTAGG(foo, bar) FROM dual"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/JsonTableOracleTest.java b/src/test/java/net/sf/jsqlparser/expression/JsonTableOracleTest.java new file mode 100644 index 000000000..4363cfb6e --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/JsonTableOracleTest.java @@ -0,0 +1,223 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.select.FromItem; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.TableFunction; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.*; + +public class JsonTableOracleTest { + + @ParameterizedTest + @ValueSource(strings = { + "SELECT jt.phones FROM j_purchaseorder,\n" + + "JSON_TABLE(po_document, '$.ShippingInstructions'\n" + + "COLUMNS(phones VARCHAR2(100) FORMAT JSON PATH '$.Phone')) AS jt", + "SELECT jt.phones FROM j_purchaseorder,\n" + + "JSON_TABLE(po_document, '$.ShippingInstructions'\n" + + "COLUMNS(phones FORMAT JSON PATH '$.Phone')) AS jt" + }) + void testObjectOracle(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "JSON_TABLE(document COLUMNS( id FOR ORDINALITY))", + "JSON_TABLE(document FORMAT JSON COLUMNS( id FOR ORDINALITY))", + "JSON_TABLE(document, '$.SubPath' COLUMNS( id FOR ORDINALITY))", + "JSON_TABLE(document NULL ON ERROR COLUMNS( id FOR ORDINALITY))", + "JSON_TABLE(document ERROR ON ERROR COLUMNS( id FOR ORDINALITY))", + "JSON_TABLE(document TYPE(LAX) COLUMNS( id FOR ORDINALITY))", + "JSON_TABLE(document TYPE(STRICT) COLUMNS( id FOR ORDINALITY))", + "JSON_TABLE(document NULL ON EMPTY COLUMNS( id FOR ORDINALITY))", + "JSON_TABLE(document ERROR ON EMPTY COLUMNS( id FOR ORDINALITY))", + }) + void testExpression(String jsonTableStr) throws JSQLParserException { + JsonTableFunction table = parseTable(jsonTableStr); + + assertThat(table.getColumnsClause().getColumnDefinitions()).hasSize(1); + } + + @ParameterizedTest + @ValueSource(strings = { + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' TRUE ON ERROR TRUE ON EMPTY))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' FALSE ON ERROR FALSE ON EMPTY))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' ERROR ON ERROR ERROR ON EMPTY))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' ERROR ON ERROR))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' ERROR ON EMPTY))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' TRUE ON ERROR))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' TRUE ON EMPTY))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' FALSE ON ERROR))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest' FALSE ON EMPTY))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS ERROR ON EMPTY))", + "JSON_TABLE(document COLUMNS( hasValue EXISTS))", + }) + void testExistsColumns(String jsonTableStr) throws JSQLParserException { + JsonTableFunction table = parseTable(jsonTableStr); + + assertThat(table.getColumnsClause().getColumnDefinitions()).hasSize(1); + } + + @ParameterizedTest + @ValueSource(strings = { + "JSON_TABLE(document COLUMNS( val PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val FORMAT JSON PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val ALLOW SCALARS PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val DISALLOW SCALARS PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val VARCHAR(240) ALLOW SCALARS PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val INT DISALLOW SCALARS PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val FORMAT JSON DISALLOW SCALARS PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITH WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITHOUT WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITH ARRAY WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITHOUT ARRAY WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITH CONDITIONAL WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITH CONDITIONAL ARRAY WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITH UNCONDITIONAL WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITH UNCONDITIONAL ARRAY WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val WITH UNCONDITIONAL ARRAY WRAPPER PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val PATH '$.pathTest' ERROR ON ERROR))", + "JSON_TABLE(document COLUMNS( val PATH '$.pathTest' NULL ON ERROR))", + "JSON_TABLE(document COLUMNS( val PATH '$.pathTest' EMPTY ON ERROR))", + "JSON_TABLE(document COLUMNS( val PATH '$.pathTest' EMPTY ARRAY ON ERROR))", + "JSON_TABLE(document COLUMNS( val PATH '$.pathTest' EMPTY OBJECT ON ERROR))", + "JSON_TABLE(document COLUMNS( val CLOB PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val BLOB PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val JSON PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val VECTOR PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val VARCHAR PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val VARCHAR(240) PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val VARCHAR(240) FORMAT JSON PATH '$.pathTest'))", + + // These would require adapting ColDataType in Line 10176 + // "JSON_TABLE(document COLUMNS( val VARCHAR2(500 BYTE) PATH '$.pathTest'))", + // "JSON_TABLE(document COLUMNS( val VARCHAR2(100 CHAR) PATH '$.pathTest'))", + "JSON_TABLE(document COLUMNS( val VARCHAR2 FORMAT JSON DISALLOW SCALARS WITH UNCONDITIONAL ARRAY WRAPPER PATH '$.pathTest' EMPTY OBJECT ON ERROR))", + }) + void testQueryColumns(String jsonTableStr) throws JSQLParserException { + JsonTableFunction table = parseTable(jsonTableStr); + + assertThat(table.getColumnsClause().getColumnDefinitions()).hasSize(1); + } + + @Test + void testFormatJson() throws JSQLParserException { + String expression = "JSON_TABLE(document FORMAT JSON COLUMNS( id FOR ORDINALITY))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getFormatJson()).isTrue(); + } + + @Test + void testPathExpression() throws JSQLParserException { + String expression = "JSON_TABLE(document, '$.SubPath' COLUMNS( id FOR ORDINALITY))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getJsonPathExpression().toString()).isEqualTo("'$.SubPath'"); + } + + @Test + void testNullOnError() throws JSQLParserException { + String expression = "JSON_TABLE(document NULL ON ERROR COLUMNS( id FOR ORDINALITY))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getOnErrorClause().getType()) + .isEqualTo(JsonTableFunction.JsonTableOnErrorType.NULL); + } + + @Test + void testErrorOnError() throws JSQLParserException { + String expression = "JSON_TABLE(document ERROR ON ERROR COLUMNS( id FOR ORDINALITY))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getOnErrorClause().getType()) + .isEqualTo(JsonTableFunction.JsonTableOnErrorType.ERROR); + } + + @Test + void testNullOnEmpty() throws JSQLParserException { + String expression = "JSON_TABLE(document NULL ON EMPTY COLUMNS( id FOR ORDINALITY))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getOnEmptyClause().getType()) + .isEqualTo(JsonTableFunction.JsonTableOnEmptyType.NULL); + } + + @Test + void testErrorOnEmpty() throws JSQLParserException { + String expression = "JSON_TABLE(document ERROR ON EMPTY COLUMNS( id FOR ORDINALITY))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getOnEmptyClause().getType()) + .isEqualTo(JsonTableFunction.JsonTableOnEmptyType.ERROR); + } + + @Test + void testParsingTypeLax() throws JSQLParserException { + String expression = "JSON_TABLE(document TYPE(LAX) COLUMNS( id FOR ORDINALITY))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getParsingTypeClause().getType()) + .isEqualTo(JsonTableFunction.JsonTableParsingType.LAX); + } + + @Test + void testParsingTypeStrict() throws JSQLParserException { + String expression = "JSON_TABLE(document TYPE(STRICT) COLUMNS( id FOR ORDINALITY))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getParsingTypeClause().getType()) + .isEqualTo(JsonTableFunction.JsonTableParsingType.STRICT); + } + + @Test + void testColumnTypeExists() throws JSQLParserException { + String expression = "JSON_TABLE(document COLUMNS( hasValue EXISTS PATH '$.pathTest'))"; + JsonTableFunction table = parseTable(expression); + + assertThat(table.getColumnsClause().getColumnDefinitions()).hasSize(1); + + JsonTableFunction.JsonTableColumnDefinition col = + table.getColumnsClause().getColumnDefinitions().get(0); + assertThat(col).isInstanceOf(JsonTableFunction.JsonTableValueColumnDefinition.class); + + JsonTableFunction.JsonTableValueColumnDefinition valueCol = + (JsonTableFunction.JsonTableValueColumnDefinition) col; + + assertThat(valueCol.isExists()).isTrue(); + } + + private JsonTableFunction parseTable(String jsonTableStr) throws JSQLParserException { + String sql = "SELECT * FROM " + jsonTableStr; + Statement stmt = CCJSqlParserUtil.parse(sql); + + TestUtils.assertSqlCanBeParsedAndDeparsed(sql, true); + + FromItem fromItem = ((PlainSelect) stmt).getFromItem(); + assertThat(fromItem).isInstanceOf(TableFunction.class); + Function function = ((TableFunction) fromItem).getFunction(); + assertThat(function).isInstanceOf(JsonTableFunction.class); + + return (JsonTableFunction) function; + } + + +} diff --git a/src/test/java/net/sf/jsqlparser/expression/LambdaExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/LambdaExpressionTest.java index 1d51dbe99..c9437437c 100644 --- a/src/test/java/net/sf/jsqlparser/expression/LambdaExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/LambdaExpressionTest.java @@ -11,7 +11,6 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.test.TestUtils; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -24,10 +23,8 @@ void testLambdaFunctionSingleParameter() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } - @Disabled @Test - // wip, right now the Grammar works but collides with Multi Value Lists - void testLambdaFunctionMultipleParameter() throws JSQLParserException { + void testNestedLambdaFunctionMultipleParameter() throws JSQLParserException { String sqlStr = "SELECT list_transform(\n" + " [1, 2, 3],\n" + " x -> list_reduce([4, 5, 6], (a, b) -> a + b) + x\n" + @@ -35,4 +32,17 @@ void testLambdaFunctionMultipleParameter() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @Test + void testLambdaMultiParameterIssue2030() throws JSQLParserException { + String sqlStr = "SELECT map_filter(my_column, v -> v.my_inner_column = 'some_value')\n" + + "FROM my_table"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testLambdaMultiParameterIssue2032() throws JSQLParserException { + String sqlStr = "SELECT array_sort(array_agg(named_struct('depth', events_union.depth, 'eventtime',events_union.eventtime)), (left, right) -> case when(left.eventtime, left.depth) <(right.eventtime, right.depth) then -1 when(left.eventtime, left.depth) >(right.eventtime, right.depth) then 1 else 0 end) as col1 FROM your_table;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + } diff --git a/src/test/java/net/sf/jsqlparser/expression/LikeExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/LikeExpressionTest.java index 3840d0935..d87614566 100644 --- a/src/test/java/net/sf/jsqlparser/expression/LikeExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/LikeExpressionTest.java @@ -26,119 +26,96 @@ public class LikeExpressionTest { public void testLikeWithEscapeExpressionIssue420() throws JSQLParserException { TestUtils.assertExpressionCanBeParsedAndDeparsed("a LIKE ?1 ESCAPE ?2", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("select * from dual where a LIKE ?1 ESCAPE ?2", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("select * from dual where a LIKE ?1 ESCAPE ?2", + true); } @Test public void testEscapeExpressionIssue1638() throws JSQLParserException { String sqlStr = "select case \n" - + " when id_portfolio like '%\\_1' escape '\\' then '1'\n" - + " end"; + + " when id_portfolio like '%\\_1' escape '\\' then '1'\n" + + " end"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(false) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(false)); Assertions.assertThrows(JSQLParserException.class, new Executable() { @Override public void execute() throws Throwable { CCJSqlParserUtil.parse( - sqlStr - , parser -> parser.withBackslashEscapeCharacter(true) - ); + sqlStr, parser -> parser.withBackslashEscapeCharacter(true)); } }); } @Test public void testEscapingIssue1209() throws JSQLParserException { - String sqlStr="INSERT INTO \"a\".\"b\"(\"c\", \"d\", \"e\") VALUES ('c c\\', 'dd', 'ee\\')"; + String sqlStr = + "INSERT INTO \"a\".\"b\"(\"c\", \"d\", \"e\") VALUES ('c c\\', 'dd', 'ee\\')"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(false) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(false)); } @Test public void testEscapingIssue1173() throws JSQLParserException { - String sqlStr="update PARAM_TBL set PARA_DESC = null where PARA_DESC = '\\' and DEFAULT_VALUE = '\\'"; + String sqlStr = + "update PARAM_TBL set PARA_DESC = null where PARA_DESC = '\\' and DEFAULT_VALUE = '\\'"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(false) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(false)); } @Test public void testEscapingIssue1172() throws JSQLParserException { - String sqlStr="SELECT A ALIA1, CASE WHEN B LIKE 'ABC\\_%' ESCAPE '\\' THEN 'DEF' ELSE 'CCCC' END AS OBJ_SUB_TYPE FROM TABLE2"; + String sqlStr = + "SELECT A ALIA1, CASE WHEN B LIKE 'ABC\\_%' ESCAPE '\\' THEN 'DEF' ELSE 'CCCC' END AS OBJ_SUB_TYPE FROM TABLE2"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(false) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(false)); } @Test public void testEscapingIssue832() throws JSQLParserException { - String sqlStr="SELECT * FROM T1 WHERE (name LIKE ? ESCAPE '\\') AND (description LIKE ? ESCAPE '\\')"; + String sqlStr = + "SELECT * FROM T1 WHERE (name LIKE ? ESCAPE '\\') AND (description LIKE ? ESCAPE '\\')"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(false) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(false)); } @Test public void testEscapingIssue827() throws JSQLParserException { - String sqlStr="INSERT INTO my_table (my_column_1, my_column_2) VALUES ('my_value_1\\', 'my_value_2')"; + String sqlStr = + "INSERT INTO my_table (my_column_1, my_column_2) VALUES ('my_value_1\\', 'my_value_2')"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(false) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(false)); } @Test public void testEscapingIssue578() throws JSQLParserException { - String sqlStr="SELECT * FROM t1 WHERE UPPER(t1.TIPCOR_A8) like ? ESCAPE '' ORDER BY PERFILB2||TRANSLATE(UPPER(AP1SOL10 || ' ' || AP2SOL10 || ',' || NOMSOL10), '?', 'A') asc"; + String sqlStr = + "SELECT * FROM t1 WHERE UPPER(t1.TIPCOR_A8) like ? ESCAPE '' ORDER BY PERFILB2||TRANSLATE(UPPER(AP1SOL10 || ' ' || AP2SOL10 || ',' || NOMSOL10), '?', 'A') asc"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(false) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(false)); } @Test public void testEscapingIssue875() throws JSQLParserException { - String sqlStr="insert into standard_table(gmt_create, gmt_modified, config_name, standard_code) values (now(), now(), null, 'if \n" - + "@fac.sql_type in \n" - + "[ ''UPDATE'', ''DELETE'', ''INSERT'', ''INSERT_SELECT''] \n" - + "then \n" - + "@act.allow_submit \n" - + "end \n" - + "')" - ; + String sqlStr = + "insert into standard_table(gmt_create, gmt_modified, config_name, standard_code) values (now(), now(), null, 'if \n" + + "@fac.sql_type in \n" + + "[ ''UPDATE'', ''DELETE'', ''INSERT'', ''INSERT_SELECT''] \n" + + "then \n" + + "@act.allow_submit \n" + + "end \n" + + "')"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(false) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(false)); - sqlStr="insert into standard_table(gmt_create, gmt_modified, config_name, standard_code) values (now(), now(), null, 'if \n" - + "@fac.sql_type in \n" - + "[ \\'UPDATE\\', \\'DELETE\\', \\'INSERT\\', \\'INSERT_SELECT\\'] \n" - + "then \n" - + "@act.allow_submit \n" - + "end \n" - + "')" - ; + sqlStr = "insert into standard_table(gmt_create, gmt_modified, config_name, standard_code) values (now(), now(), null, 'if \n" + + "@fac.sql_type in \n" + + "[ \\'UPDATE\\', \\'DELETE\\', \\'INSERT\\', \\'INSERT_SELECT\\'] \n" + + "then \n" + + "@act.allow_submit \n" + + "end \n" + + "')"; TestUtils.assertSqlCanBeParsedAndDeparsed( - sqlStr - , true - , parser -> parser.withBackslashEscapeCharacter(true) - ); + sqlStr, true, parser -> parser.withBackslashEscapeCharacter(true)); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/LimitExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/LimitExpressionTest.java index 59151487f..70dbd2103 100644 --- a/src/test/java/net/sf/jsqlparser/expression/LimitExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/LimitExpressionTest.java @@ -61,6 +61,6 @@ public void testMethods() throws JSQLParserException { plainSelect = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); AllValue allValue = plainSelect.getLimit().getRowCount(AllValue.class); - allValue.accept(new ExpressionVisitorAdapter()); + allValue.accept(new ExpressionVisitorAdapter(), null); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java new file mode 100644 index 000000000..2e17ad1f0 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java @@ -0,0 +1,24 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class OracleHierarchicalExpressionTest { + + @Test + void testIssue2231() throws JSQLParserException { + String sqlString = + "select name from product where level > 1 start with 1 = 1 or 1 = 2 connect by nextversion = prior activeversion"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlString, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameterTest.java b/src/test/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameterTest.java index f662c5a0b..98c2028a1 100644 --- a/src/test/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameterTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameterTest.java @@ -30,19 +30,19 @@ public class OracleNamedFunctionParameterTest { /** - * This test will parse and deparse the statement and assures the functional coverage by JSQLParser. + * This test will parse and deparse the statement and assures the functional coverage by + * JSQLParser. * * @throws net.sf.jsqlparser.JSQLParserException */ @Test public void testExpression() throws JSQLParserException { - String sqlStr - = "select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2"; + String sqlStr = + "select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - sqlStr - = "exec dbms_stats.gather_schema_stats(\n" + sqlStr = "exec dbms_stats.gather_schema_stats(\n" + " ownname => 'COMMON', \n" + " estimate_percent => dbms_stats.auto_sample_size, \n" + " method_opt => 'for all columns size auto', \n" @@ -54,49 +54,50 @@ public void testExpression() throws JSQLParserException { } /** - * This test will trigger the method {@link ExpressionVisitorAdaptor#visit() Visit Method} in the - * ExpressionVisitorAdaptor needed for the Code Coverage. + * This test will trigger the method {@link ExpressionVisitorAdaptor#visit() Visit Method} in + * the ExpressionVisitorAdaptor needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ @Test public void testExpressionVisitorAdaptor() throws JSQLParserException { - String sqlStr - = "select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2"; + String sqlStr = + "select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2"; CCJSqlParserUtil.parse(sqlStr).accept(new StatementVisitorAdapter()); // alternatively, for the Expression only - CCJSqlParserUtil.parseExpression("p_1 => r.param1").accept(new ExpressionVisitorAdapter()); + CCJSqlParserUtil.parseExpression("p_1 => r.param1").accept(new ExpressionVisitorAdapter(), + null); } /** - * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the TableNamesFinder needed - * for the Code Coverage. + * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the + * TableNamesFinder needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ @Test public void testTableNamesFinder() throws JSQLParserException { - String sqlStr - = "select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2 from test_table"; + String sqlStr = + "select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2 from test_table"; Statement statement = CCJSqlParserUtil.parse(sqlStr); - List tables = new TablesNamesFinder().getTableList(statement); + List tables = new TablesNamesFinder<>().getTableList(statement); assertEquals(1, tables.size()); assertTrue(tables.contains("test_table")); } /** - * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the ExpressionValidator - * needed for the Code Coverage. + * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the + * ExpressionValidator needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ @Test public void testValidator() throws JSQLParserException { - String sqlStr - = "select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2"; + String sqlStr = + "select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2"; ValidationTestAsserts.validateNoErrors(sqlStr, 1, DatabaseType.ORACLE); } diff --git a/src/test/java/net/sf/jsqlparser/expression/OverlapsConditionTest.java b/src/test/java/net/sf/jsqlparser/expression/OverlapsConditionTest.java index d91de5add..cd2c92bb1 100644 --- a/src/test/java/net/sf/jsqlparser/expression/OverlapsConditionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/OverlapsConditionTest.java @@ -17,11 +17,16 @@ public class OverlapsConditionTest { @Test public void testOverlapsCondition() throws JSQLParserException { - TestUtils.assertExpressionCanBeParsedAndDeparsed("(t1.start, t1.end) overlaps (t2.start, t2.end)", true); + TestUtils.assertExpressionCanBeParsedAndDeparsed( + "(t1.start, t1.end) overlaps (t2.start, t2.end)", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("select * from dual where (start_one, end_one) overlaps (start_two, end_two)", true); + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where (start_one, end_one) overlaps (start_two, end_two)", + true); - TestUtils.assertSqlCanBeParsedAndDeparsed("select * from t1 left join t2 on (t1.start, t1.end) overlaps (t2.start, t2.end)", true); + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from t1 left join t2 on (t1.start, t1.end) overlaps (t2.start, t2.end)", + true); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameterTest.java b/src/test/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameterTest.java new file mode 100644 index 000000000..c3e7af109 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameterTest.java @@ -0,0 +1,96 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2021 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitorAdapter; +import net.sf.jsqlparser.test.TestUtils; +import net.sf.jsqlparser.util.TablesNamesFinder; +import net.sf.jsqlparser.util.validation.ValidationTestAsserts; +import net.sf.jsqlparser.util.validation.feature.DatabaseType; +import net.sf.jsqlparser.util.validation.validator.ExpressionValidator; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * + * @author Andreas Reichel + */ +public class PostgresNamedFunctionParameterTest { + + /** + * This test will parse and deparse the statement and assures the functional coverage by + * JSQLParser. + * + * @throws JSQLParserException + */ + @Test + public void testExpression() throws JSQLParserException { + String sqlStr = + "SELECT concat_lower_or_upper(a := 'Hello', uppercase := true, b := 'World')"; + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + /** + * This test will trigger the method {@link ExpressionVisitorAdaptor#visit() Visit Method} in + * the ExpressionVisitorAdaptor needed for the Code Coverage. + * + * @throws JSQLParserException + */ + @Test + public void testExpressionVisitorAdaptor() throws JSQLParserException { + String sqlStr = + "SELECT concat_lower_or_upper(a := 'Hello', uppercase := true, b := 'World')"; + + CCJSqlParserUtil.parse(sqlStr).accept(new StatementVisitorAdapter()); + + // alternatively, for the Expression only + CCJSqlParserUtil.parseExpression("a := 'Hello'").accept(new ExpressionVisitorAdapter(), + null); + } + + /** + * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the + * TableNamesFinder needed for the Code Coverage. + * + * @throws JSQLParserException + */ + @Test + public void testTableNamesFinder() throws JSQLParserException { + String sqlStr = + "SELECT concat_lower_or_upper(a := 'Hello', uppercase := true, b := 'World') FROM test_table"; + + Statement statement = CCJSqlParserUtil.parse(sqlStr); + List tables = new TablesNamesFinder<>().getTableList(statement); + assertEquals(1, tables.size()); + assertTrue(tables.contains("test_table")); + } + + /** + * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the + * ExpressionValidator needed for the Code Coverage. + * + * @throws JSQLParserException + */ + @Test + public void testValidator() throws JSQLParserException { + String sqlStr = + "SELECT concat_lower_or_upper(a := 'Hello', uppercase := true, b := 'World') FROM test_table"; + + ValidationTestAsserts.validateNoErrors(sqlStr, 1, DatabaseType.POSTGRESQL); + } +} diff --git a/src/test/java/net/sf/jsqlparser/expression/SafeCastExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/SafeCastExpressionTest.java index 8630c6264..0d58e5c20 100644 --- a/src/test/java/net/sf/jsqlparser/expression/SafeCastExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/SafeCastExpressionTest.java @@ -17,7 +17,10 @@ public class SafeCastExpressionTest { @Test public void testSafeCast() throws JSQLParserException { - TestUtils.assertExpressionCanBeParsedAndDeparsed("SAFE_CAST(ROW(dataid, value, calcMark) AS ROW(datapointid CHAR, value CHAR, calcMark CHAR))", true); - TestUtils.assertExpressionCanBeParsedAndDeparsed("SAFE_CAST(ROW(dataid, value, calcMark) AS testcol)", true); + TestUtils.assertExpressionCanBeParsedAndDeparsed( + "SAFE_CAST(ROW(dataid, value, calcMark) AS ROW(datapointid CHAR, value CHAR, calcMark CHAR))", + true); + TestUtils.assertExpressionCanBeParsedAndDeparsed( + "SAFE_CAST(ROW(dataid, value, calcMark) AS testcol)", true); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java b/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java index 062f131aa..3dcb03a3d 100644 --- a/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java @@ -9,12 +9,14 @@ */ package net.sf.jsqlparser.expression; +import static org.junit.jupiter.api.Assertions.assertEquals; + import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * * @author toben @@ -93,4 +95,20 @@ public void testParseInput_BYTEA() throws Exception { String sqlStr = "VALUES (X'', X'01FF', X'01 bc 2a', X'01' '02')"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testDollarQuotesIssue2267() throws JSQLParserException { + String sqlStr = "SELECT $$this is a string$$, test, 'text' FROM tbl;"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Assertions.assertInstanceOf(StringValue.class, select.getSelectItem(0).getExpression()); + } + + @Test + void testDollarQuotesWithDollarSignsInside() throws JSQLParserException { + String sqlStr = "SELECT $$this references $1 and costs $5$$ FROM tbl;"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Assertions.assertInstanceOf(StringValue.class, select.getSelectItem(0).getExpression()); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java b/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java index 444197963..e579f05a1 100644 --- a/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java @@ -39,7 +39,6 @@ void testStructTypeBigQuery() throws JSQLParserException { @Test void testStructTypeDuckDB() throws JSQLParserException { - // @todo: check why the white-space after the "{" is needed?! String sqlStr = "SELECT { t:'abc',len:5}"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); @@ -58,14 +57,18 @@ void testStructTypeConstructorDuckDB() throws JSQLParserException { // @todo: check why the white-space after the "{" is needed?! String sqlStr = "SELECT { t:'abc',len:5}"; List> selectItems = List.of( - new SelectItem<>("abc", "t") - , new SelectItem<>(5, "len") - ); + new SelectItem<>("abc", "t"), new SelectItem<>(5, "len")); StructType struct = new StructType(StructType.Dialect.DUCKDB, selectItems); - PlainSelect select = new PlainSelect().withSelectItems( new SelectItem<>(struct)); + PlainSelect select = new PlainSelect().withSelectItems(new SelectItem<>(struct)); TestUtils.assertStatementCanBeDeparsedAs(select, sqlStr, true); } + @Test + void testStructTypeConstructorDuckDBWithQuotesAndTypes() throws JSQLParserException { + String sqlStr = "SELECT {'t':'abc'::STRING,'len':5::INT}"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + @Test void testStructTypeWithArgumentsDuckDB() throws JSQLParserException { // @todo: check why the white-space after the "{" is needed?! diff --git a/src/test/java/net/sf/jsqlparser/expression/TranscodingFunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/TranscodingFunctionTest.java index 090317ff0..ea48d62db 100644 --- a/src/test/java/net/sf/jsqlparser/expression/TranscodingFunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/TranscodingFunctionTest.java @@ -60,4 +60,10 @@ public void testUnPivotWithAlias() throws JSQLParserException { Statement st = assertSqlCanBeParsedAndDeparsed( "SELECT Convert( Decimal(18,2) , 1 )", true); } + + @Test + void testIssue2304() throws JSQLParserException { + String sqlStr = "SELECT TRY_CONVERT(NUMERIC(8,6), '1234') AS LATITUDE_NBR;"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/mysql/MySqlSqlCalcFoundRowsTest.java b/src/test/java/net/sf/jsqlparser/expression/mysql/MySqlSqlCalcFoundRowsTest.java index abb816607..531d8968e 100644 --- a/src/test/java/net/sf/jsqlparser/expression/mysql/MySqlSqlCalcFoundRowsTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/mysql/MySqlSqlCalcFoundRowsTest.java @@ -52,15 +52,19 @@ public void testPossibleParsingWithSqlCalcFoundRowsHint() throws JSQLParserExcep } private void accept(Statement statement, final MySqlSqlCalcFoundRowRef ref) { - statement.accept(new StatementVisitorAdapter() { + SelectVisitorAdapter selectVisitorAdapter = new SelectVisitorAdapter<>() { @Override - public void visit(Select select) { - select.accept(new SelectVisitorAdapter() { - @Override - public void visit(PlainSelect plainSelect) { - ref.sqlCalcFoundRows = plainSelect.getMySqlSqlCalcFoundRows(); - } - }); + public Void visit(PlainSelect plainSelect, S parameters) { + ref.sqlCalcFoundRows = plainSelect.getMySqlSqlCalcFoundRows(); + return null; + } + }; + + statement.accept(new StatementVisitorAdapter() { + @Override + public Void visit(Select select, S context) { + select.accept(selectVisitorAdapter, context); + return null; } }); diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/arithmetic/ArithmethicTests.java b/src/test/java/net/sf/jsqlparser/expression/operators/arithmetic/ArithmethicTests.java index 24bca2a8f..d78ce7971 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/arithmetic/ArithmethicTests.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/arithmetic/ArithmethicTests.java @@ -19,13 +19,15 @@ public class ArithmethicTests { @Test public void testAddition() { assertEquals("1 + a", - new Addition().withLeftExpression(new LongValue(1)).withRightExpression(new Column("a")).toString()); + new Addition().withLeftExpression(new LongValue(1)) + .withRightExpression(new Column("a")).toString()); } @Test public void testBitwiseAnd() { assertEquals("a & b", - new BitwiseAnd().withLeftExpression(new Column("a")).withRightExpression(new Column("b")).toString()); + new BitwiseAnd().withLeftExpression(new Column("a")) + .withRightExpression(new Column("b")).toString()); } @Test @@ -37,32 +39,37 @@ public void testBitwiseLeftShift() { @Test public void testBitwiseOr() { assertEquals("a | b", - new BitwiseOr().withLeftExpression(new Column("a")).withRightExpression(new Column("b")).toString()); + new BitwiseOr().withLeftExpression(new Column("a")) + .withRightExpression(new Column("b")).toString()); } @Test public void testBitwiseRightShift() { assertEquals("a >> b", - new BitwiseRightShift().withLeftExpression(new Column("a")).withRightExpression(new Column("b")) + new BitwiseRightShift().withLeftExpression(new Column("a")) + .withRightExpression(new Column("b")) .toString()); } @Test public void testBitwiseXor() { assertEquals("a ^ b", - new BitwiseXor().withLeftExpression(new Column("a")).withRightExpression(new Column("b")).toString()); + new BitwiseXor().withLeftExpression(new Column("a")) + .withRightExpression(new Column("b")).toString()); } @Test public void testConcat() { assertEquals("a || b", - new Concat().withLeftExpression(new Column("a")).withRightExpression(new Column("b")).toString()); + new Concat().withLeftExpression(new Column("a")) + .withRightExpression(new Column("b")).toString()); } @Test public void testDivision() { assertEquals("a / b", - new Division().withLeftExpression(new Column("a")).withRightExpression(new Column("b")).toString()); + new Division().withLeftExpression(new Column("a")) + .withRightExpression(new Column("b")).toString()); } @Test @@ -74,13 +81,15 @@ public void testIntegerDivision() { @Test public void testModulo() { assertEquals("3 % 2", - new Modulo().withLeftExpression(new LongValue(3)).withRightExpression(new LongValue(2)).toString()); + new Modulo().withLeftExpression(new LongValue(3)) + .withRightExpression(new LongValue(2)).toString()); } @Test public void testMultiplication() { assertEquals("5 * 2", - new Multiplication().withLeftExpression(new LongValue(5)).withRightExpression(new LongValue(2)) + new Multiplication().withLeftExpression(new LongValue(5)) + .withRightExpression(new LongValue(2)) .toString()); } diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/BetweenTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/BetweenTest.java index 56f2f44df..4fd8fd706 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/BetweenTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/BetweenTest.java @@ -10,7 +10,9 @@ package net.sf.jsqlparser.expression.operators.relational; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -22,4 +24,30 @@ void testBetweenWithAdditionIssue1948() throws JSQLParserException { "select col FROM tbl WHERE start_time BETWEEN 1706024185 AND MyFunc() - 734400"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testBetweenSymmetricIssue2250() throws JSQLParserException { + String sqlStr = + "SELECT *\n" + + "FROM orders\n" + + "WHERE 100 BETWEEN SYMMETRIC total_price AND discount_price;\n"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Between between = (Between) select.getWhere(); + + Assertions.assertTrue(between.isUsingSymmetric()); + Assertions.assertFalse(between.isUsingAsymmetric()); + } + + @Test + void testBetweenASymmetricIssue2250() throws JSQLParserException { + String sqlStr = + "SELECT *\n" + + "FROM orders\n" + + "WHERE 100 BETWEEN ASYMMETRIC total_price AND discount_price;\n"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Between between = (Between) select.getWhere(); + + Assertions.assertFalse(between.isUsingSymmetric()); + Assertions.assertTrue(between.isUsingAsymmetric()); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperatorTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperatorTest.java index a2687d664..7be79658a 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperatorTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperatorTest.java @@ -35,4 +35,12 @@ public void testContainedBy() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT * FROM foo WHERE a <& b"); Assertions.assertInstanceOf(ContainedBy.class, CCJSqlParserUtil.parseExpression("a <& b")); } + + @Test + void testCosineSimilarity() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "SELECT (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;"); + Assertions.assertInstanceOf(CosineSimilarity.class, + CCJSqlParserUtil.parseExpression("embedding <=> '[3,1,2]'")); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearchExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearchExpressionTest.java index 1ff244564..8a1c61714 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearchExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearchExpressionTest.java @@ -31,7 +31,8 @@ public void testFullTextSearchExpressionWithParameters() throws JSQLParserExcept public void testIssue1223() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("select\n" + "c.*,\n" + "match (name) against (?) as full_text\n" + "from\n" + "commodity c\n" + "where\n" - + "match (name) against (?)\n" + "and c.deleted = 0\n" + "order by\n" + "full_text desc", + + "match (name) against (?)\n" + "and c.deleted = 0\n" + "order by\n" + + "full_text desc", true); } } diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java index ac1e2a0cf..8698b02be 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/InExpressionTest.java @@ -10,7 +10,10 @@ package net.sf.jsqlparser.expression.operators.relational; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -30,4 +33,12 @@ void testOracleInWithBrackets() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @Test + void testPrecedenceIssue2244() throws JSQLParserException { + String sqlStr = "select * from `T_DEMO` where a in (1,3,2) or b = 2"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Assertions.assertInstanceOf(OrExpression.class, select.getWhere()); + } + } diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpressionTest.java index 98cbc695b..b7a5ec934 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpressionTest.java @@ -20,4 +20,10 @@ void testNotNullExpression() throws JSQLParserException { String sqlStr = "select * from mytable where 1 notnull"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testStringConstructor() { + IsNullExpression isNullExpression = new IsNullExpression("x", true); + TestUtils.assertExpressionCanBeDeparsedAs(isNullExpression, "x IS NOT NULL"); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpressionTest.java new file mode 100644 index 000000000..322842395 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpressionTest.java @@ -0,0 +1,47 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +class IsUnknownExpressionTest { + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM mytable WHERE 1 IS UNKNOWN", + "SELECT * FROM mytable WHERE 1 IS NOT UNKNOWN", + }) + public void testIsUnknownExpression(String sqlStr) { + assertDoesNotThrow(() -> TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr)); + } + + @Test + void testStringConstructor() { + Column column = new Column("x"); + + IsUnknownExpression defaultIsUnknownExpression = + new IsUnknownExpression().withLeftExpression(column); + TestUtils.assertExpressionCanBeDeparsedAs(defaultIsUnknownExpression, "x IS UNKNOWN"); + + IsUnknownExpression isUnknownExpression = + new IsUnknownExpression().withLeftExpression(column).withNot(false); + TestUtils.assertExpressionCanBeDeparsedAs(isUnknownExpression, "x IS UNKNOWN"); + + IsUnknownExpression isNotUnknownExpression = + new IsUnknownExpression().withLeftExpression(column).withNot(true); + TestUtils.assertExpressionCanBeDeparsedAs(isNotUnknownExpression, "x IS NOT UNKNOWN"); + } +} diff --git a/src/test/java/net/sf/jsqlparser/expression/operators/relational/LikeExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/operators/relational/LikeExpressionTest.java index acc1ef6be..eb11e86e2 100644 --- a/src/test/java/net/sf/jsqlparser/expression/operators/relational/LikeExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/operators/relational/LikeExpressionTest.java @@ -9,6 +9,8 @@ */ package net.sf.jsqlparser.expression.operators.relational; +import static org.junit.jupiter.api.Assertions.*; + import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.StringValue; @@ -16,8 +18,6 @@ import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - /** * * @author Tobias Warneke (t.warneke@gmx.net) @@ -58,4 +58,44 @@ void testDuckDBSimuilarTo() throws JSQLParserException { + " ORDER BY v;"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + public void testMatchAny() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v MATCH_ANY 'keyword1 keyword2'", true); + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v NOT MATCH_ANY 'keyword1 keyword2'", true); + } + + @Test + public void testMatchAll() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v MATCH_ALL 'keyword1 keyword2'", true); + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v NOT MATCH_ALL 'keyword1 keyword2'", true); + } + + @Test + public void testMatchPhrase() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v MATCH_PHRASE 'keyword1 keyword2'", true); + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v NOT MATCH_PHRASE 'keyword1 keyword2'", true); + } + + @Test + public void testMatchPhrasePrefix() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v MATCH_PHRASE_PREFIX 'keyword1 keyword2'", true); + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v NOT MATCH_PHRASE_PREFIX 'keyword1 keyword2'", true); + } + + @Test + public void testMatchRegexp() throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v MATCH_REGEXP 'keyword1 keyword2'", true); + TestUtils.assertSqlCanBeParsedAndDeparsed( + "select * from dual where v NOT MATCH_REGEXP 'keyword1 keyword2'", true); + } } diff --git a/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java b/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java index e9f757e4e..088eb699b 100644 --- a/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java @@ -11,9 +11,11 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.AnalyticExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.SelectItem; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -33,4 +35,25 @@ void testGetParent() throws JSQLParserException { assertInstanceOf(SelectItem.class, expression.getParent()); assertEquals(select, expression.getParent(Select.class)); } + + @Test + void testGetWherePositionIssue1339() throws JSQLParserException { + // WHERE expression at line 4 column 7 + String sqlStr = "select listagg(sellerid)\n" + + "within group (order by sellerid)\n" + + "over() AS list from winsales\n" + + "WHERE a=b\n" + + "ORDER BY 1;"; + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + Expression whereExpression = select.getWhere(); + + final Node node = whereExpression.getASTNode(); + if (node != null) { + Token token = node.jjtGetFirstToken(); + Assertions.assertEquals(4, token.beginLine); + Assertions.assertEquals(7, token.beginColumn); + } else { + throw new RuntimeException("Node not found."); + } + } } diff --git a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java index 6546eb25c..e42ca47f4 100644 --- a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java @@ -44,65 +44,64 @@ import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; public class CCJSqlParserUtilTest { - private final static String INVALID_SQL = "" - + "SELECT * FROM TABLE_1 t1\n" - + "WHERE\n" - + "(((t1.COL1 = 'VALUE2' )\n" - + "AND (t1.CAL2 = 'VALUE2' ))\n" - + "AND (((1 = 1 )\n" - + "AND ((((((t1.id IN (940550 ,940600 ,940650 ,940700 ,940750 ,940800 ,940850 ,940900 ,940950 ,941000 ,941050 ,941100 ,941150 ,941200 ,941250 ,941300 ,941350 ,941400 ,941450 ,941500 ,941550 ,941600 ,941650 ,941700 ,941750 ,941800 ,941850 ,941900 ,941950 ,942000 ,942050 ,942100 ,942150 ,942200 ,942250 ,942300 ,942350 ,942400 ,942450 ,942500 ,942550 ,942600 ,942650 ,942700 ,942750 ,942800 ,942850 ,942900 ,942950 ,943000 ,943050 ,943100 ,943150 ,943200 ,943250 ,943300 ,943350 ,943400 ,943450 ,943500 ,943550 ,943600 ,943650 ,943700 ,943750 ,943800 ,943850 ,943900 ,943950 ,944000 ,944050 ,944100 ,944150 ,944200 ,944250 ,944300 ,944350 ,944400 ,944450 ,944500 ,944550 ,944600 ,944650 ,944700 ,944750 ,944800 ,944850 ,944900 ,944950 ,945000 ,945050 ,945100 ,945150 ,945200 ,945250 ,945300 ))\n" - + "OR (t1.id IN (945350 ,945400 ,945450 ,945500 ,945550 ,945600 ,945650 ,945700 ,945750 ,945800 ,945850 ,945900 ,945950 ,946000 ,946050 ,946100 ,946150 ,946200 ,946250 ,946300 ,946350 ,946400 ,946450 ,946500 ,946550 ,946600 ,946650 ,946700 ,946750 ,946800 ,946850 ,946900 ,946950 ,947000 ,947050 ,947100 ,947150 ,947200 ,947250 ,947300 ,947350 ,947400 ,947450 ,947500 ,947550 ,947600 ,947650 ,947700 ,947750 ,947800 ,947850 ,947900 ,947950 ,948000 ,948050 ,948100 ,948150 ,948200 ,948250 ,948300 ,948350 ,948400 ,948450 ,948500 ,948550 ,948600 ,948650 ,948700 ,948750 ,948800 ,948850 ,948900 ,948950 ,949000 ,949050 ,949100 ,949150 ,949200 ,949250 ,949300 ,949350 ,949400 ,949450 ,949500 ,949550 ,949600 ,949650 ,949700 ,949750 ,949800 ,949850 ,949900 ,949950 ,950000 ,950050 ,950100 )))\n" - + "OR (t1.id IN (950150 ,950200 ,950250 ,950300 ,950350 ,950400 ,950450 ,950500 ,950550 ,950600 ,950650 ,950700 ,950750 ,950800 ,950850 ,950900 ,950950 ,951000 ,951050 ,951100 ,951150 ,951200 ,951250 ,951300 ,951350 ,951400 ,951450 ,951500 ,951550 ,951600 ,951650 ,951700 ,951750 ,951800 ,951850 ,951900 ,951950 ,952000 ,952050 ,952100 ,952150 ,952200 ,952250 ,952300 ,952350 ,952400 ,952450 ,952500 ,952550 ,952600 ,952650 ,952700 ,952750 ,952800 ,952850 ,952900 ,952950 ,953000 ,953050 ,953100 ,953150 ,953200 ,953250 ,953300 ,953350 ,953400 ,953450 ,953500 ,953550 ,953600 ,953650 ,953700 )))\n" - + "OR (t1.id IN (953750 ,953800 ,953850 ,953900 ,953950 ,954000 ,954050 ,954100 ,954150 ,954200 ,954250 ,954300 ,954350 ,954400 ,954450 ,954500 ,954550 ,954600 ,954650 ,954700 ,954750 ,954800 ,954850 ,954900 ,954950 ,955000 ,955050 ,955100 ,955150 ,955200 ,955250 ,955300 ,955350 ,955400 ,955450 ,955500 ,955550 ,955600 ,955650 ,955700 ,955750 ,955800 ,955850 ,955900 ,955950 ,956000 ,956050 ,956100 ,956150 ,956200 ,956250 ,956300 ,956350 ,956400 ,956450 ,956500 ,956550 ,956600 ,956650 ,956700 ,956750 ,956800 ,956850 ,956900 ,956950 ,957000 ,957050 ,957100 ,957150 ,957200 ,957250 ,957300 )))\n" - + "OR (t1.id IN (944100, 944150, 944200, 944250, 944300, 944350, 944400, 944450, 944500, 944550, 944600, 944650, 944700, 944750, 944800, 944850, 944900, 944950, 945000 )))\n" - + "OR (t1.id IN (957350 ,957400 ,957450 ,957500 ,957550 ,957600 ,957650 ,957700 ,957750 ,957800 ,957850 ,957900 ,957950 ,958000 ,958050 ,958100 ,958150 ,958200 ,958250 ,958300 ,958350 ,958400 ,958450 ,958500 ,958550 ,958600 ,958650 ,958700 ,958750 ,958800 ,958850 ,958900 ,958950 ,959000 ,959050 ,959100 ,959150 ,959200 ,959250 ,959300 ,959350 ,959400 ,959450 ,959500 ,959550 ,959600 ,959650 ,959700 ,959750 ,959800 ,959850 ,959900 ,959950 ,960000 ,960050 ,960100 ,960150 ,960200 ,960250 ,960300 ,960350 ,960400 ,960450 ,960500 ,960550 ,960600 ,960650 ,960700 ,960750 ,960800 ,960850 ,960900 ,960950 ,961000 ,961050 ,961100 ,961150 ,961200 ,961250 ,961300 ,961350 ,961400 ,961450 ,961500 ,961550 ,961600 ,961650 ,961700 ,961750 ,961800 ,961850 ,961900 ,961950 ,962000 ,962050 ,962100 ))))\n" - + "OR (t1.id IN (962150 ,962200 ,962250 ,962300 ,962350 ,962400 ,962450 ,962500 ,962550 ,962600 ,962650 ,962700 ,962750 ,962800 ,962850 ,962900 ,962950 ,963000 ,963050 ,963100 ,963150 ,963200 ,963250 ,963300 ,963350 ,963400 ,963450 ,963500 ,963550 ,963600 ,963650 ,963700 ,963750 ,963800 ,963850 ,963900 ,963950 ,964000 ,964050 ,964100 ,964150 ,964200 ,964250 ,964300 ,964350 ,964400 ,964450 ,964500 ,964550 ,964600 ,964650 ,964700 ,964750 ,964800 ,964850 ,964900 ,964950 ,965000 ,965050 ,965100 ,965150 ,965200 ,965250 ,965300 ,965350 ,965400 ,965450 ,965500 ))))\n" - + "AND t1.COL3 IN (\n" - + " SELECT\n" - + " t2.COL3\n" - + " FROM\n" - + " TABLE_6 t6,\n" - + " TABLE_1 t5,\n" - + " TABLE_4 t4,\n" - + " TABLE_3 t3,\n" - + " TABLE_1 t2\n" - + " WHERE\n" - + " (((((((t5.CAL3 = T6.id)\n" - + " AND (t5.CAL5 = t6.CAL5))\n" - + " AND (t5.CAL1 = t6.CAL1))\n" - + " AND (t3.CAL1 IN (108500)))\n" - + " AND (t5.id = t2.id))\n" - + " AND NOT ((t6.CAL6 IN ('VALUE'))))\n" - + " AND ((t2.id = t3.CAL2)\n" - + " AND (t4.id = t3.CAL3))))\n" + - // add two redundant unmatched brackets in order to make the Simple Parser fail - // and get the complex parser stuck - " )) \n" - + "ORDER BY\n" - + "t1.id ASC"; + private final static String INVALID_SQL = + "SELECT * FROM TABLE_1 t1\n" + + "WHERE\n" + + "(((t1.COL1 = 'VALUE2' )\n" + + "AND (t1.CAL2 = 'VALUE2' ))\n" + + "AND (((1 = 1 )\n" + + "AND ((((((t1.id IN (940550 ,940600 ,940650 ,940700 ,940750 ,940800 ,940850 ,940900 ,940950 ,941000 ,941050 ,941100 ,941150 ,941200 ,941250 ,941300 ,941350 ,941400 ,941450 ,941500 ,941550 ,941600 ,941650 ,941700 ,941750 ,941800 ,941850 ,941900 ,941950 ,942000 ,942050 ,942100 ,942150 ,942200 ,942250 ,942300 ,942350 ,942400 ,942450 ,942500 ,942550 ,942600 ,942650 ,942700 ,942750 ,942800 ,942850 ,942900 ,942950 ,943000 ,943050 ,943100 ,943150 ,943200 ,943250 ,943300 ,943350 ,943400 ,943450 ,943500 ,943550 ,943600 ,943650 ,943700 ,943750 ,943800 ,943850 ,943900 ,943950 ,944000 ,944050 ,944100 ,944150 ,944200 ,944250 ,944300 ,944350 ,944400 ,944450 ,944500 ,944550 ,944600 ,944650 ,944700 ,944750 ,944800 ,944850 ,944900 ,944950 ,945000 ,945050 ,945100 ,945150 ,945200 ,945250 ,945300 ))\n" + + "OR (t1.id IN (945350 ,945400 ,945450 ,945500 ,945550 ,945600 ,945650 ,945700 ,945750 ,945800 ,945850 ,945900 ,945950 ,946000 ,946050 ,946100 ,946150 ,946200 ,946250 ,946300 ,946350 ,946400 ,946450 ,946500 ,946550 ,946600 ,946650 ,946700 ,946750 ,946800 ,946850 ,946900 ,946950 ,947000 ,947050 ,947100 ,947150 ,947200 ,947250 ,947300 ,947350 ,947400 ,947450 ,947500 ,947550 ,947600 ,947650 ,947700 ,947750 ,947800 ,947850 ,947900 ,947950 ,948000 ,948050 ,948100 ,948150 ,948200 ,948250 ,948300 ,948350 ,948400 ,948450 ,948500 ,948550 ,948600 ,948650 ,948700 ,948750 ,948800 ,948850 ,948900 ,948950 ,949000 ,949050 ,949100 ,949150 ,949200 ,949250 ,949300 ,949350 ,949400 ,949450 ,949500 ,949550 ,949600 ,949650 ,949700 ,949750 ,949800 ,949850 ,949900 ,949950 ,950000 ,950050 ,950100 )))\n" + + "OR (t1.id IN (950150 ,950200 ,950250 ,950300 ,950350 ,950400 ,950450 ,950500 ,950550 ,950600 ,950650 ,950700 ,950750 ,950800 ,950850 ,950900 ,950950 ,951000 ,951050 ,951100 ,951150 ,951200 ,951250 ,951300 ,951350 ,951400 ,951450 ,951500 ,951550 ,951600 ,951650 ,951700 ,951750 ,951800 ,951850 ,951900 ,951950 ,952000 ,952050 ,952100 ,952150 ,952200 ,952250 ,952300 ,952350 ,952400 ,952450 ,952500 ,952550 ,952600 ,952650 ,952700 ,952750 ,952800 ,952850 ,952900 ,952950 ,953000 ,953050 ,953100 ,953150 ,953200 ,953250 ,953300 ,953350 ,953400 ,953450 ,953500 ,953550 ,953600 ,953650 ,953700 )))\n" + + "OR (t1.id IN (953750 ,953800 ,953850 ,953900 ,953950 ,954000 ,954050 ,954100 ,954150 ,954200 ,954250 ,954300 ,954350 ,954400 ,954450 ,954500 ,954550 ,954600 ,954650 ,954700 ,954750 ,954800 ,954850 ,954900 ,954950 ,955000 ,955050 ,955100 ,955150 ,955200 ,955250 ,955300 ,955350 ,955400 ,955450 ,955500 ,955550 ,955600 ,955650 ,955700 ,955750 ,955800 ,955850 ,955900 ,955950 ,956000 ,956050 ,956100 ,956150 ,956200 ,956250 ,956300 ,956350 ,956400 ,956450 ,956500 ,956550 ,956600 ,956650 ,956700 ,956750 ,956800 ,956850 ,956900 ,956950 ,957000 ,957050 ,957100 ,957150 ,957200 ,957250 ,957300 )))\n" + + "OR (t1.id IN (944100, 944150, 944200, 944250, 944300, 944350, 944400, 944450, 944500, 944550, 944600, 944650, 944700, 944750, 944800, 944850, 944900, 944950, 945000 )))\n" + + "OR (t1.id IN (957350 ,957400 ,957450 ,957500 ,957550 ,957600 ,957650 ,957700 ,957750 ,957800 ,957850 ,957900 ,957950 ,958000 ,958050 ,958100 ,958150 ,958200 ,958250 ,958300 ,958350 ,958400 ,958450 ,958500 ,958550 ,958600 ,958650 ,958700 ,958750 ,958800 ,958850 ,958900 ,958950 ,959000 ,959050 ,959100 ,959150 ,959200 ,959250 ,959300 ,959350 ,959400 ,959450 ,959500 ,959550 ,959600 ,959650 ,959700 ,959750 ,959800 ,959850 ,959900 ,959950 ,960000 ,960050 ,960100 ,960150 ,960200 ,960250 ,960300 ,960350 ,960400 ,960450 ,960500 ,960550 ,960600 ,960650 ,960700 ,960750 ,960800 ,960850 ,960900 ,960950 ,961000 ,961050 ,961100 ,961150 ,961200 ,961250 ,961300 ,961350 ,961400 ,961450 ,961500 ,961550 ,961600 ,961650 ,961700 ,961750 ,961800 ,961850 ,961900 ,961950 ,962000 ,962050 ,962100 ))))\n" + + "OR (t1.id IN (962150 ,962200 ,962250 ,962300 ,962350 ,962400 ,962450 ,962500 ,962550 ,962600 ,962650 ,962700 ,962750 ,962800 ,962850 ,962900 ,962950 ,963000 ,963050 ,963100 ,963150 ,963200 ,963250 ,963300 ,963350 ,963400 ,963450 ,963500 ,963550 ,963600 ,963650 ,963700 ,963750 ,963800 ,963850 ,963900 ,963950 ,964000 ,964050 ,964100 ,964150 ,964200 ,964250 ,964300 ,964350 ,964400 ,964450 ,964500 ,964550 ,964600 ,964650 ,964700 ,964750 ,964800 ,964850 ,964900 ,964950 ,965000 ,965050 ,965100 ,965150 ,965200 ,965250 ,965300 ,965350 ,965400 ,965450 ,965500 ))))\n" + + "AND t1.COL3 IN (\n" + + " SELECT\n" + + " t2.COL3\n" + + " FROM\n" + + " TABLE_6 t6,\n" + + " TABLE_1 t5,\n" + + " TABLE_4 t4,\n" + + " TABLE_3 t3,\n" + + " TABLE_1 t2\n" + + " WHERE\n" + + " (((((((t5.CAL3 = T6.id)\n" + + " AND (t5.CAL5 = t6.CAL5))\n" + + " AND (t5.CAL1 = t6.CAL1))\n" + + " AND (t3.CAL1 IN (108500)))\n" + + " AND (t5.id = t2.id))\n" + + " AND NOT ((t6.CAL6 IN ('VALUE'))))\n" + + " AND ((t2.id = t3.CAL2)\n" + + " AND (t4.id = t3.CAL3))))\n" + + // add two redundant unmatched brackets in order to make the Simple Parser fail + // and get the complex parser stuck + " )) \n" + + "ORDER BY\n" + + "t1.id ASC"; @Test public void testParseExpression() throws Exception { Expression result = CCJSqlParserUtil.parseExpression("a+b"); assertEquals("a + b", result.toString()); - assertTrue(result instanceof Addition); + assertInstanceOf(Addition.class, result); Addition add = (Addition) result; - assertTrue(add.getLeftExpression() instanceof Column); - assertTrue(add.getRightExpression() instanceof Column); + assertInstanceOf(Column.class, add.getLeftExpression()); + assertInstanceOf(Column.class, add.getRightExpression()); } @Test public void testParseExpression2() throws Exception { Expression result = CCJSqlParserUtil.parseExpression("2*(a+6.0)"); assertEquals("2 * (a + 6.0)", result.toString()); - assertTrue(result instanceof Multiplication); + assertInstanceOf(Multiplication.class, result); Multiplication mult = (Multiplication) result; - assertTrue(mult.getLeftExpression() instanceof LongValue); - assertTrue(mult.getRightExpression() instanceof ParenthesedExpressionList); + assertInstanceOf(LongValue.class, mult.getLeftExpression()); + assertInstanceOf(ParenthesedExpressionList.class, mult.getRightExpression()); } @Test @@ -218,7 +217,7 @@ public void accept(Statement statement) { + "select *\n" + "from dual;").getBytes(StandardCharsets.UTF_8)), "UTF-8"); - assertEquals(list.size(), 3); + assertEquals(3, list.size()); } @Test @@ -295,37 +294,38 @@ public void testNestingDepth() throws Exception { CCJSqlParserUtil.getNestingDepth("SELECT concat(concat('A','B'),'B') FROM mytbl")); assertEquals(20, CCJSqlParserUtil.getNestingDepth( "concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat('A','B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B'),'B') FROM mytbl")); - assertEquals(4, CCJSqlParserUtil.getNestingDepth("" - + "-- MERGE 1\n" - + "MERGE INTO cfe.impairment imp\n" + " USING ( WITH x AS (\n" - + " SELECT a.id_instrument\n" - + " , a.id_currency\n" - + " , a.id_instrument_type\n" - + " , b.id_portfolio\n" - + " , c.attribute_value product_code\n" - + " , t.valid_date\n" - + " , t.ccf\n" - + " FROM cfe.instrument a\n" - + " INNER JOIN cfe.impairment b\n" - + " ON a.id_instrument = b.id_instrument\n" - + " LEFT JOIN cfe.instrument_attribute c\n" - + " ON a.id_instrument = c.id_instrument\n" - + " AND c.id_attribute = 'product'\n" - + " INNER JOIN cfe.ext_ccf t\n" - + " ON ( a.id_currency LIKE t.id_currency )\n" - + " AND ( a.id_instrument_type LIKE t.id_instrument_type )\n" - + " AND ( b.id_portfolio LIKE t.id_portfolio\n" - + " OR ( b.id_portfolio IS NULL\n" - + " AND t.id_portfolio = '%' ) )\n" - + " AND ( c.attribute_value LIKE t.product_code\n" - + " OR ( c.attribute_value IS NULL\n" - + " AND t.product_code = '%' ) ) )\n" - + "SELECT /*+ PARALLEL */ *\n" + " FROM x x1\n" - + " WHERE x1.valid_date = ( SELECT max\n" - + " FROM x\n" - + " WHERE id_instrument = x1.id_instrument ) ) s\n" - + " ON ( imp.id_instrument = s.id_instrument )\n" + "WHEN MATCHED THEN\n" - + " UPDATE SET imp.ccf = s.ccf\n" + ";")); + assertEquals(4, CCJSqlParserUtil.getNestingDepth( + "-- MERGE 1\n" + + "MERGE INTO cfe.impairment imp\n" + " USING ( WITH x AS (\n" + + " SELECT a.id_instrument\n" + + " , a.id_currency\n" + + " , a.id_instrument_type\n" + + " , b.id_portfolio\n" + + " , c.attribute_value product_code\n" + + " , t.valid_date\n" + + " , t.ccf\n" + + " FROM cfe.instrument a\n" + + " INNER JOIN cfe.impairment b\n" + + " ON a.id_instrument = b.id_instrument\n" + + " LEFT JOIN cfe.instrument_attribute c\n" + + " ON a.id_instrument = c.id_instrument\n" + + " AND c.id_attribute = 'product'\n" + + " INNER JOIN cfe.ext_ccf t\n" + + " ON ( a.id_currency LIKE t.id_currency )\n" + + " AND ( a.id_instrument_type LIKE t.id_instrument_type )\n" + + " AND ( b.id_portfolio LIKE t.id_portfolio\n" + + " OR ( b.id_portfolio IS NULL\n" + + " AND t.id_portfolio = '%' ) )\n" + + " AND ( c.attribute_value LIKE t.product_code\n" + + " OR ( c.attribute_value IS NULL\n" + + " AND t.product_code = '%' ) ) )\n" + + "SELECT /*+ PARALLEL */ *\n" + " FROM x x1\n" + + " WHERE x1.valid_date = ( SELECT max\n" + + " FROM x\n" + + " WHERE id_instrument = x1.id_instrument ) ) s\n" + + " ON ( imp.id_instrument = s.id_instrument )\n" + + "WHEN MATCHED THEN\n" + + " UPDATE SET imp.ccf = s.ccf\n" + ";")); } @Test @@ -406,32 +406,34 @@ public void execute() throws Throwable { } @Test + @Disabled + //@todo: check if this still has a chance to timeout since we got too fast public void testTimeOutIssue1582() { // This statement is INVALID on purpose // There are crafted INTO keywords in order to make it fail but only after a long time (40 // seconds plus) - String sqlStr = "" - + "select\n" - + " t0.operatienr\n" - + " , case\n" - + " when\n" - + " case when (t0.vc_begintijd_operatie is null or lpad((extract('hours' into t0.vc_begintijd_operatie::timestamp))::text,2,'0') ||':'|| lpad(extract('minutes' from t0.vc_begintijd_operatie::timestamp)::text,2,'0') = '00:00') then null\n" - + " else (greatest(((extract('hours' into (t0.vc_eindtijd_operatie::timestamp-t0.vc_begintijd_operatie::timestamp))*60 + extract('minutes' from (t0.vc_eindtijd_operatie::timestamp-t0.vc_begintijd_operatie::timestamp)))/60)::numeric(12,2),0))*60\n" - + " end = 0 then null\n" - + " else '25. Meer dan 4 uur'\n" - + " end\n" - + " as snijtijd_interval"; - - // With DEFAULT TIMEOUT 6 Seconds, we expect the statement to timeout normally + String sqlStr = + "select\n" + + " t0.operatienr\n" + + " , case\n" + + " when\n" + + " case when (t0.vc_begintijd_operatie is null or lpad((extract('hours' into t0.vc_begintijd_operatie::timestamp))::text,2,'0') ||':'|| lpad(extract('minutes' from t0.vc_begintijd_operatie::timestamp)::text,2,'0') = '00:00') then null\n" + + " else (greatest(((extract('hours' into (t0.vc_eindtijd_operatie::timestamp-t0.vc_begintijd_operatie::timestamp))*60 + extract('minutes' from (t0.vc_eindtijd_operatie::timestamp-t0.vc_begintijd_operatie::timestamp)))/60)::numeric(12,2),0))*60\n" + + " end = 0 then null\n" + + " else '25. Meer dan 4 uur'\n" + + " end\n" + + " as snijtijd_interval"; + + // Within timeout, we expect the statement to timeout normally // A TimeoutException wrapped into a Parser Exception should be thrown assertThrows(JSQLParserException.class, new Executable() { @Override public void execute() throws Throwable { try { - CCJSqlParserUtil.parse(sqlStr); + CCJSqlParserUtil.parse(sqlStr, p -> p.withTimeOut(1)); } catch (JSQLParserException ex) { - assertTrue(ex.getCause() instanceof TimeoutException); + assertInstanceOf(TimeoutException.class, ex.getCause()); throw ex; } } @@ -493,11 +495,11 @@ public void execute() throws Throwable { public void execute() throws Throwable { try { CCJSqlParserUtil.parse(INVALID_SQL, executorService, parser -> { - parser.withTimeOut(1000); + parser.withTimeOut(1); parser.withAllowComplexParsing(true); }); } catch (JSQLParserException ex) { - assertTrue(ex.getCause() instanceof TimeoutException); + assertInstanceOf(TimeoutException.class, ex.getCause()); throw ex; } } diff --git a/src/test/java/net/sf/jsqlparser/parser/JSQLParserExceptionTest.java b/src/test/java/net/sf/jsqlparser/parser/JSQLParserExceptionTest.java index 34758fe48..7b5b033b2 100644 --- a/src/test/java/net/sf/jsqlparser/parser/JSQLParserExceptionTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/JSQLParserExceptionTest.java @@ -58,7 +58,8 @@ public void testExceptionPrintStacktraceNoCause() throws Exception { assertFalse(sw.toString().contains("BRATKARTOFFEL")); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ex1.printStackTrace(new PrintStream(bos, true)); - assertFalse(new String(bos.toByteArray(), StandardCharsets.UTF_8).contains("BRATKARTOFFEL")); + assertFalse( + new String(bos.toByteArray(), StandardCharsets.UTF_8).contains("BRATKARTOFFEL")); } @Test diff --git a/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java b/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java index 762620788..4f6961f19 100644 --- a/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java @@ -9,11 +9,8 @@ */ package net.sf.jsqlparser.parser; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.test.TestUtils; import org.javacc.jjtree.JJTree; -import org.javacc.parser.JavaCCErrors; -import org.javacc.parser.JavaCCGlobals; +import org.javacc.parser.Context; import org.javacc.parser.JavaCCParser; import org.javacc.parser.RCharacterList; import org.javacc.parser.RChoice; @@ -36,8 +33,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -52,7 +47,7 @@ class ParserKeywordsUtilsTest { private static void addTokenImage(TreeSet allKeywords, RStringLiteral literal) { - if (CHARSET_ENCODER.canEncode(literal.image) && literal.image.matches("[A-Za-z]+")) { + if (CHARSET_ENCODER.canEncode(literal.image) && literal.image.matches("\\w+")) { allKeywords.add(literal.image); } } @@ -141,21 +136,21 @@ public static TreeSet getAllKeywordsUsingJavaCC(File file) throws Except Path jjGrammarOutputDir = Files.createTempDirectory("jjgrammer"); new JJTree().main(new String[] { - "-JDK_VERSION=1.8", - "-OUTPUT_DIRECTORY=" + jjGrammarOutputDir.toString(), + "-JJTREE_OUTPUT_DIRECTORY=" + jjGrammarOutputDir.toString(), + "-CODE_GENERATOR=java", jjtGrammar.toString() }); Path jjGrammarFile = jjGrammarOutputDir.resolve("JSqlParserCC.jj"); + Context context = new Context(); JavaCCParser parser = new JavaCCParser(new java.io.FileInputStream(jjGrammarFile.toFile())); - parser.javacc_input(); + parser.javacc_input(context); // needed for filling JavaCCGlobals - JavaCCErrors.reInit(); - Semanticize.start(); + Semanticize.start(context); // read all the Token and get the String image - for (Map.Entry item : JavaCCGlobals.rexps_of_tokens + for (Map.Entry item : context.globals().rexps_of_tokens .entrySet()) { addTokenImage(allKeywords, item.getValue()); } @@ -169,9 +164,36 @@ public static TreeSet getAllKeywordsUsingJavaCC(File file) throws Except } @Test - void getAllKeywords() throws IOException { - Set allKeywords = ParserKeywordsUtils.getAllKeywordsUsingRegex(FILE); + void getAllSimpleKeywords() throws IOException { + Set allKeywords = ParserKeywordsUtils.getAllSimpleKeywords(FILE); Assertions.assertFalse(allKeywords.isEmpty(), "Keyword List must not be empty!"); + LOGGER.info("All simple keywords: " + allKeywords.size()); + } + + @Test + void getNonReservedKeywords() { + Set nonReserved = ParserKeywordsUtils.getNonReservedKeywords(); + Assertions.assertFalse(nonReserved.isEmpty(), + "Non-reserved Keyword List must not be empty!"); + LOGGER.info("Non-reserved keywords: " + nonReserved.size()); + } + + @Test + void getReservedKeywords() throws IOException { + Set reserved = ParserKeywordsUtils.getReservedKeywords(FILE); + Assertions.assertFalse(reserved.isEmpty(), "Reserved Keyword List must not be empty!"); + LOGGER.info("Reserved keywords: " + reserved.size()); + } + + @Test + void reservedAndNonReservedAreDisjoint() throws IOException { + Set reserved = ParserKeywordsUtils.getReservedKeywords(FILE); + Set nonReserved = ParserKeywordsUtils.getNonReservedKeywords(); + + TreeSet overlap = new TreeSet<>(reserved); + overlap.retainAll(nonReserved); + Assertions.assertTrue(overlap.isEmpty(), + "Reserved and non-reserved sets must not overlap, but found: " + overlap); } @Test @@ -180,34 +202,25 @@ void getAllKeywordsUsingJavaCC() throws Exception { Assertions.assertFalse(allKeywords.isEmpty(), "Keyword List must not be empty!"); } - // Test, if all Tokens found per RegEx are also found from the JavaCCParser + // Cross-check: compare grammar-scanned keywords with those extracted by the JavaCC Parser. @Test void compareKeywordLists() throws Exception { - Set allRegexKeywords = ParserKeywordsUtils.getAllKeywordsUsingRegex(FILE); + Set allGrammarKeywords = ParserKeywordsUtils.getAllSimpleKeywords(FILE); Set allJavaCCParserKeywords = getAllKeywordsUsingJavaCC(FILE); - // Exceptions, which should not have been found from the RegEx - List exceptions = Arrays.asList("0x"); - - // We expect all Keywords from the Regex to be found by the JavaCC Parser - for (String s : allRegexKeywords) { - Assertions.assertTrue( - exceptions.contains(s) || allJavaCCParserKeywords.contains(s), - "The Keywords from JavaCC do not contain Keyword: " + s); + // Grammar keywords not found by JavaCC — log for review + for (String s : allGrammarKeywords) { + if (!allJavaCCParserKeywords.contains(s)) { + LOGGER.info("Grammar keyword not in JavaCC extraction: " + s); + } } - // The JavaCC Parser finds some more valid Keywords (where no explicit Token has been - // defined + // We expect all simple keywords found by JavaCC to exist in the grammar set for (String s : allJavaCCParserKeywords) { - if (!(exceptions.contains(s) || allRegexKeywords.contains(s))) { - LOGGER.fine("Found Additional Keywords from Parser: " + s); + if (!allGrammarKeywords.contains(s)) { + LOGGER.info("Additional keyword found by JavaCC Parser: " + s); } } } - @Test - void testBase64() throws JSQLParserException { - String sqlStr = "SELECT base64('Spark SQL') AS b;"; - TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - } } diff --git a/src/test/java/net/sf/jsqlparser/parser/feature/FeatureSetTest.java b/src/test/java/net/sf/jsqlparser/parser/feature/FeatureSetTest.java index 850f9a504..fdf2c8745 100644 --- a/src/test/java/net/sf/jsqlparser/parser/feature/FeatureSetTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/feature/FeatureSetTest.java @@ -19,7 +19,8 @@ public class FeatureSetTest { @Test public void testGetNotContained() { assertEquals(EnumSet.of(Feature.select), new FeaturesAllowed(Feature.select, Feature.update) // - .getNotContained(new FeaturesAllowed(Feature.update, Feature.delete).getFeatures())); + .getNotContained( + new FeaturesAllowed(Feature.update, Feature.delete).getFeatures())); } @Test diff --git a/src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java b/src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java index df3b6acc9..c122279d6 100644 --- a/src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/DatabaseTest.java @@ -11,6 +11,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; /** @@ -45,4 +48,10 @@ public void testNullDatabaseAndServer() { assertSame(server, database.getServer()); } + @Test + void testBigQuerycatalogs() throws JSQLParserException { + String sqlStr = "SELECT * FROM \"starlake-325712\".starlake_tbl.transactions"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + } diff --git a/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java b/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java new file mode 100644 index 000000000..dfb5034f6 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/schema/MultiPartNameTest.java @@ -0,0 +1,24 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.schema; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class MultiPartNameTest { + + @Test + void replaceBackticksWithDoubleQuotes() { + Assertions.assertThat("\"starbake\".\"customers\"").isEqualToIgnoringCase( + MultiPartName.replaceBackticksWithDoubleQuotes("`starbake`.`customers`")); + } +} diff --git a/src/test/java/net/sf/jsqlparser/schema/SequenceTest.java b/src/test/java/net/sf/jsqlparser/schema/SequenceTest.java index a69c70920..ec027a8b5 100644 --- a/src/test/java/net/sf/jsqlparser/schema/SequenceTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/SequenceTest.java @@ -32,7 +32,8 @@ public void testSetSchemaName() { @Test public void testSetDatabase() { - Sequence sequence = new Sequence().withName("foo").withSchemaName("bar").withDatabase(new Database("default")); + Sequence sequence = new Sequence().withName("foo").withSchemaName("bar") + .withDatabase(new Database("default")); assertThat(sequence.getDatabase().getDatabaseName()).isEqualTo("default"); assertThat(sequence.getFullyQualifiedName()).isEqualTo("default.bar.foo"); diff --git a/src/test/java/net/sf/jsqlparser/schema/ServerTest.java b/src/test/java/net/sf/jsqlparser/schema/ServerTest.java index 4b891499b..216248be9 100644 --- a/src/test/java/net/sf/jsqlparser/schema/ServerTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/ServerTest.java @@ -57,7 +57,8 @@ public void testServerNameAndInstancePassValues() throws Exception { final Server server = new Server("SERVER", "INSTANCE"); assertEquals("SERVER", server.getServerName()); assertEquals("INSTANCE", server.getInstanceName()); - assertEquals(String.format("[%s\\%s]", "SERVER", "INSTANCE"), server.getFullyQualifiedName()); + assertEquals(String.format("[%s\\%s]", "SERVER", "INSTANCE"), + server.getFullyQualifiedName()); } @Test diff --git a/src/test/java/net/sf/jsqlparser/schema/TableTest.java b/src/test/java/net/sf/jsqlparser/schema/TableTest.java index fc81ce9b2..fe9cfd7bd 100644 --- a/src/test/java/net/sf/jsqlparser/schema/TableTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/TableTest.java @@ -15,6 +15,7 @@ import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.util.deparser.ExpressionDeParser; import net.sf.jsqlparser.util.deparser.SelectDeParser; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.List; @@ -22,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; /** * @@ -58,15 +60,12 @@ public void tableSetDatabaseIssue812() throws JSQLParserException { SelectDeParser deparser = new SelectDeParser(expressionDeParser, buffer) { @Override - public void visit(Table tableName) { - System.out.println(tableName); - tableName.setDatabase(database); // Exception - System.out.println(tableName.getDatabase()); + public StringBuilder visit(Table table, S parameters) { + table.setDatabase(database); // Exception + return null; } }; - - deparser.visit((PlainSelect) select); - + deparser.visit((PlainSelect) select, null); } @Test @@ -85,4 +84,49 @@ public void testConstructorDelimitersInappropriateSize() { .hasMessageContaining( "the length of the delimiters list must be 1 less than nameParts"); } + + @Test + void testBigQueryFullQuotedName() throws JSQLParserException { + String sqlStr = "select * from `d.s.t`"; + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + Table table = (Table) select.getFromItem(); + + assertEquals("\"d\"", table.getCatalogName()); + assertEquals("\"s\"", table.getSchemaName()); + assertEquals("\"t\"", table.getName()); + + assertEquals("d", table.getUnquotedDatabaseName()); + assertEquals("s", table.getUnquotedSchemaName()); + assertEquals("t", table.getUnquotedName()); + + sqlStr = "select * from `s.t`"; + select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + table = (Table) select.getFromItem(); + + assertNull(table.getCatalogName()); + assertEquals("\"s\"", table.getSchemaName()); + assertEquals("\"t\"", table.getName()); + + assertNull(table.getUnquotedDatabaseName()); + assertEquals("s", table.getUnquotedSchemaName()); + assertEquals("t", table.getUnquotedName()); + } + + @Test + void testClone() { + Table t = new Table("a.b.c"); + t.setResolvedTable(t); + + Assertions.assertNotSame(t.clone(), t); + Assertions.assertNotEquals(t.clone(), t); + } + + @Test + void testWithSchema() { + Table t = new Table("a"); + t.setSchemaName("UNNAMED.session1"); + + Assertions.assertEquals("UNNAMED", t.getDatabaseName()); + Assertions.assertEquals("session1", t.getSchemaName()); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/AdaptersTest.java b/src/test/java/net/sf/jsqlparser/statement/AdaptersTest.java index 78d559a83..98c2044b7 100644 --- a/src/test/java/net/sf/jsqlparser/statement/AdaptersTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/AdaptersTest.java @@ -36,35 +36,40 @@ public void testAdapters() throws JSQLParserException { Statement stmnt = CCJSqlParserUtil.parse(sql); final Stack> params = new Stack<>(); - stmnt.accept(new StatementVisitorAdapter() { + stmnt.accept(new StatementVisitorAdapter() { @Override - public void visit(Select select) { - select.accept(new SelectVisitorAdapter() { + public Void visit(Select select, S context) { + select.accept(new SelectVisitorAdapter() { @Override - public void visit(PlainSelect plainSelect) { - plainSelect.getWhere().accept(new ExpressionVisitorAdapter() { + public Void visit(PlainSelect plainSelect, K context) { + plainSelect.getWhere().accept(new ExpressionVisitorAdapter() { @Override - protected void visitBinaryExpression(BinaryExpression expr) { + protected Void visitBinaryExpression(BinaryExpression expr, + J context) { if (!(expr instanceof AndExpression)) { params.push(new Pair<>(null, null)); } - super.visitBinaryExpression(expr); + return super.visitBinaryExpression(expr, context); } @Override - public void visit(Column column) { + public Void visit(Column column, J context) { params.push(new Pair<>(column.getColumnName(), params.pop().getRight())); + return null; } @Override - public void visit(JdbcNamedParameter parameter) { + public Void visit(JdbcNamedParameter parameter, J context) { params.push(new Pair<>(params.pop().getLeft(), parameter.getName())); + return null; } - }); + }, null); + return null; } - }); + }, null); + return null; } }); diff --git a/src/test/java/net/sf/jsqlparser/statement/BlockTest.java b/src/test/java/net/sf/jsqlparser/statement/BlockTest.java index e0d46acf7..99aedcbde 100644 --- a/src/test/java/net/sf/jsqlparser/statement/BlockTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/BlockTest.java @@ -28,17 +28,17 @@ public class BlockTest { @Test public void testGetStatements() throws JSQLParserException { String sqlStr = "begin\n" - + "select * from feature;\n" - + "end;"; + + "select * from feature;\n" + + "end;"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } @Test public void testBlock2() throws JSQLParserException { - String sqlStr="begin\n" - + "update table1 set a = 'xx' where b = 'condition1';\n" - + "update table1 set a = 'xx' where b = 'condition2';\n" - + "end;"; + String sqlStr = "begin\n" + + "update table1 set a = 'xx' where b = 'condition1';\n" + + "update table1 set a = 'xx' where b = 'condition2';\n" + + "end;"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } @@ -54,26 +54,26 @@ public void testBlockToStringIsNullSafe() throws JSQLParserException { Block block = new Block(); block.setStatements(null); assertEquals("BEGIN\n" - + "END", block.toString()); + + "END", block.toString()); } @Test public void testIfElseBlock() throws JSQLParserException { String sqlStr = "if (a=b) begin\n" - + "update table1 set a = 'xx' where b = 'condition1';\n" - + "update table1 set a = 'xx' where b = 'condition2';\n" - + "end"; + + "update table1 set a = 'xx' where b = 'condition1';\n" + + "update table1 set a = 'xx' where b = 'condition2';\n" + + "end"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); String sqlStr2 = "if (a=b) begin\n" - + "update table1 set a = 'xx' where b = 'condition1';\n" - + "update table1 set a = 'xx' where b = 'condition2';\n" - + "end;\n" - + "else begin\n" - + "update table1 set a = 'xx' where b = 'condition1';\n" - + "update table1 set a = 'xx' where b = 'condition2';\n" - + "end;"; + + "update table1 set a = 'xx' where b = 'condition1';\n" + + "update table1 set a = 'xx' where b = 'condition2';\n" + + "end;\n" + + "else begin\n" + + "update table1 set a = 'xx' where b = 'condition1';\n" + + "update table1 set a = 'xx' where b = 'condition2';\n" + + "end;"; Statements statements = CCJSqlParserUtil.parseStatements(sqlStr2); for (Statement stm : statements.getStatements()) { diff --git a/src/test/java/net/sf/jsqlparser/statement/ConditionalKeywordsTest.java b/src/test/java/net/sf/jsqlparser/statement/ConditionalKeywordsTest.java deleted file mode 100644 index fadae1256..000000000 --- a/src/test/java/net/sf/jsqlparser/statement/ConditionalKeywordsTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2021 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.statement; - -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.parser.ParserKeywordsUtils; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Stream; - -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; - -/** - * - * @author Andreas Reichel - */ -public class ConditionalKeywordsTest { - public final static Logger LOGGER = Logger.getLogger(ConditionalKeywordsTest.class.getName()); - - public static Stream keyWords() { - File file = new File("src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt"); - List keywords = new ArrayList<>(); - try { - try { - keywords.addAll(ParserKeywordsUtils.getAllKeywordsUsingRegex(file)); - for (String reserved : ParserKeywordsUtils.getReservedKeywords( - // get all PARSER RESTRICTED without the ALIAS RESTRICTED - ParserKeywordsUtils.RESTRICTED_JSQLPARSER - | ParserKeywordsUtils.RESTRICTED_ALIAS)) { - keywords.remove(reserved); - } - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Failed to generate the Keyword List", ex); - } - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Failed to generate the Keyword List", ex); - } - return keywords.stream(); - } - - @ParameterizedTest(name = "Keyword {0}") - @MethodSource("keyWords") - public void testRelObjectNameExt(String keyword) throws JSQLParserException { - String sqlStr = String.format( - "SELECT %1$s.%1$s.%1$s \"%1$s\" from %1$s \"%1$s\" ORDER BY %1$s ", keyword); - assertSqlCanBeParsedAndDeparsed(sqlStr, true); - } -} diff --git a/src/test/java/net/sf/jsqlparser/statement/ExplainStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/ExplainStatementTest.java new file mode 100644 index 000000000..2a27bada7 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/ExplainStatementTest.java @@ -0,0 +1,47 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class ExplainStatementTest { + + @Test + void testDuckDBSummarizeTable() throws JSQLParserException { + String sqlStr = "SUMMARIZE cfe.test;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testDuckDBSummarizeSelect() throws JSQLParserException { + String sqlStr = "SUMMARIZE SELECT * FROM cfe.test;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testOracleExplainPlan() throws JSQLParserException { + String sqlStr = "EXPLAIN PLAN SELECT * FROM cfe.test;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testH2ExplainPlanFor() throws JSQLParserException { + String sqlStr = "EXPLAIN PLAN FOR SELECT * FROM cfe.test;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testH2ExplainAnalyze() throws JSQLParserException { + String sqlStr = "EXPLAIN ANALYZE SELECT * FROM cfe.test;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/ExplainTest.java b/src/test/java/net/sf/jsqlparser/statement/ExplainTest.java index 54e64cbbc..205fef5c6 100644 --- a/src/test/java/net/sf/jsqlparser/statement/ExplainTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/ExplainTest.java @@ -9,10 +9,12 @@ */ package net.sf.jsqlparser.statement; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; import static net.sf.jsqlparser.test.TestUtils.*; import static org.assertj.core.api.Assertions.assertThat; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.delete.Delete; import org.junit.jupiter.api.Test; public class ExplainTest { @@ -49,23 +51,57 @@ public void testVerbose() throws JSQLParserException { @Test public void testMultiOptions_orderPreserved() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("EXPLAIN VERBOSE ANALYZE BUFFERS COSTS SELECT * FROM mytable"); + assertSqlCanBeParsedAndDeparsed( + "EXPLAIN VERBOSE ANALYZE BUFFERS COSTS SELECT * FROM mytable"); } @Test public void getOption_returnsValues() throws JSQLParserException { - ExplainStatement explain = (ExplainStatement) CCJSqlParserUtil.parse("EXPLAIN VERBOSE FORMAT JSON BUFFERS FALSE SELECT * FROM mytable"); + ExplainStatement explain = (ExplainStatement) CCJSqlParserUtil + .parse("EXPLAIN VERBOSE FORMAT JSON BUFFERS FALSE SELECT * FROM mytable"); assertThat(explain.getOption(ExplainStatement.OptionType.ANALYZE)).isNull(); assertThat(explain.getOption(ExplainStatement.OptionType.VERBOSE)).isNotNull(); ExplainStatement.Option format = explain.getOption(ExplainStatement.OptionType.FORMAT); - assertThat(format).isNotNull().extracting(ExplainStatement.Option::getValue).isEqualTo("JSON"); + assertThat(format).isNotNull().extracting(ExplainStatement.Option::getValue) + .isEqualTo("JSON"); ExplainStatement.Option buffers = explain.getOption(ExplainStatement.OptionType.BUFFERS); - assertThat(buffers).isNotNull().extracting(ExplainStatement.Option::getValue).isEqualTo("FALSE"); + assertThat(buffers).isNotNull().extracting(ExplainStatement.Option::getValue) + .isEqualTo("FALSE"); explain = (ExplainStatement) CCJSqlParserUtil.parse("EXPLAIN SELECT * FROM mytable"); assertThat(explain.getOption(ExplainStatement.OptionType.ANALYZE)).isNull(); } + + @Test + public void testDelete() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("EXPLAIN DELETE FROM mytable"); + } + + @Test + public void testUpdate() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("EXPLAIN UPDATE mytable SET col = 1"); + } + + @Test + public void testInsert() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("EXPLAIN INSERT INTO mytable (col) VALUES (1)"); + } + + @Test + public void explainDelete_usesGenericStatementSlot() throws JSQLParserException { + ExplainStatement explain = + (ExplainStatement) CCJSqlParserUtil.parse("EXPLAIN DELETE FROM mytable"); + assertThat(explain.getStatement()).isInstanceOf(Delete.class); + } + + @Test + public void testDeleteInStatementsList() throws JSQLParserException { + Statements statements = CCJSqlParserUtil.parseStatements("EXPLAIN DELETE FROM mytable;"); + assertThat(statements).isNotNull(); + assertThat(statements).hasSize(1); + assertThat(statements.get(0)).isInstanceOf(ExplainStatement.class); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/IfElseStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/IfElseStatementTest.java index daf812567..c06b42948 100644 --- a/src/test/java/net/sf/jsqlparser/statement/IfElseStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/IfElseStatementTest.java @@ -45,10 +45,10 @@ public void testSimpleIfElseStatement() throws Exception { @Test public void testIfElseStatements1() throws Exception { - String sqlStr - = "IF OBJECT_ID('tOrigin', 'U') IS NOT NULL DROP TABLE tOrigin1; ELSE CREATE TABLE tOrigin1 (ID VARCHAR (40));\n" - + "IF OBJECT_ID('tOrigin', 'U') IS NOT NULL DROP TABLE tOrigin2; ELSE CREATE TABLE tOrigin2 (ID VARCHAR (40));\n" - + "IF OBJECT_ID('tOrigin', 'U') IS NOT NULL DROP TABLE tOrigin3; ELSE CREATE TABLE tOrigin3 (ID VARCHAR (40));\n"; + String sqlStr = + "IF OBJECT_ID('tOrigin', 'U') IS NOT NULL DROP TABLE tOrigin1; ELSE CREATE TABLE tOrigin1 (ID VARCHAR (40));\n" + + "IF OBJECT_ID('tOrigin', 'U') IS NOT NULL DROP TABLE tOrigin2; ELSE CREATE TABLE tOrigin2 (ID VARCHAR (40));\n" + + "IF OBJECT_ID('tOrigin', 'U') IS NOT NULL DROP TABLE tOrigin3; ELSE CREATE TABLE tOrigin3 (ID VARCHAR (40));\n"; Statements result = CCJSqlParserUtil.parseStatements(sqlStr); assertEquals(sqlStr, result.toString()); @@ -86,8 +86,8 @@ public void testObjectBuilder() throws JSQLParserException { @Test public void testValidation() { String sqlStr = "IF OBJECT_ID('tOrigin', 'U') IS NOT NULL DROP TABLE tOrigin1;"; - List errors - = Validation.validate(Arrays.asList(DatabaseType.SQLSERVER, FeaturesAllowed.DROP), sqlStr); + List errors = Validation + .validate(Arrays.asList(DatabaseType.SQLSERVER, FeaturesAllowed.DROP), sqlStr); ValidationTestAsserts.assertErrorsSize(errors, 0); } diff --git a/src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java b/src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java index e1d6b51e6..b595ab096 100644 --- a/src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java @@ -15,40 +15,34 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Stream; import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; /** + * Verifies that all non-reserved keywords can be used as unquoted identifiers (schema, table, + * column, alias, function names). * * @author Andreas Reichel */ public class KeywordsTest { - public final static Logger LOGGER = Logger.getLogger(KeywordsTest.class.getName()); - - public static Stream keyWords() { - File file = new File("src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt"); - List keywords = new ArrayList<>(); - try { - keywords.addAll( ParserKeywordsUtils.getAllKeywordsUsingRegex(file) ); - for (String reserved: ParserKeywordsUtils.getReservedKeywords(ParserKeywordsUtils.RESTRICTED_JSQLPARSER)) { - keywords.remove(reserved); - } - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Failed to generate the Keyword List", ex); - } - return keywords.stream(); + + public static Stream nonReservedKeywords() { + return ParserKeywordsUtils.getNonReservedKeywords().stream(); } @ParameterizedTest(name = "Keyword {0}") - @MethodSource("keyWords") + @MethodSource("nonReservedKeywords") public void testRelObjectNameWithoutValue(String keyword) throws JSQLParserException { - String sqlStr = String.format("SELECT %1$s.%1$s AS %1$s from %1$s.%1$s AS %1$s", keyword); + String sqlStr = String.format("SELECT %1$s.%1$s AS %1$s from %1$s.%1$s AS %1$s", keyword); + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest(name = "Keyword {0}") + @MethodSource("nonReservedKeywords") + public void testRelObjectNameExt(String keyword) throws JSQLParserException { + String sqlStr = String.format( + "SELECT %1$s.%1$s.%1$s \"%1$s\" from %1$s \"%1$s\" ORDER BY %1$s ", keyword); assertSqlCanBeParsedAndDeparsed(sqlStr, true); } @@ -57,5 +51,4 @@ public void testCombinedTokenKeywords() throws JSQLParserException { String sqlStr = "SELECT current_date(3)"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } - } diff --git a/src/test/java/net/sf/jsqlparser/statement/PurgeStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/PurgeStatementTest.java index 390dde2e9..a0caa5c9c 100644 --- a/src/test/java/net/sf/jsqlparser/statement/PurgeStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/PurgeStatementTest.java @@ -53,8 +53,8 @@ public void testStatementVisitorAdaptor() throws JSQLParserException { } /** - * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the TableNamesFinder needed - * for the Code Coverage. + * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the + * TableNamesFinder needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ @@ -69,8 +69,8 @@ public void testTableNamesFinder() throws JSQLParserException { } /** - * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the ExpressionValidator - * needed for the Code Coverage. + * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the + * ExpressionValidator needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ diff --git a/src/test/java/net/sf/jsqlparser/statement/ReturningClauseTest.java b/src/test/java/net/sf/jsqlparser/statement/ReturningClauseTest.java index 331f7263b..6c29f5e41 100644 --- a/src/test/java/net/sf/jsqlparser/statement/ReturningClauseTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/ReturningClauseTest.java @@ -9,7 +9,14 @@ */ package net.sf.jsqlparser.statement; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.AllTableColumns; +import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; @@ -25,4 +32,60 @@ void returnIntoTest() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @Test + void returningOldNewDefaultReferencesTest() throws JSQLParserException { + String sqlStr = "UPDATE products SET price = price * 1.10 " + + "RETURNING old.price AS old_price, new.price AS new_price, new.*"; + Update update = (Update) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + ReturningClause returningClause = update.getReturningClause(); + assertNull(returningClause.getOutputAliases()); + + Column oldPrice = returningClause.get(0).getExpression(Column.class); + assertNull(oldPrice.getTable()); + assertEquals(ReturningReferenceType.OLD, oldPrice.getReturningReferenceType()); + assertEquals("old", oldPrice.getReturningQualifier()); + + Column newPrice = returningClause.get(1).getExpression(Column.class); + assertNull(newPrice.getTable()); + assertEquals(ReturningReferenceType.NEW, newPrice.getReturningReferenceType()); + assertEquals("new", newPrice.getReturningQualifier()); + + AllTableColumns allNew = returningClause.get(2).getExpression(AllTableColumns.class); + assertNull(allNew.getTable()); + assertEquals(ReturningReferenceType.NEW, allNew.getReturningReferenceType()); + assertEquals("new", allNew.getReturningQualifier()); + } + + @Test + void returningWithOutputAliasesTest() throws JSQLParserException { + String sqlStr = "INSERT INTO products (price) VALUES (99.99) " + + "RETURNING WITH (OLD AS o, NEW AS n) o.price AS old_price, n.price AS new_price, n.*"; + Insert insert = (Insert) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + ReturningClause returningClause = insert.getReturningClause(); + assertEquals(2, returningClause.getOutputAliases().size()); + assertEquals(ReturningReferenceType.OLD, + returningClause.getOutputAliases().get(0).getReferenceType()); + assertEquals("o", returningClause.getOutputAliases().get(0).getAlias()); + assertEquals(ReturningReferenceType.NEW, + returningClause.getOutputAliases().get(1).getReferenceType()); + assertEquals("n", returningClause.getOutputAliases().get(1).getAlias()); + + Column oldPrice = returningClause.get(0).getExpression(Column.class); + assertNull(oldPrice.getTable()); + assertEquals(ReturningReferenceType.OLD, oldPrice.getReturningReferenceType()); + assertEquals("o", oldPrice.getReturningQualifier()); + + Column newPrice = returningClause.get(1).getExpression(Column.class); + assertNull(newPrice.getTable()); + assertEquals(ReturningReferenceType.NEW, newPrice.getReturningReferenceType()); + assertEquals("n", newPrice.getReturningQualifier()); + + AllTableColumns allNew = returningClause.get(2).getExpression(AllTableColumns.class); + assertNull(allNew.getTable()); + assertEquals(ReturningReferenceType.NEW, allNew.getReturningReferenceType()); + assertEquals("n", allNew.getReturningQualifier()); + } + } diff --git a/src/test/java/net/sf/jsqlparser/statement/RollbackStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/RollbackStatementTest.java index e14af0c2f..6c4da3109 100644 --- a/src/test/java/net/sf/jsqlparser/statement/RollbackStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/RollbackStatementTest.java @@ -21,11 +21,13 @@ public void testObject() { .withUsingWorkKeyword(true) .withUsingSavepointKeyword(true) .withSavepointName("mySavePoint") - .withForceDistributedTransactionIdentifier("$ForceDistributedTransactionIdentifier"); + .withForceDistributedTransactionIdentifier( + "$ForceDistributedTransactionIdentifier"); assertTrue(rollbackStatement.isUsingSavepointKeyword()); assertEquals("mySavePoint", rollbackStatement.getSavepointName()); - assertEquals("$ForceDistributedTransactionIdentifier", rollbackStatement.getForceDistributedTransactionIdentifier()); + assertEquals("$ForceDistributedTransactionIdentifier", + rollbackStatement.getForceDistributedTransactionIdentifier()); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/SerializationTest.java b/src/test/java/net/sf/jsqlparser/statement/SerializationTest.java new file mode 100644 index 000000000..f5cfad0f6 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/SerializationTest.java @@ -0,0 +1,52 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.select.PlainSelect; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +public class SerializationTest { + @Test + void serializeWithItem() throws JSQLParserException, IOException, ClassNotFoundException { + String sqlStr = + "with sample_data(day, value) as (values ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))), test2 as (values (1,2,3)) \n" + + "select day, value from sample_data as a"; + + // Parse the SQL string into a PlainSelect object + PlainSelect originalSelect = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + + // Serialize the object to a byte array + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + try (ObjectOutputStream out = new ObjectOutputStream(byteArrayOutputStream)) { + out.writeObject(originalSelect); + } + + // Deserialize the object from the byte array + PlainSelect deserializedSelect; + try (ObjectInputStream in = new ObjectInputStream( + new ByteArrayInputStream(byteArrayOutputStream.toByteArray()))) { + deserializedSelect = (PlainSelect) in.readObject(); + } + + // Verify that the original and deserialized objects are equal + Assertions.assertEquals(originalSelect.toString(), deserializedSelect.toString(), + "The deserialized object should be equal to the original"); + } + +} diff --git a/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java new file mode 100644 index 000000000..aabc40745 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/SessionStatementTest.java @@ -0,0 +1,34 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class SessionStatementTest { + + @ParameterizedTest + @ValueSource(strings = { + "SESSION START 1234", "SESSION START", "SESSION APPLY 'test'", "SESSION APPLY", + "SESSION DROP \"test\"", "SESSION DROP", "SESSION SHOW test", "SESSION SHOW", + "SESSION DESCRIBE 1234", "SESSION DESCRIBE", "SESSION START unnamed.session1", + "SESSION START unnamed.session1 WITH persist=false,cleanup=on", + "SESSION APPLY unnamed.session1 WITH persist=false,keep=true" + }) + void testStartSession(String sqlStr) throws JSQLParserException { + SessionStatement sessionStatement = + (SessionStatement) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertInstanceOf(SessionStatement.Action.class, sessionStatement.getAction()); + } + +} diff --git a/src/test/java/net/sf/jsqlparser/statement/SetStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/SetStatementTest.java index 3089d3ef1..d2619c50a 100644 --- a/src/test/java/net/sf/jsqlparser/statement/SetStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/SetStatementTest.java @@ -67,14 +67,14 @@ public void testValueOnIssue927() throws JSQLParserException { @Test public void testObject() { SetStatement setStatement = new SetStatement(); - setStatement.add("standard_conforming_strings", new ExpressionList(new StringValue("ON")), + setStatement.add("standard_conforming_strings", new ExpressionList<>(new StringValue("ON")), false); setStatement.withUseEqual(0, true).remove(0); assertEquals(0, setStatement.getCount()); setStatement.addKeyValuePairs( - new SetStatement.NameExpr("test", new ExpressionList(new StringValue("1")), false)); + new SetStatement.NameExpr("test", new ExpressionList<>(new StringValue("1")), false)); setStatement.getKeyValuePairs().get(0).setUseEqual(true); assertEquals("test", setStatement.getKeyValuePairs().get(0).getName()); diff --git a/src/test/java/net/sf/jsqlparser/statement/ShowIndexStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/ShowIndexStatementTest.java index be525fc6b..0350fd585 100644 --- a/src/test/java/net/sf/jsqlparser/statement/ShowIndexStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/ShowIndexStatementTest.java @@ -14,9 +14,9 @@ import org.junit.jupiter.api.Test; /** -* -* @author Jayant Kumar Yadav -*/ + * + * @author Jayant Kumar Yadav + */ public class ShowIndexStatementTest { @@ -24,4 +24,4 @@ public class ShowIndexStatementTest { public void testSimpleUse() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SHOW INDEX FROM mydatabase"); } -} \ No newline at end of file +} diff --git a/src/test/java/net/sf/jsqlparser/statement/StatementSeparatorTest.java b/src/test/java/net/sf/jsqlparser/statement/StatementSeparatorTest.java index f8b766300..7edbdc515 100644 --- a/src/test/java/net/sf/jsqlparser/statement/StatementSeparatorTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/StatementSeparatorTest.java @@ -53,7 +53,6 @@ void testNewLineNotGoIssue() throws JSQLParserException { void testOracleBlock() throws JSQLParserException { String sqlStr = "BEGIN\n" + "\n" + "SELECT * FROM TABLE;\n" + "\n" + "END\n" + "/\n"; Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - System.out.println(statement); } @Test @@ -69,7 +68,6 @@ void testSOQLIncludes() throws JSQLParserException { String sqlStr = "select name,\ngoods from test_table where option includes ('option1', 'option2')"; Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - System.out.println(statement); } @Test @@ -77,6 +75,5 @@ void testSOQLExcludes() throws JSQLParserException { String sqlStr = "select name,\ngoods from test_table where option excludes ('option1', 'option2')"; Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - System.out.println(statement); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterRowLevelSecurityTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterRowLevelSecurityTest.java new file mode 100644 index 000000000..d91cd6341 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterRowLevelSecurityTest.java @@ -0,0 +1,115 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.alter; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import org.junit.jupiter.api.Test; + +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for PostgreSQL ALTER TABLE ... ROW LEVEL SECURITY statements + */ +public class AlterRowLevelSecurityTest { + + @Test + public void testEnableRowLevelSecurity() throws JSQLParserException { + String sql = "ALTER TABLE table1 ENABLE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("table1", alter.getTable().getName()); + assertEquals(AlterOperation.ENABLE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testEnableRowLevelSecurityWithSchema() throws JSQLParserException { + String sql = "ALTER TABLE customer_custom_data.phone_opt_out ENABLE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals("customer_custom_data.phone_opt_out", + alter.getTable().getFullyQualifiedName()); + assertEquals(AlterOperation.ENABLE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testDisableRowLevelSecurity() throws JSQLParserException { + String sql = "ALTER TABLE table1 DISABLE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.DISABLE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testForceRowLevelSecurity() throws JSQLParserException { + String sql = "ALTER TABLE table1 FORCE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.FORCE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testNoForceRowLevelSecurity() throws JSQLParserException { + String sql = "ALTER TABLE table1 NO FORCE ROW LEVEL SECURITY"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.NO_FORCE_ROW_LEVEL_SECURITY, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testMultipleStatements() throws JSQLParserException { + // Test CREATE POLICY followed by ENABLE RLS + String sql = "CREATE POLICY policy1 ON table1 USING (id = user_id()); " + + "ALTER TABLE table1 ENABLE ROW LEVEL SECURITY"; + + net.sf.jsqlparser.statement.Statements stmts = CCJSqlParserUtil.parseStatements(sql); + assertEquals(2, stmts.getStatements().size()); + + assertInstanceOf(net.sf.jsqlparser.statement.create.policy.CreatePolicy.class, + stmts.getStatements().get(0)); + assertInstanceOf(Alter.class, stmts.getStatements().get(1)); + } + + @Test + public void testEnableKeysStillWorks() throws JSQLParserException { + // Ensure our changes don't break existing ENABLE KEYS syntax + String sql = "ALTER TABLE table1 ENABLE KEYS"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.ENABLE_KEYS, + alter.getAlterExpressions().get(0).getOperation()); + } + + @Test + public void testDisableKeysStillWorks() throws JSQLParserException { + // Ensure our changes don't break existing DISABLE KEYS syntax + String sql = "ALTER TABLE table1 DISABLE KEYS"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals(AlterOperation.DISABLE_KEYS, + alter.getAlterExpressions().get(0).getOperation()); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterSequenceTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterSequenceTest.java index c5fa4fbbf..bb97f4235 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterSequenceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterSequenceTest.java @@ -106,8 +106,10 @@ public void testAlterSequence_withGlobal() throws JSQLParserException { @Test public void testAlterSequence_preservesParamOrder() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("ALTER SEQUENCE my_sec INCREMENT BY 2 START WITH 10"); - assertSqlCanBeParsedAndDeparsed("ALTER SEQUENCE my_sec START WITH 2 INCREMENT BY 5 NOCACHE"); - assertSqlCanBeParsedAndDeparsed("ALTER SEQUENCE my_sec START WITH 2 INCREMENT BY 5 CACHE 200 CYCLE"); + assertSqlCanBeParsedAndDeparsed( + "ALTER SEQUENCE my_sec START WITH 2 INCREMENT BY 5 NOCACHE"); + assertSqlCanBeParsedAndDeparsed( + "ALTER SEQUENCE my_sec START WITH 2 INCREMENT BY 5 CACHE 200 CYCLE"); } @Test diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterSessionTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterSessionTest.java index b2a62ff13..57813ee13 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterSessionTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterSessionTest.java @@ -35,16 +35,20 @@ public void testAlterSessionEnable() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE COMMIT IN PROCEDURE", true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE GUARD", true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL DML", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL DML PARALLEL 10", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL DML PARALLEL 10", + true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL DDL", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL DDL PARALLEL 10", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL DDL PARALLEL 10", + true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL QUERY", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL QUERY PARALLEL 10", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION ENABLE PARALLEL QUERY PARALLEL 10", + true); } @Test public void testAlterSessionDisable() throws JSQLParserException { - TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION DISABLE COMMIT IN PROCEDURE", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION DISABLE COMMIT IN PROCEDURE", + true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION DISABLE GUARD", true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION DISABLE PARALLEL DML", true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION DISABLE PARALLEL DDL", true); @@ -54,17 +58,21 @@ public void testAlterSessionDisable() throws JSQLParserException { @Test public void testAlterSessionForceParallel() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL DML", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL DML PARALLEL 10", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL DML PARALLEL 10", + true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL DDL", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL DDL PARALLEL 10", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL DDL PARALLEL 10", + true); TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL QUERY", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL QUERY PARALLEL 10", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION FORCE PARALLEL QUERY PARALLEL 10", + true); } @Test public void testAlterSessionSet() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION SET ddl_lock_timeout=7200", true); - TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION SET ddl_lock_timeout = 7200", true); + TestUtils.assertSqlCanBeParsedAndDeparsed("ALTER SESSION SET ddl_lock_timeout = 7200", + true); } @Test @@ -75,7 +83,8 @@ public void testAlterSessionResumable() throws JSQLParserException { @Test public void testObject() { - AlterSession alterSession = new AlterSession(AlterSessionOperation.FORCE_PARALLEL_QUERY, Collections.emptyList()); + AlterSession alterSession = new AlterSession(AlterSessionOperation.FORCE_PARALLEL_QUERY, + Collections.emptyList()); assertEquals(AlterSessionOperation.FORCE_PARALLEL_QUERY, alterSession.getOperation()); alterSession.setOperation(AlterSessionOperation.DISABLE_PARALLEL_DML); diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterSystemTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterSystemTest.java index 3bef48a34..ea7594d21 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterSystemTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterSystemTest.java @@ -25,7 +25,8 @@ /** * * @author Andreas Reichel - * @see ALTER SESSION + * @see ALTER + * SESSION */ public class AlterSystemTest { @@ -48,8 +49,8 @@ public void testStatementVisitorAdaptor() throws JSQLParserException { } /** - * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the TableNamesFinder needed - * for the Code Coverage. + * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the + * TableNamesFinder needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ @@ -63,8 +64,8 @@ public void testTableNamesFinder() throws JSQLParserException { } /** - * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the ExpressionValidator - * needed for the Code Coverage. + * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the + * ExpressionValidator needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java index 24995bc3e..ab135ebb2 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java @@ -9,9 +9,13 @@ */ package net.sf.jsqlparser.statement.alter; -import static net.sf.jsqlparser.test.TestUtils.*; +import static net.sf.jsqlparser.test.TestUtils.assertDeparse; +import static net.sf.jsqlparser.test.TestUtils.assertEqualsObjectTree; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static net.sf.jsqlparser.test.TestUtils.assertStatementCanBeDeparsedAs; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -19,6 +23,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo; @@ -36,7 +41,12 @@ import net.sf.jsqlparser.statement.create.table.Index; import net.sf.jsqlparser.statement.create.table.Index.ColumnParams; import net.sf.jsqlparser.statement.create.table.NamedConstraint; +import net.sf.jsqlparser.statement.create.table.PartitionDefinition; +import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class AlterTest { @@ -54,6 +64,23 @@ public void testAlterTableAddColumn() throws JSQLParserException { assertEquals("varchar (255)", colDataTypes.get(0).getColDataType().toString()); } + @Test + public void testAlterTableAddColumnsWhitespace() throws JSQLParserException { + Statement stmt = + CCJSqlParserUtil.parse( + "ALTER TABLE test_catalog.test20241014.tt ADD COLUMNS (apples string, bees int)"); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + assertEquals("test_catalog.test20241014.tt", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExp = alter.getAlterExpressions().get(0); + assertNotNull(alterExp); + List colDataTypes = alterExp.getColDataTypeList(); + assertEquals("apples", colDataTypes.get(0).getColumnName()); + assertEquals("string", colDataTypes.get(0).getColDataType().toString()); + assertEquals("bees", colDataTypes.get(1).getColumnName()); + assertEquals("int", colDataTypes.get(1).getColDataType().toString()); + } + @Test public void testAlterTableAddColumn_ColumnKeyWordImplicit() throws JSQLParserException { Statement stmt = CCJSqlParserUtil.parse("ALTER TABLE mytable ADD mycolumn varchar (255)"); @@ -67,22 +94,19 @@ public void testAlterTableAddColumn_ColumnKeyWordImplicit() throws JSQLParserExc assertEquals("varchar (255)", colDataTypes.get(0).getColDataType().toString()); } - @Test public void testAlterTableBackBrackets() throws JSQLParserException { String sql = "ALTER TABLE tablename add column (field string comment 'aaaaa')"; - Statement statement = CCJSqlParserUtil.parse(sql); - Alter alter = (Alter) statement; - System.out.println(alter.toString()); + Alter alter = (Alter) assertSqlCanBeParsedAndDeparsed(sql); + assertEquals("tablename", alter.getTable().toString()); String sql2 = "ALTER TABLE tablename add column (field string comment 'aaaaa', field2 string comment 'bbbbb');"; Statement statement2 = CCJSqlParserUtil.parse(sql2); Alter alter2 = (Alter) statement2; - System.out.println(alter2.toString()); + assertEquals("tablename", alter2.getTable().toString()); } - @Test public void testAlterTableIssue1815() throws JSQLParserException { // MySQL: see https://dev.mysql.com/doc/refman/8.0/en/alter-table.html @@ -138,6 +162,11 @@ public void testAlterTableUniqueKey() throws JSQLParserException { "ALTER TABLE `schema_migrations` ADD UNIQUE KEY `unique_schema_migrations` (`version`)"); } + @Test + public void testAlterTableUniqueNamedWithoutKeyword() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("ALTER TABLE `goods` ADD UNIQUE `aaa` (`cate_id`)"); + } + @Test public void testAlterTableForgeignKey() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( @@ -225,6 +254,11 @@ public void testAlterTableDropColumn2() throws JSQLParserException { assertEquals("col2", col2Exp.getColumnName()); } + @Test + public void testAlterTableDropColumnIssue2339() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("ALTER TABLE test DROP COLUMN Data"); + } + @Test public void testAlterTableDropConstraint() throws JSQLParserException { final String sql = "ALTER TABLE test DROP CONSTRAINT YYY"; @@ -252,15 +286,14 @@ public void testAlterTablePK() throws JSQLParserException { @Test public void testAlterTableFK() throws JSQLParserException { - String sql = "ALTER TABLE `Novels` ADD FOREIGN KEY (AuthorID) REFERENCES Author (ID)"; - Statement stmt = CCJSqlParserUtil.parse(sql); - assertStatementCanBeDeparsedAs(stmt, sql); + String sql = "ALTER TABLE `Novels` ADD FOREIGN KEY (AuthorID) REFERENCES Author(ID)"; + Statement stmt = TestUtils.assertSqlCanBeParsedAndDeparsed(sql, true); AlterExpression alterExpression = ((Alter) stmt).getAlterExpressions().get(0); - assertEquals(alterExpression.getFkColumns().size(), 1); - assertEquals(alterExpression.getFkColumns().get(0), "AuthorID"); - assertEquals(alterExpression.getFkSourceTable(), "Author"); - assertEquals(alterExpression.getFkSourceColumns().size(), 1); - assertEquals(alterExpression.getFkSourceColumns().get(0), "ID"); + assertEquals(1, alterExpression.getFkColumns().size()); + assertEquals("AuthorID", alterExpression.getFkColumns().get(0)); + assertEquals("Author", alterExpression.getFkSourceTable()); + assertEquals(1, alterExpression.getFkSourceColumns().size()); + assertEquals("ID", alterExpression.getFkSourceColumns().get(0)); } @Test @@ -431,6 +464,11 @@ public void testAlterTableChangeColumn4() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("ALTER TABLE tb_test CHANGE c1 c2 INT (10)"); } + @Test + public void testAlterTableChangeColumnIssue2339() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("ALTER TABLE tb_test CHANGE data INT (10)"); + } + @Test public void testAlterTableAddColumnWithZone() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( @@ -539,6 +577,17 @@ public void testAlterTableIndex586() throws Exception { + "USING BTREE, ALGORITHM = INPLACE", result.toString()); } + @Test + public void testAlterTableDropAndAddUniqueIndexWithAscendingColumns() throws Exception { + Statement result = + CCJSqlParserUtil.parse("ALTER TABLE `wxp_dm`.`xqgl_req_report` " + + "DROP INDEX `index_name`, " + + "ADD UNIQUE INDEX `index_name`(`report_name` ASC) USING BTREE"); + assertEquals("ALTER TABLE `wxp_dm`.`xqgl_req_report` DROP INDEX `index_name`, " + + "ADD UNIQUE INDEX `index_name` (`report_name` ASC) USING BTREE", + result.toString()); + } + @Test public void testIssue259() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( @@ -606,6 +655,19 @@ public void testAlterTableRenameColumn() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed(sql); } + @Test + public void testAlterTableRenameColumn2() throws JSQLParserException { + // Additional test case: Renaming column from 'name' to 'full_name' + String sql = "ALTER TABLE test_table RENAME COLUMN name TO full_name"; + assertSqlCanBeParsedAndDeparsed(sql); + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + AlterExpression expression = alter.getAlterExpressions().get(0); + assertEquals(expression.getOperation(), AlterOperation.RENAME); + assertEquals(expression.getColOldName(), "name"); + assertEquals(expression.getColumnName(), "full_name"); + } + @Test public void testAlterTableForeignKeyIssue981() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( @@ -629,7 +691,8 @@ public void testAlterTableTableCommentIssue984() throws JSQLParserException { .addAlterExpressions(new AlterExpression().withOperation(AlterOperation.COMMENT) .withCommentText("'This is a sample comment'")); assertDeparse(created, statement); - assertEqualsObjectTree(parsed, created); + // disabled because deprecated methods are used + // assertEqualsObjectTree(parsed, created); } @Test @@ -1023,4 +1086,1241 @@ public void testIssue1875() throws JSQLParserException { "ALTER TABLE IF EXISTS usercenter.dict_surgeries ADD COLUMN IF NOT EXISTS operation_grade_id int8 NULL"; assertSqlCanBeParsedAndDeparsed(stmt); } + + @Test + public void testIssue2027() throws JSQLParserException { + String sql = "ALTER TABLE `foo_bar` ADD COLUMN `baz` text"; + assertSqlCanBeParsedAndDeparsed(sql); + + String sqlText = + "ALTER TABLE `foo_bar` ADD COLUMN `baz` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL"; + assertSqlCanBeParsedAndDeparsed(sqlText); + + String sqlTinyText = + "ALTER TABLE `foo_bar` ADD COLUMN `baz` tinytext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL"; + assertSqlCanBeParsedAndDeparsed(sqlTinyText); + + String sqlMediumText = + "ALTER TABLE `foo_bar` ADD COLUMN `baz` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL"; + assertSqlCanBeParsedAndDeparsed(sqlMediumText); + + String sqlLongText = + "ALTER TABLE `foo_bar` ADD COLUMN `baz` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL"; + assertSqlCanBeParsedAndDeparsed(sqlLongText); + } + + @Test + public void testAlterTableCollate() throws JSQLParserException { + // Case 1: Without DEFAULT and without = + String sql = "ALTER TABLE tbl_name COLLATE collation_name"; + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + AlterExpression expression = alter.getAlterExpressions().get(0); + assertEquals(expression.getOperation(), AlterOperation.COLLATE); + assertEquals(expression.getCollation(), "collation_name"); + assertFalse(expression.isDefaultCollateSpecified()); + assertSqlCanBeParsedAndDeparsed(sql); + + // Case 2: Without DEFAULT and with = + sql = "ALTER TABLE tbl_name COLLATE = collation_name"; + + alter = (Alter) CCJSqlParserUtil.parse(sql); + expression = alter.getAlterExpressions().get(0); + assertEquals(expression.getOperation(), AlterOperation.COLLATE); + assertEquals(expression.getCollation(), "collation_name"); + assertFalse(expression.isDefaultCollateSpecified()); + assertSqlCanBeParsedAndDeparsed(sql); + + // Case 3: With DEFAULT and without = + sql = "ALTER TABLE tbl_name DEFAULT COLLATE collation_name"; + + alter = (Alter) CCJSqlParserUtil.parse(sql); + expression = alter.getAlterExpressions().get(0); + assertEquals(expression.getOperation(), AlterOperation.COLLATE); + assertEquals(expression.getCollation(), "collation_name"); + assertTrue(expression.isDefaultCollateSpecified()); + assertSqlCanBeParsedAndDeparsed(sql); + + // Case 4: With DEFAULT and with = + sql = "ALTER TABLE tbl_name DEFAULT COLLATE = collation_name"; + + alter = (Alter) CCJSqlParserUtil.parse(sql); + expression = alter.getAlterExpressions().get(0); + assertEquals(expression.getOperation(), AlterOperation.COLLATE); + assertEquals(expression.getCollation(), "collation_name"); + assertTrue(expression.isDefaultCollateSpecified()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testIssue2090LockNone() throws JSQLParserException { + String sql = + "ALTER TABLE sbtest1 MODIFY COLUMN pad_3 VARCHAR(20) DEFAULT NULL, ALGORITHM=INPLACE, LOCK=NONE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + assertEquals("sbtest1", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(3, alterExpressions.size()); + + AlterExpression lockExp = alterExpressions.get(2); + assertEquals(AlterOperation.LOCK, lockExp.getOperation()); + assertEquals("NONE", lockExp.getLockOption()); + } + + @Test + public void testIssue2090LockExclusive() throws JSQLParserException { + String sql = + "ALTER TABLE sbtest1 MODIFY COLUMN pad_3 VARCHAR(20) DEFAULT NULL, ALGORITHM=INPLACE, LOCK=EXCLUSIVE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + assertEquals("sbtest1", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(3, alterExpressions.size()); + + AlterExpression lockExp = alterExpressions.get(2); + assertEquals(AlterOperation.LOCK, lockExp.getOperation()); + assertEquals("EXCLUSIVE", lockExp.getLockOption()); + } + + @Test + public void testIssue2091ModifyColumnCharacterSet() throws JSQLParserException { + String sql = "ALTER TABLE `jobs`.`runs` MODIFY COLUMN triggerInfo text " + + "CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL"; + + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + + Alter alter = (Alter) stmt; + assertEquals("`jobs`.`runs`", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + ColumnDataType column = alterExpressions.get(0).getColDataTypeList().get(0); + assertEquals("triggerInfo", column.getColumnName()); + assertEquals("text CHARACTER SET utf8mb4", column.getColDataType().toString()); + assertEquals(Arrays.asList("COLLATE", "utf8mb4_unicode_ci", "NOT", "NULL"), + column.getColumnSpecs()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @ParameterizedTest + @MethodSource("provideMySQLConvertTestCases") + public void testIssue2089(String sql, String expectedCharacterSet, String expectedCollation) + throws JSQLParserException { + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter, + "Expected instance of Alter but got: " + stmt.getClass().getSimpleName()); + + Alter alter = (Alter) stmt; + assertEquals("test_table", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions, "Alter expressions should not be null for SQL: " + sql); + assertEquals(1, alterExpressions.size(), "Expected 1 alter expression for SQL: " + sql); + + AlterExpression convertExp = alterExpressions.get(0); + assertEquals(AlterOperation.CONVERT, convertExp.getOperation()); + + assertEquals(expectedCharacterSet, convertExp.getCharacterSet(), + "CHARACTER SET mismatch for SQL: " + sql); + assertEquals(expectedCollation, convertExp.getCollation(), + "COLLATE mismatch for SQL: " + sql); + assertSqlCanBeParsedAndDeparsed(sql); + } + + private static Stream provideMySQLConvertTestCases() { + return Stream.of( + Arguments.of("ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4", "utf8mb4", + null), + Arguments.of( + "ALTER TABLE test_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of( + "ALTER TABLE test_table DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of( + "ALTER TABLE test_table DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of( + "ALTER TABLE test_table CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of( + "ALTER TABLE test_table CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci", + "utf8mb4", "utf8mb4_general_ci"), + Arguments.of("ALTER TABLE test_table DEFAULT CHARACTER SET utf8mb4", "utf8mb4", + null), + Arguments.of("ALTER TABLE test_table DEFAULT CHARACTER SET = utf8mb4", "utf8mb4", + null)); + } + + @Test + public void testIssue2106AlterTableAddPartition1() throws JSQLParserException { + String sql = "ALTER TABLE t1 ADD PARTITION (PARTITION p3 VALUES LESS THAN (2002));"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD_PARTITION, partitionExp.getOperation()); + List partitionDefinitions = partitionExp.getPartitionDefinitions(); + assertNotNull(partitionDefinitions); + assertEquals(1, partitionDefinitions.size()); + + PartitionDefinition partitionDef = partitionDefinitions.get(0); + assertEquals("p3", partitionDef.getPartitionName()); + assertEquals("VALUES LESS THAN", partitionDef.getPartitionOperation()); + assertEquals(Collections.singletonList("2002"), partitionDef.getValues()); + } + + @Test + public void testIssue2106AlterTableAddPartition2() throws JSQLParserException { + String sql = + "ALTER TABLE mtk_seat_state_hist ADD PARTITION (PARTITION SEAT_HIST_202004 VALUES LESS THAN ('2020-05-01'), PARTITION SEAT_HIST_202005 VALUES LESS THAN ('2020-06-01'), PARTITION SEAT_HIST_202006 VALUES LESS THAN ('2020-07-01'));"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD_PARTITION, partitionExp.getOperation()); + List partitions = partitionExp.getPartitionDefinitions(); + assertNotNull(partitions); + assertEquals(3, partitions.size()); + + assertEquals("SEAT_HIST_202004", partitions.get(0).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation()); + assertEquals(Collections.singletonList("'2020-05-01'"), partitions.get(0).getValues()); + + assertEquals("SEAT_HIST_202005", partitions.get(1).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(1).getPartitionOperation()); + assertEquals(Collections.singletonList("'2020-06-01'"), partitions.get(1).getValues()); + + assertEquals("SEAT_HIST_202006", partitions.get(2).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(2).getPartitionOperation()); + assertEquals(Collections.singletonList("'2020-07-01'"), partitions.get(2).getValues()); + } + + @Test + public void testIssue2106AlterTableAddPartition3() throws JSQLParserException { + String sql = + "ALTER TABLE employees ADD PARTITION (PARTITION p5 VALUES LESS THAN (2010), PARTITION p6 VALUES LESS THAN MAXVALUE);"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD_PARTITION, partitionExp.getOperation()); + List partitions = partitionExp.getPartitionDefinitions(); + assertNotNull(partitions); + assertEquals(2, partitions.size()); + + assertEquals("p5", partitions.get(0).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation()); + assertEquals(Collections.singletonList("2010"), partitions.get(0).getValues()); + + assertEquals("p6", partitions.get(1).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(1).getPartitionOperation()); + assertEquals(Collections.singletonList("MAXVALUE"), partitions.get(1).getValues()); + } + + @Test + public void testIssue2106AlterTableAddPartitionCodeTransaction() throws JSQLParserException { + String sql = + "ALTER TABLE `code_transaction` ADD PARTITION (PARTITION p202108 VALUES LESS THAN ('20210901') ENGINE = InnoDB);"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD_PARTITION, partitionExp.getOperation()); + List partitions = partitionExp.getPartitionDefinitions(); + assertNotNull(partitions); + assertEquals(1, partitions.size()); + + assertEquals("p202108", partitions.get(0).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation()); + assertEquals(Collections.singletonList("'20210901'"), partitions.get(0).getValues()); + assertEquals("InnoDB", partitions.get(0).getStorageEngine()); + } + + @Test + public void testIssue2106AlterTableDropPartition() throws JSQLParserException { + String sql = + "ALTER TABLE dkpg_payment_details DROP PARTITION p202007, p202008, p202009, p202010"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.DROP_PARTITION, partitionExp.getOperation()); + List partitionNames = partitionExp.getPartitions(); + assertNotNull(partitionNames); + assertEquals(4, partitionNames.size()); + + assertEquals("p202007", partitionNames.get(0)); + assertEquals("p202008", partitionNames.get(1)); + assertEquals("p202009", partitionNames.get(2)); + assertEquals("p202010", partitionNames.get(3)); + } + + @Test + public void testIssue2106AlterTableTruncatePartition() throws JSQLParserException { + String sql = + "ALTER TABLE dkpg_payments TRUNCATE PARTITION p201701, p201707, p201801, p201807"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.TRUNCATE_PARTITION, partitionExp.getOperation()); + List partitionNames = partitionExp.getPartitions(); + assertNotNull(partitionNames); + assertEquals(4, partitionNames.size()); + + assertEquals("p201701", partitionNames.get(0)); + assertEquals("p201707", partitionNames.get(1)); + assertEquals("p201801", partitionNames.get(2)); + assertEquals("p201807", partitionNames.get(3)); + } + + @Test + public void testIssue2114AlterTableEncryption() throws JSQLParserException { + String sql = "ALTER TABLE confidential_data ENCRYPTION = 'Y'"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression encryptionExp = alterExpressions.get(0); + assertEquals(AlterOperation.SET_TABLE_OPTION, encryptionExp.getOperation()); + assertEquals(encryptionExp.getTableOption(), "ENCRYPTION = 'Y'"); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testIssue2114AlterTableEncryptionWithoutEqual() throws JSQLParserException { + String sql = "ALTER TABLE confidential_data ENCRYPTION 'N'"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression encryptionExp = alterExpressions.get(0); + assertEquals(AlterOperation.SET_TABLE_OPTION, encryptionExp.getOperation()); + assertEquals(encryptionExp.getTableOption(), "ENCRYPTION 'N'"); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testIssue2114AlterTableAutoIncrement() throws JSQLParserException { + String sql = "ALTER TABLE tt AUTO_INCREMENT = 101"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression autoIncrementExp = alterExpressions.get(0); + assertEquals(AlterOperation.SET_TABLE_OPTION, autoIncrementExp.getOperation()); + assertEquals(autoIncrementExp.getTableOption(), "AUTO_INCREMENT = 101"); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testIssue2114AlterTableEngine() throws JSQLParserException { + String sql = "ALTER TABLE city2 ENGINE = InnoDB"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertTrue(stmt instanceof Alter); + Alter alter = (Alter) stmt; + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression engineExp = alterExpressions.get(0); + assertEquals(AlterOperation.ENGINE, engineExp.getOperation()); + assertEquals(engineExp.getEngineOption(), "InnoDB"); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testIssue2118AlterTableForceAndEngine() throws JSQLParserException { + String sql1 = "ALTER TABLE my_table FORCE"; + Statement stmt1 = CCJSqlParserUtil.parse(sql1); + assertTrue(stmt1 instanceof Alter); + Alter alter1 = (Alter) stmt1; + List alterExpressions1 = alter1.getAlterExpressions(); + assertNotNull(alterExpressions1); + assertEquals(1, alterExpressions1.size()); + + AlterExpression forceExp = alterExpressions1.get(0); + assertEquals(AlterOperation.FORCE, forceExp.getOperation()); + assertSqlCanBeParsedAndDeparsed(sql1); + + String sql2 = "ALTER TABLE tbl_name FORCE, ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE"; + Statement stmt2 = CCJSqlParserUtil.parse(sql2); + assertTrue(stmt2 instanceof Alter); + Alter alter2 = (Alter) stmt2; + List alterExpressions2 = alter2.getAlterExpressions(); + assertNotNull(alterExpressions2); + assertEquals(4, alterExpressions2.size()); + + AlterExpression forceExp2 = alterExpressions2.get(0); + assertEquals(AlterOperation.FORCE, forceExp2.getOperation()); + + AlterExpression engineExp = alterExpressions2.get(1); + assertEquals(AlterOperation.ENGINE, engineExp.getOperation()); + assertEquals(engineExp.getEngineOption(), "InnoDB"); + + AlterExpression algorithmExp = alterExpressions2.get(2); + assertEquals(AlterOperation.ALGORITHM, algorithmExp.getOperation()); + assertEquals("INPLACE", algorithmExp.getAlgorithmOption()); + + AlterExpression lockExp = alterExpressions2.get(3); + assertEquals(AlterOperation.LOCK, lockExp.getOperation()); + assertEquals("NONE", lockExp.getLockOption()); + + assertSqlCanBeParsedAndDeparsed(sql2); + } + + @Test + public void testDiscardTablespace() throws JSQLParserException { + String sql = "ALTER TABLE employees DISCARD TABLESPACE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("employees", alter.getTable().getFullyQualifiedName()); + assertEquals("DISCARD_TABLESPACE", + alter.getAlterExpressions().get(0).getOperation().toString()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testImportTablespace() throws JSQLParserException { + String sql = "ALTER TABLE employees IMPORT TABLESPACE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("employees", alter.getTable().getFullyQualifiedName()); + assertEquals("IMPORT_TABLESPACE", + alter.getAlterExpressions().get(0).getOperation().toString()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableKeys() throws JSQLParserException { + // Test for DISABLE KEYS + String sqlDisable = "ALTER TABLE tbl_name DISABLE KEYS"; + Statement stmtDisable = CCJSqlParserUtil.parse(sqlDisable); + assertTrue(stmtDisable instanceof Alter); + Alter alterDisable = (Alter) stmtDisable; + assertEquals("tbl_name", alterDisable.getTable().getFullyQualifiedName()); + AlterExpression alterExpDisable = alterDisable.getAlterExpressions().get(0); + assertEquals(AlterOperation.DISABLE_KEYS, alterExpDisable.getOperation()); + + // Test for ENABLE KEYS + String sqlEnable = "ALTER TABLE tbl_name ENABLE KEYS"; + Statement stmtEnable = CCJSqlParserUtil.parse(sqlEnable); + assertTrue(stmtEnable instanceof Alter); + Alter alterEnable = (Alter) stmtEnable; + assertEquals("tbl_name", alterEnable.getTable().getFullyQualifiedName()); + AlterExpression alterExpEnable = alterEnable.getAlterExpressions().get(0); + assertEquals(AlterOperation.ENABLE_KEYS, alterExpEnable.getOperation()); + } + + @Test + public void testAlterTablePartitionByRangeColumns() throws JSQLParserException { + String sql = "ALTER TABLE `payment_lock` " + + "PARTITION BY RANGE COLUMNS(`created_at`) (" + + "PARTITION p20210217 VALUES LESS THAN ('20210218') ENGINE = InnoDB, " + + "PARTITION p20210218 VALUES LESS THAN ('20210219') ENGINE = InnoDB);"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("`payment_lock`", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.PARTITION_BY, partitionExp.getOperation()); + List partitions = partitionExp.getPartitionDefinitions(); + assertNotNull(partitions); + assertEquals(2, partitions.size()); + + assertEquals("p20210217", partitions.get(0).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation()); + assertEquals(Collections.singletonList("'20210218'"), partitions.get(0).getValues()); + + assertEquals("p20210218", partitions.get(1).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(1).getPartitionOperation()); + assertEquals(Collections.singletonList("'20210219'"), partitions.get(1).getValues()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTablePartitionByRangeUnixTimestamp() throws JSQLParserException { + String sql = "ALTER TABLE `test`.`pipeline_service_metadata_history` " + + "PARTITION BY RANGE (FLOOR(UNIX_TIMESTAMP(requested_at))) (" + + "PARTITION p202104 VALUES LESS THAN (UNIX_TIMESTAMP('2021-05-01 00:00:00')) ENGINE = InnoDB, " + + + "PARTITION p202105 VALUES LESS THAN (UNIX_TIMESTAMP('2021-06-01 00:00:00')) ENGINE = InnoDB);"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("`test`.`pipeline_service_metadata_history`", + alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.PARTITION_BY, partitionExp.getOperation()); + List partitions = partitionExp.getPartitionDefinitions(); + assertNotNull(partitions); + assertEquals(2, partitions.size()); + + assertEquals("p202104", partitions.get(0).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation()); + assertEquals(Collections.singletonList("UNIX_TIMESTAMP('2021-05-01 00:00:00')"), + partitions.get(0).getValues()); + + assertEquals("p202105", partitions.get(1).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(1).getPartitionOperation()); + assertEquals(Collections.singletonList("UNIX_TIMESTAMP('2021-06-01 00:00:00')"), + partitions.get(1).getValues()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTablePartitionByRangeUnixTimestamp2() throws JSQLParserException { + String sql = "ALTER TABLE MP_MNEWS.PUR_MNEWS_CONTS " + + "PARTITION BY RANGE (UNIX_TIMESTAMP(REG_DATE_TS)) (" + + "PARTITION p202007 VALUES LESS THAN (1596207600) ENGINE = InnoDB, " + + "PARTITION p202008 VALUES LESS THAN (1598886000) ENGINE = InnoDB, " + + "PARTITION p202009 VALUES LESS THAN (1601478000) ENGINE = InnoDB);"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("MP_MNEWS.PUR_MNEWS_CONTS", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression partitionExp = alterExpressions.get(0); + assertEquals(AlterOperation.PARTITION_BY, partitionExp.getOperation()); + List partitions = partitionExp.getPartitionDefinitions(); + assertNotNull(partitions); + assertEquals(3, partitions.size()); + + assertEquals("p202007", partitions.get(0).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(0).getPartitionOperation()); + assertEquals(Collections.singletonList("1596207600"), partitions.get(0).getValues()); + + assertEquals("p202008", partitions.get(1).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(1).getPartitionOperation()); + assertEquals(Collections.singletonList("1598886000"), partitions.get(1).getValues()); + + assertEquals("p202009", partitions.get(2).getPartitionName()); + assertEquals("VALUES LESS THAN", partitions.get(2).getPartitionOperation()); + assertEquals(Collections.singletonList("1601478000"), partitions.get(2).getValues()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableDiscardPartitionTablespace() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name DISCARD PARTITION p1 TABLESPACE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.DISCARD_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertEquals("TABLESPACE", alterExpression.getTableOption()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableDiscardAllPartitionTablespace() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name DISCARD PARTITION ALL TABLESPACE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.DISCARD_PARTITION, alterExpression.getOperation()); + assertEquals("ALL", alterExpression.getPartitions().get(0)); + assertEquals("TABLESPACE", alterExpression.getTableOption()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableImportMultiplePartitionsTablespace() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name IMPORT PARTITION p1, p2 TABLESPACE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.IMPORT_PARTITION, alterExpression.getOperation()); + + List partitions = alterExpression.getPartitions(); + assertNotNull(partitions); + assertEquals(2, partitions.size()); + assertEquals("p1", partitions.get(0)); + assertEquals("p2", partitions.get(1)); + + assertEquals("TABLESPACE", alterExpression.getTableOption()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableTruncatePartition() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name TRUNCATE PARTITION p1"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.TRUNCATE_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableCoalescePartition() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name COALESCE PARTITION 2"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.COALESCE_PARTITION, alterExpression.getOperation()); + assertEquals(2, alterExpression.getCoalescePartitionNumber()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableReorganizePartition() throws JSQLParserException { + String sql = + "ALTER TABLE tbl_name REORGANIZE PARTITION p1 INTO (PARTITION p2 VALUES LESS THAN (100))"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.REORGANIZE_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + PartitionDefinition partitionDef = alterExpression.getPartitionDefinitions().get(0); + assertEquals("p2", partitionDef.getPartitionName()); + assertEquals("VALUES LESS THAN", partitionDef.getPartitionOperation()); + assertEquals(Collections.singletonList("100"), partitionDef.getValues()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableExchangePartition() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name EXCHANGE PARTITION p1 WITH TABLE tbl_name2"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.EXCHANGE_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertEquals("tbl_name2", alterExpression.getExchangePartitionTableName()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableExchangePartitionWithValidation() throws JSQLParserException { + String sql = + "ALTER TABLE tbl_name EXCHANGE PARTITION p1 WITH TABLE tbl_name2 WITH VALIDATION"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.EXCHANGE_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertEquals("tbl_name2", alterExpression.getExchangePartitionTableName()); + assertTrue(alterExpression.isExchangePartitionWithValidation()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAnalyzePartition() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name ANALYZE PARTITION p1"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.ANALYZE_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableCheckPartition() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name CHECK PARTITION p1"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.CHECK_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableOptimizePartition() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name OPTIMIZE PARTITION p1"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.OPTIMIZE_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableRebuildPartition() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name REBUILD PARTITION p1"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.REBUILD_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableRepairPartition() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name REPAIR PARTITION p1"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.REPAIR_PARTITION, alterExpression.getOperation()); + assertEquals("p1", alterExpression.getPartitions().get(0)); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableRemovePartitioning() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name REMOVE PARTITIONING"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("tbl_name", alter.getTable().getFullyQualifiedName()); + AlterExpression alterExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.REMOVE_PARTITIONING, alterExpression.getOperation()); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableKeyBlockSizeAlgorithmLock() throws JSQLParserException { + String sql = "ALTER TABLE dw_rpt " + + "KEY_BLOCK_SIZE = 8, " + + "ALGORITHM = INPLACE, " + + "LOCK = NONE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + Alter alter = (Alter) stmt; + assertEquals("dw_rpt", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(3, alterExpressions.size()); + + AlterExpression keyBlockSizeExp = alterExpressions.get(0); + assertEquals(AlterOperation.KEY_BLOCK_SIZE, keyBlockSizeExp.getOperation()); + assertEquals(8, keyBlockSizeExp.getKeyBlockSize()); + + AlterExpression algorithmExp = alterExpressions.get(1); + assertEquals(AlterOperation.ALGORITHM, algorithmExp.getOperation()); + assertEquals("INPLACE", algorithmExp.getAlgorithmOption()); + + AlterExpression lockExp = alterExpressions.get(2); + assertEquals(AlterOperation.LOCK, lockExp.getOperation()); + assertEquals("NONE", lockExp.getLockOption()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddFullTextIndex() throws JSQLParserException { + String sql = "ALTER TABLE yum_table_myisam ADD FULLTEXT (name)"; + Statement stmt = CCJSqlParserUtil.parse(sql); + + Alter alter = (Alter) stmt; + assertEquals("yum_table_myisam", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression indexExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, indexExp.getOperation()); + assertEquals("FULLTEXT", indexExp.getIndex().getType()); + assertEquals("name", indexExp.getIndex().getColumnsNames().get(0)); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddSpatialIndex() throws JSQLParserException { + String sql = "ALTER TABLE places ADD SPATIAL KEY sp_idx_location(location)"; + Statement stmt = CCJSqlParserUtil.parse(sql); + + Alter alter = (Alter) stmt; + assertEquals("places", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression indexExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, indexExp.getOperation()); + assertEquals("SPATIAL", indexExp.getIndex().getType()); + assertEquals("sp_idx_location", indexExp.getIndex().getName()); + assertEquals("location", indexExp.getIndex().getColumnsNames().get(0)); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddFullTextIndexWithOptions() throws JSQLParserException { + String sql = "ALTER TABLE my_table ADD FULLTEXT my_idx(col1, col2) " + + "KEY_BLOCK_SIZE = 8 WITH PARSER ngram COMMENT 'fulltext' INVISIBLE"; + + Statement stmt = CCJSqlParserUtil.parse(sql); + Alter alter = (Alter) stmt; + + assertEquals("my_table", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression indexExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, indexExp.getOperation()); + + Index index = indexExp.getIndex(); + assertNotNull(index); + assertEquals("FULLTEXT", index.getType()); + assertEquals("my_idx", index.getName()); + + List columnNames = index.getColumnsNames(); + assertEquals(2, columnNames.size()); + assertEquals("col1", columnNames.get(0)); + assertEquals("col2", columnNames.get(1)); + + List indexSpec = index.getIndexSpec(); + assertNotNull(indexSpec); + assertEquals(4, indexSpec.size()); + assertEquals("KEY_BLOCK_SIZE = 8", indexSpec.get(0)); + assertEquals("WITH PARSER ngram", indexSpec.get(1)); + assertEquals("COMMENT 'fulltext'", indexSpec.get(2)); + assertEquals("INVISIBLE", indexSpec.get(3)); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddUnnamedIndex() throws JSQLParserException { + String sql = "ALTER TABLE employees ADD INDEX (name1, name2)"; + + Statement stmt = CCJSqlParserUtil.parse(sql); + Alter alter = (Alter) stmt; + + assertEquals("employees", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression indexExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, indexExp.getOperation()); + + Index index = indexExp.getIndex(); + assertNotNull(index); + assertNull(index.getName()); + + List columnNames = index.getColumnsNames(); + assertEquals(2, columnNames.size()); + assertEquals("name1", columnNames.get(0)); + assertEquals("name2", columnNames.get(1)); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddIndexWithOptions() throws JSQLParserException { + String sql = "ALTER TABLE employees ADD INDEX idx_lastname (last_name) " + + "USING BTREE KEY_BLOCK_SIZE = 16 COMMENT 'Performance tuning' VISIBLE"; + + Statement stmt = CCJSqlParserUtil.parse(sql); + Alter alter = (Alter) stmt; + + assertEquals("employees", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression indexExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, indexExp.getOperation()); + + Index index = indexExp.getIndex(); + assertNotNull(index); + assertEquals("INDEX", index.getIndexKeyword()); + assertEquals("idx_lastname", index.getName()); + assertEquals("last_name", index.getColumnsNames().get(0)); + + List indexSpec = index.getIndexSpec(); + assertNotNull(indexSpec); + assertEquals(4, indexSpec.size()); + assertEquals("USING BTREE", indexSpec.get(0)); + assertEquals("KEY_BLOCK_SIZE = 16", indexSpec.get(1)); + assertEquals("COMMENT 'Performance tuning'", indexSpec.get(2)); + assertEquals("VISIBLE", indexSpec.get(3)); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddIndex_UsingBeforeColumns() throws JSQLParserException { + String sql = "ALTER TABLE t ADD INDEX idx_name USING BTREE (col)"; + + Statement stmt = CCJSqlParserUtil.parse(sql); + Alter alter = (Alter) stmt; + + assertEquals("t", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertEquals(1, alterExpressions.size()); + + AlterExpression expr = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, expr.getOperation()); + + Index index = expr.getIndex(); + assertEquals("idx_name", index.getName()); + assertEquals("INDEX", index.getIndexKeyword()); + assertEquals("BTREE", index.getUsing()); + assertEquals(List.of("col"), index.getColumnsNames()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddFunctionalIndexes() throws JSQLParserException { + String sql = "ALTER TABLE PPK_OLPN ADD INDEX fAdd ((b + c)), " + + "ADD INDEX fCoalesce ((COALESCE(PK, b)) DESC)"; + + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + assertEquals("PPK_OLPN", alter.getTable().getFullyQualifiedName()); + assertEquals(2, alter.getAlterExpressions().size()); + + AlterExpression addExpression = alter.getAlterExpressions().get(0); + assertEquals(AlterOperation.ADD, addExpression.getOperation()); + assertEquals("fAdd", addExpression.getIndex().getName()); + assertTrue(addExpression.getIndex().getColumns().get(0).isExpression()); + assertEquals("b + c", addExpression.getIndex().getColumns().get(0).getColumnName()); + + AlterExpression coalesceExpression = alter.getAlterExpressions().get(1); + assertEquals(AlterOperation.ADD, coalesceExpression.getOperation()); + assertEquals("fCoalesce", coalesceExpression.getIndex().getName()); + assertTrue(coalesceExpression.getIndex().getColumns().get(0).isExpression()); + assertEquals("COALESCE(PK, b)", + coalesceExpression.getIndex().getColumns().get(0).getColumnName()); + assertEquals(List.of("DESC"), + coalesceExpression.getIndex().getColumns().get(0).getParams()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableSetDefaultWithAlgorithm() throws JSQLParserException { + String sql = "ALTER TABLE t2 ALTER COLUMN b SET DEFAULT 100, ALGORITHM = INSTANT"; + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + + assertEquals("t2", alter.getTable().getFullyQualifiedName()); + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(2, alterExpressions.size()); + + AlterExpression setDefaultExp = alterExpressions.get(0); + assertEquals(AlterOperation.ALTER, setDefaultExp.getOperation()); + assertEquals("b", setDefaultExp.getColumnSetDefaultList().get(0).getColumnName()); + assertEquals("100", setDefaultExp.getColumnSetDefaultList().get(0).getDefaultValue()); + + AlterExpression algorithmExp = alterExpressions.get(1); + assertEquals(AlterOperation.ALGORITHM, algorithmExp.getOperation()); + assertEquals("INSTANT", algorithmExp.getAlgorithmOption()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableDropDefaultWithAlgorithm() throws JSQLParserException { + String sql = "ALTER TABLE t2 ALTER COLUMN b DROP DEFAULT, ALGORITHM = INSTANT"; + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + + assertEquals("t2", alter.getTable().getFullyQualifiedName()); + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(2, alterExpressions.size()); + + AlterExpression dropDefaultExp = alterExpressions.get(0); + assertEquals(AlterOperation.ALTER, dropDefaultExp.getOperation()); + assertEquals("b", dropDefaultExp.getColumnDropDefaultList().get(0).getColumnName()); + + AlterExpression algorithmExp = alterExpressions.get(1); + assertEquals(AlterOperation.ALGORITHM, algorithmExp.getOperation()); + assertEquals("INSTANT", algorithmExp.getAlgorithmOption()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + + @Test + public void testAlterTableColumnSetInvisible() throws JSQLParserException { + String sql = "ALTER TABLE tbl ALTER COLUMN ts SET INVISIBLE"; + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + + assertEquals("tbl", alter.getTable().getFullyQualifiedName()); + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression setInvisibleExp = alterExpressions.get(0); + assertEquals(AlterOperation.ALTER, setInvisibleExp.getOperation()); + assertEquals("ts", setInvisibleExp.getColumnSetVisibilityList().get(0).getColumnName()); + assertFalse(setInvisibleExp.getColumnSetVisibilityList().get(0).isVisible()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableSetInvisible() throws JSQLParserException { + String sql = "ALTER TABLE tbl ALTER ts SET INVISIBLE"; + Alter alter = (Alter) CCJSqlParserUtil.parse(sql); + + assertEquals("tbl", alter.getTable().getFullyQualifiedName()); + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression setInvisibleExp = alterExpressions.get(0); + assertEquals(AlterOperation.ALTER, setInvisibleExp.getOperation()); + assertEquals("ts", setInvisibleExp.getColumnSetVisibilityList().get(0).getColumnName()); + assertFalse(setInvisibleExp.getColumnSetVisibilityList().get(0).isVisible()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterIndexVisibility() throws JSQLParserException { + String sql = "ALTER TABLE tbl_name ALTER INDEX idx_name VISIBLE"; + Alter alterVisible = (Alter) CCJSqlParserUtil.parse(sql); + + assertEquals("tbl_name", alterVisible.getTable().getFullyQualifiedName()); + List alterExpressionsVisible = alterVisible.getAlterExpressions(); + assertNotNull(alterExpressionsVisible); + assertEquals(1, alterExpressionsVisible.size()); + + AlterExpression visibleExp = alterExpressionsVisible.get(0); + assertEquals(AlterOperation.ALTER, visibleExp.getOperation()); + assertEquals("idx_name", visibleExp.getIndex().getName()); + assertEquals("VISIBLE", visibleExp.getIndex().getIndexSpec().get(0)); + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAlterConstraintEnforced() throws JSQLParserException { + String sql = "ALTER TABLE employees ALTER CONSTRAINT chk_salary ENFORCED"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + + Alter alter = (Alter) stmt; + assertEquals("employees", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression alterConstraintExp = alterExpressions.get(0); + assertEquals(AlterOperation.ALTER, alterConstraintExp.getOperation()); + assertEquals("CONSTRAINT", alterConstraintExp.getConstraintType()); + assertEquals("chk_salary", alterConstraintExp.getConstraintSymbol()); + assertTrue(alterConstraintExp.isEnforced()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAlterCheckNotEnforced() throws JSQLParserException { + String sql = "ALTER TABLE employees ALTER CHECK chk_salary NOT ENFORCED"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + + Alter alter = (Alter) stmt; + assertEquals("employees", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression alterCheckExp = alterExpressions.get(0); + assertEquals(AlterOperation.ALTER, alterCheckExp.getOperation()); + assertEquals("CHECK", alterCheckExp.getConstraintType()); + assertEquals("chk_salary", alterCheckExp.getConstraintSymbol()); + assertFalse(alterCheckExp.isEnforced()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddConstraintUniqueKey() throws JSQLParserException { + String sql = "ALTER TABLE sbtest1 ADD CONSTRAINT UNIQUE KEY ux_c3 (c3)"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + + Alter alter = (Alter) stmt; + assertEquals("sbtest1", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression alterExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, alterExp.getOperation()); + assertEquals("UNIQUE KEY", alterExp.getConstraintType()); + assertEquals("ux_c3", alterExp.getConstraintSymbol()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAlterIndexInvisible() throws JSQLParserException { + String sql = "ALTER TABLE sbtest1 ALTER INDEX c4 INVISIBLE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + + Alter alter = (Alter) stmt; + assertEquals("sbtest1", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression alterExp = alterExpressions.get(0); + assertEquals(AlterOperation.ALTER, alterExp.getOperation()); + assertEquals("c4", alterExp.getIndex().getName()); + assertEquals("INVISIBLE", alterExp.getIndex().getIndexSpec().get(0)); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddIndexInvisible() throws JSQLParserException { + String sql = "ALTER TABLE t1 ADD INDEX k_idx (k) INVISIBLE"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + + Alter alter = (Alter) stmt; + assertEquals("t1", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression alterExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, alterExp.getOperation()); + assertNotNull(alterExp.getIndex()); + assertEquals("k_idx", alterExp.getIndex().getName()); + assertEquals("INDEX", alterExp.getIndex().getIndexKeyword()); + + List columnNames = alterExp.getIndex().getColumnsNames(); + assertNotNull(columnNames); + assertEquals(1, columnNames.size()); + assertEquals("k", columnNames.get(0)); + + List indexSpec = alterExp.getIndex().getIndexSpec(); + assertNotNull(indexSpec); + assertTrue(indexSpec.contains("INVISIBLE")); + + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testAlterTableAddConstraintPrimaryKeyUsingIndexName() throws JSQLParserException { + String sql = + "ALTER TABLE TNWAV ADD CONSTRAINT PK_TNWAV PRIMARY KEY (NWNAME, ZEILE, BESTGRU) USING INDEX PK_TNWAV"; + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(Alter.class, stmt); + + Alter alter = (Alter) stmt; + assertEquals("TNWAV", alter.getTable().getFullyQualifiedName()); + + List alterExpressions = alter.getAlterExpressions(); + assertNotNull(alterExpressions); + assertEquals(1, alterExpressions.size()); + + AlterExpression alterExp = alterExpressions.get(0); + assertEquals(AlterOperation.ADD, alterExp.getOperation()); + assertNotNull(alterExp.getIndex()); + assertEquals(Arrays.asList("USING", "INDEX", "PK_TNWAV"), alterExp.getParameters()); + + assertSqlCanBeParsedAndDeparsed(sql); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/alter/RenameTableStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/RenameTableStatementTest.java index a53a5051e..6123687ad 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/RenameTableStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/RenameTableStatementTest.java @@ -32,7 +32,8 @@ public class RenameTableStatementTest { /** - * This test will parse and deparse the statement and assures the functional coverage by JSQLParser. + * This test will parse and deparse the statement and assures the functional coverage by + * JSQLParser. * * @throws net.sf.jsqlparser.JSQLParserException */ @@ -65,8 +66,8 @@ public void testStatementVisitorAdaptor() throws JSQLParserException { } /** - * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the TableNamesFinder needed - * for the Code Coverage. + * This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the + * TableNamesFinder needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ @@ -82,8 +83,8 @@ public void testTableNamesFinder() throws JSQLParserException { } /** - * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the ExpressionValidator - * needed for the Code Coverage. + * This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the + * ExpressionValidator needed for the Code Coverage. * * @throws net.sf.jsqlparser.JSQLParserException */ @@ -101,7 +102,8 @@ public void testValidator() throws JSQLParserException { sqlStr = "ALTER TABLE public.oldTableName RENAME TO newTableName"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - // this needs to succeed according to: https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_3001.htm + // this needs to succeed according to: + // https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_3001.htm ValidationTestAsserts.validateNoErrors(sqlStr, 1, DatabaseType.ORACLE); // this needs to succeed @@ -110,7 +112,7 @@ public void testValidator() throws JSQLParserException { sqlStr = "ALTER TABLE IF EXISTS public.oldTableName RENAME TO newTableName"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); - // should fail when IF EXISTS is not supported in Oracle 11 + // should fail when IF EXISTS is not supported in Oracle 11 ValidationTestAsserts.validateNoErrors(sqlStr, 1, DatabaseType.ORACLE); // this needs to succeed diff --git a/src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java b/src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java index 087bc4ebb..7f19370f4 100644 --- a/src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/analyze/AnalyzeTest.java @@ -33,7 +33,7 @@ public void testAnalyze() throws JSQLParserException { assertDeparse(new Analyze().withTable(new Table("mytab")), statement); } - + @Test public void testAnalyze2() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("ANALYZE mytable"); diff --git a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java index 7d4c33714..3fbfe8d96 100644 --- a/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java @@ -16,8 +16,8 @@ import net.sf.jsqlparser.statement.create.table.ColDataType; import net.sf.jsqlparser.statement.refresh.RefreshMode; import net.sf.jsqlparser.statement.select.ParenthesedSelect; -import net.sf.jsqlparser.statement.update.UpdateSet; import net.sf.jsqlparser.util.ReflectionTestUtils; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -110,6 +110,7 @@ public class ReflectionModelTest { new net.sf.jsqlparser.expression.operators.relational.InExpression(), new net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression(), new net.sf.jsqlparser.expression.operators.relational.IsNullExpression(), + new net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression(), new net.sf.jsqlparser.expression.operators.relational.JsonOperator("@>"), new net.sf.jsqlparser.expression.operators.relational.LikeExpression(), new net.sf.jsqlparser.expression.operators.relational.Matches(), @@ -169,7 +170,7 @@ public class ReflectionModelTest { new net.sf.jsqlparser.statement.grant.Grant(), new net.sf.jsqlparser.statement.insert.Insert(), new net.sf.jsqlparser.statement.merge.Merge(), - new net.sf.jsqlparser.statement.merge.MergeUpdate(new ArrayList()), + new net.sf.jsqlparser.statement.merge.MergeUpdate(new ArrayList<>()), new net.sf.jsqlparser.statement.select.AllColumns(), // new net.sf.jsqlparser.statement.select.AllTableColumns(new Table()), new net.sf.jsqlparser.statement.select.Distinct(), @@ -189,7 +190,7 @@ public class ReflectionModelTest { new net.sf.jsqlparser.statement.select.OrderByElement(), // new net.sf.jsqlparser.statement.select.ParenthesisFromItem().getFromItem(), new net.sf.jsqlparser.statement.select.Pivot(), - new net.sf.jsqlparser.statement.select.PivotXml(), + // new net.sf.jsqlparser.statement.select.PivotXml(), // new net.sf.jsqlparser.statement.select.PlainSelect(), // new net.sf.jsqlparser.statement.select.Select(), new net.sf.jsqlparser.statement.select.SelectItem<>(), @@ -210,6 +211,7 @@ public class ReflectionModelTest { null)); @Test + @Disabled public void testModels() { ReflectionTestUtils.testGetterSetterChaining(MODEL_OBJECTS, m -> !"setASTNode".equals(m.getName())); diff --git a/src/test/java/net/sf/jsqlparser/statement/comment/CommentTest.java b/src/test/java/net/sf/jsqlparser/statement/comment/CommentTest.java index 231a9f1b6..840905bdd 100755 --- a/src/test/java/net/sf/jsqlparser/statement/comment/CommentTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/comment/CommentTest.java @@ -48,7 +48,8 @@ public void testCommentTableDeparse() throws JSQLParserException { String statement = "COMMENT ON TABLE table1 IS 'comment1'"; assertSqlCanBeParsedAndDeparsed(statement); - Comment c = new Comment().withTable(new Table("table1")).withComment(new StringValue("comment1")); + Comment c = new Comment().withTable(new Table("table1")) + .withComment(new StringValue("comment1")); assertEquals("table1", c.getTable().getName()); assertEquals("comment1", c.getComment().getValue()); assertDeparse(c, statement, false); @@ -82,12 +83,14 @@ public void testToString() { @Test public void testCommentColumnDeparseIssue696() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("COMMENT ON COLUMN hotels.hotelid IS 'Primary key of the table'"); + assertSqlCanBeParsedAndDeparsed( + "COMMENT ON COLUMN hotels.hotelid IS 'Primary key of the table'"); } @Test public void testCommentTableColumnDiffersIssue984() throws JSQLParserException { - Comment comment = (Comment) CCJSqlParserUtil.parse("COMMENT ON COLUMN myTable.myColumn is 'Some comment'"); + Comment comment = (Comment) CCJSqlParserUtil + .parse("COMMENT ON COLUMN myTable.myColumn is 'Some comment'"); assertThat(comment.getTable()).isNull(); assertThat(comment.getColumn().getColumnName()).isEqualTo("myColumn"); assertThat(comment.getColumn().getTable().getFullyQualifiedName()).isEqualTo("myTable"); @@ -95,10 +98,12 @@ public void testCommentTableColumnDiffersIssue984() throws JSQLParserException { @Test public void testCommentTableColumnDiffersIssue984_2() throws JSQLParserException { - Comment comment = (Comment) CCJSqlParserUtil.parse("COMMENT ON COLUMN mySchema.myTable.myColumn is 'Some comment'"); + Comment comment = (Comment) CCJSqlParserUtil + .parse("COMMENT ON COLUMN mySchema.myTable.myColumn is 'Some comment'"); assertThat(comment.getTable()).isNull(); assertThat(comment.getColumn().getColumnName()).isEqualTo("myColumn"); - assertThat(comment.getColumn().getTable().getFullyQualifiedName()).isEqualTo("mySchema.myTable"); + assertThat(comment.getColumn().getTable().getFullyQualifiedName()) + .isEqualTo("mySchema.myTable"); assertThat(comment.getColumn().getTable().getName()).isEqualTo("myTable"); assertThat(comment.getColumn().getTable().getSchemaName()).isEqualTo("mySchema"); } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateFunctionalStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateFunctionalStatementTest.java index 9689737ff..66880938c 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateFunctionalStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateFunctionalStatementTest.java @@ -9,18 +9,21 @@ */ package net.sf.jsqlparser.statement.create; +import static net.sf.jsqlparser.test.TestUtils.assertDeparse; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.assertj.core.api.Assertions.assertThat; + import java.util.Arrays; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statements; import net.sf.jsqlparser.statement.create.function.CreateFunction; import net.sf.jsqlparser.statement.create.procedure.CreateProcedure; -import static net.sf.jsqlparser.test.TestUtils.assertDeparse; -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; -import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Test; /** - * Tests the behavior of {@link net.sf.jsqlparser.statement.CreateFunctionalStatement funtion statements} + * Tests the behavior of {@link net.sf.jsqlparser.statement.CreateFunctionalStatement funtion + * statements} */ public class CreateFunctionalStatementTest { @@ -36,16 +39,17 @@ public void createFunctionMinimal() throws JSQLParserException { @Test public void createFunctionLong() throws JSQLParserException { - CreateFunction stm = (CreateFunction) CCJSqlParserUtil.parse("CREATE FUNCTION fun(query_from_time date) RETURNS TABLE(foo double precision, bar double precision)\n" - + " LANGUAGE plpgsql\n" - + " AS $$\n" - + " BEGIN\n" - + " RETURN QUERY\n" - + " WITH bla AS (\n" - + " SELECT * from foo)\n" - + " Select * from bla;\n" - + " END;\n" - + " $$;"); + CreateFunction stm = (CreateFunction) CCJSqlParserUtil.parse( + "CREATE FUNCTION fun(query_from_time date) RETURNS TABLE(foo double precision, bar double precision)\n" + + " LANGUAGE plpgsql\n" + + " AS $$\n" + + " BEGIN\n" + + " RETURN QUERY\n" + + " WITH bla AS (\n" + + " SELECT * from foo)\n" + + " Select * from bla;\n" + + " END;\n" + + " $$;"); assertThat(stm).isNotNull(); assertThat(stm.formatDeclaration()).contains("fun ( query_from_time date )"); } @@ -62,13 +66,14 @@ public void createProcedureMinimal() throws JSQLParserException { @Test public void createProcedureLong() throws JSQLParserException { - CreateProcedure stm = (CreateProcedure) CCJSqlParserUtil.parse("CREATE PROCEDURE remove_emp (employee_id NUMBER) AS\n" - + " tot_emps NUMBER;\n" - + " BEGIN\n" - + " DELETE FROM employees\n" - + " WHERE employees.employee_id = remove_emp.employee_id;\n" - + " tot_emps := tot_emps - 1;\n" - + " END;"); + CreateProcedure stm = (CreateProcedure) CCJSqlParserUtil + .parse("CREATE PROCEDURE remove_emp (employee_id NUMBER) AS\n" + + " tot_emps NUMBER;\n" + + " BEGIN\n" + + " DELETE FROM employees\n" + + " WHERE employees.employee_id = remove_emp.employee_id;\n" + + " tot_emps := tot_emps - 1;\n" + + " END;"); assertThat(stm).isNotNull(); assertThat(stm.formatDeclaration()).contains("remove_emp ( employee_id NUMBER )"); } @@ -83,4 +88,66 @@ public void createOrReplaceFunctionMinimal() throws JSQLParserException { func.setOrReplace(true); assertDeparse(func, statement); } + + @Test + public void createFunctionWithPositionalParametersAcrossStatementsIssue2322() + throws JSQLParserException { + String sql = "create table if not exists test_table (\n" + + " id bigint not null\n" + + ");\n" + + "\n" + + "create or replace function test_fn_1(\n" + + " target text,\n" + + " characters text\n" + + ") returns boolean as $$\n" + + " select trim($2 from $1) <> $1\n" + + "$$ language sql immutable;\n" + + "\n" + + "create or replace function test_fn_2(\n" + + " target text,\n" + + " characters text\n" + + ") returns boolean as $$\n" + + " select position(repeat(first_char, 2) in translate(\n" + + " $1, $2, repeat(first_char, length($2))\n" + + " )) > 0\n" + + " from (values (left($2, 1))) params(first_char)\n" + + "$$ language sql immutable;\n" + + "\n" + + "create table if not exists test_table_2 (\n" + + " id bigint not null\n" + + ");"; + + Statements statements = CCJSqlParserUtil.parseStatements(sql); + + assertThat(statements.getStatements()).hasSize(4); + assertThat(statements.getStatements().get(1)).isInstanceOf(CreateFunction.class); + assertThat(statements.getStatements().get(2)).isInstanceOf(CreateFunction.class); + + CreateFunction function1 = (CreateFunction) statements.getStatements().get(1); + CreateFunction function2 = (CreateFunction) statements.getStatements().get(2); + + assertThat(function1.getFunctionDeclarationParts()).anySatisfy( + token -> assertThat(token).startsWith("$$").endsWith("$$")); + assertThat(function1.getFunctionDeclarationParts()).containsSequence("language", "sql", + "immutable", ";"); + assertThat(String.join(" ", function1.getFunctionDeclarationParts())) + .contains("test_fn_1") + .contains("$2") + .contains("$1") + .doesNotContain("create or replace function test_fn_2"); + + assertThat(function2.getFunctionDeclarationParts()).anySatisfy( + token -> assertThat(token).startsWith("$$").endsWith("$$")); + assertThat(function2.getFunctionDeclarationParts()).containsSequence("language", "sql", + "immutable", ";"); + assertThat(String.join(" ", function2.getFunctionDeclarationParts())) + .contains("test_fn_2") + .contains("params") + .doesNotContain("create table if not exists test_table_2"); + + assertThat(function1.formatDeclaration()).contains("test_fn_1"); + assertThat(function1.formatDeclaration()).doesNotContain("test_fn_2"); + assertThat(function2.formatDeclaration()).contains("test_fn_2"); + assertThat(function2.formatDeclaration()).doesNotContain("test_table_2"); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java index 23b1d581a..0a95930a3 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateIndexTest.java @@ -11,7 +11,9 @@ import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.StringReader; import java.util.List; @@ -148,4 +150,22 @@ void testCreateIndexIssue1814() throws JSQLParserException { "CREATE INDEX idx_operationlog_operatetime_regioncode USING BTREE ON operation_log (operate_time,region_biz_code)"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + public void testCreateIndexWithFunctionalKeyParts() throws JSQLParserException { + String statement = + "CREATE INDEX fAdd ON PPK_OLPN ((b + c), (COALESCE(PK, b)) DESC)"; + CreateIndex createIndex = (CreateIndex) parserManager.parse(new StringReader(statement)); + + assertEquals(2, createIndex.getIndex().getColumns().size()); + assertTrue(createIndex.getIndex().getColumns().get(0).isExpression()); + assertEquals("b + c", createIndex.getIndex().getColumns().get(0).getColumnName()); + assertTrue(createIndex.getIndex().getColumns().get(1).isExpression()); + assertEquals("COALESCE(PK, b)", createIndex.getIndex().getColumns().get(1).getColumnName()); + assertNotNull(createIndex.getIndex().getColumns().get(1).getParams()); + assertEquals("DESC", createIndex.getIndex().getColumns().get(1).getParams().get(0)); + assertEquals(statement, createIndex.toString()); + + assertSqlCanBeParsedAndDeparsed(statement); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTablesFinderTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTablesFinderTest.java new file mode 100644 index 000000000..031c86b6e --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTablesFinderTest.java @@ -0,0 +1,263 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.create; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.util.TablesNamesFinder; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for TablesNamesFinder integration with PostgreSQL CREATE POLICY statements. + * + *

    + * These tests verify that TablesNamesFinder correctly identifies ALL tables referenced in a CREATE + * POLICY statement, including: + *

      + *
    • The policy's target table
    • + *
    • Tables in USING expression subqueries
    • + *
    • Tables in WITH CHECK expression subqueries
    • + *
    • Tables in complex expressions (JOINs, CTEs, nested subqueries)
    • + *
    + * + *

    + * Current Status: These tests will FAIL until + * TablesNamesFinder.visit(CreatePolicy) is updated to traverse USING and WITH CHECK expressions. + * This is incomplete feature support, not a regression - CREATE POLICY parsing works correctly, but + * analysis tools don't yet have complete integration. + * + *

    + * Expected Behavior: Once fixed, TablesNamesFinder should find tables in policy + * expressions using the same pattern as other statements (CreateView, Insert, Update). + */ +public class CreatePolicyTablesFinderTest { + + // ========================================================================= + // Helper Methods + // ========================================================================= + + /** + * Parse SQL and extract table names using TablesNamesFinder. + */ + private List getTablesFromSQL(String sql) throws JSQLParserException { + Statement stmt = CCJSqlParserUtil.parse(sql); + TablesNamesFinder finder = new TablesNamesFinder(); + return finder.getTableList(stmt); + } + + /** + * Assert that the actual table list contains exactly the expected tables. + */ + private void assertContainsAllTables(List actual, String... expected) { + assertEquals(expected.length, actual.size(), + "Expected " + expected.length + " tables but found " + actual.size() + ". " + + "Expected: " + java.util.Arrays.toString(expected) + ", " + + "Actual: " + actual); + + for (String table : expected) { + assertTrue(actual.contains(table), + "Expected to find table '" + table + "' but it was missing. " + + "Found tables: " + actual); + } + } + + // ========================================================================= + // Simple Subqueries - Basic USE Cases + // ========================================================================= + + @Test + public void testTablesFinderWithSubqueryInUsing() throws JSQLParserException { + String sql = "CREATE POLICY tenant_policy ON documents " + + "USING (tenant_id IN (SELECT tenant_id FROM tenant_access))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table in USING subquery + assertContainsAllTables(tables, "documents", "tenant_access"); + } + + @Test + public void testTablesFinderWithSubqueryInWithCheck() throws JSQLParserException { + String sql = "CREATE POLICY data_policy ON user_data " + + "WITH CHECK (status IN (SELECT allowed_status FROM status_config))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table in WITH CHECK subquery + assertContainsAllTables(tables, "user_data", "status_config"); + } + + @Test + public void testTablesFinderWithBothUsingAndWithCheck() throws JSQLParserException { + String sql = "CREATE POLICY dual_check_policy ON records " + + "USING (user_id IN (SELECT id FROM active_users)) " + + "WITH CHECK (status IN (SELECT status FROM valid_statuses))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table in USING + table in WITH CHECK + assertContainsAllTables(tables, "records", "active_users", "valid_statuses"); + } + + // ========================================================================= + // Complex Expressions - Multiple/Nested Subqueries + // ========================================================================= + + @Test + public void testTablesFinderWithMultipleSubqueries() throws JSQLParserException { + String sql = "CREATE POLICY complex_policy ON documents " + + "USING (" + + " tenant_id IN (SELECT tenant_id FROM tenant_access) " + + " AND status IN (SELECT status FROM allowed_statuses) " + + " AND department_id = (SELECT id FROM departments WHERE name = 'Engineering')" + + ")"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + 3 tables from subqueries + assertContainsAllTables(tables, "documents", "tenant_access", "allowed_statuses", + "departments"); + } + + @Test + public void testTablesFinderWithNestedSubqueries() throws JSQLParserException { + String sql = "CREATE POLICY nested_policy ON orders " + + "USING (customer_id IN (" + + " SELECT customer_id FROM customer_access " + + " WHERE region_id IN (SELECT id FROM regions WHERE active = true)" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + tables from nested subqueries + assertContainsAllTables(tables, "orders", "customer_access", "regions"); + } + + @Test + public void testTablesFinderWithJoinsInSubquery() throws JSQLParserException { + String sql = "CREATE POLICY join_policy ON orders " + + "USING (EXISTS (" + + " SELECT 1 FROM customers c " + + " JOIN customer_access ca ON c.id = ca.customer_id " + + " WHERE c.id = orders.customer_id" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + tables from JOIN in subquery + assertContainsAllTables(tables, "orders", "customers", "customer_access"); + } + + // ========================================================================= + // Advanced SQL Features - CTEs, Schema Qualification, Functions + // ========================================================================= + + @Test + public void testTablesFinderWithCTE() throws JSQLParserException { + String sql = "CREATE POLICY cte_policy ON documents " + + "USING (tenant_id IN (" + + " WITH active_tenants AS (SELECT id FROM tenants WHERE active = true) " + + " SELECT id FROM active_tenants" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table referenced in CTE + assertContainsAllTables(tables, "documents", "tenants"); + } + + @Test + public void testTablesFinderWithSchemaQualifiedTables() throws JSQLParserException { + String sql = "CREATE POLICY schema_policy ON myschema.documents " + + "USING (tenant_id IN (SELECT id FROM otherschema.tenants))"; + + List tables = getTablesFromSQL(sql); + + // Should find both schema-qualified tables + assertEquals(2, tables.size(), + "Should find both schema-qualified tables. Found: " + tables); + + // Check if tables are found (with or without schema prefix depending on TablesNamesFinder + // behavior) + boolean foundDocuments = tables.stream() + .anyMatch(t -> t.contains("documents")); + boolean foundTenants = tables.stream() + .anyMatch(t -> t.contains("tenants")); + + assertTrue(foundDocuments, "Should find documents table. Found: " + tables); + assertTrue(foundTenants, "Should find tenants table. Found: " + tables); + } + + @Test + public void testTablesFinderWithTableFunctions() throws JSQLParserException { + // PostgreSQL table-valued functions can be used in FROM clauses + String sql = "CREATE POLICY function_policy ON documents " + + "USING (tenant_id IN (" + + " SELECT tenant_id FROM get_accessible_tenants(current_user_id())" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should at least find the target table + // Note: Table-valued functions might not be reported as "tables" depending on + // implementation + assertTrue(tables.contains("documents"), + "Should at least find the target table. Found: " + tables); + } + + // ========================================================================= + // Edge Cases - EXISTS, UNION, Empty Policies + // ========================================================================= + + @Test + public void testTablesFinderWithExistsClause() throws JSQLParserException { + String sql = "CREATE POLICY exists_policy ON documents " + + "USING (EXISTS (" + + " SELECT 1 FROM tenant_access " + + " WHERE tenant_id = documents.tenant_id AND active = true" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + table in EXISTS subquery + assertContainsAllTables(tables, "documents", "tenant_access"); + } + + @Test + public void testTablesFinderWithUnionInSubquery() throws JSQLParserException { + String sql = "CREATE POLICY union_policy ON documents " + + "USING (tenant_id IN (" + + " SELECT tenant_id FROM primary_tenants " + + " UNION " + + " SELECT tenant_id FROM secondary_tenants" + + "))"; + + List tables = getTablesFromSQL(sql); + + // Should find: target table + both tables in UNION + assertContainsAllTables(tables, "documents", "primary_tenants", "secondary_tenants"); + } + + @Test + public void testTablesFinderEmptyPolicy() throws JSQLParserException { + // Policy with no USING or WITH CHECK clauses + String sql = "CREATE POLICY simple_policy ON documents"; + + List tables = getTablesFromSQL(sql); + + // Should only find the target table + assertContainsAllTables(tables, "documents"); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTest.java new file mode 100644 index 000000000..829efd2c7 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreatePolicyTest.java @@ -0,0 +1,158 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.create; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; +import org.junit.jupiter.api.Test; + +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for PostgreSQL CREATE POLICY statement (Row Level Security) + */ +public class CreatePolicyTest { + + @Test + public void testCreatePolicyBasic() throws JSQLParserException { + String sql = "CREATE POLICY policy_name ON table_name"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Statement stmt = CCJSqlParserUtil.parse(sql); + assertInstanceOf(CreatePolicy.class, stmt); + CreatePolicy policy = (CreatePolicy) stmt; + assertEquals("policy_name", policy.getPolicyName()); + assertEquals("table_name", policy.getTable().getName()); + } + + @Test + public void testCreatePolicyWithSchema() throws JSQLParserException { + String sql = + "CREATE POLICY single_tenant_access_policy ON customer_custom_data.phone_opt_out"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + Statement stmt = CCJSqlParserUtil.parse(sql); + CreatePolicy policy = (CreatePolicy) stmt; + assertEquals("single_tenant_access_policy", policy.getPolicyName()); + assertEquals("customer_custom_data.phone_opt_out", + policy.getTable().getFullyQualifiedName()); + } + + @Test + public void testCreatePolicyWithForClause() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 FOR SELECT"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals("SELECT", policy.getCommand()); + } + + @Test + public void testCreatePolicyWithAllCommands() throws JSQLParserException { + String[] commands = {"ALL", "SELECT", "INSERT", "UPDATE", "DELETE"}; + for (String cmd : commands) { + String sql = "CREATE POLICY p ON t FOR " + cmd; + assertSqlCanBeParsedAndDeparsed(sql, true); + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals(cmd, policy.getCommand()); + } + } + + @Test + public void testCreatePolicyWithSingleRole() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 TO role1"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals(1, policy.getRoles().size()); + assertEquals("role1", policy.getRoles().get(0)); + } + + @Test + public void testCreatePolicyWithMultipleRoles() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 TO role1, role2, role3"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals(3, policy.getRoles().size()); + assertEquals("role1", policy.getRoles().get(0)); + assertEquals("role2", policy.getRoles().get(1)); + assertEquals("role3", policy.getRoles().get(2)); + } + + @Test + public void testCreatePolicyWithUsing() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 USING (user_id = current_user_id())"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertNotNull(policy.getUsingExpression()); + } + + @Test + public void testCreatePolicyWithWithCheck() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 WITH CHECK (status = 'active')"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertNotNull(policy.getWithCheckExpression()); + } + + @Test + public void testCreatePolicyComplete() throws JSQLParserException { + String sql = + "CREATE POLICY single_tenant_access_policy ON customer_custom_data.phone_opt_out " + + "FOR SELECT " + + "TO gong_app_single_tenant_ro_role, gong_app_single_tenant_rw_role " + + "USING (company_id = current_setting('gong.tenant.company_id')::bigint)"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals("single_tenant_access_policy", policy.getPolicyName()); + assertEquals("customer_custom_data.phone_opt_out", + policy.getTable().getFullyQualifiedName()); + assertEquals("SELECT", policy.getCommand()); + assertEquals(2, policy.getRoles().size()); + assertNotNull(policy.getUsingExpression()); + } + + @Test + public void testCreatePolicyWithBothUsingAndWithCheck() throws JSQLParserException { + String sql = "CREATE POLICY policy1 ON table1 " + + "USING (department_id = current_user_department()) " + + "WITH CHECK (status IN ('draft', 'published'))"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertNotNull(policy.getUsingExpression()); + assertNotNull(policy.getWithCheckExpression()); + } + + @Test + public void testCreatePolicyCompleteWithAllClauses() throws JSQLParserException { + String sql = "CREATE POLICY admin_policy ON documents " + + "FOR UPDATE " + + "TO admin_role, superuser " + + "USING (author_id = current_user_id()) " + + "WITH CHECK (updated_at >= CURRENT_TIMESTAMP)"; + assertSqlCanBeParsedAndDeparsed(sql, true); + + CreatePolicy policy = (CreatePolicy) CCJSqlParserUtil.parse(sql); + assertEquals("admin_policy", policy.getPolicyName()); + assertEquals("documents", policy.getTable().getName()); + assertEquals("UPDATE", policy.getCommand()); + assertEquals(2, policy.getRoles().size()); + assertNotNull(policy.getUsingExpression()); + assertNotNull(policy.getWithCheckExpression()); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java index d73e433bd..10a37207c 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java @@ -9,13 +9,14 @@ */ package net.sf.jsqlparser.statement.create; +import static net.sf.jsqlparser.test.TestUtils.*; + import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.schema.Database; import net.sf.jsqlparser.schema.Sequence; import net.sf.jsqlparser.schema.Sequence.Parameter; import net.sf.jsqlparser.schema.Sequence.ParameterType; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; -import static net.sf.jsqlparser.test.TestUtils.*; import org.junit.jupiter.api.Test; public class CreateSequenceTest { @@ -24,7 +25,8 @@ public class CreateSequenceTest { public void testCreateSequence_noParams() throws JSQLParserException { String statement = "CREATE SEQUENCE my_seq"; assertSqlCanBeParsedAndDeparsed(statement); - assertDeparse(new CreateSequence().withSequence(new Sequence().withName("my_seq")), statement); + assertDeparse(new CreateSequence().withSequence(new Sequence().withName("my_seq")), + statement); } @Test @@ -32,8 +34,15 @@ public void testCreateSequence_withIncrement() throws JSQLParserException { String statement = "CREATE SEQUENCE db.schema.my_seq INCREMENT BY 1"; assertSqlCanBeParsedAndDeparsed(statement); assertDeparse(new CreateSequence().withSequence( - new Sequence().withDatabase(new Database("db")).withSchemaName("schema").withName("my_seq") - .addParameters(new Parameter(ParameterType.INCREMENT_BY).withValue(1L))), statement); + new Sequence().withDatabase(new Database("db")).withSchemaName("schema") + .withName("my_seq") + .addParameters(new Parameter(ParameterType.INCREMENT_BY).withValue(1L))), + statement); + } + + @Test + public void testCreateSequence_withIncrementPostres() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE db.schema.my_seq INCREMENT 1"); } @Test @@ -41,6 +50,11 @@ public void testCreateSequence_withStart() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE my_seq START WITH 10"); } + @Test + public void testCreateSequence_withStartPostgres() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE my_seq START 10"); + } + @Test public void testCreateSequence_withMaxValue() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE my_seq MAXVALUE 5"); @@ -117,7 +131,8 @@ public void testCreateSequence_withGlobal() throws JSQLParserException { @Test public void testCreateSequence_preservesParamOrder() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE my_sec INCREMENT BY 2 START WITH 10"); - assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE my_sec START WITH 2 INCREMENT BY 5 NOCACHE"); + assertSqlCanBeParsedAndDeparsed( + "CREATE SEQUENCE my_sec START WITH 2 INCREMENT BY 5 NOCACHE"); String statement = "CREATE SEQUENCE my_sec START WITH 2 INCREMENT BY 5 CACHE 200 CYCLE"; assertSqlCanBeParsedAndDeparsed(statement); assertDeparse(new CreateSequence().withSequence(new Sequence().withName("my_sec") @@ -129,4 +144,20 @@ public void testCreateSequence_preservesParamOrder() throws JSQLParserException statement); } + @Test + public void testCreateSequence_withAsDataType() throws JSQLParserException { + String statement = + "CREATE SEQUENCE public.activites_activite_id_seq AS integer START WITH 1 INCREMENT BY 1 NOMINVALUE NOMAXVALUE CACHE 1"; + assertSqlCanBeParsedAndDeparsed(statement); + } + + @Test + public void testCreateSequence_withAsDataTypeSimple() throws JSQLParserException { + String statement = "CREATE SEQUENCE my_seq AS integer"; + assertSqlCanBeParsedAndDeparsed(statement); + assertDeparse(new CreateSequence().withSequence( + new Sequence().withName("my_seq").withDataType("integer")), + statement); + } + } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java index d9c477159..646f406e8 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java @@ -9,6 +9,21 @@ */ package net.sf.jsqlparser.statement.create; +import static net.sf.jsqlparser.test.TestUtils.assertDeparse; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.operators.relational.GreaterThan; @@ -26,22 +41,6 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.StringTokenizer; - -import static net.sf.jsqlparser.test.TestUtils.assertDeparse; -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - public class CreateTableTest { private final CCJSqlParserManager parserManager = new CCJSqlParserManager(); @@ -219,6 +218,30 @@ public void testCreateTableDefault2() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("CREATE TABLE T1 (id integer default 1)"); } + @Test + public void testCreateTableClickHouseMaterializedColumn() throws JSQLParserException { + String statement = "CREATE TABLE t (\n" + + " url String,\n" + + " domain String MATERIALIZED regexpExtract(url, '^(?:https?://)?([^/]+)', 1)\n" + + ")\n" + + "ENGINE = MergeTree()\n" + + "ORDER BY tuple()"; + assertSqlCanBeParsedAndDeparsed(statement, true); + } + + @Test + public void testCreateTableClickHouseSampleBy() throws JSQLParserException { + String statement = "CREATE TABLE tmp.events (\n" + + " id UInt64,\n" + + " user_id UInt32,\n" + + " timestamp DateTime\n" + + ")\n" + + "ENGINE = MergeTree()\n" + + "ORDER BY id\n" + + "SAMPLE BY id"; + assertSqlCanBeParsedAndDeparsed(statement, true); + } + @Test public void testCreateTableIfNotExists() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("CREATE TABLE IF NOT EXISTS animals (id INT NOT NULL)"); @@ -341,6 +364,31 @@ public void testMySqlCreateTableWithTextIndexes() throws JSQLParserException { "CREATE TABLE table2 (id INT (10) UNSIGNED NOT NULL AUTO_INCREMENT, name TEXT, url TEXT, created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), FULLTEXT KEY idx_table2_name (name)) ENGINE = InnoDB AUTO_INCREMENT = 7334 DEFAULT CHARSET = utf8"); } + @Test + public void testMySqlCreateTableWithSpatialIndex() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "CREATE TABLE places (id INT NOT NULL, location GEOMETRY NOT NULL, SPATIAL KEY sp_idx_location (location))"); + } + + @Test + public void testMySqlCreateTableIssue2367() + throws JSQLParserException { + String sql = "CREATE TABLE test (\n" + + "id int(11) NOT NULL COMMENT 'data id',\n" + + "code varchar(100) NOT NULL COMMENT 'code',\n" + + "name varchar(300) DEFAULT NULL COMMENT 'name',\n" + + "geo geometry NOT NULL,\n" + + "PRIMARY KEY (id),\n" + + "UNIQUE KEY index_code (code) USING HASH COMMENT 'unique index on code',\n" + + "UNIQUE KEY inx_code_name (code,name) USING BTREE COMMENT 'unique index on code and name',\n" + + "UNIQUE KEY inx_id_code_name (id,code,name) USING BTREE COMMENT 'index 1',\n" + + "SPATIAL KEY SPATIAL_geo (geo),\n" + + "KEY NORMAL_name (name) COMMENT 'normal index',\n" + + "FULLTEXT KEY fulltext_name (name)\n" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='test table'"; + assertSqlCanBeParsedAndDeparsed(sql); + } + @Test public void testCreateTableWithCheck() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( @@ -759,6 +807,24 @@ public void testCreateTableIssue924_2() throws JSQLParserException { "CREATE TABLE test_descending_indexes (c1 INT, c2 INT, INDEX idx1 (c1 ASC, c2 ASC), INDEX idx2 (c1 ASC, c2 DESC), INDEX idx3 (c1 DESC, c2 ASC), INDEX idx4 (c1 DESC, c2 DESC))"); } + @Test + public void testCreateTableWithFunctionalIndex() throws JSQLParserException { + String sql = + "CREATE TABLE t (PK INT, b INT, c INT, INDEX fAdd ((b + c), (COALESCE(PK, b)) DESC))"; + CreateTable createTable = (CreateTable) CCJSqlParserUtil.parse(sql); + + assertNotNull(createTable.getIndexes()); + assertEquals(1, createTable.getIndexes().size()); + assertEquals("fAdd", createTable.getIndexes().get(0).getName()); + assertTrue(createTable.getIndexes().get(0).getColumns().get(0).isExpression()); + assertEquals("b + c", createTable.getIndexes().get(0).getColumns().get(0).getColumnName()); + assertTrue(createTable.getIndexes().get(0).getColumns().get(1).isExpression()); + assertEquals("COALESCE(PK, b)", + createTable.getIndexes().get(0).getColumns().get(1).getColumnName()); + + assertSqlCanBeParsedAndDeparsed(sql); + } + @Test public void testCreateTableIssue921() throws JSQLParserException { String statement = "CREATE TABLE binary_test (c1 binary (10))"; @@ -878,6 +944,18 @@ public void testCreateTableIssue1230() throws JSQLParserException { "CREATE TABLE TABLE_HISTORY (ID bigint generated by default as identity, CREATED_AT timestamp not null, TEXT varchar (255), primary key (ID))"); } + @Test + public void testCreateTableGeneratedAlwaysAsIdentityRegression() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "create table if not exists book_type ( id bigint not null generated always as identity )"); + } + + @Test + public void testCreateTableGeneratedByDefaultAsIdentityRegression() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "create table if not exists book_type ( id bigint not null generated by default as identity )"); + } + @Test public void testCreateUnionIssue1309() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( @@ -1059,4 +1137,29 @@ void testIssue1864() throws JSQLParserException { + " CHARACTER SET armscii8 COLLATE armscii8_bin NULL DEFAULT NULL FIRST"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testUniqueAfterForeignKeyIssue2082() throws JSQLParserException { + String sqlStr = + "CREATE TABLE employees (\n" + + "employee_number int NOT NULL\n" + + ", employee_name char (50) NOT NULL\n" + + ", department_id int\n" + + ", salary int\n" + + ", PRIMARY KEY (employee_number)\n" + + ", FOREIGN KEY (department_id) REFERENCES departments(id)\n" + + ", UNIQUE (employee_name));"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testWithCatalog() throws JSQLParserException { + String sqlStr = "CREATE TABLE UNNAMED.session1.a (b VARCHAR (1))"; + CreateTable st = (CreateTable) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Table t = st.getTable(); + assertEquals("UNNAMED", t.getCatalogName()); + assertEquals("session1", t.getSchemaName()); + assertEquals("a", t.getUnquotedName()); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java index 328b8ecca..b23850b11 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java @@ -180,7 +180,7 @@ public void testCreateViewAutoFails() { assertThatThrownBy(throwingCallable).isInstanceOf(JSQLParserException.class) .hasRootCauseInstanceOf(ParseException.class).rootCause() - .hasMessageStartingWith("Encountered unexpected token"); + .hasMessageStartingWith("Encountered: / \"AUTO\""); } @Test @@ -191,7 +191,7 @@ public void testCreateViewRefreshFails() { assertThatThrownBy(throwingCallable).isInstanceOf(JSQLParserException.class) .hasRootCauseInstanceOf(ParseException.class).rootCause() - .hasMessageStartingWith("Encountered unexpected token"); + .hasMessageStartingWith("Encountered: / \"REFRESH\""); } @Test @@ -202,7 +202,7 @@ public void testCreateViewAutoRefreshFails() { assertThatThrownBy(throwingCallable).isInstanceOf(JSQLParserException.class) .hasRootCauseInstanceOf(ParseException.class).rootCause() - .hasMessageStartingWith("Encountered unexpected token"); + .hasMessageStartingWith("Encountered: / \"AUTO\""); } @Test diff --git a/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java b/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java index 7dd8496c1..51aec7a84 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/schema/CreateSchemaTest.java @@ -27,10 +27,26 @@ public void testSimpleCreateSchema() throws JSQLParserException { assertDeparse(new CreateSchema().withSchemaName("myschema"), statement); } + @Test + public void testCreateSchemaWithcatalog() throws JSQLParserException { + String statement = "CREATE SCHEMA unnamed.myschema"; + assertSqlCanBeParsedAndDeparsed(statement); + + statement = "CREATE SCHEMA unnamed.session1"; + assertSqlCanBeParsedAndDeparsed(statement); + } + @Test public void testSimpleCreateWithAuth() throws JSQLParserException { String statement = "CREATE SCHEMA myschema AUTHORIZATION myauth"; assertSqlCanBeParsedAndDeparsed(statement); - assertDeparse(new CreateSchema().withSchemaName("myschema").withAuthorization("myauth"), statement); + assertDeparse(new CreateSchema().withSchemaName("myschema").withAuthorization("myauth"), + statement); + } + + @Test + void testIfNotExistsIssue2061() throws JSQLParserException { + String sqlStr = "CREATE SCHEMA IF NOT EXISTS sales_kpi"; + assertSqlCanBeParsedAndDeparsed(sqlStr); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/synonym/CreateSynonymTest.java b/src/test/java/net/sf/jsqlparser/statement/create/synonym/CreateSynonymTest.java index 9669f1efe..53886e267 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/synonym/CreateSynonymTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/synonym/CreateSynonymTest.java @@ -21,17 +21,20 @@ public class CreateSynonymTest { @Test public void createPublic() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("CREATE PUBLIC SYNONYM TBL_TABLE_NAME FOR SCHEMA.T_TBL_NAME"); + assertSqlCanBeParsedAndDeparsed( + "CREATE PUBLIC SYNONYM TBL_TABLE_NAME FOR SCHEMA.T_TBL_NAME"); } @Test public void createWithReplace() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("CREATE OR REPLACE SYNONYM TBL_TABLE_NAME FOR SCHEMA.T_TBL_NAME"); + assertSqlCanBeParsedAndDeparsed( + "CREATE OR REPLACE SYNONYM TBL_TABLE_NAME FOR SCHEMA.T_TBL_NAME"); } @Test public void createWithReplacePublic() throws Exception { - assertSqlCanBeParsedAndDeparsed("CREATE OR REPLACE PUBLIC SYNONYM TBL_TABLE_NAME FOR SCHEMA.T_TBL_NAME"); + assertSqlCanBeParsedAndDeparsed( + "CREATE OR REPLACE PUBLIC SYNONYM TBL_TABLE_NAME FOR SCHEMA.T_TBL_NAME"); } /** @@ -41,12 +44,14 @@ public void createWithReplacePublic() throws Exception { */ @Test public void createWithDbLink() throws Exception { - assertSqlCanBeParsedAndDeparsed("CREATE PUBLIC SYNONYM emp_table FOR hr.employees@remote.us.oracle.com"); + assertSqlCanBeParsedAndDeparsed( + "CREATE PUBLIC SYNONYM emp_table FOR hr.employees@remote.us.oracle.com"); } @Test public void synonymAttributes() throws Exception { - final CreateSynonym createSynonym = (CreateSynonym) CCJSqlParserUtil.parse("CREATE OR REPLACE PUBLIC SYNONYM TBL_TABLE_NAME FOR SCHEMA.T_TBL_NAME"); + final CreateSynonym createSynonym = (CreateSynonym) CCJSqlParserUtil + .parse("CREATE OR REPLACE PUBLIC SYNONYM TBL_TABLE_NAME FOR SCHEMA.T_TBL_NAME"); assertThat(createSynonym.isOrReplace()).isTrue(); assertThat(createSynonym.isPublicSynonym()).isTrue(); @@ -54,6 +59,7 @@ public void synonymAttributes() throws Exception { assertThat(createSynonym.getFor()).isEqualTo("SCHEMA.T_TBL_NAME"); assertEquals(2, createSynonym.getForList().size()); - assertEquals("NEW_TBL_TABLE_NAME", createSynonym.withSynonym(new Synonym().withName("NEW_TBL_TABLE_NAME")).getSynonym().getName()); + assertEquals("NEW_TBL_TABLE_NAME", createSynonym + .withSynonym(new Synonym().withName("NEW_TBL_TABLE_NAME")).getSynonym().getName()); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/table/ColDataTypeTest.java b/src/test/java/net/sf/jsqlparser/statement/create/table/ColDataTypeTest.java index e3462a66f..5fdae46c2 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/table/ColDataTypeTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/table/ColDataTypeTest.java @@ -47,4 +47,14 @@ void testIssue1879() throws JSQLParserException { public void testNestedCast() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SELECT acolumn::bit(64)::int(64) FROM mytable"); } + + @Test + void testStruct() throws JSQLParserException { + String sqlStr = + "CREATE TABLE IT.u (\n" + + " details struct( id varchar(255), name varchar(255)) NOT NULL,\n" + + " name VARCHAR(255) NOT NULL\n" + + " );\n"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java index 7c32fe3ec..2b7bab5e9 100644 --- a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java @@ -10,6 +10,8 @@ package net.sf.jsqlparser.statement.delete; import java.io.StringReader; +import java.util.List; + import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; @@ -22,7 +24,17 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; + +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.ParenthesedSelect; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SelectItem; +import net.sf.jsqlparser.statement.select.WithItem; +import net.sf.jsqlparser.statement.update.Update; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; public class DeleteTest { @@ -58,7 +70,8 @@ public void testDeleteWithLimit() throws JSQLParserException { @Test public void testDeleteDoesNotAllowLimitOffset() { String statement = "DELETE FROM table1 WHERE A.cod_table = 'YYY' LIMIT 3,4"; - assertThrows(JSQLParserException.class, () -> parserManager.parse(new StringReader(statement))); + assertThrows(JSQLParserException.class, + () -> parserManager.parse(new StringReader(statement))); } @Test @@ -86,8 +99,10 @@ public void testDeleteFromTableUsingLeftJoinToAnotherTable() throws JSQLParserEx } @Test - public void testDeleteFromTableUsingInnerJoinToAnotherTableWithAlias() throws JSQLParserException { - String stmt = "DELETE gc FROM guide_category AS gc LEFT JOIN guide AS g ON g.id_guide = gc.id_guide WHERE g.title IS NULL LIMIT 5"; + public void testDeleteFromTableUsingInnerJoinToAnotherTableWithAlias() + throws JSQLParserException { + String stmt = + "DELETE gc FROM guide_category AS gc LEFT JOIN guide AS g ON g.id_guide = gc.id_guide WHERE g.title IS NULL LIMIT 5"; assertSqlCanBeParsedAndDeparsed(stmt); } @@ -102,13 +117,12 @@ public void testOracleHint() throws JSQLParserException { assertOracleHintExists(sql, true, "SOMEHINT"); - //@todo: add a testcase supposed to not finding a misplaced hint + // @todo: add a testcase supposed to not finding a misplaced hint } @Test public void testWith() throws JSQLParserException { - String statement - = "" + String statement = "" + "WITH a\n" + " AS (SELECT 1 id_instrument_ref)\n" + " , b\n" @@ -116,8 +130,20 @@ public void testWith() throws JSQLParserException { + "DELETE FROM cfe.instrument_ref\n" + "WHERE id_instrument_ref = (SELECT id_instrument_ref\n" + " FROM a)"; - - assertSqlCanBeParsedAndDeparsed(statement, true); + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(statement, true); + List> withItems = delete.getWithItemsList(); + assertEquals("cfe.instrument_ref", delete.getTable().getFullyQualifiedName()); + assertEquals(2, withItems.size()); + SelectItem selectItem1 = + withItems.get(0).getSelect().getPlainSelect().getSelectItems().get(0); + assertEquals("1", selectItem1.getExpression().toString()); + assertEquals(" id_instrument_ref", selectItem1.getAlias().toString()); + assertEquals(" a", withItems.get(0).getAlias().toString()); + SelectItem selectItem2 = + withItems.get(1).getSelect().getPlainSelect().getSelectItems().get(0); + assertEquals("1", selectItem2.getExpression().toString()); + assertEquals(" id_instrument_ref", selectItem2.getAlias().toString()); + assertEquals(" b", withItems.get(1).getAlias().toString()); } @Test @@ -189,17 +215,14 @@ public void testDeleteReturningIssue1527() throws JSQLParserException { " RETURNING name, price AS new_price"; assertSqlCanBeParsedAndDeparsed(statement, true); } + @Test public void testDeleteOutputClause() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( - "DELETE Sales.ShoppingCartItem OUTPUT DELETED.* FROM Sales" - , true - ); + "DELETE Sales.ShoppingCartItem OUTPUT DELETED.* FROM Sales", true); assertSqlCanBeParsedAndDeparsed( - "DELETE Sales.ShoppingCartItem OUTPUT Sales.ShoppingCartItem FROM Sales" - , true - ); + "DELETE Sales.ShoppingCartItem OUTPUT Sales.ShoppingCartItem FROM Sales", true); assertSqlCanBeParsedAndDeparsed( "DELETE Production.ProductProductPhoto \n" + @@ -211,9 +234,184 @@ public void testDeleteOutputClause() throws JSQLParserException { "FROM Production.ProductProductPhoto AS ph \n" + "JOIN Production.Product as p \n" + " ON ph.ProductID = p.ProductID \n" + - " WHERE p.ProductModelID BETWEEN 120 and 130" - , true - ); + " WHERE p.ProductModelID BETWEEN 120 and 130", + true); + } + + @Test + void testInsertWithinCte() throws JSQLParserException { + String sqlStr = "WITH inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " RETURNING y " + + ") " + + "DELETE " + + " FROM z" + + " WHERE y IN (SELECT y FROM inserted)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(1, withItems.size()); + Insert insert = withItems.get(0).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b", insert.getSelect().toString()); + assertEquals(" RETURNING y", insert.getReturningClause().toString()); + assertEquals("INSERT INTO x (foo) SELECT bar FROM b RETURNING y", insert.toString()); + assertEquals(" inserted", withItems.get(0).getAlias().toString()); + } + @Test + void testUpdateWithinCte() throws JSQLParserException { + String sqlStr = "WITH updated AS ( " + + " UPDATE x " + + " SET foo = 1 " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "DELETE " + + " FROM z" + + " WHERE y IN (SELECT y FROM updated)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(1, withItems.size()); + Update update = withItems.get(0).getUpdate().getUpdate(); + assertEquals("x", update.getTable().toString()); + assertEquals("foo", update.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("1", update.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("bar = 2", update.getWhere().toString()); + assertEquals(" RETURNING y", update.getReturningClause().toString()); + assertEquals(" updated", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteWithinCte() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "DELETE " + + " FROM z" + + " WHERE y IN (SELECT y FROM deleted)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(1, withItems.size()); + Delete innerDelete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", innerDelete.getTable().toString()); + assertEquals("bar = 2", innerDelete.getWhere().toString()); + assertEquals(" RETURNING y", innerDelete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM deleted) " + + " RETURNING w " + + ") " + + "DELETE " + + " FROM z" + + " WHERE w IN (SELECT w FROM inserted)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(2, withItems.size()); + Delete innerDelete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", innerDelete.getTable().toString()); + assertEquals("bar = 2", innerDelete.getWhere().toString()); + assertEquals(" RETURNING y", innerDelete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM deleted)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM deleted) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testSelectAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH selection AS ( " + + " SELECT y " + + " FROM z " + + " WHERE foo = 'bar' " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM selection) " + + " RETURNING w " + + ") " + + "DELETE " + + " FROM z" + + " WHERE w IN (SELECT w FROM inserted)"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", delete.getTable().toString()); + List> withItems = delete.getWithItemsList(); + assertEquals(2, withItems.size()); + PlainSelect innerSelect = withItems.get(0).getSelect().getPlainSelect(); + assertEquals("SELECT y FROM z WHERE foo = 'bar'", innerSelect.toString()); + assertEquals(" selection", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM selection)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM selection) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @ParameterizedTest + @ValueSource(strings = { + "DELETE FROM mytable PREFERRING HIGH mycolumn", + "DELETE FROM mytable PREFERRING LOW mycolumn", + "DELETE FROM mytable PREFERRING 1 = 1", + "DELETE FROM mytable PREFERRING (HIGH mycolumn)", + "DELETE FROM mytable PREFERRING INVERSE (HIGH mycolumn)", + "DELETE FROM mytable PREFERRING HIGH mycolumn1 PRIOR TO LOW mycolumn2", + "DELETE FROM mytable PREFERRING HIGH mycolumn1 PLUS LOW mycolumn2" + }) + public void testPreferringClause(String sqlStr) throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed(sqlStr); + } + + @Test + public void testDeleteWithSkylineKeywords() throws JSQLParserException { + String statement = + "DELETE FROM mytable WHERE low = 1 AND high = 2 AND inverse = 3 AND plus = 4"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(statement); + assertEquals("mytable", delete.getTable().toString()); + assertEquals("low = 1 AND high = 2 AND inverse = 3 AND plus = 4", + delete.getWhere().toString()); + } + + @Test + public void testDeleteUsingFromItem() throws JSQLParserException { + String statement = + "DELETE A USING B.C D,(SELECT id FROM producers WHERE active = false) p WHERE D.Z = 1 and p.id = D.id"; + Delete delete = (Delete) assertSqlCanBeParsedAndDeparsed(statement); + assertEquals("B.C", + ((Table) delete.getUsingFromItemList().get(0)).getFullyQualifiedName()); + assertEquals("D", + ((Table) delete.getUsingFromItemList().get(0)).getAlias().getName()); + assertEquals("producers", + ((Table) ((ParenthesedSelect) delete.getUsingFromItemList().get(1)).getPlainSelect() + .getFromItem()).getFullyQualifiedName()); + assertEquals("p", + delete.getUsingFromItemList().get(1).getAlias().getName()); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java index 062374f39..a48b2fe7d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java @@ -42,16 +42,27 @@ public void testDropIndex() throws JSQLParserException { assertEquals("myindex", parsed.getName().getFullyQualifiedName()); assertEquals("CASCADE", parsed.getParameters().get(0)); assertEquals(statement, "" + parsed); - Drop created = new Drop().withType("INDEX").withName(new Table("myindex")).addParameters("CASCADE"); + Drop created = new Drop().withType("INDEX").withName(new Table("myindex")) + .addParameters("CASCADE"); assertDeparse(created, statement); assertEqualsObjectTree(parsed, created); } - + @Test public void testDropIndexOnTable() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("DROP INDEX idx ON abc"); } + @Test + public void testDropIndexOnQualifiedTable() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("DROP INDEX idx ON qual.tbl"); + } + + @Test + public void testDropIndexOnDoubleQualifiedTable() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("DROP INDEX idx ON dbl.qual.tbl"); + } + @Test public void testDrop2() throws JSQLParserException { Drop drop = (Drop) parserManager.parse(new StringReader("DROP TABLE \"testtable\"")); @@ -63,7 +74,8 @@ public void testDrop2() throws JSQLParserException { public void testDropIfExists() throws JSQLParserException { String statement = "DROP TABLE IF EXISTS my_table"; Statement parsed = assertSqlCanBeParsedAndDeparsed(statement); - Drop created = new Drop().withType("TABLE").withIfExists(true).withName(new Table("my_table")); + Drop created = + new Drop().withType("TABLE").withIfExists(true).withName(new Table("my_table")); assertDeparse(created, statement); assertEqualsObjectTree(parsed, created); } @@ -72,7 +84,8 @@ public void testDropIfExists() throws JSQLParserException { public void testDropRestrictIssue510() throws JSQLParserException { String statement = "DROP TABLE TABLE2 RESTRICT"; Statement parsed = assertSqlCanBeParsedAndDeparsed(statement); - Drop created = new Drop().withType("TABLE").withName(new Table("TABLE2")).addParameters(asList("RESTRICT")); + Drop created = new Drop().withType("TABLE").withName(new Table("TABLE2")) + .addParameters(asList("RESTRICT")); assertDeparse(created, statement); assertEqualsObjectTree(parsed, created); } @@ -95,6 +108,7 @@ public void testDropMaterializedView() throws JSQLParserException { @Test public void testDropSchemaIssue855() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("DROP SCHEMA myschema"); + assertSqlCanBeParsedAndDeparsed("DROP SCHEMA unnamed.myschema"); } @Test @@ -104,7 +118,7 @@ public void testDropSequence() throws JSQLParserException { @Test public void testOracleMultiColumnDrop() throws JSQLParserException { - //assertSqlCanBeParsedAndDeparsed("ALTER TABLE foo DROP (bar, baz)"); + // assertSqlCanBeParsedAndDeparsed("ALTER TABLE foo DROP (bar, baz)"); assertSqlCanBeParsedAndDeparsed("ALTER TABLE foo DROP (bar, baz) CASCADE"); } @@ -135,7 +149,7 @@ public void testDropFunctionWithNameAndParameterizedType() throws JSQLParserExce @Test void dropTemporaryTableTestIssue1712() throws JSQLParserException { - String sqlStr="drop temporary table if exists tmp_MwYT8N0z"; + String sqlStr = "drop temporary table if exists tmp_MwYT8N0z"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/export/ExportTest.java b/src/test/java/net/sf/jsqlparser/statement/export/ExportTest.java new file mode 100644 index 000000000..1d158b975 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/export/ExportTest.java @@ -0,0 +1,272 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.export; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@Execution(ExecutionMode.CONCURRENT) +public class ExportTest { + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv'", + "EXPORT schemaName.tableName ( columnName ) INTO LOCAL CSV FILE 'file.csv'", + "EXPORT schemaName.tableName ( columnName1, columnName2 ) INTO LOCAL CSV FILE 'file.csv'", + + "EXPORT ( select 1 ) INTO LOCAL CSV FILE 'file.csv'", + }) + public void testExport(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file1.csv' FILE 'file2.csv'", + + "EXPORT schemaName.tableName INTO LOCAL SECURE CSV FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL SECURE CSV FILE 'file1.csv' FILE 'file2.csv'" + }) + public void testExportIntoFileCSV(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1, 2 )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format' )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 DELIMIT = ALWAYS )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 DELIMIT = NEVER )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 DELIMIT = AUTO )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format', 2 DELIMIT = NEVER )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format', 2 DELIMIT = NEVER, 3 FORMAT = 'format' DELIMIT = ALWAYS )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1 .. 2 )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1, 1 .. 2 )", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ( 1, 1 .. 2, 3 )" + }) + public void testExportIntoFileCSVCols(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv'", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file1.fbv' FILE 'file2.fbv'", + + "EXPORT schemaName.tableName INTO LOCAL SECURE FBV FILE 'file.fbv'", + "EXPORT schemaName.tableName INTO LOCAL SECURE FBV FILE 'file1.fbv' FILE 'file2.fbv'" + }) + public void testExportIntoFileFBV(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( SIZE = 1 )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( FORMAT = 'format' )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( ALIGN = LEFT )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( ALIGN = RIGHT )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( PADDING = '0' )", + + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( SIZE = 1, PADDING = '0' )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( SIZE = 1 PADDING = '0' )", + "EXPORT schemaName.tableName INTO LOCAL FBV FILE 'file.fbv' ( SIZE = 1 PADDING = '0', FORMAT = 'format' )" + }) + public void testExportIntoFileFBVCols(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REPLACE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' TRUNCATE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' NULL = 'null'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' BOOLEAN = 'yes/no'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ROW SEPARATOR = 'CRLF'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' COLUMN SEPARATOR = ','", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' COLUMN DELIMITER = '\"'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' DELIMIT = ALWAYS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' DELIMIT = NEVER", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' DELIMIT = AUTO", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' WITH COLUMN NAMES", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8' REPLACE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8' REPLACE WITH COLUMN NAMES" + }) + public void testExportIntoFileFileOpts(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' VERIFY CERTIFICATE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' IGNORE CERTIFICATE", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' PUBLIC KEY 'publicKey'", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' VERIFY CERTIFICATE PUBLIC KEY 'publicKey'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' IGNORE CERTIFICATE PUBLIC KEY 'publicKey'" + }) + public void testExportIntoFileCertVerification(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO CSV AT connectionName FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' FILE 'file.csv'", + + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + + "EXPORT schemaName.tableName INTO CSV AT connectionName IGNORE CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName VERIFY CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT connectionName USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'" + }) + public void testExportIntoConnectionDef(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO CSV AT CLOUD NONE connectionName FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD NONE '127.0.0.1' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD NONE connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD NONE '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD AZURE BLOBSTORAGE connectionName FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD AZURE BLOBSTORAGE '127.0.0.1' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD AZURE BLOBSTORAGE connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "EXPORT schemaName.tableName INTO CSV AT CLOUD AZURE BLOBSTORAGE '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'" + }) + public void testExportIntoCloudConnectionDef(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName ( columnName )", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 )", + + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName REPLACE", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName TRUNCATE", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName CREATED BY 'CREATE OR REPLACE TABLE schemaName (columnName INTEGER)'", + + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName REPLACE TRUNCATE", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName ( columnName ) REPLACE TRUNCATE", + "EXPORT schemaName.tableName INTO EXA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 ) REPLACE TRUNCATE", + + "EXPORT schemaName.tableName INTO EXA AT connectionName STATEMENT 'insert into schemaName.tableName ( columnName ) values ( ? )'" + }) + public void testExportIntoDBMSEXA(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO ORA AT connectionName TABLE schemaName.tableName", + "EXPORT schemaName.tableName INTO ORA AT connectionName TABLE schemaName.tableName ( columnName )", + "EXPORT schemaName.tableName INTO ORA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 )", + + "EXPORT schemaName.tableName INTO ORA AT connectionName STATEMENT 'insert into schemaName.tableName ( columnName ) values ( ? )'" + }) + public void testExportIntoDBMSORA(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO JDBC AT connectionName TABLE tableName", + "EXPORT schemaName.tableName INTO JDBC DRIVER = 'driverName' AT connectionName TABLE tableName" + }) + public void testExportIntoDBMSJDBC(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO SCRIPT scriptName", + "EXPORT schemaName.tableName INTO SCRIPT scriptName AT connectionName", + "EXPORT schemaName.tableName INTO SCRIPT scriptName WITH propertyName = 'value'", + "EXPORT schemaName.tableName INTO SCRIPT scriptName WITH propertyName = 'value' propertyName2 = 'value2'", + "EXPORT schemaName.tableName INTO SCRIPT scriptName AT connectionName WITH propertyName = 'value' propertyName2 = 'value2'" + }) + public void testExportIntoScript(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv'", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT 1", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT 1 ERRORS", + + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT UNLIMITED", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT UNLIMITED", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "EXPORT schemaName.tableName INTO LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT UNLIMITED ERRORS" + }) + public void testImportErrorClause(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/grant/GrantTest.java b/src/test/java/net/sf/jsqlparser/statement/grant/GrantTest.java index e0bb8faa4..fd41bda45 100644 --- a/src/test/java/net/sf/jsqlparser/statement/grant/GrantTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/grant/GrantTest.java @@ -13,6 +13,7 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserManager; import static net.sf.jsqlparser.test.TestUtils.*; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; @@ -97,4 +98,10 @@ public void testGrantQueryWithRole() throws JSQLParserException { public void testGrantSchemaParsingIssue1080() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("GRANT SELECT ON schema_name.table_name TO XYZ"); } + + @Test + void testPublicKeywordIssue2230() throws JSQLParserException { + String sqlStr = "grant select on da380_now to public;"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/imprt/ImportTest.java b/src/test/java/net/sf/jsqlparser/statement/imprt/ImportTest.java new file mode 100644 index 000000000..1539d4375 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/imprt/ImportTest.java @@ -0,0 +1,281 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.imprt; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@Execution(ExecutionMode.CONCURRENT) +public class ImportTest { + @ParameterizedTest + @ValueSource(strings = { + "IMPORT INTO schemaName.tableName FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO schemaName.tableName ( columnName ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO schemaName.tableName ( columnName1, columnName2 ) FROM LOCAL CSV FILE 'file.csv'" + }) + public void testImportIntoTable(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT INTO ( columnName integer ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( columnName1 integer, columnName2 varchar(100) ) FROM LOCAL CSV FILE 'file.csv'", + + "IMPORT INTO ( LIKE schemaName.tableName ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName ) ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName1, columnName2 ) ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName AS aliasName ) ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName aliasName ) ) FROM LOCAL CSV FILE 'file.csv'", + "IMPORT INTO ( LIKE schemaName.tableName ( columnName1 AS aliasName2, columnName2 AS aliasName2 ) ) FROM LOCAL CSV FILE 'file.csv'" + }) + public void testImportIntoImportColumns(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv'", + "IMPORT FROM LOCAL CSV FILE 'file1.csv' FILE 'file2.csv'", + + "IMPORT FROM LOCAL SECURE CSV FILE 'file.csv'", + "IMPORT FROM LOCAL SECURE CSV FILE 'file1.csv' FILE 'file2.csv'" + }) + public void testImportFromFileCSV(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1 )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1, 2 )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format' )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1 FORMAT = 'format', 2 FORMAT = 'format' )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1 .. 2 )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1, 1 .. 2 )", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ( 1, 1 .. 2, 3 )" + }) + public void testImportFromFileCSVCols(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL FBV FILE 'file.fbv'", + "IMPORT FROM LOCAL FBV FILE 'file1.fbv' FILE 'file2.fbv'", + + "IMPORT FROM LOCAL SECURE FBV FILE 'file.fbv'", + "IMPORT FROM LOCAL SECURE FBV FILE 'file1.fbv' FILE 'file2.fbv'" + }) + public void testImportFromFileFBV(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( SIZE = 1 )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( START = 1 )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( FORMAT = 'format' )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( ALIGN = LEFT )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( ALIGN = RIGHT )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( PADDING = 'padding' )", + + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( SIZE = 1, START = 1 )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( SIZE = 1 START = 1 )", + "IMPORT FROM LOCAL FBV FILE 'file.fbv' ( SIZE = 1 START = 1, FORMAT = 'format' )" + }) + public void testImportFromFileFBVCols(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' SKIP = 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' TRIM", + "IMPORT FROM LOCAL CSV FILE 'file.csv' LTRIM", + "IMPORT FROM LOCAL CSV FILE 'file.csv' RTRIM", + "IMPORT FROM LOCAL CSV FILE 'file.csv' NULL = 'null'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ROW SEPARATOR = 'CRLF'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' COLUMN SEPARATOR = ','", + "IMPORT FROM LOCAL CSV FILE 'file.csv' COLUMN DELIMITER = '\"'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ROW SIZE = 1", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8' SKIP = 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ENCODING = 'UTF-8' SKIP = 1 TRIM" + }) + public void testImportFromFileFileOpts(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv' VERIFY CERTIFICATE", + "IMPORT FROM LOCAL CSV FILE 'file.csv' IGNORE CERTIFICATE", + "IMPORT FROM LOCAL CSV FILE 'file.csv' PUBLIC KEY 'publicKey'", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' VERIFY CERTIFICATE PUBLIC KEY 'publicKey'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' IGNORE CERTIFICATE PUBLIC KEY 'publicKey'" + }) + public void testImportFromFileCertVerification(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM CSV AT connectionName FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' FILE 'file.csv'", + + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + + "IMPORT FROM CSV AT connectionName IGNORE CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName VERIFY CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' IGNORE CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT connectionName USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'", + "IMPORT FROM CSV AT '127.0.0.1' USER 'user' IDENTIFIED BY 'password' VERIFY CERTIFICATE PUBLIC KEY 'publicKey' FILE 'file.csv'" + }) + public void testImportFromConnectionDef(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM CSV AT CLOUD NONE connectionName FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD NONE '127.0.0.1' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD NONE connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD NONE '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD AZURE BLOBSTORAGE connectionName FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD AZURE BLOBSTORAGE '127.0.0.1' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD AZURE BLOBSTORAGE connectionName USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'", + "IMPORT FROM CSV AT CLOUD AZURE BLOBSTORAGE '127.0.0.1' USER 'user' IDENTIFIED BY 'password' FILE 'file.csv'" + }) + public void testImportFromCloudConnectionDef(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM EXA AT connectionName TABLE schemaName.tableName", + "IMPORT FROM EXA AT connectionName TABLE schemaName.tableName ( columnName )", + "IMPORT FROM EXA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 )", + + "IMPORT FROM EXA AT connectionName STATEMENT 'select 1'", + "IMPORT FROM EXA AT connectionName STATEMENT 'select 1' STATEMENT 'select 2'" + }) + public void testImportFromDBMSEXA(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM ORA AT connectionName TABLE schemaName.tableName", + "IMPORT FROM ORA AT connectionName TABLE schemaName.tableName ( columnName )", + "IMPORT FROM ORA AT connectionName TABLE schemaName.tableName ( columnName1, columnName2 )", + + "IMPORT FROM ORA AT connectionName STATEMENT 'select 1'", + "IMPORT FROM ORA AT connectionName STATEMENT 'select 1' STATEMENT 'select 2'" + }) + public void testImportFromDBMSORA(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM JDBC AT connectionName TABLE tableName", + "IMPORT FROM JDBC DRIVER = 'driverName' AT connectionName TABLE tableName", + + "IMPORT FROM JDBC AT connectionName STATEMENT 'select 1'", + "IMPORT FROM JDBC AT connectionName STATEMENT 'select 1' STATEMENT 'select 2'", + "IMPORT FROM JDBC DRIVER = 'driverName' AT connectionName STATEMENT 'select 1'", + "IMPORT FROM JDBC DRIVER = 'driverName' AT connectionName STATEMENT 'select 1' STATEMENT 'select 2'" + }) + public void testImportFromDBMSJDBC(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM SCRIPT scriptName", + "IMPORT FROM SCRIPT scriptName AT connectionName", + "IMPORT FROM SCRIPT scriptName WITH propertyName = 'value'", + "IMPORT FROM SCRIPT scriptName WITH propertyName = 'value' propertyName2 = 'value2'", + "IMPORT FROM SCRIPT scriptName AT connectionName WITH propertyName = 'value' propertyName2 = 'value2'" + }) + public void testImportFromScript(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @ParameterizedTest + @ValueSource(strings = { + "IMPORT FROM LOCAL CSV FILE 'file.csv' REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv'", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT 1", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT 1 ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT 1 ERRORS", + + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT UNLIMITED", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT UNLIMITED", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT UNLIMITED", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO CSV AT connectionName FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO LOCAL SECURE CSV FILE 'file.csv' REJECT LIMIT UNLIMITED ERRORS", + "IMPORT FROM LOCAL CSV FILE 'file.csv' ERRORS INTO schemaName.tableName REJECT LIMIT UNLIMITED ERRORS" + }) + public void testImportErrorClause(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java index 8e3704dd1..18a9019e1 100644 --- a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java @@ -9,39 +9,44 @@ */ package net.sf.jsqlparser.statement.insert; +import static net.sf.jsqlparser.test.TestUtils.assertDeparse; +import static net.sf.jsqlparser.test.TestUtils.assertOracleHintExists; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static net.sf.jsqlparser.test.TestUtils.assertStatementCanBeDeparsedAs; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.StringReader; +import java.util.List; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.DoubleValue; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.JdbcParameter; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.select.AllColumns; -import net.sf.jsqlparser.statement.select.PlainSelect; -import net.sf.jsqlparser.statement.select.Select; -import net.sf.jsqlparser.statement.select.Values; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.*; +import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.update.UpdateSet; +import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; - -import java.io.StringReader; - -import static net.sf.jsqlparser.test.TestUtils.assertDeparse; -import static net.sf.jsqlparser.test.TestUtils.assertOracleHintExists; -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; -import static net.sf.jsqlparser.test.TestUtils.assertStatementCanBeDeparsedAs; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; -import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; public class InsertTest { @@ -234,14 +239,94 @@ public void execute() throws Throwable { } @Test - @Disabled public void testOracleInsertMultiRowValue() throws JSQLParserException { String sqlStr = "INSERT ALL\n" + " INTO suppliers (supplier_id, supplier_name) VALUES (1000, 'IBM')\n" + " INTO suppliers (supplier_id, supplier_name) VALUES (2000, 'Microsoft')\n" + " INTO suppliers (supplier_id, supplier_name) VALUES (3000, 'Google')\n" + "SELECT * FROM dual;"; - assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + assertTrue(insert.isOracleMultiInsert()); + assertFalse(insert.isOracleMultiInsertFirst()); + assertEquals(1, insert.getOracleMultiInsertBranches().size()); + assertEquals(3, insert.getOracleMultiInsertBranches().get(0).getClauses().size()); + assertEquals("suppliers", + insert.getOracleMultiInsertBranches().get(0).getClauses().get(0).getTable() + .toString()); + assertEquals("supplier_id, supplier_name", + insert.getOracleMultiInsertBranches().get(0).getClauses().get(0).getColumns() + .toString()); + assertEquals("VALUES (1000, 'IBM')", + insert.getOracleMultiInsertBranches().get(0).getClauses().get(0).getSelect() + .toString()); + assertEquals("SELECT * FROM dual", insert.getSelect().toString()); + } + + @Test + public void testOracleInsertAllWithJdbcParameters() throws JSQLParserException { + String sqlStr = "INSERT ALL INTO spm_message (xx, xx) VALUES (?, ?) SELECT * FROM dual"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + assertTrue(insert.isOracleMultiInsert()); + assertFalse(insert.isOracleMultiInsertFirst()); + assertEquals(1, insert.getOracleMultiInsertBranches().size()); + assertNull(insert.getOracleMultiInsertBranches().get(0).getWhenExpression()); + assertFalse(insert.getOracleMultiInsertBranches().get(0).isElseClause()); + assertEquals(1, insert.getOracleMultiInsertBranches().get(0).getClauses().size()); + assertEquals("spm_message", + insert.getOracleMultiInsertBranches().get(0).getClauses().get(0).getTable() + .toString()); + assertEquals("VALUES (?, ?)", + insert.getOracleMultiInsertBranches().get(0).getClauses().get(0).getSelect() + .toString()); + } + + @Test + public void testOracleInsertAllWithWhenElse() throws JSQLParserException { + String sqlStr = + "INSERT ALL WHEN qty > 10 THEN INTO big_orders (id) VALUES (id) " + + "WHEN qty > 0 THEN INTO small_orders (id) VALUES (id) " + + "ELSE INTO invalid_orders (id) VALUES (id) " + + "SELECT id, qty FROM orders"; + + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + assertTrue(insert.isOracleMultiInsert()); + assertFalse(insert.isOracleMultiInsertFirst()); + assertEquals(3, insert.getOracleMultiInsertBranches().size()); + assertEquals("qty > 10", + insert.getOracleMultiInsertBranches().get(0).getWhenExpression().toString()); + assertEquals("qty > 0", + insert.getOracleMultiInsertBranches().get(1).getWhenExpression().toString()); + assertTrue(insert.getOracleMultiInsertBranches().get(2).isElseClause()); + assertEquals(1, insert.getOracleMultiInsertBranches().get(0).getClauses().size()); + assertEquals(1, insert.getOracleMultiInsertBranches().get(1).getClauses().size()); + assertEquals(1, insert.getOracleMultiInsertBranches().get(2).getClauses().size()); + } + + @Test + public void testOracleInsertFirstWithWhenMultipleInto() throws JSQLParserException { + String sqlStr = + "INSERT FIRST WHEN region = 'APAC' THEN INTO apac_orders (id) VALUES (id) " + + "INTO apac_audit (id) VALUES (id) " + + "ELSE INTO other_orders (id) VALUES (id) " + + "SELECT id, region FROM orders"; + + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + assertTrue(insert.isOracleMultiInsert()); + assertTrue(insert.isOracleMultiInsertFirst()); + assertEquals(2, insert.getOracleMultiInsertBranches().size()); + assertEquals(2, insert.getOracleMultiInsertBranches().get(0).getClauses().size()); + assertEquals("region = 'APAC'", + insert.getOracleMultiInsertBranches().get(0).getWhenExpression().toString()); + assertTrue(insert.getOracleMultiInsertBranches().get(1).isElseClause()); + assertEquals("apac_orders", + insert.getOracleMultiInsertBranches().get(0).getClauses().get(0).getTable() + .toString()); + assertEquals("apac_audit", + insert.getOracleMultiInsertBranches().get(0).getClauses().get(1).getTable() + .toString()); + assertEquals("other_orders", + insert.getOracleMultiInsertBranches().get(1).getClauses().get(0).getTable() + .toString()); } @Test @@ -276,12 +361,30 @@ public void testInsertSelect() throws JSQLParserException { @Test public void testInsertWithSelect() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "INSERT INTO mytable (mycolumn) WITH a AS (SELECT mycolumn FROM mytable) SELECT mycolumn FROM a", - true); - assertSqlCanBeParsedAndDeparsed( - "INSERT INTO mytable (mycolumn) (WITH a AS (SELECT mycolumn FROM mytable) SELECT mycolumn FROM a)", - true); + String sqlStr1 = + "INSERT INTO mytable (mycolumn) WITH a AS (SELECT mycolumn FROM mytable) SELECT mycolumn FROM a"; + Insert insert1 = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr1, true); + List> insertWithItems1 = insert1.getWithItemsList(); + List> selectWithItems1 = insert1.getSelect().getWithItemsList(); + assertEquals("mytable", insert1.getTable().getFullyQualifiedName()); + assertNull(insertWithItems1); + assertEquals(1, selectWithItems1.size()); + assertEquals("SELECT mycolumn FROM mytable", + selectWithItems1.get(0).getSelect().getPlainSelect().toString()); + assertEquals(" a", selectWithItems1.get(0).getAlias().toString()); + + String sqlStr2 = + "INSERT INTO mytable (mycolumn) (WITH a AS (SELECT mycolumn FROM mytable) SELECT mycolumn FROM a)"; + Insert insert2 = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr2, true); + List> insertWithItems2 = insert2.getWithItemsList(); + assertEquals("mytable", insert2.getTable().getFullyQualifiedName()); + assertNull(insertWithItems2); + ParenthesedSelect select = (ParenthesedSelect) insert2.getSelect(); + List> selectWithItems2 = select.getSelect().getWithItemsList(); + assertEquals(1, selectWithItems2.size()); + assertEquals("SELECT mycolumn FROM mytable", + selectWithItems2.get(0).getSelect().getPlainSelect().toString()); + assertEquals(" a", selectWithItems2.get(0).getAlias().toString()); } @Test @@ -347,9 +450,17 @@ public void testKeywordPrecisionIssue363() throws JSQLParserException { @Test public void testWithDeparsingIssue406() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "insert into mytab3 (a,b,c) select a,b,c from mytab where exists(with t as (select * from mytab2) select * from t)", - true); + String sqlStr = + "insert into mytab3 (a,b,c) select a,b,c from mytab where exists(with t as (select * from mytab2) select * from t)"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + List> insertWithItems = insert.getWithItemsList(); + List> selectWithItems = insert.getSelect().getWithItemsList(); + assertEquals("mytab3", insert.getTable().getFullyQualifiedName()); + assertNull(insertWithItems); + assertNull(selectWithItems); + ExistsExpression exists = (ExistsExpression) insert.getPlainSelect().getWhere(); + assertEquals("(WITH t AS (SELECT * FROM mytab2) SELECT * FROM t)", + exists.getRightExpression().toString()); } @Test @@ -363,16 +474,29 @@ public void testInsertValuesWithDuplicateEliminationInDeparsing() throws JSQLPar + "ON DUPLICATE KEY UPDATE COUNTER = COUNTER + 1"); } + @Test + public void testInsertValuesAliasWithDuplicateEliminationIssue() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new" + + " ON DUPLICATE KEY UPDATE c = new.a+new.b;"); + + assertSqlCanBeParsedAndDeparsed( + "INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new(m,n,p) " + + " ON DUPLICATE KEY UPDATE c = m+n;"); + } + @Test public void testInsertSetWithDuplicateEliminationInDeparsing() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("INSERT INTO mytable SET col1 = 122 " + "ON DUPLICATE KEY UPDATE col2 = col2 + 1, col3 = 'saint'"); + + assertSqlCanBeParsedAndDeparsed("INSERT INTO t1 SET a=1,b=2,c=3 AS new" + + " ON DUPLICATE KEY UPDATE c = new.a+new.b;"); } @Test public void testInsertTableWithAliasIssue526() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( - "INSERT INTO account t (name, addr, phone) SELECT * FROM user"); + "INSERT INTO account AS t (name, addr, phone) SELECT * FROM user"); } @Test @@ -389,9 +513,18 @@ public void testInsertKeyWordIntervalIssue682() throws JSQLParserException { @Test public void testWithAtFront() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "WITH foo AS ( SELECT attr FROM bar ) INSERT INTO lalelu (attr) SELECT attr FROM foo", - true); + String sqlStr = + "WITH foo AS ( SELECT attr FROM bar ) INSERT INTO lalelu (attr) SELECT attr FROM foo"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + List> insertWithItems = insert.getWithItemsList(); + assertEquals("lalelu", insert.getTable().getFullyQualifiedName()); + assertEquals(1, insertWithItems.size()); + assertEquals("SELECT attr FROM bar", + insertWithItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals(" foo", insertWithItems.get(0).getAlias().toString()); + assertEquals("SELECT attr FROM foo", insert.getSelect().toString()); + assertEquals("foo", insert.getSelect().getPlainSelect().getFromItem().toString()); + assertEquals("[attr]", insert.getSelect().getPlainSelect().getSelectItems().toString()); } @Test @@ -426,8 +559,18 @@ public void testDisableKeywordIssue945() throws JSQLParserException { @Test public void testWithListIssue282() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "WITH myctl AS (SELECT a, b FROM mytable) INSERT INTO mytable SELECT a, b FROM myctl"); + String sqlStr = + "WITH myctl AS (SELECT a, b FROM mytable) INSERT INTO mytable SELECT a, b FROM myctl"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + List> insertWithItems = insert.getWithItemsList(); + assertEquals("mytable", insert.getTable().getFullyQualifiedName()); + assertEquals(1, insertWithItems.size()); + assertEquals("SELECT a, b FROM mytable", + insertWithItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals(" myctl", insertWithItems.get(0).getAlias().toString()); + assertEquals("SELECT a, b FROM myctl", insert.getSelect().toString()); + assertEquals("myctl", insert.getSelect().getPlainSelect().getFromItem().toString()); + assertEquals("[a, b]", insert.getSelect().getPlainSelect().getSelectItems().toString()); } @Test @@ -467,8 +610,20 @@ public void testInsertUnionSelectIssue1491() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("insert into table1 (tf1,tf2,tf2)\n" + "((select sf1,sf2,sf3 from s1)" + "union " + "(select rf1,rf2,rf2 from r1))", true); + } - assertSqlCanBeParsedAndDeparsed("(with a as (select * from dual) select * from a)", true); + @Test + public void testWithSelectFromDual() throws JSQLParserException { + String sqlStr = "(with a as (select * from dual) select * from a)"; + ParenthesedSelect parenthesedSelect = + (ParenthesedSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + List> withItems = parenthesedSelect.getSelect().getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("SELECT * FROM dual", + withItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals(" a", withItems.get(0).getAlias().toString()); + assertEquals("a", parenthesedSelect.getPlainSelect().getFromItem().toString()); + assertEquals("[*]", parenthesedSelect.getPlainSelect().getSelectItems().toString()); } @Test @@ -527,6 +682,12 @@ public void insertOnConflictObjectsTest() throws JSQLParserException { String sqlStr = "WITH a ( a, b , c ) \n" + "AS (SELECT 1 , 2 , 3 )\n" + "insert into test\n" + "select * from a"; Insert insert = (Insert) CCJSqlParserUtil.parse(sqlStr); + List> withItems = insert.getWithItemsList(); + assertEquals("test", insert.getTable().getFullyQualifiedName()); + assertEquals(1, withItems.size()); + assertEquals("[1, 2, 3]", + withItems.get(0).getSelect().getPlainSelect().getSelectItems().toString()); + assertEquals(" a", withItems.get(0).getAlias().toString()); Expression whereExpression = CCJSqlParserUtil.parseExpression("a=1", false); Expression valueExpression = CCJSqlParserUtil.parseExpression("b/2", false); @@ -590,4 +751,269 @@ void testMultiColumnConflictTargetIssue955() throws JSQLParserException { + "on conflict(xxx0, xxx1) do update set xxx1=?, update_time=?"; assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + public void testDefaultValues() throws JSQLParserException { + String statement = "INSERT INTO mytable DEFAULT VALUES"; + // assertSqlCanBeParsedAndDeparsed(statement); + Insert insert = (Insert) parserManager.parse(new StringReader(statement)); + assertEquals("mytable", insert.getTable().getFullyQualifiedName()); + assertEquals("INSERT INTO MYTABLE DEFAULT VALUES", insert.toString().toUpperCase()); + assertTrue(insert.isOnlyDefaultValues()); + assertDeparse(new Insert() + .withTable(new Table("mytable")) + .withOnlyDefaultValues(true), statement); + } + + @Test + public void testDefaultValuesWithAlias() throws JSQLParserException { + String statement = "INSERT INTO mytable x DEFAULT VALUES"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(statement); + assertEquals("mytable", insert.getTable().getFullyQualifiedName()); + assertEquals("INSERT INTO MYTABLE X DEFAULT VALUES", insert.toString().toUpperCase()); + assertEquals("x", insert.getTable().getAlias().getName()); + assertTrue(insert.isOnlyDefaultValues()); + assertDeparse(new Insert() + .withTable(new Table("mytable") + .withAlias(new Alias("x").withUseAs(false))) + .withOnlyDefaultValues(true), statement); + } + + @Test + public void testDefaultValuesWithAliasAndAs() throws JSQLParserException { + String statement = "INSERT INTO mytable AS x DEFAULT VALUES"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(statement); + assertEquals("mytable", insert.getTable().getFullyQualifiedName()); + assertEquals("INSERT INTO MYTABLE AS X DEFAULT VALUES", insert.toString().toUpperCase()); + assertEquals("x", insert.getTable().getAlias().getName()); + assertTrue(insert.isOnlyDefaultValues()); + assertDeparse(new Insert() + .withTable(new Table("mytable") + .withAlias(new Alias("x").withUseAs(true))) + .withOnlyDefaultValues(true), statement); + } + + @Test + @Disabled + // @todo: verify if this is really necessary + public void throwsParseWhenDefaultKeywordUsedAsAlias() { + String statement = "INSERT INTO mytable default DEFAULT VALUES"; + assertThrows(JSQLParserException.class, + () -> parserManager.parse(new StringReader(statement))); + } + + @Test + void testInsertWithinCte() throws JSQLParserException { + String sqlStr = "WITH inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " RETURNING y " + + ") " + + "INSERT INTO z (blah) " + + "SELECT y FROM inserted"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(1, withItems.size()); + Insert innerInsert = withItems.get(0).getInsert().getInsert(); + assertEquals("x", innerInsert.getTable().toString()); + assertEquals("SELECT bar FROM b", innerInsert.getSelect().toString()); + assertEquals(" RETURNING y", innerInsert.getReturningClause().toString()); + assertEquals("INSERT INTO x (foo) SELECT bar FROM b RETURNING y", innerInsert.toString()); + assertEquals(" inserted", withItems.get(0).getAlias().toString()); + } + + @Test + void testUpdateWithinCte() throws JSQLParserException { + String sqlStr = "WITH updated AS ( " + + " UPDATE x " + + " SET foo = 1 " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "INSERT INTO z (blah) " + + "SELECT y FROM updated"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(1, withItems.size()); + Update update = withItems.get(0).getUpdate().getUpdate(); + assertEquals("x", update.getTable().toString()); + assertEquals("foo", update.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("1", update.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("bar = 2", update.getWhere().toString()); + assertEquals(" RETURNING y", update.getReturningClause().toString()); + assertEquals(" updated", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteWithinCte() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "INSERT INTO z (blah) " + + "SELECT y FROM deleted"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(1, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM deleted) " + + " RETURNING w " + + ") " + + "INSERT INTO z (blah) " + + "SELECT w FROM inserted"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(2, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + Insert innerInsert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", innerInsert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM deleted)", + innerInsert.getSelect().toString()); + assertEquals(" RETURNING w", innerInsert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM deleted) RETURNING w", + innerInsert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testSelectAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH selection AS ( " + + " SELECT y " + + " FROM z " + + " WHERE foo = 'bar' " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM selection) " + + " RETURNING w " + + ") " + + "INSERT INTO z (blah) " + + "SELECT w FROM inserted"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", insert.getTable().toString()); + List> withItems = insert.getWithItemsList(); + assertEquals(2, withItems.size()); + PlainSelect select = withItems.get(0).getSelect().getPlainSelect(); + assertEquals("SELECT y FROM z WHERE foo = 'bar'", select.toString()); + assertEquals(" selection", withItems.get(0).getAlias().toString()); + Insert innerInsert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", innerInsert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM selection)", + innerInsert.getSelect().toString()); + assertEquals(" RETURNING w", innerInsert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM selection) RETURNING w", + innerInsert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testInsertOverwrite() throws JSQLParserException { + String sqlStr = "INSERT OVERWRITE TABLE t SELECT * FROM a"; + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("t", insert.getTable().getName()); + assertTrue(insert.isOverwrite()); + + sqlStr = "INSERT OVERWRITE TABLE t PARTITION (pt1, pt2) SELECT * FROM a"; + insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("t", insert.getTable().getName()); + assertEquals(2, insert.getPartitions().size()); + assertEquals("pt1", insert.getPartitions().get(0).getColumn().getColumnName()); + assertNull(insert.getPartitions().get(0).getValue()); + assertTrue(insert.isOverwrite()); + + sqlStr = "INSERT OVERWRITE\nTABLE t PARTITION (pt1 = 'pt1', pt2 = 'pt2') SELECT * FROM a"; + insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("t", insert.getTable().getName()); + assertEquals(2, insert.getPartitions().size()); + assertEquals("pt2", insert.getPartitions().get(1).getColumn().getColumnName()); + assertEquals("'pt2'", insert.getPartitions().get(1).getValue().toString()); + assertTrue(insert.isOverwrite()); + + sqlStr = "INSERT INTO\tTABLE t PARTITION (pt1 = 'pt1', pt2 = 'pt2') SELECT * FROM a"; + insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("t", insert.getTable().getName()); + assertEquals(2, insert.getPartitions().size()); + assertEquals("pt1", insert.getPartitions().get(0).getColumn().getColumnName()); + assertEquals("'pt1'", insert.getPartitions().get(0).getValue().toString()); + assertFalse(insert.isOverwrite()); + } + + @ParameterizedTest + @ValueSource(strings = { + "INSERT INTO mytable (foo) OVERRIDING SYSTEM VALUE VALUES (1)", + "INSERT INTO mytable (foo) OVERRIDING SYSTEM VALUE SELECT bar FROM b WHERE y = 1", + "INSERT INTO mytable (foo) OVERRIDING SYSTEM VALUE VALUES (1) ON CONFLICT (foo) DO UPDATE SET foo = 2", + "INSERT INTO mytable (foo) OVERRIDING SYSTEM VALUE SELECT bar FROM b WHERE y = 1 ON CONFLICT (foo) DO UPDATE SET foo = 2", + "INSERT INTO mytable (foo) OVERRIDING SYSTEM VALUE VALUES (1) ON CONFLICT (foo) DO NOTHING", + "INSERT INTO mytable (foo) OVERRIDING SYSTEM VALUE SELECT bar FROM b WHERE y = 1 ON CONFLICT (foo) DO NOTHING" + }) + public void testOverridingSystemValueInsertsParse(String sqlStr) throws JSQLParserException { + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("mytable", insert.getTable().getName()); + assertEquals(true, insert.isOverriding()); + } + + @ParameterizedTest + @ValueSource(strings = { + "INSERT INTO overriding (foo) OVERRIDING SYSTEM VALUE VALUES (1)", + "INSERT INTO overriding (foo) OVERRIDING SYSTEM VALUE SELECT bar FROM b WHERE y = 1", + "INSERT INTO overriding (foo) OVERRIDING SYSTEM VALUE VALUES (1) ON CONFLICT (foo) DO UPDATE SET foo = 2", + "INSERT INTO overriding (foo) OVERRIDING SYSTEM VALUE SELECT bar FROM b WHERE y = 1 ON CONFLICT (foo) DO UPDATE SET foo = 2", + "INSERT INTO overriding (foo) OVERRIDING SYSTEM VALUE VALUES (1) ON CONFLICT (foo) DO NOTHING", + "INSERT INTO overriding (foo) OVERRIDING SYSTEM VALUE SELECT bar FROM b WHERE y = 1 ON CONFLICT (foo) DO NOTHING" + }) + public void testOverridingSystemValueInsertsParseWithTableNamedOverriding(String sqlStr) + throws JSQLParserException { + Insert insert = (Insert) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("overriding", insert.getTable().getName()); + assertEquals(true, insert.isOverriding()); + } + + @Test + void insertDemo() { + Insert insert = + new Insert() + .withTable(new Table("test")) + .withSelect( + new Values() + .addExpressions( + new StringValue("A"), new StringValue("B"))); + + TestUtils.assertStatementCanBeDeparsedAs( + insert, "INSERT INTO test VALUES ('A', 'B')"); + } + + @Test + public void testSimpleDuplicateInsert() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "INSERT INTO example (num, name, address, tel) VALUES (1, 'name', 'test ', '1234-1234') ON DUPLICATE KEY update NOTHING"); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java b/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java new file mode 100644 index 000000000..1ffed8cc4 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/lock/LockTest.java @@ -0,0 +1,126 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.lock; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + +@Execution(ExecutionMode.CONCURRENT) +public class LockTest { + + @ParameterizedTest + @ValueSource(strings = { + "LOCK TABLE a IN EXCLUSIVE MODE", + "LOCK TABLE a IN ROW EXCLUSIVE MODE", + "LOCK TABLE a IN ROW SHARE MODE", + "LOCK TABLE a IN SHARE MODE", + "LOCK TABLE a IN SHARE UPDATE MODE", + "LOCK TABLE a IN SHARE ROW EXCLUSIVE MODE", + "LOCK TABLE a IN EXCLUSIVE MODE NOWAIT", + "LOCK TABLE a IN SHARE ROW EXCLUSIVE MODE NOWAIT", + "LOCK TABLE a IN SHARE ROW EXCLUSIVE MODE WAIT 10", + "LOCK TABLE a IN EXCLUSIVE MODE WAIT 23", + }) + void testLockStatementsParseDeparse(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr); + } + + @Test + void testLockExclusiveMode() throws JSQLParserException { + String sqlStr = "LOCK TABLE a IN EXCLUSIVE MODE"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + assertInstanceOf(LockStatement.class, statement); + + LockStatement ls = (LockStatement) statement; + assertEquals(LockMode.Exclusive, ls.getLockMode()); + assertFalse(ls.isNoWait()); + } + + @Test + void testNoWait() throws JSQLParserException { + String sqlStr = "LOCK TABLE a IN SHARE MODE NOWAIT"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + assertInstanceOf(LockStatement.class, statement); + + LockStatement ls = (LockStatement) statement; + assertEquals(LockMode.Share, ls.getLockMode()); + assertTrue(ls.isNoWait()); + } + + @Test + void testWaitTimeout() throws JSQLParserException { + String sqlStr = "LOCK TABLE a IN SHARE MODE WAIT 300"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + assertInstanceOf(LockStatement.class, statement); + + LockStatement ls = (LockStatement) statement; + assertEquals(LockMode.Share, ls.getLockMode()); + assertNotNull(ls.getWaitSeconds()); + assertEquals(300, ls.getWaitSeconds()); + } + + @Test + void testCreateLockStatement() { + Table t = new Table("a"); + + LockStatement ls = new LockStatement(t, LockMode.Exclusive); + assertEquals("LOCK TABLE a IN EXCLUSIVE MODE", ls.toString()); + + ls.setLockMode(LockMode.Share); + assertEquals("LOCK TABLE a IN SHARE MODE", ls.toString()); + + ls.setNoWait(true); + assertEquals("LOCK TABLE a IN SHARE MODE NOWAIT", ls.toString()); + + ls.setNoWait(false); + ls.setWaitSeconds(60L); + assertEquals("LOCK TABLE a IN SHARE MODE WAIT 60", ls.toString()); + + ls.setWaitSeconds(null); + assertEquals("LOCK TABLE a IN SHARE MODE", ls.toString()); + + ls.setTable(new Table("b")); + assertEquals("LOCK TABLE b IN SHARE MODE", ls.toString()); + } + + @Test + void testIllegalStateWaitSeconds() { + Table t = new Table("a"); + LockStatement ls = new LockStatement(t, LockMode.Exclusive); + + assertThrows(IllegalStateException.class, () -> { + ls.setNoWait(true); + ls.setWaitSeconds(60L); + }); + } + + @Test + void testIllegalStateNoWait() { + Table t = new Table("a"); + LockStatement ls = new LockStatement(t, LockMode.Exclusive); + + assertThrows(IllegalStateException.class, () -> { + ls.setWaitSeconds(60L); + ls.setNoWait(true); + }); + } + + +} diff --git a/src/test/java/net/sf/jsqlparser/statement/merge/MergeTest.java b/src/test/java/net/sf/jsqlparser/statement/merge/MergeTest.java index 678b8e7f8..470b8c163 100644 --- a/src/test/java/net/sf/jsqlparser/statement/merge/MergeTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/merge/MergeTest.java @@ -42,10 +42,6 @@ public void testOracleMergeIntoStatement() throws JSQLParserException { + " INSERT (B.employee_id, B.bonus)\n" + " VALUES (E.employee_id, E.salary * 0.05) "; - Statement statement = CCJSqlParserUtil.parse(sql); - - System.out.println(statement.toString()); - assertSqlCanBeParsedAndDeparsed(sql, true); } diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/AsPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/AsPipeOperatorTest.java new file mode 100644 index 000000000..17b90e28b --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/AsPipeOperatorTest.java @@ -0,0 +1,32 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class AsPipeOperatorTest { + + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr="(\n" + + " SELECT '000123' AS id, 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT '000456' AS id, 'bananas' AS item, 5 AS sales\n" + + ") AS sales_table\n" + + "|> AGGREGATE SUM(sales) AS total_sales GROUP BY id, item\n" + + "|> AS t1\n" + + "|> JOIN (SELECT 456 AS id, 'yellow' AS color) AS t2\n" + + " ON CAST(t1.id AS INT64) = t2.id\n" + + "|> SELECT t2.id, total_sales, color;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/CallPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/CallPipeOperatorTest.java new file mode 100644 index 000000000..a8f921617 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/CallPipeOperatorTest.java @@ -0,0 +1,25 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + + +class CallPipeOperatorTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "FROM input_table\n" + + "|> CALL tvf1(arg1)\n" + + "|> CALL tvf2(arg2, arg3);"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/DropPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/DropPipeOperatorTest.java new file mode 100644 index 000000000..5c8ce0a15 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/DropPipeOperatorTest.java @@ -0,0 +1,34 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class DropPipeOperatorTest { + + @Test + void testParseAndDeParseWithoutFromKeyword() throws JSQLParserException { + String sqlStr = "SELECT 'apples' AS item, 2 AS sales, 'fruit' AS category\n" + + "|> DROP sales, category;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParseAndDeParse() throws JSQLParserException { + String sqlStr = "FROM (SELECT 1 AS x, 2 AS y) AS t\n" + + "|> DROP x\n" + + "|> SELECT t.x AS original_x, y;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperatorTest.java new file mode 100644 index 000000000..652838017 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperatorTest.java @@ -0,0 +1,40 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class ExtendPipeOperatorTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "FROM (\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> EXTEND item IN ('carrots', 'oranges') AS is_orange;"; + FromQuery fromQuery = (FromQuery) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + // Assertions.assertInstanceOf(ExtendPipeOperator.class, fromQuery.get(0)); + } + + @Test + void testParseAndDeparseWithoutFromKeyword() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> EXTEND item IN ('carrots', 'oranges') AS is_orange;"; + FromQuery fromQuery = (FromQuery) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + // Assertions.assertInstanceOf(ExtendPipeOperator.class, fromQuery.get(0)); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/FromQueryTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/FromQueryTest.java new file mode 100644 index 000000000..a10e0c570 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/FromQueryTest.java @@ -0,0 +1,256 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class FromQueryTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + // formatter:off + String sqlStr = "FROM Produce\n" + + "|> WHERE\n" + + " item != 'bananas'\n" + + " AND category IN ('fruit', 'nut')\n" + + "|> AGGREGATE COUNT(*) AS num_items, SUM(sales) AS total_sales\n" + + " GROUP BY item\n" + + "|> ORDER BY item DESC;"; + // formatter:on + FromQuery fromQuery = (FromQuery) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Assertions.assertInstanceOf(WherePipeOperator.class, fromQuery.get(0)); + Assertions.assertInstanceOf(AggregatePipeOperator.class, fromQuery.get(1)); + Assertions.assertInstanceOf(OrderByPipeOperator.class, fromQuery.get(2)); + } + + @Test + void testParseAndDeparseJoin() throws JSQLParserException { + // formatter:off + String sqlStr = + "FROM Produce INNER JOIN Price USING(id_product) \n" + + "|> WHERE\n" + + " item != 'bananas'\n" + + " AND category IN ('fruit', 'nut')\n" + + "|> AGGREGATE COUNT(*) AS num_items, SUM(sales) AS total_sales\n" + + " GROUP BY item\n" + + "|> ORDER BY item DESC;"; + // formatter:on + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParseAndDeparseWithIssue73() throws JSQLParserException { + // formatter:off + String sqlStr = + "with client_info as (\n" + + " with client as (\n" + + " select 1 as client_id\n" + + " |> UNION ALL\n" + + " (select 2),\n" + + " (select 3)\n" + + " ), basket as (\n" + + " select 1 as basket_id, 1 as client_id\n" + + " |> UNION ALL\n" + + " (select 2, 2)\n" + + " ), basket_item as (\n" + + " select 1 as item_id, 1 as basket_id\n" + + " |> UNION ALL\n" + + " (select 2, 1),\n" + + " (select 3, 1),\n" + + " (select 4, 2)\n" + + " ), item as (\n" + + " select 1 as item_id, 'milk' as name\n" + + " |> UNION ALL\n" + + " (select 2, \"chocolate\"),\n" + + " (select 3, \"donut\"),\n" + + " (select 4, \"croissant\")\n" + + " ), wrapper as (\n" + + " FROM client c\n" + + " |> aggregate count(i.item_id) as bought_item\n" + + " group by c.client_id, i.item_id, i.name\n" + + " |> aggregate array_agg((select as struct item_id, name, bought_item)) as items_info\n" + + + " group by client_id\n" + + " )\n" + + " select * from wrapper\n" + + ")\n" + + "select * from client_info"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParseAndDeparseWithJoinIssue72() throws JSQLParserException { + // formatter:off + String sqlStr = + "with client as (\n" + + " select 1 as client_id\n" + + " |> UNION ALL\n" + + " (select 2),\n" + + " (select 3)\n" + + "), basket as (\n" + + " select 1 as basket_id, 1 as client_id\n" + + " |> UNION ALL\n" + + " (select 2, 2)\n" + + "), basket_item as (\n" + + " select 1 as item_id, 1 as basket_id\n" + + " |> UNION ALL\n" + + " (select 2, 1),\n" + + " (select 3, 1),\n" + + " (select 4, 2)\n" + + "), item as (\n" + + " select 1 as item_id, 'milk' as name\n" + + " |> UNION ALL\n" + + " (select 2, \"chocolate\"),\n" + + " (select 3, \"donut\"),\n" + + " (select 4, \"croissant\")\n" + + ")\n" + + "FROM client c\n" + + " left join basket b using(client_id)\n" + + " left join basket_item bi using(basket_id)\n" + + " left join item i on i.item_id = bi.item_id\n" + + "|> aggregate count(i.item_id) as bought_item\n" + + " group by c.client_id, i.item_id, i.name\n" + + "|> aggregate array_agg((select as struct item_id, name, bought_item)) as items_info\n" + + + " group by client_id"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParseAndDeparseIssue74() throws JSQLParserException { + // formatter:off + String sqlStr = + "FROM\n" + + " Produce AS p1\n" + + " JOIN Produce AS p2\n" + + " USING (item)\n" + + "|> WHERE item = 'bananas'\n" + + "|> SELECT p1.item, p2.sales;"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + // formatter:off + sqlStr = + "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> EXTEND item IN ('carrots', 'oranges') AS is_orange;"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + // formatter:off + sqlStr = + "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'bananas' AS item, 5 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> EXTEND SUM(sales) OVER() AS total_sales;"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + // formatter:off + sqlStr = + "(\n" + + " SELECT 1 AS x, 11 AS y\n" + + " UNION ALL\n" + + " SELECT 2 AS x, 22 AS y\n" + + ")\n" + + "|> SET x = x * x, y = 3"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + // formatter:off + sqlStr = + "(\n" + + " SELECT \"000123\" AS id, \"apples\" AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT \"000456\" AS id, \"bananas\" AS item, 5 AS sales\n" + + ") AS sales_table\n" + + "|> AGGREGATE SUM(sales) AS total_sales GROUP BY id, item\n" + + "-- The sales_table alias is now out of scope. We must introduce a new one.\n" + + + "|> AS t1\n" + + "|> JOIN (SELECT 456 AS id, \"yellow\" AS color) AS t2\n" + + " ON CAST(t1.id AS INT64) = t2.id\n" + + "|> SELECT t2.id, total_sales, color;"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + // formatter:off + sqlStr = + "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'bananas' AS item, 5 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> WHERE sales >= 3;"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + + // formatter:off + sqlStr = + "FROM Produce\n" + + "|> AGGREGATE SUM(sales) AS total_sales ASC\n" + + " GROUP BY item, category DESC;"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + // formatter:off + sqlStr = + "SELECT * FROM UNNEST(ARRAY[1, 2, 3]) AS number\n" + + "|> UNION ALL (SELECT 1);"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + + // formatter:off + sqlStr = + "WITH\n" + + " NumbersTable AS (\n" + + " SELECT 1 AS one_digit, 10 AS two_digit\n" + + " UNION ALL\n" + + " SELECT 2, 20\n" + + " UNION ALL\n" + + " SELECT 3, 30\n" + + " )\n" + + "SELECT one_digit, two_digit FROM NumbersTable\n" + + "|> INTERSECT ALL BY NAME\n" + + " (SELECT 10 AS two_digit, 1 AS one_digit);"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParseAndDeparseNestedWithIssue2168() throws JSQLParserException { + // formatter:off + String sqlStr = + "with b as (\n" + + " with a as (select 1)\n" + + " from a )\n" + + "from b\n" + + ";"; + // formatter:on + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/JoinPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/JoinPipeOperatorTest.java new file mode 100644 index 000000000..f14de993a --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/JoinPipeOperatorTest.java @@ -0,0 +1,38 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class JoinPipeOperatorTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "FROM (\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'bananas' AS item, 5 AS sales\n" + + ")\n" + + "|> AS produce_sales\n" + + "|> LEFT JOIN\n" + + " (\n" + + " SELECT \"apples\" AS item, 123 AS id\n" + + " ) AS produce_data\n" + + " ON produce_sales.item = produce_data.item\n" + + "|> SELECT produce_sales.item, sales, id;"; + FromQuery fromQuery = (FromQuery) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertInstanceOf(AsPipeOperator.class, fromQuery.get(0)); + Assertions.assertInstanceOf(JoinPipeOperator.class, fromQuery.get(1)); + Assertions.assertInstanceOf(SelectPipeOperator.class, fromQuery.get(2)); + } + +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/LimitPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/LimitPipeOperatorTest.java new file mode 100644 index 000000000..10468390a --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/LimitPipeOperatorTest.java @@ -0,0 +1,47 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class LimitPipeOperatorTest { + + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'bananas' AS item, 5 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> ORDER BY item\n" + + "|> LIMIT 1;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParseAndDeparseWithOffset() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'bananas' AS item, 5 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> ORDER BY item\n" + + "|> LIMIT 1 OFFSET 2;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/PivotPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/PivotPipeOperatorTest.java new file mode 100644 index 000000000..6898099f4 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/PivotPipeOperatorTest.java @@ -0,0 +1,34 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + + +class PivotPipeOperatorTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT \"kale\" AS product, 51 AS sales, \"Q1\" AS quarter\n" + + " UNION ALL\n" + + " SELECT \"kale\" AS product, 4 AS sales, \"Q1\" AS quarter\n" + + " UNION ALL\n" + + " SELECT \"kale\" AS product, 45 AS sales, \"Q2\" AS quarter\n" + + " UNION ALL\n" + + " SELECT \"apple\" AS product, 8 AS sales, \"Q1\" AS quarter\n" + + " UNION ALL\n" + + " SELECT \"apple\" AS product, 10 AS sales, \"Q2\" AS quarter\n" + + ")\n" + + "|> PIVOT(SUM(sales) FOR quarter IN (\"Q1\", \"Q2\"));"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/SelectPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/SelectPipeOperatorTest.java new file mode 100644 index 000000000..cc164b55a --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/SelectPipeOperatorTest.java @@ -0,0 +1,36 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class SelectPipeOperatorTest { + + @Test + void testRename() throws JSQLParserException { + String sqlStr = "SELECT 1 AS x, 2 AS y, 3 AS z\n" + + "|> AS t\n" + + "|> RENAME y AS renamed_y\n" + + "|> SELECT *, t.y AS t_y;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testDistinct() throws JSQLParserException { + String sqlStr = "FROM orders\n" + + "|> WHERE order_date >= '2024-01-01'\n" + + "|> SELECT DISTINCT customer_id \n" + + "|> INNER JOIN customers USING(customer_id)\n" + + "|> SELECT *;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperatorTest.java new file mode 100644 index 000000000..7efbc0758 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperatorTest.java @@ -0,0 +1,48 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + + +class SetOperationPipeOperatorTest { + + @Test + void parseAndDeparseUnion() throws JSQLParserException { + String sqlStr = + "SELECT 3\n" + + "|> UNION ALL\n" + + " (SELECT 1),\n" + + " (SELECT 2);"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + // @todo: parse SELECT * FROM UNNEST(ARRAY[2, 3, 3, 5]) AS number + + @Test + void parseAndDeparseIntersect() throws JSQLParserException { + String sqlStr = + "SELECT * FROM UNNEST(ARRAY[1, 2, 3, 3, 4]) AS number\n" + + "|> INTERSECT DISTINCT\n" + + " (SELECT * FROM UNNEST(ARRAY[2, 3, 3, 5]) AS number);"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void parseAndDeparseExcept() throws JSQLParserException { + String sqlStr = + "SELECT * FROM UNNEST(ARRAY[1, 2, 3, 3, 4]) AS number\n" + + "|> EXCEPT DISTINCT\n" + + " (SELECT * FROM UNNEST(ARRAY[1, 2]) AS number);"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/SetPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/SetPipeOperatorTest.java new file mode 100644 index 000000000..369298718 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/SetPipeOperatorTest.java @@ -0,0 +1,28 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class SetPipeOperatorTest { + + @Test + void parseAndDeparse() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 1 AS x, 11 AS y\n" + + " UNION ALL\n" + + " SELECT 2 AS x, 22 AS y\n" + + ")\n" + + "|> SET x = x * x, y = 3;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperatorTest.java new file mode 100644 index 000000000..f96e963fc --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperatorTest.java @@ -0,0 +1,24 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + + +class TableSamplePipeOperatorTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "FROM LargeTable\n" + + "|> TABLESAMPLE SYSTEM (1.0 PERCENT);\n"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperatorTest.java new file mode 100644 index 000000000..4126bce6c --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperatorTest.java @@ -0,0 +1,29 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class UnPivotPipeOperatorTest { + + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 'kale' as product, 55 AS Q1, 45 AS Q2\n" + + " UNION ALL\n" + + " SELECT 'apple', 8, 10\n" + + ")\n" + + "|> UNPIVOT(sales FOR quarter IN (Q1, Q2));"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/AllColumnsTest.java b/src/test/java/net/sf/jsqlparser/statement/select/AllColumnsTest.java index 35173ec3d..7f5aaba4c 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/AllColumnsTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/AllColumnsTest.java @@ -19,7 +19,15 @@ class AllColumnsTest { @Test void testBigQuerySyntax() throws JSQLParserException { String sqlStr = - "SELECT * EXCEPT (order_id) REPLACE (\"widget\" AS item_name), \"more\" as more_fields\n" + "SELECT * EXCEPT(order_id) REPLACE(\"widget\" AS item_name), \"more\" as more_fields\n" + + "FROM orders"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testDuckDBQuerySyntax() throws JSQLParserException { + String sqlStr = + "SELECT * EXCLUDE(order_id) REPLACE(\"widget\" AS item_name), \"more\" as more_fields\n" + "FROM orders"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/AllTableColumnsTest.java b/src/test/java/net/sf/jsqlparser/statement/select/AllTableColumnsTest.java index 0a0a9950c..f6dca8eba 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/AllTableColumnsTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/AllTableColumnsTest.java @@ -22,4 +22,12 @@ void testBigQuerySyntax() throws JSQLParserException { + "FROM orders"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testDuckDBSyntax() throws JSQLParserException { + String sqlStr = + "SELECT orders.* EXCLUDE (order_id)\n" + + "FROM orders"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/BigQueryTest.java b/src/test/java/net/sf/jsqlparser/statement/select/BigQueryTest.java index 18a11a52b..81a321784 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/BigQueryTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/BigQueryTest.java @@ -11,6 +11,7 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -80,4 +81,33 @@ void testAggregateFunctionHaving() throws JSQLParserException { "SELECT ANY_VALUE(fruit HAVING MAX sold) AS a_highest_selling_fruit FROM Store;\n"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testAsStruct() throws JSQLParserException { + String sqlStr = "SELECT ARRAY(SELECT AS STRUCT 1 a, 2 b)"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testAsValue() throws JSQLParserException { + String sqlStr = "SELECT AS VALUE STRUCT(1 AS a, 2 AS b) xyz"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testTimeSeriesFunction() throws JSQLParserException { + String sqlStr = "with raw_data as (\n" + + " select timestamp('2024-12-01') zetime\n" + + " union all \n" + + " select timestamp('2024-12-04')\n" + + " )\n" + + "select zetime from GAP_FILL(\n" + + " TABLE raw_data,\n" + + " ts_column => 'zetime',\n" + + " bucket_width => INTERVAL 4 HOUR\n" + + ")"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + TableFunction function = select.getFromItem(TableFunction.class); + Assertions.assertEquals("TABLE", function.getFunction().getExtraKeyword()); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/ClickHouseTest.java b/src/test/java/net/sf/jsqlparser/statement/select/ClickHouseTest.java index 72b8508df..a7046ada0 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/ClickHouseTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/ClickHouseTest.java @@ -9,13 +9,13 @@ */ package net.sf.jsqlparser.statement.select; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; + import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Function; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; public class ClickHouseTest { @@ -26,6 +26,46 @@ public void testGlobalJoin() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed(sql, true); } + @Test + public void testGlobalAnyLeftJoin() throws JSQLParserException { + String sql = "SELECT * FROM events e GLOBAL ANY LEFT JOIN users u ON e.user_id = u.id"; + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); + Join join = select.getJoins().get(0); + Assertions.assertTrue(join.isGlobal()); + Assertions.assertTrue(join.isAny()); + Assertions.assertTrue(join.isLeft()); + } + + @Test + public void testGlobalAllRightJoin() throws JSQLParserException { + String sql = "SELECT * FROM events e GLOBAL ALL RIGHT JOIN users u ON e.user_id = u.id"; + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); + Join join = select.getJoins().get(0); + Assertions.assertTrue(join.isGlobal()); + Assertions.assertTrue(join.isAll()); + Assertions.assertTrue(join.isRight()); + } + + @Test + public void testLeftAnyJoinOrderVariant() throws JSQLParserException { + String sql = "SELECT * FROM events e LEFT ANY JOIN users u ON e.user_id = u.id"; + Select statement = (Select) CCJSqlParserUtil.parse(sql); + PlainSelect select = (PlainSelect) statement.getSelectBody(); + Join join = select.getJoins().get(0); + Assertions.assertTrue(join.isAny()); + Assertions.assertTrue(join.isLeft()); + } + + @Test + public void testRightAllJoinOrderVariant() throws JSQLParserException { + String sql = "SELECT * FROM events e RIGHT ALL JOIN users u ON e.user_id = u.id"; + Select statement = (Select) CCJSqlParserUtil.parse(sql); + PlainSelect select = (PlainSelect) statement.getSelectBody(); + Join join = select.getJoins().get(0); + Assertions.assertTrue(join.isAll()); + Assertions.assertTrue(join.isRight()); + } + @Test public void testFunctionWithAttributesIssue1742() throws JSQLParserException { String sql = "SELECT f1(arguments).f2.f3 from dual"; @@ -50,13 +90,54 @@ public void testGlobalKeywordIssue1883() throws JSQLParserException { String sqlStr = "select a.* from a global join b on a.name = b.name "; PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); Assertions.assertTrue(select.getJoins().get(0).isGlobal()); + } - Assertions.assertThrows( - JSQLParserException.class, new Executable() { - @Override - public void execute() throws Throwable { - CCJSqlParserUtil.parse("select a.* from a global"); - } - }, "Fail when restricted keyword GLOBAL is used as an Alias."); + @Test + public void testPreWhereClause() throws JSQLParserException { + String sqlStr = "SELECT * FROM table1 PREWHERE column_name = 'value'"; + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertNotNull(select.getPreWhere()); + Assertions.assertNull(select.getWhere()); + } + + @Test + public void testPreWhereWithWhereClause() throws JSQLParserException { + String sqlStr = + "SELECT * FROM table1 PREWHERE column_name = 'value' WHERE id > 10"; + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertNotNull(select.getPreWhere()); + Assertions.assertNotNull(select.getWhere()); + } + + @Test + public void testParameterizedAggregateFunctionIssue2125() throws JSQLParserException { + String sql = + "SELECT toStartOfDay(timestamp) AS date, count(1) AS count, quantile(0.95)(cost) AS cost95 FROM apm_log_event"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sql, true); + + Function function = ((PlainSelect) select.getSelectBody()) + .getSelectItem(2) + .getExpression(Function.class); + Assertions.assertNotNull(function.getParameters()); + Assertions.assertNotNull(function.getChainedParameters()); + Assertions.assertEquals(1, function.getParameters().size()); + Assertions.assertEquals(1, function.getChainedParameters().size()); + } + + @Test + public void testSettingsClauseIssue2362() throws JSQLParserException { + String sql = "SELECT *\nFROM events\nSETTINGS max_threads = 1"; + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); + Assertions.assertNotNull(select.getSettings()); + Assertions.assertEquals(1, select.getSettings().size()); + Assertions.assertEquals("max_threads = 1", select.getSettings().get(0).toString()); + } + + @Test + public void testMultipleSettingsClauseIssue2362() throws JSQLParserException { + String sql = "SELECT * FROM events SETTINGS max_threads = 1, max_rows_to_read = 1000"; + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); + Assertions.assertNotNull(select.getSettings()); + Assertions.assertEquals(2, select.getSettings().size()); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/DB2Test.java b/src/test/java/net/sf/jsqlparser/statement/select/DB2Test.java index 296aab55d..4b71a4830 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/DB2Test.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/DB2Test.java @@ -12,6 +12,8 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; public class DB2Test { @Test @@ -20,4 +22,16 @@ void testDB2SpecialRegister() throws JSQLParserException { "SELECT * FROM TABLE1 where COL_WITH_TIMESTAMP <= CURRENT TIMESTAMP - CURRENT TIMEZONE"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM table WITH UR", + "SELECT * FROM table WITH UR FOR READ ONLY", + "SELECT * FROM table FOR READ ONLY", + "SELECT * FROM table FOR FETCH ONLY", + "SELECT * FROM table FETCH FIRST 100 ROWS ONLY FOR READ ONLY" + }) + void testWithIsolationLevelAndReadOnlyModes(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java b/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java new file mode 100644 index 000000000..aad68683b --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java @@ -0,0 +1,39 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class DuckDBTest { + + @Test + void testFileTable() throws JSQLParserException { + String sqlStr = "SELECT * FROM '/tmp/test.parquet'"; + PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Table table = (Table) select.getFromItem(); + + Assertions.assertEquals("'/tmp/test.parquet'", table.getName()); + } + + @Test + void testCreateWithStruct() throws JSQLParserException { + String sqlStr = + "CREATE TABLE starbake.array_test (\n" + + " keys VARCHAR[] NOT NULL,\n" + + " values1 struct( field1 varchar(255), field2 double) NOT NULL,\n" + + " values2 struct( field1 varchar(255), field2 double) NOT NULL\n" + + ");"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/ExpressionDelimiterTest.java b/src/test/java/net/sf/jsqlparser/statement/select/ExpressionDelimiterTest.java index cb4a63c97..6c14a331f 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/ExpressionDelimiterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/ExpressionDelimiterTest.java @@ -10,7 +10,10 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.JsonExpression; import net.sf.jsqlparser.schema.Column; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.List; @@ -24,12 +27,13 @@ public class ExpressionDelimiterTest { public void testColumnWithDifferentDelimiters() throws JSQLParserException { String statement = "SELECT mytable.mycolumn:parent:child FROM mytable"; PlainSelect parsed = (PlainSelect) assertSqlCanBeParsedAndDeparsed(statement); - Column column = parsed.getSelectItem(0).getExpression(Column.class); - assertEquals(":", column.getTableDelimiter()); - assertEquals(List.of(":", "."), column.getTable().getNamePartDelimiters()); + Assertions.assertInstanceOf(JsonExpression.class, parsed.getSelectItem(0).getExpression()); } + // I don't know what kind of Operator ".:." shall present + // please rework @Test + @Disabled public void testColumnWithEmptyNameParts() throws JSQLParserException { String statement = "SELECT mytable.:.child FROM mytable"; PlainSelect parsed = (PlainSelect) assertSqlCanBeParsedAndDeparsed(statement); diff --git a/src/test/java/net/sf/jsqlparser/statement/select/ForClauseTest.java b/src/test/java/net/sf/jsqlparser/statement/select/ForClauseTest.java index b8e22ed6e..dee2c99ba 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/ForClauseTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/ForClauseTest.java @@ -30,6 +30,13 @@ void testForXMLPath() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + @Test + void testForXMLPathAfterOrderByInSubSelect() throws JSQLParserException { + String sqlStr = + "SELECT STUFF((SELECT ',' + name FROM class ORDER BY id FOR XML PATH('')),1,1,'') AS names FROM users"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + @Test void testForXMLRaw() throws JSQLParserException { String sqlStr = diff --git a/src/test/java/net/sf/jsqlparser/statement/select/ForUpdateTest.java b/src/test/java/net/sf/jsqlparser/statement/select/ForUpdateTest.java index ecd216217..23eb3d229 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/ForUpdateTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/ForUpdateTest.java @@ -10,9 +10,13 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + public class ForUpdateTest { @Test @@ -44,4 +48,101 @@ void testMySqlIssue1995() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + + @Test + void testForUpdateMultipleTables() throws JSQLParserException { + String sqlStr = + "select employee_id from (select employee_id+1 as employee_id from employees)" + + " for update of a, b.c, d skip locked"; + + Statement stmt = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + PlainSelect plainSelect = (PlainSelect) stmt; + + assertThat(plainSelect.getForMode()).isEqualTo(ForMode.UPDATE); + assertThat(plainSelect.getForUpdateTables()).hasSize(3); + assertThat(plainSelect.isSkipLocked()).isTrue(); + + ForUpdateClause forUpdate = plainSelect.getForUpdate(); + assertThat(forUpdate).isNotNull(); + assertThat(forUpdate.isForUpdate()).isTrue(); + assertThat(forUpdate.getTables()).hasSize(3); + assertThat(forUpdate.isSkipLocked()).isTrue(); + } + + @Test + void testForUpdateOrderByAfter() throws JSQLParserException { + String sqlStr = + "select su.ttype, su.cid, su.s_id, sessiontimezone from sku su" + + " where (nvl(su.up, 'n') = 'n' and su.ttype = :b0)" + + " for update of su.up order by su.d"; + + Statement stmt = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + PlainSelect plainSelect = (PlainSelect) stmt; + + assertThat(plainSelect.getForMode()).isEqualTo(ForMode.UPDATE); + assertThat(plainSelect.getForUpdateTables()).hasSize(1); + assertThat(plainSelect.getOrderByElements()).hasSize(1); + assertThat(plainSelect.isForUpdateBeforeOrderBy()).isTrue(); + } + + @Test + void testForUpdateDetection() throws JSQLParserException { + Statement stmt = CCJSqlParserUtil.parse("SELECT * FROM users FOR UPDATE"); + PlainSelect plainSelect = (PlainSelect) stmt; + + // ForMode is set for FOR UPDATE + assertThat(plainSelect.getForMode()).isEqualTo(ForMode.UPDATE); + + // getForUpdate() returns a ForUpdateClause + ForUpdateClause forUpdate = plainSelect.getForUpdate(); + assertThat(forUpdate).isNotNull(); + assertThat(forUpdate.isForUpdate()).isTrue(); + assertThat(forUpdate.isForShare()).isFalse(); + assertThat(forUpdate.getTables()).isNull(); + } + + @Test + void testForShare() throws JSQLParserException { + Statement stmt = CCJSqlParserUtil.parse("SELECT * FROM users FOR SHARE"); + PlainSelect plainSelect = (PlainSelect) stmt; + + assertThat(plainSelect.getForMode()).isEqualTo(ForMode.SHARE); + + ForUpdateClause forUpdate = plainSelect.getForUpdate(); + assertThat(forUpdate).isNotNull(); + assertThat(forUpdate.isForShare()).isTrue(); + assertThat(forUpdate.isForUpdate()).isFalse(); + } + + @Test + void testForUpdateNowait() throws JSQLParserException { + String sqlStr = + "select employee_id from (select employee_id+1 as employee_id from employees)" + + " for update of employee_id nowait"; + Statement stmt = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + PlainSelect plainSelect = (PlainSelect) stmt; + + assertThat(plainSelect.getForMode()).isEqualTo(ForMode.UPDATE); + assertThat(plainSelect.isNoWait()).isTrue(); + + ForUpdateClause forUpdate = plainSelect.getForUpdate(); + assertThat(forUpdate.isNoWait()).isTrue(); + assertThat(forUpdate.isSkipLocked()).isFalse(); + } + + @Test + void testForUpdateWait() throws JSQLParserException { + String sqlStr = + "select employee_id from (select employee_id+1 as employee_id from employees)" + + " for update of employee_id wait 10"; + Statement stmt = TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + PlainSelect plainSelect = (PlainSelect) stmt; + + assertThat(plainSelect.getWait()).isNotNull(); + assertThat(plainSelect.getWait().getTimeout()).isEqualTo(10L); + + ForUpdateClause forUpdate = plainSelect.getForUpdate(); + assertThat(forUpdate.getWait()).isNotNull(); + assertThat(forUpdate.getWait().getTimeout()).isEqualTo(10L); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/MemoryTest.java b/src/test/java/net/sf/jsqlparser/statement/select/MemoryTest.java index 1c0135ec1..9f452566f 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/MemoryTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/MemoryTest.java @@ -23,19 +23,28 @@ public static void main(String[] args) throws Exception { String longQuery = "select * from k where ID > 4"; /* - * String longQuery = "select * from ( SELECT intermediate.id as id , intermediate.date as " - * + "date FROM ( SELECT DISTINCT ( id ) FROM ( SELECT " + - * "wct_workflows.workflow_id as id , wct_transaction.date as date FROM " + - * "wct_audit_entry , wct_transaction , wct_workflows WHERE " + - * "( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = " + "'C' ))))"; + * String longQuery = + * "select * from ( SELECT intermediate.id as id , intermediate.date as " + * + + * "date FROM ( SELECT DISTINCT ( id ) FROM ( SELECT " + * + + * "wct_workflows.workflow_id as id , wct_transaction.date as date FROM " + * + + * "wct_audit_entry , wct_transaction , wct_workflows WHERE " + * + + * "( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = " + * + "'C' ))))"; */ - /* + /* * String longQuery = "select * from d WHERE " + - * "( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = " + - * "'C' ) and wct_audit_entry.outcome = 't' and " + - * "wct_audit_entry.transaction_id = wct_transaction.transaction_id and " + - * "wct_transaction.user_id = 164 and wct_audit_entry.object_id = " + - * "wct_workflows.active_version_id "; + * "( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = " + * + + * "'C' ) and wct_audit_entry.outcome = 't' and " + * + + * "wct_audit_entry.transaction_id = wct_transaction.transaction_id and " + * + + * "wct_transaction.user_id = 164 and wct_audit_entry.object_id = " + * + "wct_workflows.active_version_id "; */ StringReader stringReader = new StringReader(longQuery); Statement statement = parserManager.parse(stringReader); diff --git a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java index 83a4fe7ae..fc5bd785d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java @@ -10,16 +10,17 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import org.junit.jupiter.api.Disabled; +import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.util.logging.Logger; import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import org.junit.jupiter.api.Assertions; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; +import org.junit.jupiter.api.function.Executable; /** * @@ -35,14 +36,15 @@ public class NestedBracketsPerformanceTest { public void testIssue766() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( "SELECT concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat(concat('1','2'),'3'),'4'),'5'),'6'),'7'),'8'),'9'),'10'),'11'),'12'),'13'),'14'),'15'),'16'),'17'),'18'),'19'),'20'),'21'),col1 FROM tbl t1", - true); + true, parser -> parser.withTimeOut(60000)); } @Test @Timeout(2000) public void testIssue766_2() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( - "SELECT concat(concat(concat('1', '2'), '3'), '4'), col1 FROM tbl t1"); + "SELECT concat(concat(concat('1', '2'), '3'), '4'), col1 FROM tbl t1", true, + parser -> parser.withTimeOut(60000)); } @Test @@ -50,7 +52,7 @@ public void testIssue766_2() throws JSQLParserException { public void testIssue235() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( "SELECT CASE WHEN ( CASE WHEN ( CASE WHEN ( CASE WHEN ( 1 ) THEN 0 END ) THEN 0 END ) THEN 0 END ) THEN 0 END FROM a", - true); + true, parser -> parser.withTimeOut(60000)); } @Test @@ -71,7 +73,7 @@ public void testNestedCaseWhenWithoutBracketsIssue1162() throws JSQLParserExcept + "WHEN WDGFLD.PORTTYPE = 1 THEN 'INPUT PORT'\n" + "ELSE CASE\n" + "WHEN WDGFLD.PORTTYPE = 1 THEN 'INPUT PORT'\n" + "ELSE CASE WHEN WDGFLD.PORTTYPE = 1 THEN 'INPUT PORT' ELSE '0' END END END END END END END END END END END END END END COLUMNALIAS\n" - + "FROM TABLE1", true); + + "FROM TABLE1", true, parser -> parser.withTimeOut(60000)); } @Test @@ -92,26 +94,31 @@ public void testNestedCaseWhenWithBracketsIssue1162() throws JSQLParserException + "WHEN WDGFLD.PORTTYPE = 1 THEN 'INPUT PORT'\n" + "ELSE (CASE\n" + "WHEN WDGFLD.PORTTYPE = 1 THEN 'INPUT PORT'\n" + "ELSE (CASE WHEN WDGFLD.PORTTYPE = 1 THEN 'INPUT PORT' ELSE '0' END) END) END) END) END) END) END) END) END) END) END) END) END) END COLUMNALIAS\n" - + "FROM TABLE1", true); + + "FROM TABLE1", true, parser -> parser.withTimeOut(60000)); } @Test - @Timeout(2000) - @Disabled + @Timeout(10000) public void testIssue496() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "select isNull(charLen(TEST_ID,0)+ isNull(charLen(TEST_DVC,0)+ isNull(charLen(TEST_NO,0)+ isNull(charLen(ATEST_ID,0)+ isNull(charLen(TESTNO,0)+ isNull(charLen(TEST_CTNT,0)+ isNull(charLen(TEST_MESG_CTNT,0)+ isNull(charLen(TEST_DTM,0)+ isNull(charLen(TEST_DTT,0)+ isNull(charLen(TEST_ADTT,0)+ isNull(charLen(TEST_TCD,0)+ isNull(charLen(TEST_PD,0)+ isNull(charLen(TEST_VAL,0)+ isNull(charLen(TEST_YN,0)+ isNull(charLen(TEST_DTACM,0)+ isNull(charLen(TEST_MST,0) from test_info_m", - true); + Assertions.assertThrowsExactly(JSQLParserException.class, new Executable() { + @Override + public void execute() throws Throwable { + assertSqlCanBeParsedAndDeparsed( + "select isNull(charLen(TEST_ID,0)+ isNull(charLen(TEST_DVC,0)+ isNull(charLen(TEST_NO,0)+ isNull(charLen(ATEST_ID,0)+ isNull(charLen(TESTNO,0)+ isNull(charLen(TEST_CTNT,0)+ isNull(charLen(TEST_MESG_CTNT,0)+ isNull(charLen(TEST_DTM,0)+ isNull(charLen(TEST_DTT,0)+ isNull(charLen(TEST_ADTT,0)+ isNull(charLen(TEST_TCD,0)+ isNull(charLen(TEST_PD,0)+ isNull(charLen(TEST_VAL,0)+ isNull(charLen(TEST_YN,0)+ isNull(charLen(TEST_DTACM,0)+ isNull(charLen(TEST_MST,0) from test_info_m", + true, parser -> parser.withTimeOut(6000)); + } + }); + } @Test - // @Todo Investigate performance deterioration since JSQLParser 5.0pre development + @Timeout(2000) public void testIssue856() throws JSQLParserException { String sql = "SELECT " + buildRecursiveBracketExpression( - "if(month(today()) = 3, sum(\"Table5\".\"Month 002\"), $1)", "0", 3) + "if(month(today()) = 3, sum(\"Table5\".\"Month 002\"), $1)", "0", 10) + " FROM mytbl"; - assertSqlCanBeParsedAndDeparsed(sql); + assertSqlCanBeParsedAndDeparsed(sql, true, parser -> parser.withTimeOut(60000)); } @Test @@ -127,37 +134,61 @@ public void testRecursiveBracketExpressionIssue1019() { // maxDepth = 10 collides with the Parser Timeout = 6 seconds // @todo: implement methods to set the Parser Timeout explicitly and on demand @Test + @Timeout(2000) public void testRecursiveBracketExpressionIssue1019_2() throws JSQLParserException { - doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 8); + doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 20); + } + + @Test void testIssue2422() throws JSQLParserException { + String sqlStr = + "SELECT\n" + + "\t\t\t\t ((((position('-' IN (\n" + + "\t\t\t\t CASE WHEN ((\n" + + "\t\t\t\t CASE WHEN (5 < 0) THEN\n" + + "\t\t\t\t 'yes'\n" + + "\t\t\t\t ELSE\n" + + "\t\t\t\t 'no'\n" + + "\t\t\t\t END) = 'yes') THEN\n" + + "\t\t\t\t SUBSTRING('2012-january-18', (((LENGTH('2012-january-18')) + (5)) + (1)), ABS((0) - (5)))\n" + + "\t\t\t\t ELSE\n" + + "\t\t\t\t SUBSTRING('2012-january-18', ((5) + (1)))\n" + + "\t\t\t\t END)) - 1) + (1)) - (5)) + (0))\n" + + "\t\t\t\tFROM\n" + + "\t\t\t\t testtable"; + assertSqlCanBeParsedAndDeparsed(sqlStr); } @Test @Timeout(2000) public void testIssue1013() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("SELECT ((((((((((((((((tblA)))))))))))))))) FROM mytable"); + assertSqlCanBeParsedAndDeparsed("SELECT ((((((((((((((((tblA)))))))))))))))) FROM mytable", + true, parser -> parser.withTimeOut(60000)); } @Test @Timeout(2000) public void testIssue1013_2() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("SELECT * FROM ((((((((((((((((tblA))))))))))))))))"); + assertSqlCanBeParsedAndDeparsed("SELECT * FROM ((((((((((((((((tblA))))))))))))))))", true, + parser -> parser.withTimeOut(60000)); } @Test + @Timeout(2000) public void testIssue1013_3() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("SELECT * FROM (((tblA)))"); + assertSqlCanBeParsedAndDeparsed("SELECT * FROM (((tblA)))", true, + parser -> parser.withTimeOut(60000)); } @Test @Timeout(2000) public void testIssue1013_4() throws JSQLParserException { - String s = "tblA"; + StringBuilder s = new StringBuilder("tblA"); for (int i = 1; i < 100; i++) { - s = "(" + s + ")"; + s = new StringBuilder("(" + s + ")"); } String sql = "SELECT * FROM " + s; LOG.info("testing " + sql); - assertSqlCanBeParsedAndDeparsed(sql); + assertSqlCanBeParsedAndDeparsed(sql, true, parser -> parser.withTimeOut(60000)); } /** @@ -165,7 +196,8 @@ public void testIssue1013_4() throws JSQLParserException { * * @throws JSQLParserException */ - // @Test(timeout = 6000) + @Test + @Timeout(2000) public void testIncreaseOfParseTime() throws JSQLParserException { doIncreaseOfParseTimeTesting("concat($1,'B')", "'A'", 50); } @@ -178,7 +210,7 @@ private void doIncreaseOfParseTimeTesting(String template, String finalExpressio String sql = "SELECT " + buildRecursiveBracketExpression(template, finalExpression, i) + " FROM mytbl"; long startTime = System.currentTimeMillis(); - assertSqlCanBeParsedAndDeparsed(sql, true); + assertSqlCanBeParsedAndDeparsed(sql, true, parser -> parser.withTimeOut(12000)); long durationTime = System.currentTimeMillis() - startTime; if (i > 0) { @@ -197,6 +229,7 @@ private void doIncreaseOfParseTimeTesting(String template, String finalExpressio } @Test + @Timeout(2000) public void testRecursiveBracketExpression() { assertEquals("concat('A','B')", buildRecursiveBracketExpression("concat($1,'B')", "'A'", 0)); @@ -225,10 +258,11 @@ public void testIssue1103() throws JSQLParserException { + "ROUND(ROUND(ROUND(ROUND(ROUND(ROUND(ROUND(ROUND(0\n" + ",0),0),0),0),0),0),0),0)\n" + ",0),0),0),0),0),0),0),0)\n" + ",0),0),0),0),0),0),0),0)\n" + ",0),0),0),0),0),0),0),0)", - true); + true, parser -> parser.withTimeOut(60000)); } @Test + @Timeout(2000) public void testDeepFunctionParameters() throws JSQLParserException { String sqlStr = "SELECT a.*\n" + " , To_Char( a.eingangsdat, 'MM.YY' ) AS eingmonat\n" @@ -352,11 +386,10 @@ public void testDeepFunctionParameters() throws JSQLParserException { + " FROM beschfehler\n" + " WHERE beschfehler_id = a.beschwkat_id ), 0 ) > 0\n"; - assertSqlCanBeParsedAndDeparsed(sqlStr, true); + assertSqlCanBeParsedAndDeparsed(sqlStr, true, parser -> parser.withTimeOut(60000)); } @Test - @Disabled void testIssue1983() throws JSQLParserException { String sqlStr = "INSERT INTO\n" + "C01_INDIV_TELBK_CUST_INFO_H_T2 (PARTY_ID, PARTY_SIGN_STAT_CD, SIGN_TM, CLOSE_TM)\n" @@ -513,9 +546,759 @@ void testIssue1983() throws JSQLParserException { "2,\n" + "3,\n" + "4"; - CCJSqlParserUtil.parse(sqlStr, parser -> parser - .withSquareBracketQuotation(false) - .withAllowComplexParsing(true) - .withTimeOut(60000)); + Assertions.assertThrows( + JSQLParserException.class, new Executable() { + @Override + public void execute() throws Throwable { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + } + ); + } + + @Test + // see https://github.com/javacc/javacc/issues/296 + void testIssue2140() throws JSQLParserException { + String sqlStr = "SELECT (((IIF((CASE WHEN 1 = 2 THEN 'a' ELSE 'b') = 'b'), 2, 3)))"; + Assertions.assertThrows( + JSQLParserException.class, new Executable() { + @Override + public void execute() throws Throwable { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + } + ); + } + + @Test + void testIssue2401Performance() throws JSQLParserException { + String sqlStr = + "SELECT \"тип\" AS \"тип\"\n" + + " , Sum( ( CASE\n" + + " WHEN 'Портфель заказов' = 'Портфель заказов'\n" + + " THEN CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"тип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND \"Тип документа\" <> 'Проект (<70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR \"Новый продукт\" = 'Да'\n" + + " AND ( \"Организация Росатом\" <> 'Да'\n" + + " OR ( 'Консолидированно' <> 'Консолидированно'\n" + + " AND \"ВГО РОСАТОМ\" = '+' ) ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND ( 'Консолидированно' <> 'Консолидированно'\n" + + " OR \"ВГО РОСАТОМ\" <> '+' )\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) BETWEEN 2025 + 1\n" + + " AND 2025 + 10\n" + + " THEN CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) - ( CASE\n" + + " WHEN \"Перенос\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Перенос\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " ELSE ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " END / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END\n" + + " ELSE CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"тип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND \"Тип документа\" <> 'Проект (<70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR \"Новый продукт\" = 'Да'\n" + + " AND ( \"Организация Росатом\" <> 'Да'\n" + + " OR ( 'Консолидированно' <> 'Консолидированно'\n" + + " AND \"ВГО РОСАТОМ\" = '+' ) ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND ( 'Консолидированно' <> 'Консолидированно'\n" + + " OR \"ВГО РОСАТОМ\" <> '+' )\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) = 2025\n" + + " THEN CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN ( CASE\n" + + " WHEN \"Факт USD\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Факт USD\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) + ( CASE\n" + + " WHEN \"Прогноз1 USD\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз1 USD\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " ELSE ( CASE\n" + + " WHEN \"Факт RUB\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Факт RUB\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) + ( CASE\n" + + " WHEN \"Прогноз1 RUB\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз1 RUB\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " END / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END + ( CASE\n" + + " WHEN \"Прогноз2 валюта договора\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз2 валюта договора\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END + CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"тип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) = 2025\n" + + " AND \"Тип документа\" = 'Проект (>=70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR ( \"Новый продукт\" = 'Да'\n" + + " AND \"Организация Росатом\" <> 'Да' ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND \"ВГО РОСАТОМ\" <> '+'\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) = 2025\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END\n" + + " END ) - ( ( CASE\n" + + " WHEN CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN ( \"тип\" = 'БП'\n" + + " OR \"тип\" = 'БПКПРАО' )\n" + + " ELSE \"тип\" = 'БП'\n" + + " END\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN \"Новый продукт\" = 'Да'\n" + + " AND CASE\n" + + " WHEN 'Консолидированно' = 'Консолидированно'\n" + + " THEN \"Организация Росатом\" <> 'Да'\n" + + " ELSE \"Организация Росатом\" <> 'Да'\n" + + " OR ( \"Организация Росатом\" = 'Да'\n" + + " AND \"ВГО РОСАТОМ\" = '+' )\n" + + " END\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Страна покупателя\" <> 'РОССИЯ'\n" + + " ELSE true\n" + + " END\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND CASE\n" + + " WHEN 'Консолидированно' = 'Консолидированно'\n" + + " THEN \"ВГО РОСАТОМ\" <> '+'\n" + + " ELSE true\n" + + " END\n" + + " AND \"Предприятие\" = CASE\n" + + " WHEN 'Дивизион' = 'Дивизион'\n" + + " THEN \"Предприятие\"\n" + + " ELSE 'Дивизион'\n" + + " END\n" + + " AND CASE\n" + + " WHEN 'Портфель заказов' = 'Портфель заказов'\n" + + " THEN Cast( \"Год\" AS INTEGER ) > 2025\n" + + " AND Cast( \"Год\" AS INTEGER ) < ( 2025 + 11 )\n" + + " ELSE Cast( \"Год\" AS INTEGER ) = 2025\n" + + " END\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Дол\"\n" + + " ELSE \"Дол\" / Nullif( \"Руб\", 0 )\n" + + " END\n" + + " ELSE 0\n" + + " END ) / ( CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END ) ) ) AS \"Лист 6.1 Прогноз - БП\"\n" + + " , NULL AS \"coloring_0\"\n" + + " , CASE\n" + + " WHEN ( Sum( ( ( CASE\n" + + " WHEN 'Портфель заказов' = 'Портфель заказов'\n" + + " THEN CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"тип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND \"Тип документа\" <> 'Проект (<70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR \"Новый продукт\" = 'Да'\n" + + " AND ( \"Организация Росатом\" <> 'Да'\n" + + " OR ( 'Консолидированно' <> 'Консолидированно'\n" + + " AND \"ВГО РОСАТОМ\" = '+' ) ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND ( 'Консолидированно' <> 'Консолидированно'\n" + + " OR \"ВГО РОСАТОМ\" <> '+' )\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) BETWEEN 2025 + 1\n" + + " AND 2025 + 10\n" + + " THEN CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) - ( CASE\n" + + " WHEN \"Перенос\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Перенос\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " ELSE ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " END / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END\n" + + " ELSE CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"тип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND \"Тип документа\" <> 'Проект (<70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR \"Новый продукт\" = 'Да'\n" + + " AND ( \"Организация Росатом\" <> 'Да'\n" + + " OR ( 'Консолидированно' <> 'Консолидированно'\n" + + " AND \"ВГО РОСАТОМ\" = '+' ) ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND ( 'Консолидированно' <> 'Консолидированно'\n" + + " OR \"ВГО РОСАТОМ\" <> '+' )\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) = 2025\n" + + " THEN CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN ( CASE\n" + + " WHEN \"Факт USD\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Факт USD\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) + ( CASE\n" + + " WHEN \"Прогноз1 USD\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз1 USD\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " ELSE ( CASE\n" + + " WHEN \"Факт RUB\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Факт RUB\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) + ( CASE\n" + + " WHEN \"Прогноз1 RUB\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз1 RUB\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " END / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END + ( CASE\n" + + " WHEN \"Прогноз2 валюта договора\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз2 валюта договора\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END + CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"тип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) = 2025\n" + + " AND \"Тип документа\" = 'Проект (>=70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR ( \"Новый продукт\" = 'Да'\n" + + " AND \"Организация Росатом\" <> 'Да' ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND \"ВГО РОСАТОМ\" <> '+'\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) = 2025\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END\n" + + " END ) - ( ( CASE\n" + + " WHEN CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN ( \"тип\" = 'БП'\n" + + " OR \"тип\" = 'БПКПРАО' )\n" + + " ELSE \"тип\" = 'БП'\n" + + " END\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN \"Новый продукт\" = 'Да'\n" + + " AND CASE\n" + + " WHEN 'Консолидированно' = 'Консолидированно'\n" + + " THEN \"Организация Росатом\" <> 'Да'\n" + + " ELSE \"Организация Росатом\" <> 'Да'\n" + + " OR ( \"Организация Росатом\" = 'Да'\n" + + " AND \"ВГО РОСАТОМ\" = '+' )\n" + + " END\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Страна покупателя\" <> 'РОССИЯ'\n" + + " ELSE true\n" + + " END\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND CASE\n" + + " WHEN 'Консолидированно' = 'Консолидированно'\n" + + " THEN \"ВГО РОСАТОМ\" <> '+'\n" + + " ELSE true\n" + + " END\n" + + " AND \"Предприятие\" = CASE\n" + + " WHEN 'Дивизион' = 'Дивизион'\n" + + " THEN \"Предприятие\"\n" + + " ELSE 'Дивизион'\n" + + " END\n" + + " AND CASE\n" + + " WHEN 'Портфель заказов' = 'Портфель заказов'\n" + + " THEN Cast( \"Год\" AS INTEGER ) > 2025\n" + + " AND Cast( \"Год\" AS INTEGER ) < ( 2025 + 11 )\n" + + " ELSE Cast( \"Год\" AS INTEGER ) = 2025\n" + + " END\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Дол\"\n" + + " ELSE \"Дол\" / Nullif( \"Руб\", 0 )\n" + + " END\n" + + " ELSE 0\n" + + " END ) / ( CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END ) ) ) ) >= 0 )\n" + + " THEN '{\"color\":\"#273D79FF\",\"backgroundColor\":\"#87D9F9FF\",\"iconId\":null,\"onlyIcon\":false,\"barProps\":null}'\n" + + " WHEN ( Sum( ( ( CASE\n" + + " WHEN 'Портфель заказов' = 'Портфель заказов'\n" + + " THEN CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"тип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND \"Тип документа\" <> 'Проект (<70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR \"Новый продукт\" = 'Да'\n" + + " AND ( \"Организация Росатом\" <> 'Да'\n" + + " OR ( 'Консолидированно' <> 'Консолидированно'\n" + + " AND \"ВГО РОСАТОМ\" = '+' ) ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND ( 'Консолидированно' <> 'Консолидированно'\n" + + " OR \"ВГО РОСАТОМ\" <> '+' )\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) BETWEEN 2025 + 1\n" + + " AND 2025 + 10\n" + + " THEN CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) - ( CASE\n" + + " WHEN \"Перенос\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Перенос\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " ELSE ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " END / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END\n" + + " ELSE CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"�2026-03-07T14:44:27\".\"373903777Z �ип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND \"Тип документа\" <> 'Проект (<70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR \"Новый продукт\" = 'Да'\n" + + " AND ( \"Организация Росатом\" <> 'Да'\n" + + " OR ( 'Консолидированно' <> 'Консолидированно'\n" + + " AND \"ВГО РОСАТОМ\" = '+' ) ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND ( 'Консолидированно' <> 'Консолидированно'\n" + + " OR \"ВГО РОСАТОМ\" <> '+' )\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) = 2025\n" + + " THEN CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN ( CASE\n" + + " WHEN \"Факт USD\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Факт USD\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) + ( CASE\n" + + " WHEN \"Прогноз1 USD\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз1 USD\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " ELSE ( CASE\n" + + " WHEN \"Факт RUB\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Факт RUB\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) + ( CASE\n" + + " WHEN \"Прогноз1 RUB\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз1 RUB\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END )\n" + + " END / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END + ( CASE\n" + + " WHEN \"Прогноз2 валюта договора\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Прогноз2 валюта договора\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END + CASE\n" + + " WHEN \"Открытый заказ\" = 'Да'\n" + + " AND ( \"тип\" = 'Прогноз'\n" + + " OR ( 'Весь объем' = 'НП'\n" + + " AND \"тип\" = 'КПРАО' ) )\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) = 2025\n" + + " AND \"Тип документа\" = 'Проект (>=70)'\n" + + " AND ( 'Весь объем' <> 'НП'\n" + + " OR ( \"Новый продукт\" = 'Да'\n" + + " AND \"Организация Росатом\" <> 'Да' ) )\n" + + " AND ( 'Весь объем' <> 'Зарубеж'\n" + + " OR \"Страна покупателя\" <> 'РОССИЯ' )\n" + + " AND \"ВГО РОСАТОМ\" <> '+'\n" + + " AND ( 'Дивизион' = 'Дивизион'\n" + + " OR \"Предприятие\" = 'Дивизион' )\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND Cast( \"Год\" AS INTEGER ) = 2025\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Дол\"\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Курс_дол\"\n" + + " ELSE 1\n" + + " END / Nullif( CASE\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " AND 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " WHEN 'Сценарный' = 'Сценарный'\n" + + " THEN \"Руб\"\n" + + " ELSE \"Курс\"\n" + + " END, 0 ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END\n" + + " ELSE 0\n" + + " END\n" + + " END ) - ( ( CASE\n" + + " WHEN CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN ( \"тип\" = 'БП'\n" + + " OR \"тип\" = 'БПКПРАО' )\n" + + " ELSE \"тип\" = 'БП'\n" + + " END\n" + + " AND EXTRACT( YEAR FROM \"Дата договора\" ) <= 2025\n" + + " AND CASE\n" + + " WHEN 'Весь объем' = 'НП'\n" + + " THEN \"Новый продукт\" = 'Да'\n" + + " AND CASE\n" + + " WHEN 'Консолидированно' = 'Консолидированно'\n" + + " THEN \"Организация Росатом\" <> 'Да'\n" + + " ELSE \"Организация Росатом\" <> 'Да'\n" + + " OR ( \"Организация Росатом\" = 'Да'\n" + + " AND \"ВГО РОСАТОМ\" = '+' )\n" + + " END\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Страна покупателя\" <> 'РОССИЯ'\n" + + " ELSE true\n" + + " END\n" + + " AND \"Предприятие\" <> 'ТТ ААЭМ'\n" + + " AND CASE\n" + + " WHEN 'Консолидированно' = 'Консолидированно'\n" + + " THEN \"ВГО РОСАТОМ\" <> '+'\n" + + " ELSE true\n" + + " END\n" + + " AND \"Предприятие\" = CASE\n" + + " WHEN 'Дивизион' = 'Дивизион'\n" + + " THEN \"Предприятие\"\n" + + " ELSE 'Дивизион'\n" + + " END\n" + + " AND CASE\n" + + " WHEN 'Портфель заказов' = 'Портфель заказов'\n" + + " THEN Cast( \"Год\" AS INTEGER ) > 2025\n" + + " AND Cast( \"Год\" AS INTEGER ) < ( 2025 + 11 )\n" + + " ELSE Cast( \"Год\" AS INTEGER ) = 2025\n" + + " END\n" + + " THEN ( CASE\n" + + " WHEN \"Выручка\" = '-'\n" + + " THEN 0\n" + + " ELSE Cast( Replace( \"Выручка\", ',', '.' ) AS DECIMAL (18, 4) )\n" + + " END ) / CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN \"Дол\"\n" + + " ELSE \"Дол\" / Nullif( \"Руб\", 0 )\n" + + " END\n" + + " ELSE 0\n" + + " END ) / ( CASE\n" + + " WHEN 'Весь объем' = 'Зарубеж'\n" + + " THEN 1\n" + + " ELSE 1000\n" + + " END ) ) ) ) <= 0 )\n" + + " THEN '{\"color\":\"#DC1C0CFF\",\"backgroundColor\":\"#EAD0D0FF\",\"iconId\":null,\"onlyIcon\":false,\"barProps\":null}'\n" + + " ELSE NULL\n" + + " END AS \"coloring_1\"\n" + + "FROM ( SELECT \"тип\"\n" + + " , \"Тип документа\"\n" + + " , \"Унифицированный код\"\n" + + " , \"Предприятие\"\n" + + " , \"Бизнес направление\"\n" + + " , \"Новый продукт\"\n" + + " , \"Объект (станция)\"\n" + + " , \"Блок объекта\"\n" + + " , \"Наименование покупателя\"\n" + + " , \"Страна покупателя\"\n" + + " , \"Организация Росатом\"\n" + + " , \"Ключевой заказ\"\n" + + " , \"Вероят получ заказа\" AS \"Вероят получения заказ\"\n" + + " , \"Номер договора\"\n" + + " , \"Предмет договора\"\n" + + " , \"Валюта договора\" AS \"Валюта\"\n" + + " , \"Дата договора\"\n" + + " , \"ВГО РОСАТОМ\"\n" + + " , \"ВГО АЭМ\"\n" + + " , \"Категория продукции\"\n" + + " , \"Вид продукции\"\n" + + " , \"Дата посл изм док\" AS \"Дата послед измен док\"\n" + + " , \"Дата создания документа\"\n" + + " , \"Открытый заказ\"\n" + + " , \"Статус работы\"\n" + + " , \"Статус\"\n" + + " , \"Причина завершения\"\n" + + " , \"Общ стоим дог тыс ед\"\n" + + " , \"Факт валюта договора\"\n" + + " , \"Факт RUB\"\n" + + " , \"Факт USD\"\n" + + " , \"Прогноз1 валюта договора\"\n" + + " , \"Прогноз1 RUB\"\n" + + " , \"Прогноз1 USD\"\n" + + " , \"Прогноз2 валюта договора\"\n" + + " , \"Прогноз2 RUB\"\n" + + " , \"Прогноз2 USD\"\n" + + " , \"Год\"\n" + + " , \"Выручка\"\n" + + " , \"Вероят испол выручки\" AS \"Вероят исполн выручки\"\n" + + " , \"Риски\"\n" + + " , \"Комментарий\"\n" + + " , \"Перенос\"\n" + + " , \"СценарныеУсловия\"\n" + + " , \"Дол\"\n" + + " , \"Руб\"\n" + + " , \"Курс\"\n" + + " , \"Курс_дол\"\n" + + " , \"БП по БК2\"\n" + + " , \"ЦУ КПЭ\"\n" + + " , \"НУ КПЭ\"\n" + + " , \"ЦУ выручка\"\n" + + " FROM \"bi_data\".\"v_massive_su\" ) v13ca28644a0f4af9869465def634f52a\n" + + "GROUP BY \"тип\"\n" + + "LIMIT 100\n" + + ";"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/NestedCommentTest.java b/src/test/java/net/sf/jsqlparser/statement/select/NestedCommentTest.java new file mode 100644 index 000000000..a470257d2 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/NestedCommentTest.java @@ -0,0 +1,105 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class NestedCommentTest { + + private void assertParses(String sql) { + assertDoesNotThrow(() -> CCJSqlParserUtil.parse(sql), + "Failed to parse: " + sql); + } + + @Test + void testFlatBlockComment() { + assertParses("SELECT /* simple comment */ 1"); + } + + @Test + void testNestedBlockComment() { + assertParses("SELECT /* outer /* inner */ outer */ 1"); + } + + @Test + void testDeeplyNestedBlockComment() { + assertParses( + "SELECT /* level 0 /* level 1 /* level 2 */ back to 1 */ back to 0 */ 1"); + } + + @Test + void testNestedCommentInWhereClause() { + assertParses( + "SELECT * FROM t WHERE /* a /* nested */ comment */ x = 1"); + } + + @Test + void testNestedCommentContainingStars() { + assertParses("SELECT /* ** /* * */ ** */ 1"); + } + + @Test + void testNestedCommentContainingSlashes() { + assertParses("SELECT /* // /* -- */ // */ 1"); + } + + @Test + void testMultipleNestedCommentsInSequence() { + assertParses("SELECT /* /* a */ */ 1, /* /* b */ */ 2"); + } + + @Test + @Disabled + void testNestedCommentWithSQL() { + // Common use case: commenting out code that already contains comments + assertParses( + "SELECT * FROM t WHERE 1 = 1\n" + + "/* commented out:\n" + + " AND x = /* default */ 42\n" + + " AND y = 0\n" + + "*/"); + } + + @Test + void testEmptyNestedComment() { + assertParses("SELECT /* /**/ */ 1"); + } + + @Test + void testLineCommentStillWorks() { + assertParses("SELECT 1 -- line comment"); + } + + @Test + void testLineCommentInsideBlockComment() { + assertParses("SELECT /* -- not a line comment */ 1"); + } + + @Test + void testMultilineNestedComment() { + assertParses( + "SELECT *\n" + + "/*\n" + + " /*\n" + + " nested across lines\n" + + " */\n" + + "*/\n" + + "FROM t"); + } + + @Test + void testOracleHintPreserved() { + assertParses("SELECT /*+ FULL(t) */ * FROM t"); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java b/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java new file mode 100644 index 000000000..a599d85f4 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/OrderByCollateTest.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; + +import net.sf.jsqlparser.JSQLParserException; +import org.junit.jupiter.api.Test; + +public class OrderByCollateTest { + + @Test + public void testOrderByWithCollate() throws JSQLParserException { + String sql = "SELECT * FROM a ORDER BY CAST(a.xyz AS TEXT) COLLATE \"und-x-icu\" ASC NULLS FIRST"; + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testOrderByWithCollateSimple() throws JSQLParserException { + String sql = "SELECT * FROM a ORDER BY col COLLATE \"C\" ASC"; + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testOrderByWithCollateMultiple() throws JSQLParserException { + String sql = "SELECT * FROM a ORDER BY col1 COLLATE \"C\" ASC, col2 COLLATE \"POSIX\" DESC"; + assertSqlCanBeParsedAndDeparsed(sql); + } + + @Test + public void testOrderByWithCollateAndNulls() throws JSQLParserException { + String sql = "SELECT * FROM a ORDER BY col COLLATE \"C\" DESC NULLS LAST"; + assertSqlCanBeParsedAndDeparsed(sql); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java b/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java index 56d36d854..9ded16786 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/PostgresTest.java @@ -10,13 +10,17 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.JsonExpression; +import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statements; import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.List; @@ -58,7 +62,7 @@ public void testJSonExpressionIssue1696() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); SelectItem selectExpressionItem = plainSelect.getSelectItems().get(0); - Assertions.assertEquals("'key'", + Assertions.assertEquals(new StringValue("key"), selectExpressionItem.getExpression(JsonExpression.class).getIdent(0).getKey()); } @@ -101,4 +105,37 @@ void testNextValueIssue1863() throws JSQLParserException { String sqlStr = "SELECT nextval('client_id_seq')"; assertSqlCanBeParsedAndDeparsed(sqlStr); } + + @Test + @Disabled + // wip + void testDollarQuotedText() throws JSQLParserException { + String sqlStr = "SELECT $tag$This\nis\na\nselect\ntest\n$tag$ from dual where a=b"; + PlainSelect st = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + + StringValue stringValue = st.getSelectItem(0).getExpression(StringValue.class); + + Assertions.assertEquals("This\nis\na\nselect\ntest\n", stringValue.getValue()); + } + + @Test + @Disabled + // wip + void testQuotedIdentifier() throws JSQLParserException { + String sqlStr = "SELECT \"This is a Test Column\" AS [Alias] from `This is a Test Table`"; + PlainSelect st = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + + Column column = st.getSelectItem(0).getExpression(Column.class); + Assertions.assertEquals("This is a Test Column", column.getUnquotedName()); + Assertions.assertEquals("\"This is a Test Column\"", column.getColumnName()); + + Alias alias = st.getSelectItem(0).getAlias(); + Assertions.assertEquals("Alias", alias.getUnquotedName()); + Assertions.assertEquals("[Alias]", alias.getName()); + + Table table = st.getFromItem(Table.class); + Assertions.assertEquals("This is a Test Table", table.getUnquotedName()); + Assertions.assertEquals("`This is a Test Table`", table.getName()); + + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java index cd8e41c95..ecb120495 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java @@ -16,7 +16,7 @@ public class SQLiteTest { @Test void testInsertOrReplaceUpsert() throws JSQLParserException { - String sqlString="INSERT OR REPLACE INTO kjobLocks VALUES (?, ?, ?)"; + String sqlString = "INSERT OR REPLACE INTO kjobLocks VALUES (?, ?, ?)"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlString, true); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SampleClauseTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SampleClauseTest.java index ea0cf4abf..759e4d0d1 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SampleClauseTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SampleClauseTest.java @@ -11,6 +11,7 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -37,8 +38,33 @@ void standardTestIssue1593(String sqlStr) throws JSQLParserException { "SELECT * from table_name SAMPLE BLOCK (99) SEED (10) ", "SELECT * from table_name SAMPLE BLOCK (99.1) SEED (10.1)" }) - void standardOracleIssue1826() throws JSQLParserException { - String sqlStr = "SELECT * from table_name SAMPLE(99)"; + void standardOracleIssue1826(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM events SAMPLE 0.1", + "SELECT * FROM events SAMPLE 10000", + "SELECT * FROM events SAMPLE 0.1 OFFSET 1000" + }) + void clickHouseSampleClause(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testDuckDB() throws JSQLParserException { + String sqlStr = "SELECT *\n" + + "FROM (SELECT * FROM addresses)\n" + + "USING SAMPLE SYSTEM (10 PERCENT);"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testBigQuery() throws JSQLParserException { + String sqlStr = "SELECT *\n" + + "FROM (SELECT * FROM addresses)\n" + + "TABLESAMPLE SYSTEM (10 PERCENT);"; TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java index 2888ed72c..8c2a36261 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java @@ -15,7 +15,7 @@ import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor; import net.sf.jsqlparser.parser.CCJSqlParserTreeConstants; import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import net.sf.jsqlparser.parser.SimpleNode; +import net.sf.jsqlparser.parser.Node; import net.sf.jsqlparser.parser.Token; import net.sf.jsqlparser.schema.Column; @@ -39,13 +39,13 @@ public void testSelectASTColumn() throws JSQLParserException { for (SelectItem item : plainSelect.getSelectItems()) { SelectItem sei = (SelectItem) item; Column c = sei.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().beginColumn - 1, '*'); } for (OrderByElement item : plainSelect.getOrderByElements()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().beginColumn - 1, '#'); } @@ -55,7 +55,7 @@ public void testSelectASTColumn() throws JSQLParserException { @Test public void testSelectASTNode() throws JSQLParserException { String sql = "SELECT a, b FROM mytable order by b, c"; - SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node node = (Node) CCJSqlParserUtil.parseAST(sql); node.dump("*"); assertEquals(CCJSqlParserTreeConstants.JJTSTATEMENT, node.getId()); } @@ -66,12 +66,12 @@ public void testSelectASTNode() throws JSQLParserException { // @Test // public void testSelectASTNodeSubSelect() throws JSQLParserException { // String sql = "SELECT * FROM mytable where 0<(select count(*) from mytable2)"; - // SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + // Node node = (Node) CCJSqlParserUtil.parseAST(sql); // node.dump("*"); // assertEquals(CCJSqlParserTreeConstants.JJTSTATEMENT, node.getId()); // node.jjtAccept(new CCJSqlParserDefaultVisitor() { // @Override - // public Object visit(SimpleNode node, Object data) { + // public Object visit(Node node, Object data) { // if (node.getId() == CCJSqlParserTreeConstants.JJTSUBSELECT) { // subSelectStart = node.jjtGetFirstToken(); // subSelectEnd = node.jjtGetLastToken(); @@ -95,13 +95,13 @@ public void testSelectASTColumnLF() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); for (SelectItem item : plainSelect.getSelectItems()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '*'); } for (OrderByElement item : plainSelect.getOrderByElements()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '#'); } @@ -116,13 +116,13 @@ public void testSelectASTCommentLF() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); for (SelectItem item : plainSelect.getSelectItems()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '*'); } for (OrderByElement item : plainSelect.getOrderByElements()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '#'); } @@ -139,13 +139,13 @@ public void testSelectASTCommentCRLF() throws JSQLParserException { PlainSelect plainSelect = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); for (SelectItem item : plainSelect.getSelectItems()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '*'); } for (OrderByElement item : plainSelect.getOrderByElements()) { Column c = item.getExpression(Column.class); - SimpleNode astNode = c.getASTNode(); + Node astNode = c.getASTNode(); assertNotNull(astNode); b.setCharAt(astNode.jjtGetFirstToken().absoluteBegin - 1, '#'); } @@ -157,12 +157,12 @@ public void testSelectASTCommentCRLF() throws JSQLParserException { @Test public void testDetectInExpressions() throws JSQLParserException { String sql = "SELECT * FROM mytable WHERE a IN (1,2,3,4,5,6,7)"; - SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node node = (Node) CCJSqlParserUtil.parseAST(sql); node.dump("*"); assertEquals(CCJSqlParserTreeConstants.JJTSTATEMENT, node.getId()); node.jjtAccept(new CCJSqlParserDefaultVisitor() { @Override - public Object visit(SimpleNode node, Object data) { + public Object visit(Node node, Object data) { if (node.getId() == CCJSqlParserTreeConstants.JJTINEXPRESSION) { subSelectStart = node.jjtGetFirstToken(); subSelectEnd = node.jjtGetLastToken(); @@ -175,7 +175,7 @@ public Object visit(SimpleNode node, Object data) { assertNotNull(subSelectStart); assertNotNull(subSelectEnd); - assertEquals(30, subSelectStart.beginColumn); + assertEquals(32, subSelectStart.beginColumn); assertEquals(49, subSelectEnd.endColumn); } @@ -183,12 +183,12 @@ public Object visit(SimpleNode node, Object data) { public void testSelectASTExtractWithCommentsIssue1580() throws JSQLParserException { String sql = "SELECT /* testcomment */ \r\n a, b FROM -- testcomment2 \r\n mytable \r\n order by b, c"; - SimpleNode root = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node root = (Node) CCJSqlParserUtil.parseAST(sql); List comments = new ArrayList<>(); root.jjtAccept(new CCJSqlParserDefaultVisitor() { @Override - public Object visit(SimpleNode node, Object data) { + public Object visit(Node node, Object data) { if (node.jjtGetFirstToken().specialToken != null) { // needed since for different nodes we got the same first token if (!comments.contains(node.jjtGetFirstToken().specialToken)) { @@ -199,7 +199,7 @@ public Object visit(SimpleNode node, Object data) { } }, null); - assertThat(comments).extracting(token -> token.image).containsExactly("/* testcomment */", + assertThat(comments).extracting(token -> token.image).containsExactly("/* testcomment */ ", "-- testcomment2 "); } @@ -207,9 +207,9 @@ public Object visit(SimpleNode node, Object data) { public void testSelectASTExtractWithCommentsIssue1580_2() throws JSQLParserException { String sql = "/* I want this comment */\n" + "SELECT order_detail_id, quantity\n" + "/* But ignore this one safely */\n" + "FROM order_details;"; - SimpleNode root = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node root = (Node) CCJSqlParserUtil.parseAST(sql); assertThat(root.jjtGetFirstToken().specialToken.image) - .isEqualTo("/* I want this comment */"); + .isEqualTo("/* I want this comment */\n"); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java index c7cbec8f3..e2233a885 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -55,10 +55,13 @@ import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.expression.operators.relational.EqualsTo; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.FullTextSearch; import net.sf.jsqlparser.expression.operators.relational.GreaterThan; import net.sf.jsqlparser.expression.operators.relational.InExpression; import net.sf.jsqlparser.expression.operators.relational.LikeExpression; -import net.sf.jsqlparser.parser.*; +import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; +import net.sf.jsqlparser.parser.CCJSqlParserManager; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Database; import net.sf.jsqlparser.schema.Server; @@ -66,6 +69,9 @@ import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitorAdapter; import net.sf.jsqlparser.statement.Statements; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.test.TestUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.SerializationUtils; @@ -1054,6 +1060,27 @@ public void testDistinct() throws JSQLParserException { .getExpression()).getColumnName()); } + @Test + public void testDistinctRow() throws JSQLParserException { + String statement = + "SELECT DISTINCTROW col1, col2 FROM mytable WHERE mytable.col = 9"; + Select select = (Select) TestUtils.assertSqlCanBeParsedAndDeparsed(statement, true); + + assertInstanceOf(PlainSelect.class, select); + + PlainSelect plainSelect = (PlainSelect) select; + Distinct distinct = plainSelect.getDistinct(); + + assertNotNull(distinct); + assertTrue(distinct.isUseDistinctRow()); + assertNull(distinct.getOnSelectItems()); + + assertEquals("col1", ((Column) (plainSelect.getSelectItems().get(0)) + .getExpression()).getColumnName()); + assertEquals("col2", ((Column) (plainSelect.getSelectItems().get(1)) + .getExpression()).getColumnName()); + } + @Test public void testIsDistinctFrom() throws JSQLParserException { String stmt = "SELECT name FROM tbl WHERE name IS DISTINCT FROM foo"; @@ -1184,6 +1211,12 @@ public void testJoin() throws JSQLParserException { assertEquals("b", plainSelect.getJoins().get(0).getFromItem().getAlias().getName()); } + @Test + public void testJoinFetch() throws JSQLParserException { + String statement = "SELECT c FROM Customer c LEFT JOIN FETCH c.orders o"; + assertSqlCanBeParsedAndDeparsed(statement, true); + } + @Test public void testFunctions() throws JSQLParserException { String statement = "SELECT MAX(id) AS max FROM mytable WHERE mytable.col = 9"; @@ -1701,13 +1734,29 @@ public void testWith() throws JSQLParserException { + "SELECT THIS_EMP.EMPNO, THIS_EMP.SALARY, DINFO.AVGSALARY, DINFO.EMPCOUNT, DINFOMAX.AVGMAX " + "FROM EMPLOYEE AS THIS_EMP INNER JOIN DINFO INNER JOIN DINFOMAX " + "WHERE THIS_EMP.JOB = 'SALESREP' AND THIS_EMP.WORKDEPT = DINFO.DEPTNO"; - assertSqlCanBeParsedAndDeparsed(statement); + Select select = (Select) assertSqlCanBeParsedAndDeparsed(statement); + List> withItems = select.getWithItemsList(); + assertEquals(2, withItems.size()); + assertEquals( + "SELECT OTHERS.WORKDEPT, AVG(OTHERS.SALARY), COUNT(*) FROM EMPLOYEE AS OTHERS GROUP BY OTHERS.WORKDEPT", + withItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals(" DINFO", withItems.get(0).getAlias().toString()); + assertEquals("SELECT MAX(AVGSALARY) AS AVGMAX FROM DINFO", + withItems.get(1).getSelect().getPlainSelect().toString()); + assertEquals(" DINFOMAX", withItems.get(1).getAlias().toString()); } @Test public void testWithRecursive() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "WITH RECURSIVE t (n) AS ((SELECT 1) UNION ALL (SELECT n + 1 FROM t WHERE n < 100)) SELECT sum(n) FROM t"); + String statement = + "WITH RECURSIVE t (n) AS ((SELECT 1) UNION ALL (SELECT n + 1 FROM t WHERE n < 100)) SELECT sum(n) FROM t"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(statement); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("((SELECT 1) UNION ALL (SELECT n + 1 FROM t WHERE n < 100))", + withItems.get(0).getSelect().toString()); + assertEquals(" t", withItems.get(0).getAlias().toString()); + assertTrue(withItems.get(0).isRecursive()); } @Test @@ -1756,10 +1805,14 @@ public void testCount3() throws JSQLParserException { @Test public void testMysqlQuote() throws JSQLParserException { - String statement = "SELECT `a.OWNERLASTNAME`, `OWNERFIRSTNAME` " + String sqlStr = "SELECT `a.OWNERLASTNAME`, `OWNERFIRSTNAME` " + "FROM `ANTIQUEOWNERS` AS a, ANTIQUES AS b " + "WHERE b.BUYERID = a.OWNERID AND b.ITEM = 'Chair'"; - assertSqlCanBeParsedAndDeparsed(statement); + + String expected = + "SELECT \"a\".\"OWNERLASTNAME\", `OWNERFIRSTNAME` FROM `ANTIQUEOWNERS` AS a, ANTIQUES AS b WHERE b.BUYERID = a.OWNERID AND b.ITEM = 'Chair'"; + + assertStatementCanBeDeparsedAs(CCJSqlParserUtil.parse(sqlStr), expected); } @Test @@ -2227,6 +2280,18 @@ public void testFullTextSearchInDefaultMode() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed(statement); } + @Test + public void testFullTextSearchAgainstFunctionInBooleanMode() throws JSQLParserException { + String statement = + "SELECT MATCH (name) AGAINST (concat('',?,'') IN BOOLEAN MODE) AS full_text FROM commodity"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(statement); + FullTextSearch fullTextSearch = assertInstanceOf(FullTextSearch.class, + select.getPlainSelect().getSelectItem(0).getExpression()); + + assertInstanceOf(Function.class, fullTextSearch.getAgainstValue()); + assertEquals("IN BOOLEAN MODE", fullTextSearch.getSearchModifier()); + } + @Test public void testIsTrue() throws JSQLParserException { String statement = "SELECT col FROM tbl WHERE col IS TRUE"; @@ -2251,6 +2316,18 @@ public void testIsNotFalse() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed(statement); } + @Test + public void testIsUnknown() throws JSQLParserException { + String statement = "SELECT col FROM tbl WHERE col IS UNKNOWN"; + assertSqlCanBeParsedAndDeparsed(statement); + } + + @Test + public void testIsNotUnknown() throws JSQLParserException { + String statement = "SELECT col FROM tbl WHERE col IS NOT UNKNOWN"; + assertSqlCanBeParsedAndDeparsed(statement); + } + @Test public void testTSQLJoin() throws JSQLParserException { String stmt = "SELECT * FROM tabelle1, tabelle2 WHERE tabelle1.a *= tabelle2.b"; @@ -2315,6 +2392,19 @@ public void testOracleJoinIssue318() throws JSQLParserException { "SELECT * FROM TBL_A, TBL_B, TBL_C WHERE TBL_A.ID(+) = TBL_B.ID AND TBL_C.ROOM(+) = TBL_B.ROOM"); } + @Test + public void testOracleJoinWithinNvlArgument() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "SELECT * FROM dual d, dual d2 WHERE d.dummy = nvl(d2.dummy (+), 'y')", true); + } + + @Test + public void testOracleJoinWithinCoalesceArgument() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "SELECT * FROM dual d, dual d2 WHERE d.dummy = coalesce(d2.dummy (+), 'y')", + true); + } + @Test public void testProblemSqlIntersect() throws Exception { String stmt = "(SELECT * FROM a) INTERSECT (SELECT * FROM b)"; @@ -2361,7 +2451,12 @@ public void testProblemSqlCombinedSets() throws Exception { public void testWithStatement() throws JSQLParserException { String stmt = "WITH test AS (SELECT mslink FROM feature) SELECT * FROM feature WHERE mslink IN (SELECT mslink FROM test)"; - assertSqlCanBeParsedAndDeparsed(stmt); + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("SELECT mslink FROM feature", + withItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals(" test", withItems.get(0).getAlias().toString()); } @Test @@ -2374,35 +2469,63 @@ public void testSubjoinWithJoins() throws JSQLParserException { public void testWithUnionProblem() throws JSQLParserException { String stmt = "WITH test AS ((SELECT mslink FROM tablea) UNION (SELECT mslink FROM tableb)) SELECT * FROM tablea WHERE mslink IN (SELECT mslink FROM test)"; - assertSqlCanBeParsedAndDeparsed(stmt); + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("((SELECT mslink FROM tablea) UNION (SELECT mslink FROM tableb))", + withItems.get(0).getSelect().toString()); + assertEquals(" test", withItems.get(0).getAlias().toString()); } @Test public void testWithUnionAllProblem() throws JSQLParserException { String stmt = "WITH test AS ((SELECT mslink FROM tablea) UNION ALL (SELECT mslink FROM tableb)) SELECT * FROM tablea WHERE mslink IN (SELECT mslink FROM test)"; - assertSqlCanBeParsedAndDeparsed(stmt); + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("((SELECT mslink FROM tablea) UNION ALL (SELECT mslink FROM tableb))", + withItems.get(0).getSelect().toString()); + assertEquals(" test", withItems.get(0).getAlias().toString()); } @Test public void testWithUnionProblem3() throws JSQLParserException { String stmt = "WITH test AS ((SELECT mslink, CAST(tablea.fname AS varchar) FROM tablea INNER JOIN tableb ON tablea.mslink = tableb.mslink AND tableb.deleted = 0 WHERE tablea.fname IS NULL AND 1 = 0) UNION ALL (SELECT mslink FROM tableb)) SELECT * FROM tablea WHERE mslink IN (SELECT mslink FROM test)"; - assertSqlCanBeParsedAndDeparsed(stmt); + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals( + "((SELECT mslink, CAST(tablea.fname AS varchar) FROM tablea INNER JOIN tableb ON tablea.mslink = tableb.mslink AND tableb.deleted = 0 WHERE tablea.fname IS NULL AND 1 = 0) UNION ALL (SELECT mslink FROM tableb))", + withItems.get(0).getSelect().toString()); + assertEquals(" test", withItems.get(0).getAlias().toString()); } @Test public void testWithUnionProblem4() throws JSQLParserException { String stmt = "WITH hist AS ((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0)) SELECT mslink, space(level * 4) + txt AS txt, nr, feature, path FROM hist WHERE EXISTS (SELECT feature FROM tablec WHERE mslink = 0 AND ((feature IN (1, 2) AND hist.feature = 3) OR (feature IN (4) AND hist.feature = 2)))"; - assertSqlCanBeParsedAndDeparsed(stmt); + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals( + "((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0))", + withItems.get(0).getSelect().toString()); + assertEquals(" hist", withItems.get(0).getAlias().toString()); } @Test public void testWithUnionProblem5() throws JSQLParserException { String stmt = "WITH hist AS ((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, 5 AS feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0)) SELECT * FROM hist"; - assertSqlCanBeParsedAndDeparsed(stmt); + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals( + "((SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, 0 AS level, CAST(gl.mslink AS VARCHAR) AS path, ae.feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 WHERE gl.parent IS NULL AND gl.mslink <> 0) UNION ALL (SELECT gl.mslink, ba.gl_name AS txt, ba.gl_nummer AS nr, hist.level + 1 AS level, CAST(hist.path + '.' + CAST(gl.mslink AS VARCHAR) AS VARCHAR) AS path, 5 AS feature FROM tablea AS gl INNER JOIN tableb AS ba ON gl.mslink = ba.gl_mslink INNER JOIN tablec AS ae ON gl.mslink = ae.mslink AND ae.deleted = 0 INNER JOIN hist ON gl.parent = hist.mslink WHERE gl.mslink <> 0))", + withItems.get(0).getSelect().toString()); + assertEquals(" hist", withItems.get(0).getAlias().toString()); } @Test @@ -2709,6 +2832,19 @@ public void testPivot5() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed(stmt); } + @Test + void testPivotWithOrderBy() throws JSQLParserException { + String sqlStr = "" + + "SELECT *\n" + + "FROM (\n" + + " SELECT 'kale' AS product, 51 AS sales, 'Q1' AS quarter\n" + + " )\n" + + "PIVOT(SUM(sales) FOR quarter IN ('Q1', 'Q2'))\n" + + "ORDER BY 1\n" + + ";"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + @Test public void testPivotXml1() throws JSQLParserException { String stmt = "SELECT * FROM mytable PIVOT XML (count(a) FOR b IN ('val1'))"; @@ -2844,6 +2980,12 @@ public void testRlike() throws JSQLParserException { "SELECT * FROM mytable WHERE first_name RLIKE '^Ste(v|ph)en$'"); } + @Test + public void testRegexpLike() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "SELECT * FROM mytable WHERE first_name REGEXP_LIKE '^Ste(v|ph)en$'"); + } + @Test public void testBooleanFunction1() throws JSQLParserException { String stmt = "SELECT * FROM mytable WHERE test_func(col1)"; @@ -2997,10 +3139,11 @@ public void testReservedKeyword2() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed(stmt); } + // PRIOR is a reserved keyword in Oracle @Test public void testReservedKeyword3() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( - "SELECT * FROM mytable1 t JOIN mytable2 AS prior ON t.id = prior.id"); + "SELECT * FROM mytable1 t JOIN mytable2 AS \"prior\" ON t.id = \"prior\".id"); } @Test @@ -3079,6 +3222,57 @@ public void testSelectInto1() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SELECT * INTO user_copy FROM user"); } + @Test + public void testMySqlSelectIntoOutfileBeforeFrom() throws JSQLParserException { + String stmt = "SELECT a, b INTO OUTFILE '/tmp/result.txt' " + + "FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' " + + "LINES TERMINATED BY '\\n' FROM test_table"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); + MySqlSelectIntoClause intoClause = select.getPlainSelect().getMySqlSelectIntoClause(); + assertNotNull(intoClause); + assertEquals(MySqlSelectIntoClause.Position.BEFORE_FROM, intoClause.getPosition()); + assertEquals(MySqlSelectIntoClause.Type.OUTFILE, intoClause.getType()); + assertEquals("'/tmp/result.txt'", intoClause.getFileName().toString()); + assertEquals("','", intoClause.getFieldsTerminatedBy().toString()); + assertTrue(intoClause.isFieldsOptionallyEnclosed()); + assertEquals("'\"'", intoClause.getFieldsEnclosedBy().toString()); + assertEquals("'\\n'", intoClause.getLinesTerminatedBy().toString()); + } + + @Test + public void testMySqlSelectIntoOutfileTrailing() throws JSQLParserException { + String stmt = "SELECT * FROM users INTO OUTFILE '/tmp/users.csv' " + + "FIELDS TERMINATED BY ',' ENCLOSED BY '\"' " + + "LINES TERMINATED BY '\\n'"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); + MySqlSelectIntoClause intoClause = select.getPlainSelect().getMySqlSelectIntoClause(); + assertNotNull(intoClause); + assertEquals(MySqlSelectIntoClause.Position.TRAILING, intoClause.getPosition()); + assertEquals(MySqlSelectIntoClause.Type.OUTFILE, intoClause.getType()); + assertEquals("'/tmp/users.csv'", intoClause.getFileName().toString()); + assertEquals("'\"'", intoClause.getFieldsEnclosedBy().toString()); + assertEquals("'\\n'", intoClause.getLinesTerminatedBy().toString()); + } + + @Test + public void testMySqlSelectIntoDumpfileTrailing() throws JSQLParserException { + String stmt = "SELECT id FROM users INTO DUMPFILE '/tmp/users.dump'"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); + MySqlSelectIntoClause intoClause = select.getPlainSelect().getMySqlSelectIntoClause(); + assertNotNull(intoClause); + assertEquals(MySqlSelectIntoClause.Position.TRAILING, intoClause.getPosition()); + assertEquals(MySqlSelectIntoClause.Type.DUMPFILE, intoClause.getType()); + assertEquals("'/tmp/users.dump'", intoClause.getFileName().toString()); + } + + @Test + public void testMySqlSelectIntoOutfileRejectsFieldsAfterLines() { + String stmt = "SELECT * FROM users INTO OUTFILE '/tmp/users.csv' " + + "LINES TERMINATED BY '\\n' FIELDS TERMINATED BY ','"; + Assertions.assertThrows(JSQLParserException.class, + () -> CCJSqlParserUtil.parse(stmt)); + } + @Test public void testSelectForUpdate() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SELECT * FROM user_table FOR UPDATE"); @@ -3128,9 +3322,24 @@ public void testSelectOracleColl() throws JSQLParserException { } @Test - public void testSelectInnerWith() throws JSQLParserException { + public void testSelectWithMaterializedWith() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( - "SELECT * FROM (WITH actor AS (SELECT 'a' aid FROM DUAL) SELECT aid FROM actor)"); + "WITH tokens_with_supply AS MATERIALIZED (SELECT * FROM tokens) SELECT * FROM tokens_with_supply"); + } + + @Test + public void testSelectInnerWith() throws JSQLParserException { + String stmt = + "SELECT * FROM (WITH actor AS (SELECT 'a' aid FROM DUAL) SELECT aid FROM actor)"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems1 = select.getWithItemsList(); + assertNull(withItems1); + ParenthesedSelect parenthesedSelect = + (ParenthesedSelect) select.getPlainSelect().getFromItem(); + List> withItems2 = parenthesedSelect.getPlainSelect().getWithItemsList(); + assertEquals(1, withItems2.size()); + assertEquals("(SELECT 'a' aid FROM DUAL)", withItems2.get(0).getSelect().toString()); + assertEquals(" actor", withItems2.get(0).getAlias().toString()); } // @Test @@ -3138,10 +3347,16 @@ public void testSelectInnerWith() throws JSQLParserException { // assertSqlCanBeParsedAndDeparsed("WITH actor AS (SELECT 'b' aid FROM DUAL) SELECT aid FROM // actor UNION WITH actor2 AS (SELECT 'a' aid FROM DUAL) SELECT aid FROM actor2"); // } + @Test public void testSelectInnerWithAndUnionIssue1084_2() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "WITH actor AS (SELECT 'b' aid FROM DUAL) SELECT aid FROM actor UNION SELECT aid FROM actor2"); + String stmt = + "WITH actor AS (SELECT 'b' aid FROM DUAL) SELECT aid FROM actor UNION SELECT aid FROM actor2"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("(SELECT 'b' aid FROM DUAL)", withItems.get(0).getSelect().toString()); + assertEquals(" actor", withItems.get(0).getAlias().toString()); } @Test @@ -4372,21 +4587,22 @@ public void testDateArithmentic11() throws JSQLParserException { String sql = "select CURRENT_DATE + (dayofweek(MY_DUE_DATE) + 5) DAY FROM mytable"; assertSqlCanBeParsedAndDeparsed(sql, true); Select select = (Select) CCJSqlParserUtil.parse(sql); - final List list = new ArrayList<>(); - select.accept(new SelectVisitorAdapter() { + final List> list = new ArrayList<>(); + select.accept(new SelectVisitorAdapter() { @Override - public void visit(PlainSelect plainSelect) { + public Void visit(PlainSelect plainSelect, S parameters) { list.addAll(plainSelect.getSelectItems()); + return null; } - }); + }, null); assertEquals(1, list.size()); - assertTrue(list.get(0) instanceof SelectItem); - SelectItem item = list.get(0); - assertTrue(item.getExpression() instanceof Addition); + assertInstanceOf(SelectItem.class, list.get(0)); + SelectItem item = list.get(0); + assertInstanceOf(Addition.class, item.getExpression()); Addition add = (Addition) item.getExpression(); - assertTrue(add.getRightExpression() instanceof IntervalExpression); + assertInstanceOf(IntervalExpression.class, add.getRightExpression()); } @Test @@ -4401,18 +4617,19 @@ public void testDateArithmentic13() throws JSQLParserException { String sql = "SELECT INTERVAL 5 MONTH MONTH FROM mytable"; assertSqlCanBeParsedAndDeparsed(sql); Select select = (Select) CCJSqlParserUtil.parse(sql); - final List list = new ArrayList<>(); - select.accept(new SelectVisitorAdapter() { + final List> list = new ArrayList<>(); + select.accept(new SelectVisitorAdapter() { @Override - public void visit(PlainSelect plainSelect) { + public Void visit(PlainSelect plainSelect, S parameters) { list.addAll(plainSelect.getSelectItems()); + return null; } - }); + }, null); assertEquals(1, list.size()); - assertTrue(list.get(0) instanceof SelectItem); - SelectItem item = list.get(0); - assertTrue(item.getExpression() instanceof IntervalExpression); + assertInstanceOf(SelectItem.class, list.get(0)); + SelectItem item = list.get(0); + assertInstanceOf(IntervalExpression.class, item.getExpression()); IntervalExpression interval = (IntervalExpression) item.getExpression(); assertEquals("INTERVAL 5 MONTH", interval.toString()); assertEquals("MONTH", item.getAlias().getName()); @@ -4424,21 +4641,23 @@ public void testRawStringExpressionIssue656(String prefix) throws JSQLParserExce String sql = "select " + prefix + "'test' from foo"; Statement statement = CCJSqlParserUtil.parse(sql); assertNotNull(statement); - statement.accept(new StatementVisitorAdapter() { + statement.accept(new StatementVisitorAdapter() { @Override - public void visit(Select select) { - select.accept(new SelectVisitorAdapter() { + public Void visit(Select select, S context) { + select.accept(new SelectVisitorAdapter() { @Override - public void visit(PlainSelect plainSelect) { - SelectItem typedExpression = - (SelectItem) plainSelect.getSelectItems().get(0); + public Void visit(PlainSelect plainSelect, K context) { + SelectItem typedExpression = + (SelectItem) plainSelect.getSelectItems().get(0); assertNotNull(typedExpression); assertNull(typedExpression.getAlias()); StringValue value = (StringValue) typedExpression.getExpression(); assertEquals(prefix.toUpperCase(), value.getPrefix()); assertEquals("test", value.getValue()); + return null; } - }); + }, context); + return null; } }); } @@ -4468,13 +4687,6 @@ public void testLongQualifiedNamesIssue763() throws JSQLParserException { "SELECT mongodb.test.test.intField, postgres.test.test.intField, postgres.test.test.datefield FROM mongodb.test.test JOIN postgres.postgres.test.test ON mongodb.test.test.intField = postgres.test.test.intField WHERE mongodb.test.test.intField = 123"); } - @Test - public void testLongQualifiedNamesIssue763_2() throws JSQLParserException { - Statement parse = CCJSqlParserUtil.parse(new StringReader( - "SELECT mongodb.test.test.intField, postgres.test.test.intField, postgres.test.test.datefield FROM mongodb.test.test JOIN postgres.postgres.test.test ON mongodb.test.test.intField = postgres.test.test.intField WHERE mongodb.test.test.intField = 123")); - System.out.println(parse.toString()); - } - @Test public void testSubQueryAliasIssue754() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed( @@ -4527,8 +4739,16 @@ public void testEmptyDoubleQuotes_2() throws JSQLParserException { @Test public void testInnerWithBlock() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "select 1 from (with mytable1 as (select 2 ) select 3 from mytable1 ) first", true); + String stmt = "select 1 from (with mytable1 as (select 2 ) select 3 from mytable1 ) first"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); + List> withItems1 = select.getWithItemsList(); + assertNull(withItems1); + ParenthesedSelect parenthesedSelect = + (ParenthesedSelect) select.getPlainSelect().getFromItem(); + List> withItems2 = parenthesedSelect.getPlainSelect().getWithItemsList(); + assertEquals(1, withItems2.size()); + assertEquals("(SELECT 2)", withItems2.get(0).getSelect().toString()); + assertEquals(" mytable1", withItems2.get(0).getAlias().toString()); } @Test @@ -4670,8 +4890,14 @@ public void testPartitionByWithBracketsIssue865() throws JSQLParserException { @Test public void testWithAsRecursiveIssue874() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "WITH rn AS (SELECT rownum rn FROM dual CONNECT BY level <= (SELECT max(cases) FROM t1)) SELECT pname FROM t1, rn WHERE rn <= cases ORDER BY pname"); + String stmt = + "WITH rn AS (SELECT rownum rn FROM dual CONNECT BY level <= (SELECT max(cases) FROM t1)) SELECT pname FROM t1, rn WHERE rn <= cases ORDER BY pname"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("(SELECT rownum rn FROM dual CONNECT BY level <= (SELECT max(cases) FROM t1))", + withItems.get(0).getSelect().toString()); + assertEquals(" rn", withItems.get(0).getAlias().toString()); } @Test @@ -5108,8 +5334,14 @@ public void testProblematicDeparsingIssue1183_2() throws JSQLParserException { @Test public void testKeywordCostsIssue1185() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "WITH costs AS (SELECT * FROM MY_TABLE1 AS ALIAS_TABLE1) SELECT * FROM TESTSTMT"); + String stmt = + "WITH costs AS (SELECT * FROM MY_TABLE1 AS ALIAS_TABLE1) SELECT * FROM TESTSTMT"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("(SELECT * FROM MY_TABLE1 AS ALIAS_TABLE1)", + withItems.get(0).getSelect().toString()); + assertEquals(" costs", withItems.get(0).getAlias().toString()); } @Test @@ -5124,25 +5356,49 @@ public void testConditionsWithExtraBrackets_Issue1194() throws JSQLParserExcepti @Test public void testWithValueListWithExtraBrackets1135() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "with sample_data(day, value) as (values ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))) select day, value from sample_data", - true); + String stmt = + "with sample_data(day, value) as (values ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))) select day, value from sample_data"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals("VALUES ((0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16))", + withItems.get(0).getSelect().getValues().toString()); + assertEquals(" sample_data", withItems.get(0).getAlias().toString()); } @Test public void testWithValueListWithOutExtraBrackets1135() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed("with sample_data(\"DAY\") as (values 0, 1, 2)\n" - + " select \"DAY\" from sample_data", true); - assertSqlCanBeParsedAndDeparsed( - "with sample_data(day, value) as (values (0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16)) select day, value from sample_data", - true); + String stmt1 = "with sample_data(\"DAY\") as (values 0, 1, 2)\n" + + " select \"DAY\" from sample_data"; + Select select1 = (Select) assertSqlCanBeParsedAndDeparsed(stmt1, true); + List> withItems1 = select1.getWithItemsList(); + assertEquals(1, withItems1.size()); + assertEquals("VALUES 0, 1, 2", withItems1.get(0).getSelect().getValues().toString()); + assertEquals(" sample_data", withItems1.get(0).getAlias().toString()); + + String stmt2 = + "with sample_data(day, value) as (values (0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16)) select day, value from sample_data"; + Select select2 = (Select) assertSqlCanBeParsedAndDeparsed(stmt2, true); + List> withItems2 = select2.getWithItemsList(); + assertEquals(1, withItems2.size()); + assertEquals("VALUES (0, 13), (1, 12), (2, 15), (3, 4), (4, 8), (5, 16)", + withItems2.get(0).getSelect().getValues().toString()); + assertEquals(" sample_data", withItems2.get(0).getAlias().toString()); } @Test public void testWithInsideWithIssue1186() throws JSQLParserException { - assertSqlCanBeParsedAndDeparsed( - "WITH TESTSTMT1 AS ( WITH TESTSTMT2 AS (SELECT * FROM MY_TABLE2) SELECT col1, col2 FROM TESTSTMT2) SELECT * FROM TESTSTMT", - true); + String stmt = + "WITH TESTSTMT1 AS ( WITH TESTSTMT2 AS (SELECT * FROM MY_TABLE2) SELECT col1, col2 FROM TESTSTMT2) SELECT * FROM TESTSTMT"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(stmt, true); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals(" TESTSTMT1", withItems.get(0).getAlias().toString()); + ParenthesedSelect parenthesedSelect = (ParenthesedSelect) withItems.get(0).getSelect(); + List> withItems2 = parenthesedSelect.getSelect().getWithItemsList(); + assertEquals(1, withItems2.size()); + assertEquals("(SELECT * FROM MY_TABLE2)", withItems2.get(0).getSelect().toString()); + assertEquals(" TESTSTMT2", withItems2.get(0).getAlias().toString()); } @Test @@ -5339,6 +5595,12 @@ public void testReservedKeywordsIssue1352() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("SELECT fulltext from fulltext.fulltext", true); } + @Test + public void testGroupByWithAllTableColumns() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "select c.post_id, p.* from posts p inner join comments c on c.post_id = p.post_id group by p.post_id, c.post_id, p.*;"); + } + @Test public void testTableSpaceKeyword() throws JSQLParserException { // without extra brackets @@ -5645,7 +5907,19 @@ void testSetOperationListWithBracketsIssue1737() throws JSQLParserException { void testNestedWithItems() throws JSQLParserException { String sqlStr = "with a as ( with b as ( with c as (select 1) select c.* from c) select b.* from b) select a.* from a"; - TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + assertEquals(" a", withItems.get(0).getAlias().toString()); + ParenthesedSelect parenthesedSelect = (ParenthesedSelect) withItems.get(0).getSelect(); + List> withItems2 = parenthesedSelect.getSelect().getWithItemsList(); + assertEquals(1, withItems2.size()); + assertEquals(" b", withItems2.get(0).getAlias().toString()); + ParenthesedSelect parenthesedSelect2 = (ParenthesedSelect) withItems2.get(0).getSelect(); + List> withItems3 = parenthesedSelect2.getSelect().getWithItemsList(); + assertEquals(1, withItems3.size()); + assertEquals("(SELECT 1)", withItems3.get(0).getSelect().toString()); + assertEquals(" c", withItems3.get(0).getAlias().toString()); } @Test @@ -5814,4 +6088,433 @@ public void testIssue1833() throws JSQLParserException { String stmt = "SELECT age, name, gender FROM user_info INTO TEMP user_temp WITH NO LOG"; assertSqlCanBeParsedAndDeparsed(stmt); } + + @Test + void testGroupByWithHaving() throws JSQLParserException { + String sqlStr = "-- GROUP BY\n" + + "SELECT a\n" + + " , b\n" + + " , c\n" + + " , Sum( d )\n" + + "FROM t\n" + + "GROUP BY a\n" + + " , b\n" + + " , c\n" + + "HAVING Sum( d ) > 0\n" + + " AND Count( * ) > 1\n" + + ";"; + Statement stmt = assertSqlCanBeParsedAndDeparsed(sqlStr); + Assertions.assertInstanceOf(Select.class, stmt); + } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT SELECT 1", + "SELECT 1 WHERE 1 = SELECT 1", + "SELECT 1 WHERE 1 IN SELECT 1", + "SELECT * FROM SELECT 1", + "SELECT * FROM SELECT SELECT 1", + "SELECT * FROM SELECT 1 WHERE 1 = SELECT 1", + "SELECT * FROM SELECT 1 WHERE 1 IN SELECT 1" + }) + public void testUnparenthesizedSubSelect(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withUnparenthesizedSubSelects(true)); + + Assertions.assertThrowsExactly(JSQLParserException.class, new Executable() { + @Override + public void execute() throws Throwable { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withUnparenthesizedSubSelects(false)); + } + + }); + } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM mytable PREFERRING HIGH mycolumn", + "SELECT * FROM mytable PREFERRING LOW mycolumn", + "SELECT * FROM mytable PREFERRING 1 = 1", + "SELECT * FROM mytable PREFERRING (HIGH mycolumn)", + "SELECT * FROM mytable PREFERRING INVERSE (HIGH mycolumn)", + "SELECT * FROM mytable PREFERRING HIGH mycolumn1 PRIOR TO LOW mycolumn2", + "SELECT * FROM mytable PREFERRING HIGH mycolumn1 PLUS LOW mycolumn2", + "SELECT * FROM mytable PREFERRING HIGH mycolumn PARTITION BY mycolumn" + }) + public void testPreferringClause(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr); + } + + @Test + void testInsertWithinCte() throws JSQLParserException { + String sqlStr = "WITH inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " RETURNING y " + + ") " + + "SELECT y " + + " FROM inserted"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + Insert insert = withItems.get(0).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b", insert.getSelect().toString()); + assertEquals(" RETURNING y", insert.getReturningClause().toString()); + assertEquals("INSERT INTO x (foo) SELECT bar FROM b RETURNING y", insert.toString()); + assertEquals(" inserted", withItems.get(0).getAlias().toString()); + } + + @Test + void testUpdateWithinCte() throws JSQLParserException { + String sqlStr = "WITH updated AS ( " + + " UPDATE x " + + " SET foo = 1 " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "SELECT y " + + " FROM updated"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + Update update = withItems.get(0).getUpdate().getUpdate(); + assertEquals("x", update.getTable().toString()); + assertEquals("foo", update.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("1", update.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("bar = 2", update.getWhere().toString()); + assertEquals(" RETURNING y", update.getReturningClause().toString()); + assertEquals(" updated", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteWithinCte() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + "SELECT y " + + " FROM deleted"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(1, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM deleted) " + + " RETURNING w " + + ") " + + "SELECT w " + + " FROM inserted"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(2, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM deleted)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM deleted) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testSelectAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH selection AS ( " + + " SELECT y " + + " FROM z " + + " WHERE foo = 'bar' " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM selection) " + + " RETURNING w " + + ") " + + "SELECT w " + + " FROM inserted"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(sqlStr); + List> withItems = select.getWithItemsList(); + assertEquals(2, withItems.size()); + PlainSelect innerSelect = withItems.get(0).getSelect().getPlainSelect(); + assertEquals("SELECT y FROM z WHERE foo = 'bar'", innerSelect.toString()); + assertEquals(" selection", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM selection)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM selection) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + public void testSelectWithSkylineKeywords() throws JSQLParserException { + String statement = "SELECT low, high, inverse, plus FROM mytable"; + Select select = (Select) assertSqlCanBeParsedAndDeparsed(statement); + assertEquals("mytable", select.getPlainSelect().getFromItem().toString()); + assertEquals("[low, high, inverse, plus]", + select.getPlainSelect().getSelectItems().toString()); + } + + @Test + @Disabled + // see issue #2207 + public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException { + String sql = "SELECT (pg_stat_file('postgresql.conf')).*"; + Statement statement = CCJSqlParserUtil.parse(sql); + assertNotNull(statement); + assertTrue(statement instanceof Select); + + // Ensure the function is recognized correctly + Select select = (Select) statement; + PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); + assertNotNull(plainSelect); + assertEquals(1, plainSelect.getSelectItems().size()); + assertTrue(plainSelect.getSelectItems().get(0) + .getExpression() instanceof FunctionAllColumns); + assertEquals("(pg_stat_file('postgresql.conf')).*", + plainSelect.getSelectItems().get(0).toString()); + } + + @Test + @Disabled + // see issue #2207 + public void testSelectAllColumnsFromFunctionReturnWithMultipleParentheses() + throws JSQLParserException { + String sql = "SELECT ( ( ( pg_stat_file('postgresql.conf') ) )) . *"; + Statement statement = CCJSqlParserUtil.parse(sql); + assertNotNull(statement); + assertTrue(statement instanceof Select); + + // Ensure the function is recognized correctly + Select select = (Select) statement; + PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); + assertNotNull(plainSelect); + assertEquals(1, plainSelect.getSelectItems().size()); + assertTrue(plainSelect.getSelectItems().get(0) + .getExpression() instanceof FunctionAllColumns); + assertEquals("(pg_stat_file('postgresql.conf')).*", + plainSelect.getSelectItems().get(0).toString()); + } + + @Test + void testIssue2242SubSelectLookAhead() throws JSQLParserException { + String sqlStr = "INSERT INTO foo(col1, col2, col3, col4, col5, col6)\n" + + " VALUES ( (SELECT blah FROM bar INNER JOIN bam ON bar.col1 = bam.col1 WHERE bar.id = ? AND et.id = ?), ?, ?, ?, ?, ?)\n" + + " ON CONFLICT (id) DO UPDATE\n" + + " SET col4 = ?, col5 = ?, col6 = ?"; + Statement statement = CCJSqlParserUtil.parse(sqlStr); + System.out.println(statement.toString()); + Insert insert = (Insert) statement; + Assertions.assertEquals("foo", insert.getTable().toString()); + } + + @Test + void testIssue2255() throws JSQLParserException { + String sqlStr = "select\n" + + " sum(if(log.\"output\" = 'SUCCESS', 1, 0)) success_req_num\n" + + "from mysql_kt_plan.daily_cvmapi_runinstance_log log"; + CCJSqlParserUtil.parse(sqlStr); + } + + @Test + void testIssue2257() throws JSQLParserException { + String sqlStr = "SELECT sum(iif(diff = 7, lc_lv, 0)) AS lc_7\n" + + "FROM ( SELECT a.day\n" + + " , a.channel_type\n" + + " , a.username\n" + + " , a.diff\n" + + " , a.cnt\n" + + " , lc\n" + + " , Cast( lc / cnt AS DECIMAL (38, 4) ) AS lc_lv\n" + + " FROM ( SELECT a.day\n" + + " , a.channel_type\n" + + " , a.username\n" + + " , Datediff( b.day, a.day )\n" + + " + 1 AS diff\n" + + " , cnt\n" + + " , Count( DISTINCT b.user_id ) AS lc\n" + + " FROM ( SELECT a.day\n" + + " , a.user_id\n" + + " , channel_id channel_type\n" + + " , adtrace_adgroup_id AS username\n" + + " FROM ( SELECT day\n" + + " , a.user_id\n" + + " , last_login_channel_id AS channel_id\n" + + " , last_adtrace_adgroup_id AS adtrace_adgroup_id\n" + + " FROM ( SELECT day\n" + + " , user_id\n" + + " , yidevice\n" + + " FROM ( SELECT day\n" + + " , user_id\n" + + " , yidevice\n" + + " , Row_Number( )\n" + + " OVER (PARTITION BY day, user_id ORDER BY event_time) AS rk\n" + + " FROM dwd_table.event_pj\n" + + " WHERE day BETWEEN '2025-05-30'\n" + + " AND '2025-06-06'\n" + + " AND event_id = 'device_login'\n" + + " AND yidevice IS NOT NULL\n" + + " AND yidevice != '' ) a\n" + + " WHERE rk = 1 ) a\n" + + " LEFT JOIN ( SELECT DISTINCT\n" + + " From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ) AS last_adtrace_dt\n" + + " , yidevice\n" + + " , last_login_channel_id\n" + + " , last_adtrace_adgroup_id\n" + + " , last_adtrace_creative_id\n" + + " FROM dwd_user.yidevice_pj\n" + + " WHERE Cast( adtrace_reattributed_times AS INT ) > 0\n" + + " AND Datediff( From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ), create_date ) >= 30\n" + + " AND From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ) BETWEEN '2025-05-30'\n" + + " AND '2025-06-06' ) b\n" + + " ON a.day = b.last_adtrace_dt\n" + + " AND a.yidevice = b.yidevice ) a ) a\n" + + " LEFT JOIN ( SELECT day\n" + + " , user_id\n" + + " FROM dwd_table.event_pj\n" + + " WHERE day BETWEEN '2025-05-30'\n" + + " AND '2025-06-06'\n" + + " AND event_id = 'login'\n" + + " GROUP BY day\n" + + " , user_id ) b\n" + + " ON a.user_id = b.user_id\n" + + " LEFT JOIN ( SELECT a.day\n" + + " , channel_type\n" + + " , username\n" + + " , Count( DISTINCT a.user_id ) AS cnt\n" + + " FROM ( SELECT a.day\n" + + " , a.user_id\n" + + " , channel_id AS channel_type\n" + + " , adtrace_adgroup_id username\n" + + " FROM ( SELECT day\n" + + " , a.user_id\n" + + " , last_login_channel_id AS channel_id\n" + + " , last_adtrace_adgroup_id AS adtrace_adgroup_id\n" + + " FROM ( SELECT day\n" + + " , user_id\n" + + " , yidevice\n" + + " FROM ( SELECT day\n" + + " , user_id\n" + + " , yidevice\n" + + " , Row_Number( )\n" + + " OVER (PARTITION BY day, user_id ORDER BY event_time) AS rk\n" + + " FROM dwd_table.event_pj\n" + + " WHERE day BETWEEN '2025-05-30'\n" + + " AND '2025-06-06'\n" + + " AND event_id = 'device_login'\n" + + " AND yidevice IS NOT NULL\n" + + " AND yidevice != '' ) a\n" + + " WHERE rk = 1 ) a\n" + + " LEFT JOIN ( SELECT DISTINCT\n" + + " From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ) AS last_adtrace_dt\n" + + " , yidevice\n" + + " , last_login_channel_id\n" + + " , last_adtrace_adgroup_id\n" + + " , last_adtrace_creative_id\n" + + " FROM dwd_user.yidevice_pj\n" + + " WHERE Cast( adtrace_reattributed_times AS INT ) > 0\n" + + " AND Datediff( From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ), create_date ) >= 30\n" + + " AND From_Unixtime( Cast( ( Cast( last_adtrace_time AS BIGINT ) + 28800000 ) / 1000 AS BIGINT ), 'yyyy-MM-dd' ) BETWEEN '2025-05-30'\n" + + " AND '2025-06-06' ) b\n" + + " ON a.day = b.last_adtrace_dt\n" + + " AND a.yidevice = b.yidevice ) a ) a\n" + + " GROUP BY a.day\n" + + " , channel_type\n" + + " , username ) c\n" + + " ON a.day = c.day\n" + + " AND a.channel_type = c.channel_type\n" + + " AND a.username = c.username\n" + + " GROUP BY a.day\n" + + " , a.channel_type\n" + + " , a.username\n" + + " , diff\n" + + " , cnt ) a\n" + + " WHERE diff > 1\n" + + " AND diff <= 7 ) a\n" + + "GROUP BY username\n" + + " , channel_type\n" + + " , day\n" + + " , cnt\n" + + "ORDER BY username DESC\n" + + " , channel_type\n" + + " , day DESC\n" + + ";"; + TestUtils.assertSqlCanBeParsedAndDeparsed( + sqlStr, true, parser -> parser + .withAllowComplexParsing(true) + .withAllowedNestingDepth(-1)); + } + + @Test + void testQuotedStringValueIssue2258() throws JSQLParserException { + String sqlStr = "SELECT 'yyyy-MM-dd''T''HH:mm:ss'"; + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertEquals( + "yyyy-MM-dd'T'HH:mm:ss", select + .getSelectItem(0) + .getExpression(StringValue.class) + .getNotExcapedValue()); + } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM ( IMPORT FROM EXA AT connectionName STATEMENT 'select 1' )", + "SELECT * FROM ( IMPORT INTO ( LIKE schemaName.tableName ( a, b as c) ) FROM EXA AT connectionName STATEMENT 'select 1' )", + "SELECT * FROM schemaName.tableName JOIN ( IMPORT FROM EXA AT connectionName STATEMENT 'select 1' ) USING ( columnName )" + }) + public void testSelectWithSubImport(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true, + parser -> parser.withDialect(Dialect.EXASOL)); + } + + @Test + void testSQL2016CorrespondingBy() throws JSQLParserException { + String sqlStr = + "SELECT id, name, dept, salary\n" + + "FROM Employees_US\n" + + "UNION CORRESPONDING BY (id, name, dept)\n" + + "SELECT dept, id, name, country\n" + + "FROM Employees_EU;"; + + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testIssue2332SubStrCTE() throws JSQLParserException { + String sqlStr = + "create table t as\n" + + " with\n" + + " _ as (select f(id = '') from v)\n" + + " select\n" + + " substring (f (u.id))\n" + + " from u ;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SetOperationModifierTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SetOperationModifierTest.java new file mode 100644 index 000000000..a30f3e2fa --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/SetOperationModifierTest.java @@ -0,0 +1,93 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.stream.Stream; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +/** + * Regression tests for EXCEPT/MINUS ALL/DISTINCT modifier handling. + *

    + * Verifies that the ALL and DISTINCT modifiers are correctly preserved during parse-toString + * round-trips for all set operation types: UNION, INTERSECT, EXCEPT, and MINUS. + * + * @see #2419 + */ +@Execution(ExecutionMode.CONCURRENT) +public class SetOperationModifierTest { + + @ParameterizedTest + @ValueSource(strings = { + "SELECT a FROM t1 EXCEPT ALL SELECT a FROM t2", + "SELECT a FROM t1 EXCEPT DISTINCT SELECT a FROM t2", + "SELECT a FROM t1 EXCEPT SELECT a FROM t2", + "SELECT a FROM t1 MINUS ALL SELECT a FROM t2", + "SELECT a FROM t1 MINUS DISTINCT SELECT a FROM t2", + "SELECT a FROM t1 MINUS SELECT a FROM t2", + "SELECT a FROM t1 UNION ALL SELECT a FROM t2", + "SELECT a FROM t1 INTERSECT ALL SELECT a FROM t2", + "SELECT a FROM t1 UNION ALL SELECT b FROM t2 EXCEPT DISTINCT SELECT c FROM t3" + }) + void testSetOperationModifierRoundTrip(String sql) throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed(sql); + } + + @ParameterizedTest + @MethodSource("provideModifierLeakCases") + void testModifierDoesNotLeakBetweenOperators(String sql, String forbidden) + throws JSQLParserException { + Statement stmt = CCJSqlParserUtil.parse(sql); + String deparsed = stmt.toString(); + assertFalse(deparsed.contains(forbidden), + "Modifier leaked: found '" + forbidden + "' in: " + deparsed); + } + + private static Stream provideModifierLeakCases() { + return Stream.of( + Arguments.of( + "SELECT a FROM t1 UNION ALL SELECT b FROM t2 EXCEPT SELECT c FROM t3", + "EXCEPT ALL"), + Arguments.of( + "SELECT a FROM t1 INTERSECT ALL SELECT b FROM t2 UNION SELECT c FROM t3", + "UNION ALL")); + } + + @ParameterizedTest + @MethodSource("provideSetOperationObjectCases") + void testSetOperationObjectState(String sql, Class expectedType, + boolean expectedAll, boolean expectedDistinct) throws JSQLParserException { + SetOperationList setOpList = (SetOperationList) CCJSqlParserUtil.parse(sql); + SetOperation op = setOpList.getOperations().get(0); + assertInstanceOf(expectedType, op); + assertEquals(expectedAll, op.isAll(), + "isAll() mismatch for: " + sql); + assertEquals(expectedDistinct, op.isDistinct(), + "isDistinct() mismatch for: " + sql); + } + + private static Stream provideSetOperationObjectCases() { + return Stream.of( + Arguments.of("SELECT a FROM t1 EXCEPT ALL SELECT a FROM t2", + ExceptOp.class, true, false), + Arguments.of("SELECT a FROM t1 MINUS ALL SELECT a FROM t2", + MinusOp.class, true, false)); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SpecialOracleTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SpecialOracleTest.java index f4cb8637d..4c95872f8 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SpecialOracleTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SpecialOracleTest.java @@ -61,6 +61,7 @@ public class SpecialOracleTest { private final List EXPECTED_SUCCESSES = Arrays.asList("aggregate01.sql", "analytic_query04.sql", "analytic_query05.sql", "analytic_query06.sql", + "analytic_query07.sql", "analytic_query08.sql", "analytic_query09.sql", "analytic_query10.sql", "bindvar01.sql", "bindvar02.sql", "bindvar05.sql", "case_when01.sql", "case_when02.sql", "case_when03.sql", "case_when04.sql", "case_when05.sql", "cast_multiset01.sql", @@ -75,23 +76,29 @@ public class SpecialOracleTest { "cast_multiset30.sql", "cast_multiset31.sql", "cast_multiset32.sql", "cast_multiset33.sql", "cast_multiset35.sql", "cast_multiset36.sql", "cast_multiset40.sql", "cast_multiset41.sql", "cast_multiset42.sql", - "cast_multiset43.sql", "columns01.sql", "condition01.sql", "condition02.sql", - "condition03.sql", "condition04.sql", "condition05.sql", "condition07.sql", - "condition08.sql", "condition09.sql", "condition10.sql", "condition12.sql", + "cast_multiset43.sql", "cluster_set01.sql", "columns01.sql", "condition01.sql", + "condition02.sql", + "condition03.sql", "condition04.sql", "condition05.sql", "condition06.sql", + "condition07.sql", + "condition08.sql", "condition09.sql", "condition10.sql", "condition11.sql", + "condition12.sql", "condition14.sql", "condition15.sql", "condition19.sql", "condition20.sql", "connect_by01.sql", "connect_by02.sql", "connect_by03.sql", "connect_by04.sql", - "connect_by05.sql", "connect_by06.sql", "connect_by07.sql", "datetime01.sql", + "connect_by05.sql", "connect_by06.sql", "connect_by07.sql", "connect_by08.sql", + "connect_by09.sql", "connect_by10.sql", "datetime01.sql", "datetime02.sql", "datetime04.sql", "datetime05.sql", "datetime06.sql", "dblink01.sql", "for_update01.sql", "for_update02.sql", "for_update03.sql", "function04.sql", "function05.sql", "for_update04.sql", "for_update05.sql", "for_update06.sql", + "for_update07.sql", "for_update08.sql", "function01.sql", "function02.sql", "function03.sql", - "function06.sql", + "function06.sql", "function07.sql", "groupby01.sql", "groupby02.sql", "groupby03.sql", "groupby04.sql", "groupby05.sql", "groupby06.sql", "groupby08.sql", "groupby09.sql", "groupby10.sql", "groupby11.sql", "groupby12.sql", "groupby13.sql", "groupby14.sql", "groupby15.sql", "groupby16.sql", "groupby17.sql", "groupby19.sql", "groupby20.sql", "groupby21.sql", "groupby22.sql", "groupby23.sql", - "insert02.sql", "insert11.sql", "insert12.sql", "interval02.sql", "interval04.sql", + "insert02.sql", "insert04.sql", "insert05.sql", "insert06.sql", "insert07.sql", + "insert11.sql", "insert12.sql", "interval02.sql", "interval04.sql", "interval05.sql", "join01.sql", "join02.sql", "join03.sql", "join04.sql", "join06.sql", "join07.sql", "join08.sql", "join09.sql", "join10.sql", "join11.sql", "join12.sql", "join13.sql", "join14.sql", @@ -105,14 +112,15 @@ public class SpecialOracleTest { "order_by05.sql", "order_by06.sql", "pivot01.sql", "pivot02.sql", "pivot03.sql", "pivot04.sql", "pivot05.sql", "pivot06.sql", "pivot07.sql", "pivot07_Parenthesis.sql", "pivot08.sql", "pivot09.sql", "pivot11.sql", "pivot12.sql", "query_factoring01.sql", - "query_factoring02.sql", "query_factoring03.sql", "query_factoring06.sql", + "query_factoring02.sql", "query_factoring03.sql", "query_factoring04.sql", + "query_factoring06.sql", "query_factoring14.sql", "query_factoring07.sql", "query_factoring08.sql", "query_factoring09.sql", "query_factoring11.sql", "query_factoring12.sql", "set01.sql", "set02.sql", "simple02.sql", "simple03.sql", "simple04.sql", "simple05.sql", "simple06.sql", "simple07.sql", "simple08.sql", "simple09.sql", "simple10.sql", "simple11.sql", "simple12.sql", "simple13.sql", "union01.sql", "union02.sql", "union03.sql", "union04.sql", "union05.sql", "union06.sql", "union07.sql", "union08.sql", - "union09.sql", "union10.sql", "xmltable02.sql"); + "union09.sql", "union10.sql", "xmltable01.sql", "xmltable02.sql"); @Test public void testAllSqlsParseDeparse() throws IOException { diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java index 21565c78f..19908e675 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SpeedTest.java @@ -15,6 +15,7 @@ import net.sf.jsqlparser.statement.simpleparsing.CCJSqlParserManagerTest; import net.sf.jsqlparser.test.TestException; import net.sf.jsqlparser.util.TablesNamesFinder; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.io.BufferedReader; @@ -30,6 +31,9 @@ public class SpeedTest { private final CCJSqlParserManager parserManager = new CCJSqlParserManager(); @Test + @Disabled + // replaced by a proper JMH based benchmark + // @todo: remove this eventually public void testSpeed() throws Exception { // all the statements in testfiles/simple_parsing.txt BufferedReader in = new BufferedReader( diff --git a/src/test/java/net/sf/jsqlparser/statement/select/TableFunctionTest.java b/src/test/java/net/sf/jsqlparser/statement/select/TableFunctionTest.java index dec463eda..faf4cbe8c 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/TableFunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/TableFunctionTest.java @@ -12,6 +12,8 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; @@ -31,4 +33,30 @@ void testLateralFlat() throws JSQLParserException { TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); } + /** + * The SQL keyword "OUTER" is a valid parameter name for Snowflake's FLATTEN table function. + */ + @Test + void testTableFunctionWithNamedParameterWhereNameIsOuterKeyword() throws JSQLParserException { + String sqlStr = + "INSERT INTO db.schema.target\n" + + " (Name, FriendParent)\n" + + " SELECT\n" + + " i.DATA_VALUE:Name AS Name,\n" + + " f1.Value:Parent:Name AS FriendParent\n" + + " FROM\n" + + " db.schema.source AS i,\n" + + " lateral flatten(input => i.DATA_VALUE:Friends, outer => true) AS f1;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "OFFSET", + "ORDINALITY" + }) + void testTableFunctionWithSupportedWithClauses(String withClause) throws JSQLParserException { + String sqlStr = "SELECT * FROM UNNEST(ARRAY[1, 2, 3]) WITH " + withClause + " AS t(a, b)"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java new file mode 100644 index 000000000..1c7f2eb23 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/TimeTravelTest.java @@ -0,0 +1,101 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class TimeTravelTest { + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM my_table AT(TIMESTAMP => 'Wed, 26 Jun 2024 09:20:00 -0700'::TIMESTAMP_LTZ);", + "SELECT * FROM my_table AT(OFFSET => -60*5) AS T WHERE T.flag = 'valid';", + "SELECT * FROM my_table AT(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');", + "SELECT * FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');", + "SELECT oldt.* ,newt.*\n" + + " FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726') AS oldt\n" + + " FULL OUTER JOIN my_table AT(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726') AS newt\n" + + " ON oldt.id = newt.id\n" + + " WHERE oldt.id IS NULL OR newt.id IS NULL;" + }) + void testSnowflakeAtBefore(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT C1\n" + + " FROM t1\n" + + " CHANGES(INFORMATION => APPEND_ONLY)\n" + + " AT(TIMESTAMP => CURRENT_TIMESTAMP)\n" + + " END(TIMESTAMP => CURRENT_TIMESTAMP);", + "SELECT *\n" + + " FROM t1\n" + + " CHANGES(INFORMATION => APPEND_ONLY)\n" + + " AT(TIMESTAMP => $ts1);", + "CREATE OR REPLACE TABLE t2 (\n" + + " c1 varchar(255) default NULL\n" + + " )\n" + + "AS SELECT C1\n" + + " FROM t1\n" + + " CHANGES(INFORMATION => APPEND_ONLY)\n" + + " AT(TIMESTAMP => $ts1)\n" + + " END(TIMESTAMP => $ts2);\n", + "CREATE OR REPLACE TABLE t2 (\n" + + " c1 varchar(255) default NULL\n" + + " )\n" + + "AS SELECT C1\n" + + " FROM t1\n" + + " CHANGES(INFORMATION => APPEND_ONLY)\n" + + " AT(STREAM => 's1')\n" + + " END(TIMESTAMP => $ts2);\n" + }) + void testSnowflakeChange(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT * FROM delta.`/delta/events` @ 20240618093000000;\n", + "SELECT * FROM delta.`/delta/events` @V 5;\n", + "SELECT * FROM delta.`/delta/events` TIMESTAMP AS OF '2024-06-01T00:00:00';\n", + "SELECT * FROM delta.`/delta/events` VERSION AS OF 3;\n", + "MERGE INTO target_table AS t\n" + + "USING source_table VERSION AS OF 5 AS s\n" + + "ON t.id = s.id\n" + + "WHEN MATCHED THEN UPDATE SET t.value = s.value;\n" + }) + void testDataBricksTemporalSpec(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "SELECT *\n" + + "FROM t\n" + + " FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR);\n", + "SELECT *\n" + + "FROM t\n" + + " FOR SYSTEM_TIME AS OF '2017-01-01 10:00:00-07:00';\n", + "SELECT *\n" + + "FROM t1\n" + + "WHERE t1.a IN (SELECT t2.a\n" + + " FROM t2 FOR SYSTEM_TIME AS OF t1.timestamp_column);\n", + "SELECT * FROM books FOR SYSTEM_TIME AS OF before_replace_timestamp;", + "INSERT INTO t1\n" + + "SELECT * FROM t1\n" + + " FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY);\n" + }) + void testBigQueryHistoricVersion(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java new file mode 100644 index 000000000..ed84b4aa7 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionDeclarationTest.java @@ -0,0 +1,130 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class WithFunctionDeclarationTest { + static final String FUNCTION_NAME = "func1"; + static final String RETURN_TYPE = "integer"; + + @Mock + Expression expression; + @Mock + WithFunctionParameter withFunctionParameter1; + @Mock + WithFunctionParameter withFunctionParameter2; + + WithFunctionDeclaration withFunctionDeclaration; + + @Test + void fullConstructorAndGetters() { + withFunctionDeclaration = new WithFunctionDeclaration(FUNCTION_NAME, + List.of(withFunctionParameter1, withFunctionParameter2), RETURN_TYPE, expression); + assertThat(withFunctionDeclaration.getFunctionName()).isEqualTo(FUNCTION_NAME); + assertThat(withFunctionDeclaration.getParameters()) + .isEqualTo(List.of(withFunctionParameter1, withFunctionParameter2)); + assertThat(withFunctionDeclaration.getReturnType()).isEqualTo(RETURN_TYPE); + assertThat(withFunctionDeclaration.getReturnExpression()).isEqualTo(expression); + } + + @Test + void defaultConstructorAndSetters() { + withFunctionDeclaration = new WithFunctionDeclaration(); + withFunctionDeclaration.setFunctionName(FUNCTION_NAME); + withFunctionDeclaration + .setParameters(List.of(withFunctionParameter1, withFunctionParameter2)); + withFunctionDeclaration.setReturnType(RETURN_TYPE); + withFunctionDeclaration.setReturnExpression(expression); + assertThat(withFunctionDeclaration.getFunctionName()).isEqualTo(FUNCTION_NAME); + assertThat(withFunctionDeclaration.getParameters()) + .isEqualTo(List.of(withFunctionParameter1, withFunctionParameter2)); + assertThat(withFunctionDeclaration.getReturnType()).isEqualTo(RETURN_TYPE); + assertThat(withFunctionDeclaration.getReturnExpression()).isEqualTo(expression); + } + + @Test + void defaultConstructorAndWithers() { + withFunctionDeclaration = new WithFunctionDeclaration() + .withFunctionName(FUNCTION_NAME) + .withParameters(List.of(withFunctionParameter1, withFunctionParameter2)) + .withReturnType(RETURN_TYPE) + .withReturnExpression(expression); + assertThat(withFunctionDeclaration.getFunctionName()).isEqualTo(FUNCTION_NAME); + assertThat(withFunctionDeclaration.getParameters()) + .isEqualTo(List.of(withFunctionParameter1, withFunctionParameter2)); + assertThat(withFunctionDeclaration.getReturnType()).isEqualTo(RETURN_TYPE); + assertThat(withFunctionDeclaration.getReturnExpression()).isEqualTo(expression); + } + + @Test + void toStringTestWithParameters() { + when(withFunctionParameter1.appendTo(any(StringBuilder.class))).thenAnswer(invocation -> { + StringBuilder builder = invocation.getArgument(0); + return builder.append("param1 bigint"); + }); + when(withFunctionParameter2.appendTo(any(StringBuilder.class))).thenAnswer(invocation -> { + StringBuilder builder = invocation.getArgument(0); + return builder.append("param2 double"); + }); + when(expression.toString()).thenReturn("1 + 1"); + withFunctionDeclaration = new WithFunctionDeclaration(FUNCTION_NAME, + List.of(withFunctionParameter1, withFunctionParameter2), RETURN_TYPE, expression); + + assertThat(withFunctionDeclaration.toString()).isEqualTo( + "FUNCTION func1(param1 bigint, param2 double) RETURNS integer RETURN 1 + 1"); + } + + @Test + void toStringTestWithNoParameters() { + when(expression.toString()).thenReturn("1 + 1"); + withFunctionDeclaration = + new WithFunctionDeclaration(FUNCTION_NAME, List.of(), RETURN_TYPE, expression); + + assertThat(withFunctionDeclaration.toString()) + .isEqualTo("FUNCTION func1() RETURNS integer RETURN 1 + 1"); + } + + @Test + void expressionVisitorIsNotCalledWhenNoReturnExpressionDeclared( + @Mock ExpressionVisitor expressionVisitor) { + withFunctionDeclaration = new WithFunctionDeclaration(); + + withFunctionDeclaration.accept(expressionVisitor, "RANDOM_CONTEXT"); + + verifyNoInteractions(expressionVisitor); + } + + @Test + void expressionVisitorCalledWhenReturnExpressionDeclared( + @Mock ExpressionVisitor expressionVisitor) { + String context = "RANDOM_CONTEXT"; + withFunctionDeclaration = new WithFunctionDeclaration() + .withReturnExpression(expression); + + withFunctionDeclaration.accept(expressionVisitor, context); + + verify(expression).accept(expressionVisitor, context); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java new file mode 100644 index 000000000..9e29552ad --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithFunctionParameterTest.java @@ -0,0 +1,52 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class WithFunctionParameterTest { + static final String PARAMETER_NAME = "param1"; + static final String PARAMETER_TYPE = "integer"; + + WithFunctionParameter withFunctionParameter; + + @Test + void fullConstructorAndGetters() { + withFunctionParameter = new WithFunctionParameter(PARAMETER_NAME, PARAMETER_TYPE); + assertThat(withFunctionParameter.getName()).isEqualTo(PARAMETER_NAME); + assertThat(withFunctionParameter.getType()).isEqualTo(PARAMETER_TYPE); + } + + @Test + void defaultConstructorAndSetters() { + withFunctionParameter = new WithFunctionParameter(); + withFunctionParameter.setName(PARAMETER_NAME); + withFunctionParameter.setType(PARAMETER_TYPE); + assertThat(withFunctionParameter.getName()).isEqualTo(PARAMETER_NAME); + assertThat(withFunctionParameter.getType()).isEqualTo(PARAMETER_TYPE); + } + + @Test + void defaultConstructorAndWithers() { + withFunctionParameter = new WithFunctionParameter() + .withName(PARAMETER_NAME) + .withType(PARAMETER_TYPE); + assertThat(withFunctionParameter.getName()).isEqualTo(PARAMETER_NAME); + assertThat(withFunctionParameter.getType()).isEqualTo(PARAMETER_TYPE); + } + + @Test + void testToString() { + withFunctionParameter = new WithFunctionParameter(PARAMETER_NAME, PARAMETER_TYPE); + assertThat(withFunctionParameter.toString()).isEqualTo("param1 integer"); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java new file mode 100644 index 000000000..f84bfa4b7 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.java @@ -0,0 +1,102 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.select; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class WithItemTest { + + @Test + void testNotMaterializedIssue2251() throws JSQLParserException { + String sqlStr = "WITH devices AS NOT MATERIALIZED (\n" + + " SELECT\n" + + " d.uuid AS device_uuid\n" + + " FROM active_devices d\n" + + ")\n" + + "SELECT 1;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @ParameterizedTest + @ValueSource(strings = { + "WITH\n" + + " FUNCTION doubleup(x integer)\n" + + " RETURNS integer\n" + + " RETURN x * 2\n" + + "SELECT doubleup(21);\n", + "WITH\n" + + " FUNCTION doubleup(x integer)\n" + + " RETURNS integer\n" + + " RETURN x * 2,\n" + + " FUNCTION doubleupplusone(x integer)\n" + + " RETURNS integer\n" + + " RETURN doubleup(x) + 1\n" + + "SELECT doubleupplusone(21);", + "WITH\n" + + " FUNCTION takesArray(x array)\n" + + " RETURNS double\n" + + " RETURN x[1] + x[2] + x[3]\n" + + "SELECT takesArray(ARRAY[1.0, 2.0, 3.0]);" + + }) + void testWithFunction(String sqlStr) throws JSQLParserException { + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testRecursiveWithSearchBreadthClause() throws JSQLParserException { + String sqlStr = "WITH RECURSIVE team_hierarchy AS (\n" + + " SELECT employee_id, first_name, manager_id, ARRAY[employee_id] AS path\n" + + " FROM employees\n" + + " WHERE manager_id IS NULL\n" + + " UNION ALL\n" + + " SELECT e.employee_id, e.first_name, e.manager_id, th.path || e.employee_id\n" + + " FROM employees e\n" + + " INNER JOIN team_hierarchy th ON e.manager_id = th.employee_id\n" + + ")\n" + + "SEARCH BREADTH FIRST BY employee_id SET order_col\n" + + "SELECT employee_id, first_name, path, order_col FROM team_hierarchy ORDER BY order_col"; + + Select select = (Select) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + WithSearchClause searchClause = select.getWithItemsList().get(0).getSearchClause(); + + assertNotNull(searchClause); + assertEquals(WithSearchClause.SearchOrder.BREADTH, searchClause.getSearchOrder()); + assertEquals("employee_id", searchClause.getSearchColumns().get(0).toString()); + assertEquals("order_col", searchClause.getSequenceColumnName()); + } + + @Test + void testRecursiveWithSearchDepthClause() throws JSQLParserException { + String sqlStr = "WITH RECURSIVE search_tree AS (\n" + + " SELECT id, parent_id FROM nodes WHERE parent_id IS NULL\n" + + " UNION ALL\n" + + " SELECT n.id, n.parent_id FROM nodes n JOIN search_tree st ON st.id = n.parent_id\n" + + ")\n" + + "SEARCH DEPTH FIRST BY id, parent_id SET traversal_order\n" + + "SELECT traversal_order FROM search_tree"; + + Select select = (Select) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + WithSearchClause searchClause = select.getWithItemsList().get(0).getSearchClause(); + + assertNotNull(searchClause); + assertEquals(WithSearchClause.SearchOrder.DEPTH, searchClause.getSearchOrder()); + assertEquals("id", searchClause.getSearchColumns().get(0).toString()); + assertEquals("parent_id", searchClause.getSearchColumns().get(1).toString()); + assertEquals("traversal_order", searchClause.getSequenceColumnName()); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/show/ShowTablesStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/show/ShowTablesStatementTest.java index e5743e7a3..c880640b1 100644 --- a/src/test/java/net/sf/jsqlparser/statement/show/ShowTablesStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/show/ShowTablesStatementTest.java @@ -50,15 +50,20 @@ public void showTablesWhereExpression() throws Exception { @Test public void testObject() throws JSQLParserException, JSQLParserException { - ShowTablesStatement showTablesStatement = (ShowTablesStatement) CCJSqlParserUtil.parse("SHOW TABLES WHERE table_name = 'FOO'"); + ShowTablesStatement showTablesStatement = (ShowTablesStatement) CCJSqlParserUtil + .parse("SHOW TABLES WHERE table_name = 'FOO'"); assertEquals(0, showTablesStatement.getModifiers().size()); - TestUtils.assertExpressionCanBeDeparsedAs(showTablesStatement.getWhereCondition(), "table_name = 'FOO'"); + TestUtils.assertExpressionCanBeDeparsedAs(showTablesStatement.getWhereCondition(), + "table_name = 'FOO'"); - showTablesStatement = (ShowTablesStatement) CCJSqlParserUtil.parse("SHOW FULL TABLES IN db_name"); + showTablesStatement = + (ShowTablesStatement) CCJSqlParserUtil.parse("SHOW FULL TABLES IN db_name"); assertEquals(1, showTablesStatement.getModifiers().size()); assertEquals(ShowTablesStatement.SelectionMode.IN, showTablesStatement.getSelectionMode()); - showTablesStatement = (ShowTablesStatement) CCJSqlParserUtil.parse("SHOW TABLES LIKE '%FOO%'"); - TestUtils.assertExpressionCanBeDeparsedAs(showTablesStatement.getLikeExpression(), "'%FOO%'"); + showTablesStatement = + (ShowTablesStatement) CCJSqlParserUtil.parse("SHOW TABLES LIKE '%FOO%'"); + TestUtils.assertExpressionCanBeDeparsedAs(showTablesStatement.getLikeExpression(), + "'%FOO%'"); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/simpleparsing/CCJSqlParserManagerTest.java b/src/test/java/net/sf/jsqlparser/statement/simpleparsing/CCJSqlParserManagerTest.java index 6664f5405..ba588c417 100644 --- a/src/test/java/net/sf/jsqlparser/statement/simpleparsing/CCJSqlParserManagerTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/simpleparsing/CCJSqlParserManagerTest.java @@ -13,32 +13,42 @@ import java.io.InputStreamReader; import java.io.StringReader; import java.util.Objects; +import java.util.stream.Stream; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.statement.create.CreateTableTest; import net.sf.jsqlparser.test.TestException; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + public class CCJSqlParserManagerTest { - @Test - public void testParse() throws Exception { - CCJSqlParserManager parserManager = new CCJSqlParserManager(); - BufferedReader in = new BufferedReader(new InputStreamReader(Objects.requireNonNull(CreateTableTest.class. - getResourceAsStream("/simple_parsing.txt")))); + // Create a DynamicTest stream for every statement in the file simple_parsing.txt + @TestFactory + Stream testParsePerStatement() { + BufferedReader in = new BufferedReader(new InputStreamReader(Objects + .requireNonNull(CreateTableTest.class.getResourceAsStream("/simple_parsing.txt")))); - String statement = ""; - while (true) { + // Convert buffered reader to stream of statements + return Stream.generate(() -> { try { - statement = CCJSqlParserManagerTest.getStatement(in); - if (statement == null) { - break; - } - - parserManager.parse(new StringReader(statement)); - } catch (JSQLParserException e) { - throw new TestException("impossible to parse statement: " + statement, e); + return CCJSqlParserManagerTest.getStatement(in); + } catch (Exception e) { + throw new RuntimeException(e); } + }).takeWhile(Objects::nonNull) + .map(statement -> DynamicTest.dynamicTest("Parsing statement: " + statement, () -> { + testParse(statement); + })); + } + + private void testParse(String statement) throws Exception { + CCJSqlParserManager parserManager = new CCJSqlParserManager(); + try { + parserManager.parse(new StringReader(statement)); + } catch (JSQLParserException e) { + throw new TestException("impossible to parse statement: " + statement, e); } } @@ -69,8 +79,7 @@ public static String getLine(BufferedReader in) throws Exception { while (true) { line = in.readLine(); if (line != null) { - if (line.length() < 2 || !(line.charAt(0) == '/' && line. - charAt(1) == '/')) { + if (line.length() < 2 || !(line.charAt(0) == '/' && line.charAt(1) == '/')) { break; } } else { diff --git a/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateMultipleTablesTest.java b/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateMultipleTablesTest.java new file mode 100644 index 000000000..18894c8ca --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateMultipleTablesTest.java @@ -0,0 +1,110 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.truncate; + +import static net.sf.jsqlparser.test.TestUtils.assertDeparse; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.StringReader; +import java.util.List; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.CCJSqlParserManager; +import net.sf.jsqlparser.schema.Table; +import org.junit.jupiter.api.Test; + +public class TruncateMultipleTablesTest { + + private CCJSqlParserManager parserManager = new CCJSqlParserManager(); + + @Test + public void testTruncate2Tables() throws Exception { + String statement = "TRUncATE TABLE myschema.mytab, myschema2.mytab2"; + Truncate truncate = (Truncate) parserManager.parse(new StringReader(statement)); + assertEquals("myschema2", truncate.getTable().getSchemaName()); + assertEquals("myschema2.mytab2", truncate.getTable().getFullyQualifiedName()); + assertEquals(statement.toUpperCase(), truncate.toString().toUpperCase()); + assertEquals("myschema.mytab", truncate.getTables().get(0).getFullyQualifiedName()); + assertEquals("myschema2.mytab2", truncate.getTables().get(1).getFullyQualifiedName()); + + statement = "TRUncATE TABLE mytab, my2ndtab"; + String toStringStatement = "TRUncATE TABLE mytab, my2ndtab"; + truncate = (Truncate) parserManager.parse(new StringReader(statement)); + assertEquals("my2ndtab", truncate.getTable().getName()); + assertEquals(toStringStatement.toUpperCase(), truncate.toString().toUpperCase()); + assertEquals("mytab", truncate.getTables().get(0).getFullyQualifiedName()); + assertEquals("my2ndtab", truncate.getTables().get(1).getFullyQualifiedName()); + + statement = "TRUNCATE TABLE mytab, my2ndtab CASCADE"; + truncate = (Truncate) parserManager.parse(new StringReader(statement)); + assertNull(truncate.getTables().get(0).getSchemaName()); + assertEquals("mytab", truncate.getTables().get(0).getFullyQualifiedName()); + assertEquals("my2ndtab", truncate.getTables().get(1).getFullyQualifiedName()); + assertTrue(truncate.getCascade()); + assertEquals(statement, truncate.toString()); + } + + @Test + public void testTruncatePostgresqlWithoutTableNames() throws Exception { + String statement = "TRUncATE myschema.mytab, myschema2.mytab2"; + Truncate truncate = (Truncate) parserManager.parse(new StringReader(statement)); + assertEquals("myschema2", truncate.getTable().getSchemaName()); + assertEquals("myschema2.mytab2", truncate.getTable().getFullyQualifiedName()); + assertEquals(statement.toUpperCase(), truncate.toString().toUpperCase()); + assertEquals("myschema.mytab", truncate.getTables().get(0).getFullyQualifiedName()); + assertEquals("myschema2.mytab2", truncate.getTables().get(1).getFullyQualifiedName()); + + statement = "TRUncATE mytab, my2ndtab"; + String toStringStatement = "TRUncATE mytab, my2ndtab"; + truncate = (Truncate) parserManager.parse(new StringReader(statement)); + assertEquals("my2ndtab", truncate.getTable().getName()); + assertEquals(toStringStatement.toUpperCase(), truncate.toString().toUpperCase()); + assertEquals("mytab", truncate.getTables().get(0).getFullyQualifiedName()); + assertEquals("my2ndtab", truncate.getTables().get(1).getFullyQualifiedName()); + + statement = "TRUNCATE mytab, my2ndtab CASCADE"; + truncate = (Truncate) parserManager.parse(new StringReader(statement)); + assertNull(truncate.getTables().get(0).getSchemaName()); + assertEquals("mytab", truncate.getTables().get(0).getFullyQualifiedName()); + assertEquals("my2ndtab", truncate.getTables().get(1).getFullyQualifiedName()); + assertTrue(truncate.getCascade()); + assertEquals(statement, truncate.toString()); + } + + @Test + public void testTruncateDeparse() throws JSQLParserException { + String statement = "TRUNCATE TABLE foo, bar"; + assertSqlCanBeParsedAndDeparsed(statement); + assertDeparse(new Truncate() + .withTables(List.of(new Table("foo"), new Table("bar"))) + .withTableToken(true), statement); + } + + @Test + public void testTruncateCascadeDeparse() throws JSQLParserException { + String statement = "TRUNCATE TABLE foo, bar CASCADE"; + assertSqlCanBeParsedAndDeparsed(statement); + assertDeparse(new Truncate() + .withTables(List.of(new Table("foo"), new Table("bar"))) + .withTableToken(true) + .withCascade(true), statement); + } + + @Test + public void testTruncateDoesNotAllowOnlyWithMultipleTables() { + String statement = "TRUNCATE TABLE ONLY foo, bar"; + assertThrows(JSQLParserException.class, + () -> parserManager.parse(new StringReader(statement))); + } + +} diff --git a/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateTest.java b/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateTest.java index 036aa64ad..698d2a5b8 100644 --- a/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/truncate/TruncateTest.java @@ -18,6 +18,7 @@ import static net.sf.jsqlparser.test.TestUtils.assertDeparse; import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; @@ -71,8 +72,8 @@ public void testTruncateDeparse() throws JSQLParserException { String statement = "TRUNCATE TABLE foo"; assertSqlCanBeParsedAndDeparsed(statement); assertDeparse(new Truncate() - .withTable(new Table("foo")) - .withTableToken(true), statement); + .withTable(new Table("foo")) + .withTableToken(true), statement); } @Test @@ -80,19 +81,36 @@ public void testTruncateCascadeDeparse() throws JSQLParserException { String statement = "TRUNCATE TABLE foo CASCADE"; assertSqlCanBeParsedAndDeparsed(statement); assertDeparse(new Truncate() - .withTable(new Table("foo")) - .withTableToken(true) - .withCascade(true), statement); + .withTable(new Table("foo")) + .withTableToken(true) + .withCascade(true), statement); } @Test public void testTruncateOnlyDeparse() throws JSQLParserException { - String statement = "TRUNCATE TABLE ONLY foo CASCADE"; + String statement = "TRUNCATE TABLE ONLY foo"; assertSqlCanBeParsedAndDeparsed(statement); assertDeparse(new Truncate() - .withTable(new Table("foo")) - .withCascade(true) - .withTableToken(true) - .withOnly(true), statement); + .withTable(new Table("foo")) + .withTableToken(true) + .withOnly(true), statement); } + + @Test + public void testTruncateOnlyAndCascadeDeparse() throws JSQLParserException { + String statement = "TRUNCATE ONLY foo CASCADE"; + assertSqlCanBeParsedAndDeparsed(statement); + assertDeparse(new Truncate() + .withTable(new Table("foo")) + .withCascade(true) + .withOnly(true), statement); + } + + @Test + public void throwsParseWhenOnlyUsedWithMultipleTables() { + String statement = "TRUNCATE TABLE ONLY foo, bar"; + assertThrows(JSQLParserException.class, + () -> parserManager.parse(new StringReader(statement))); + } + } diff --git a/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java b/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java index 342d1eea6..85a31bf16 100644 --- a/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java @@ -10,25 +10,35 @@ package net.sf.jsqlparser.statement.update; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.BooleanValue; import net.sf.jsqlparser.expression.DoubleValue; import net.sf.jsqlparser.expression.JdbcParameter; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.insert.Insert; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.io.StringReader; +import java.util.List; import static net.sf.jsqlparser.test.TestUtils.assertOracleHintExists; import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; import static net.sf.jsqlparser.test.TestUtils.assertUpdateMysqlHintExists; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -229,8 +239,21 @@ public void testWith() throws JSQLParserException { + "SET id_instrument=null\n" + "WHERE id_instrument_ref = (SELECT id_instrument_ref\n" + " FROM a)"; - - assertSqlCanBeParsedAndDeparsed(statement, true); + Update update = (Update) assertSqlCanBeParsedAndDeparsed(statement, true); + List> withItems = update.getWithItemsList(); + assertEquals("cfe.instrument_ref", update.getTable().getFullyQualifiedName()); + assertEquals(2, withItems.size()); + assertEquals("SELECT 1 id_instrument_ref", + withItems.get(0).getSelect().getPlainSelect().toString()); + assertEquals(" a", withItems.get(0).getAlias().toString()); + assertEquals("SELECT 1 id_instrument_ref", + withItems.get(1).getSelect().getPlainSelect().toString()); + assertEquals(" b", withItems.get(1).getAlias().toString()); + assertEquals(1, update.getUpdateSets().size()); + assertEquals("id_instrument", update.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("NULL", update.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("id_instrument_ref = (SELECT id_instrument_ref FROM a)", + update.getWhere().toString()); } @Test @@ -268,9 +291,7 @@ public void testUpdateSetsIssue1316() throws JSQLParserException { + " , b.packageunit = '4101170402' -- this is supposed to be UpdateSet 3\n" + "WHERE b.payrefno = 'B370202091026000005'"; - assertSqlCanBeParsedAndDeparsed(sqlStr, true); - - Update update = (Update) CCJSqlParserUtil.parse(sqlStr); + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr, true); assertEquals(3, update.getUpdateSets().size()); assertEquals(3, update.getUpdateSets().get(0).getColumns().size()); @@ -380,4 +401,185 @@ void testIssue1910() throws JSQLParserException { TestUtils.assertStatementCanBeDeparsedAs(update, "UPDATE sys_dept SET (deleted, created) = (1,2)", true); } + + @Test + void testInsertWithinCte() throws JSQLParserException { + String sqlStr = "WITH inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " RETURNING y " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(1, withItems.size()); + Insert insert = withItems.get(0).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b", insert.getSelect().toString()); + assertEquals(" RETURNING y", insert.getReturningClause().toString()); + assertEquals("INSERT INTO x (foo) SELECT bar FROM b RETURNING y", insert.toString()); + assertEquals(" inserted", withItems.get(0).getAlias().toString()); + } + + @Test + void testUpdateWithinCte() throws JSQLParserException { + String sqlStr = "WITH updated AS ( " + + " UPDATE x " + + " SET foo = 1 " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(1, withItems.size()); + Update innerUpdate = withItems.get(0).getUpdate().getUpdate(); + assertEquals("x", innerUpdate.getTable().toString()); + assertEquals("foo", innerUpdate.getUpdateSets().get(0).getColumn(0).toString()); + assertEquals("1", innerUpdate.getUpdateSets().get(0).getValue(0).toString()); + assertEquals("bar = 2", innerUpdate.getWhere().toString()); + assertEquals(" RETURNING y", innerUpdate.getReturningClause().toString()); + assertEquals(" updated", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteWithinCte() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(1, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + } + + @Test + void testDeleteAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH deleted AS ( " + + " DELETE FROM x " + + " WHERE bar = 2 " + + " RETURNING y " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM deleted) " + + " RETURNING w " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(2, withItems.size()); + Delete delete = withItems.get(0).getDelete().getDelete(); + assertEquals("x", delete.getTable().toString()); + assertEquals("bar = 2", delete.getWhere().toString()); + assertEquals(" RETURNING y", delete.getReturningClause().toString()); + assertEquals(" deleted", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM deleted)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM deleted) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @Test + void testSelectAndInsertWithin2Ctes() throws JSQLParserException { + String sqlStr = "WITH selection AS ( " + + " SELECT y " + + " FROM z " + + " WHERE foo = 'bar' " + + ") " + + ", inserted AS ( " + + " INSERT INTO x (foo) " + + " SELECT bar FROM b " + + " WHERE y IN (SELECT y FROM selection) " + + " RETURNING w " + + ") " + + " UPDATE z " + + " SET foo = 1 " + + " WHERE y IN (SELECT y FROM inserted) "; + Update update = (Update) assertSqlCanBeParsedAndDeparsed(sqlStr); + assertEquals("z", update.getTable().toString()); + List> withItems = update.getWithItemsList(); + assertEquals(2, withItems.size()); + PlainSelect select = withItems.get(0).getSelect().getPlainSelect(); + assertEquals("SELECT y FROM z WHERE foo = 'bar'", select.toString()); + assertEquals(" selection", withItems.get(0).getAlias().toString()); + Insert insert = withItems.get(1).getInsert().getInsert(); + assertEquals("x", insert.getTable().toString()); + assertEquals("SELECT bar FROM b WHERE y IN (SELECT y FROM selection)", + insert.getSelect().toString()); + assertEquals(" RETURNING w", insert.getReturningClause().toString()); + assertEquals( + "INSERT INTO x (foo) SELECT bar FROM b WHERE y IN (SELECT y FROM selection) RETURNING w", + insert.toString()); + assertEquals(" inserted", withItems.get(1).getAlias().toString()); + } + + @ParameterizedTest + @ValueSource(strings = { + "UPDATE mytable SET mycolumn1 = mycolumn2 PREFERRING HIGH mycolumn", + "UPDATE mytable SET mycolumn1 = mycolumn2 PREFERRING LOW mycolumn", + "UPDATE mytable SET mycolumn1 = mycolumn2 PREFERRING 1 = 1", + "UPDATE mytable SET mycolumn1 = mycolumn2 PREFERRING (HIGH mycolumn)", + "UPDATE mytable SET mycolumn1 = mycolumn2 PREFERRING INVERSE (HIGH mycolumn)", + "UPDATE mytable SET mycolumn1 = mycolumn2 PREFERRING HIGH mycolumn1 PRIOR TO LOW mycolumn2", + "UPDATE mytable SET mycolumn1 = mycolumn2 PREFERRING HIGH mycolumn1 PLUS LOW mycolumn2" + }) + public void testPreferringClause(String sqlStr) throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed(sqlStr); + } + + @Test + public void testUpdateWithBoolean() throws JSQLParserException { + String statement = "UPDATE mytable set col1='as', col2=true Where o >= 3"; + Update update = (Update) PARSER_MANAGER.parse(new StringReader(statement)); + assertEquals("mytable", update.getTable().toString()); + assertEquals(2, update.getUpdateSets().size()); + assertEquals("col1", update.getUpdateSets().get(0).getColumns().get(0).getColumnName()); + assertEquals("col2", update.getUpdateSets().get(1).getColumns().get(0).getColumnName()); + assertEquals("as", + ((StringValue) update.getUpdateSets().get(0).getValues().get(0)).getValue()); + assertInstanceOf(BooleanValue.class, update.getUpdateSets().get(1).getValues().get(0)); + assertTrue(((BooleanValue) update.getUpdateSets().get(1).getValues().get(0)).getValue()); + assertInstanceOf(GreaterThanEquals.class, update.getWhere()); + } + + @Test + public void testUpdateWithSkylineKeywords() throws JSQLParserException { + String statement = + "UPDATE mytable SET low = 1, high = 2, inverse = 3, plus = 4 WHERE id = 6"; + Update update = (Update) PARSER_MANAGER.parse(new StringReader(statement)); + assertEquals("mytable", update.getTable().toString()); + assertEquals(4, update.getUpdateSets().size()); + assertEquals("low", update.getUpdateSets().get(0).getColumns().get(0).getColumnName()); + assertEquals("high", update.getUpdateSets().get(1).getColumns().get(0).getColumnName()); + assertEquals("inverse", update.getUpdateSets().get(2).getColumns().get(0).getColumnName()); + assertEquals("plus", update.getUpdateSets().get(3).getColumns().get(0).getColumnName()); + assertInstanceOf(EqualsTo.class, update.getWhere()); + } + } diff --git a/src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java b/src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java index 508a2da03..3a01b890d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java @@ -108,6 +108,13 @@ public void testUpsertMultiRowValue() throws JSQLParserException { true); } + @Test + public void testUpsertMultiRowValueDoNothing() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "UPSERT INTO mytable (col1, col2) VALUES (a, b) ON DUPLICATE KEY UPDATE nothing", + true); + } + @Test @Disabled /* not the job of the parser to validate this, it even may be valid eventually */ diff --git a/src/test/java/net/sf/jsqlparser/statement/values/ValuesTest.java b/src/test/java/net/sf/jsqlparser/statement/values/ValuesTest.java index cc0eb5499..62a07a9ba 100644 --- a/src/test/java/net/sf/jsqlparser/statement/values/ValuesTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/values/ValuesTest.java @@ -64,4 +64,11 @@ public void testObject() { valuesStatement.accept(new StatementVisitorAdapter()); } + + @Test + public void testValuesWithAliasWithoutAs() throws JSQLParserException { + String sqlStr = "SELECT a, b, cume_dist() OVER (PARTITION BY a ORDER BY b) AS cume_dist\n" + + " FROM VALUES ('A1', 2), ('A1', 1), ('A2', 3), ('A1', 1) tab(a, b);"; + assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } } diff --git a/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java b/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java index 971a7f434..c0132155f 100644 --- a/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java +++ b/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java @@ -10,10 +10,14 @@ package net.sf.jsqlparser.test; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.Function; import net.sf.jsqlparser.expression.LongValue; import net.sf.jsqlparser.expression.StringValue; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.util.deparser.ExpressionDeParser; import net.sf.jsqlparser.util.deparser.SelectDeParser; import net.sf.jsqlparser.util.deparser.StatementDeParser; @@ -24,13 +28,15 @@ public class AssortedFeatureTests { static class ReplaceColumnAndLongValues extends ExpressionDeParser { @Override - public void visit(StringValue stringValue) { - this.getBuffer().append("?"); + public StringBuilder visit(StringValue stringValue, K parameters) { + this.getBuilder().append("?"); + return null; } @Override - public void visit(LongValue longValue) { - this.getBuffer().append("?"); + public StringBuilder visit(LongValue longValue, K parameters) { + this.getBuilder().append("?"); + return null; } } @@ -40,21 +46,73 @@ public static String cleanStatement(String sql) throws JSQLParserException { SelectDeParser selectDeparser = new SelectDeParser(expr, buffer); expr.setSelectVisitor(selectDeparser); - expr.setBuffer(buffer); + expr.setBuilder(buffer); StatementDeParser stmtDeparser = new StatementDeParser(expr, selectDeparser, buffer); Statement stmt = CCJSqlParserUtil.parse(sql); stmt.accept(stmtDeparser); - return stmtDeparser.getBuffer().toString(); + return stmtDeparser.getBuilder().toString(); } @Test public void testIssue1608() throws JSQLParserException { System.out.println(cleanStatement("SELECT 'abc', 5 FROM mytable WHERE col='test'")); - System.out.println(cleanStatement("UPDATE table1 A SET A.columna = 'XXX' WHERE A.cod_table = 'YYY'")); - System.out.println(cleanStatement("INSERT INTO example (num, name, address, tel) VALUES (1, 'name', 'test ', '1234-1234')")); + System.out.println( + cleanStatement("UPDATE table1 A SET A.columna = 'XXX' WHERE A.cod_table = 'YYY'")); + System.out.println(cleanStatement( + "INSERT INTO example (num, name, address, tel) VALUES (1, 'name', 'test ', '1234-1234')")); System.out.println(cleanStatement("DELETE FROM table1 where col=5 and col2=4")); } + + @Test + void addSelectItemTest() throws JSQLParserException { + String provided = "SELECT col1 FROM WHATEVER"; + String expected = "SELECT col1, Sum(1, 2) AS col2 FROM WHATEVER"; + + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(provided); + + Function f = new Function("Sum", new LongValue(1), new LongValue(2)); + SelectItem i = new SelectItem<>(f, new Alias("col2", true)); + + select + .getSelectItems() + .add(i); + + TestUtils.assertStatementCanBeDeparsedAs(select, expected); + } + + @Test + void removeSelectItemTest() throws JSQLParserException { + String provided = "SELECT col1, Sum(1, 2) AS col2 FROM WHATEVER"; + String expected = "SELECT col1 FROM WHATEVER"; + + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(provided); + + select + .getSelectItems() + .remove(1); + + TestUtils.assertStatementCanBeDeparsedAs(select, expected); + } + + @Test + void sweapSelectItemTest() throws JSQLParserException { + String provided = "SELECT col1 FROM WHATEVER"; + String expected = "SELECT Sum(1, 2) AS col1 FROM WHATEVER"; + + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(provided); + + Function f = new Function("Sum", new LongValue(1), new LongValue(2)); + SelectItem i = new SelectItem<>(f, new Alias("col1", true)); + select + .getSelectItems() + .remove(0); + select + .getSelectItems() + .add(0, i); + + TestUtils.assertStatementCanBeDeparsedAs(select, expected); + } } diff --git a/src/test/java/net/sf/jsqlparser/test/HowToUseSample.java b/src/test/java/net/sf/jsqlparser/test/HowToUseSample.java index 993436dc2..731e24e2c 100644 --- a/src/test/java/net/sf/jsqlparser/test/HowToUseSample.java +++ b/src/test/java/net/sf/jsqlparser/test/HowToUseSample.java @@ -118,7 +118,7 @@ public void howToParseStatement() throws JSQLParserException { PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); - SelectItem selectItem = + SelectItem selectItem = select.getSelectItems().get(0); Assertions.assertEquals( new LongValue(1), selectItem.getExpression()); @@ -138,30 +138,33 @@ public void howToUseVisitors() throws JSQLParserException { // Define an Expression Visitor reacting on any Expression // Overwrite the visit() methods for each Expression Class - ExpressionVisitorAdapter expressionVisitorAdapter = new ExpressionVisitorAdapter() { - public void visit(EqualsTo equalsTo) { - equalsTo.getLeftExpression().accept(this); - equalsTo.getRightExpression().accept(this); - } - - public void visit(Column column) { - System.out.println("Found a Column " + column.getColumnName()); - } - }; + ExpressionVisitorAdapter expressionVisitorAdapter = + new ExpressionVisitorAdapter() { + public Void visit(EqualsTo equalsTo, K context) { + equalsTo.getLeftExpression().accept(this, context); + equalsTo.getRightExpression().accept(this, context); + return null; + } + + public Void visit(Column column, K context) { + System.out.println("Found a Column " + column.getColumnName()); + return null; + } + }; // Define a Select Visitor reacting on a Plain Select invoking the Expression Visitor on the // Where Clause - SelectVisitorAdapter selectVisitorAdapter = new SelectVisitorAdapter() { + SelectVisitorAdapter selectVisitorAdapter = new SelectVisitorAdapter() { @Override - public void visit(PlainSelect plainSelect) { - plainSelect.getWhere().accept(expressionVisitorAdapter); + public Void visit(PlainSelect plainSelect, K context) { + return plainSelect.getWhere().accept(expressionVisitorAdapter, context); } }; // Define a Statement Visitor for dispatching the Statements - StatementVisitorAdapter statementVisitor = new StatementVisitorAdapter() { - public void visit(Select select) { - select.accept(selectVisitorAdapter); + StatementVisitorAdapter statementVisitor = new StatementVisitorAdapter() { + public Void visit(Select select, K context) { + return select.accept(selectVisitorAdapter, context); } }; diff --git a/src/test/java/net/sf/jsqlparser/test/MemoryLeakVerifier.java b/src/test/java/net/sf/jsqlparser/test/MemoryLeakVerifier.java index 112b6896d..f93e178c1 100644 --- a/src/test/java/net/sf/jsqlparser/test/MemoryLeakVerifier.java +++ b/src/test/java/net/sf/jsqlparser/test/MemoryLeakVerifier.java @@ -9,24 +9,23 @@ */ package net.sf.jsqlparser.test; -/* ==================================================================== - Taken from Apache POI, with a big thanks. - - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -==================================================================== */ +/* + * ==================================================================== Taken from Apache POI, with + * a big thanks. + * + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. ==================================================================== + */ import static org.junit.jupiter.api.Assertions.assertNull; @@ -40,28 +39,21 @@ Licensed to the Apache Software Foundation (ASF) under one or more * * Usage is something like * - * private final MemoryLeakVerifier verifier = new MemoryLeakVerifier(); - - {@literal}After - void tearDown() { - verifier.assertGarbageCollected(); - } - - {@literal}Test - void someTest() { - ... - verifier.addObject(object); - } - + * private final MemoryLeakVerifier verifier = new MemoryLeakVerifier(); + * + * {@literal}After void tearDown() { verifier.assertGarbageCollected(); } + * + * {@literal}Test void someTest() { ... verifier.addObject(object); } * - * This will verify at the end of the test if the object is actually removed by the - * garbage collector or if it lingers in memory for some reason. + * + * This will verify at the end of the test if the object is actually removed by the garbage + * collector or if it lingers in memory for some reason. * * Idea taken from http://stackoverflow.com/a/7410460/411846 */ public class MemoryLeakVerifier { private static final int MAX_GC_ITERATIONS = 50; - private static final int GC_SLEEP_TIME = 100; + private static final int GC_SLEEP_TIME = 100; private final List> references = new ArrayList<>(); @@ -70,13 +62,15 @@ public void addObject(Object object) { } /** - * Attempts to perform a full garbage collection so that all weak references will be removed. Usually only - * a single GC is required, but there have been situations where some unused memory is not cleared up on the - * first pass. This method performs a full garbage collection and then validates that the weak reference - * now has been cleared. If it hasn't then the thread will sleep for 100 milliseconds and then retry up to - * 50 more times. If after this the object still has not been collected then the assertion will fail. + * Attempts to perform a full garbage collection so that all weak references will be removed. + * Usually only a single GC is required, but there have been situations where some unused memory + * is not cleared up on the first pass. This method performs a full garbage collection and then + * validates that the weak reference now has been cleared. If it hasn't then the thread will + * sleep for 100 milliseconds and then retry up to 50 more times. If after this the object still + * has not been collected then the assertion will fail. * - * Based upon the method described in: http://www.javaworld.com/javaworld/javatips/jw-javatip130.html + * Based upon the method described in: + * http://www.javaworld.com/javaworld/javatips/jw-javatip130.html */ public void assertGarbageCollected() { assertGarbageCollected(MAX_GC_ITERATIONS); @@ -84,7 +78,9 @@ public void assertGarbageCollected() { /** * Used only for testing the class itself where we would like to fail faster than 5 seconds - * @param maxIterations The number of times a GC will be invoked until a possible memory leak is reported + * + * @param maxIterations The number of times a GC will be invoked until a possible memory leak is + * reported */ void assertGarbageCollected(int maxIterations) { try { @@ -96,7 +92,8 @@ void assertGarbageCollected(int maxIterations) { } } - private static void assertGarbageCollected(WeakReference ref, int maxIterations) throws InterruptedException { + private static void assertGarbageCollected(WeakReference ref, int maxIterations) + throws InterruptedException { Runtime runtime = Runtime.getRuntime(); for (int i = 0; i < maxIterations; i++) { runtime.runFinalization(); @@ -106,11 +103,13 @@ private static void assertGarbageCollected(WeakReference ref, int maxIte } // Pause for a while and then go back around the loop to try again... - //EventQueue.invokeAndWait(Procedure.NoOp); // Wait for the AWT event queue to have completed processing + // EventQueue.invokeAndWait(Procedure.NoOp); // Wait for the AWT event queue to have + // completed processing Thread.sleep(GC_SLEEP_TIME); } - assertNull(ref.get(), "Object should not exist after " + MAX_GC_ITERATIONS + " collections, but still had: " + ref.get()); + assertNull(ref.get(), "Object should not exist after " + MAX_GC_ITERATIONS + + " collections, but still had: " + ref.get()); } } diff --git a/src/test/java/net/sf/jsqlparser/test/TestUtils.java b/src/test/java/net/sf/jsqlparser/test/TestUtils.java index df6b8b69d..b41497ed0 100644 --- a/src/test/java/net/sf/jsqlparser/test/TestUtils.java +++ b/src/test/java/net/sf/jsqlparser/test/TestUtils.java @@ -312,7 +312,7 @@ public static void assertDeparse(Statement stmt, String statement, boolean laxDe StatementDeParser deParser = new StatementDeParser(new StringBuilder()); stmt.accept(deParser); assertEquals(buildSqlString(statement, laxDeparsingCheck), - buildSqlString(deParser.getBuffer().toString(), laxDeparsingCheck)); + buildSqlString(deParser.getBuilder().toString(), laxDeparsingCheck)); } public static String buildSqlString(final String originalSql, boolean laxDeparsingCheck) { @@ -359,10 +359,10 @@ public void testBuildSqlString() { public static void assertExpressionCanBeDeparsedAs(final Expression parsed, String expression) { ExpressionDeParser expressionDeParser = new ExpressionDeParser(); StringBuilder stringBuilder = new StringBuilder(); - expressionDeParser.setBuffer(stringBuilder); + expressionDeParser.setBuilder(stringBuilder); SelectDeParser selectDeParser = new SelectDeParser(expressionDeParser, stringBuilder); expressionDeParser.setSelectVisitor(selectDeParser); - parsed.accept(expressionDeParser); + parsed.accept(expressionDeParser, null); assertEquals(expression, stringBuilder.toString()); } diff --git a/src/test/java/net/sf/jsqlparser/util/AddAliasesVisitorTest.java b/src/test/java/net/sf/jsqlparser/util/AddAliasesVisitorTest.java index e079a9427..6a8a919e5 100644 --- a/src/test/java/net/sf/jsqlparser/util/AddAliasesVisitorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/AddAliasesVisitorTest.java @@ -20,7 +20,7 @@ public class AddAliasesVisitorTest { - private CCJSqlParserManager parserManager = new CCJSqlParserManager(); + private final CCJSqlParserManager parserManager = new CCJSqlParserManager(); /** * Test of visit method, of class AddAliasesVisitor. @@ -29,8 +29,8 @@ public class AddAliasesVisitorTest { public void testVisit_PlainSelect() throws JSQLParserException { String sql = "select a,b,c from test"; Select select = (Select) parserManager.parse(new StringReader(sql)); - final AddAliasesVisitor instance = new AddAliasesVisitor(); - select.accept(instance); + final AddAliasesVisitor instance = new AddAliasesVisitor<>(); + select.accept(instance, null); assertEquals("SELECT a AS A1, b AS A2, c AS A3 FROM test", select.toString()); } @@ -39,8 +39,8 @@ public void testVisit_PlainSelect() throws JSQLParserException { public void testVisit_PlainSelect_duplicates() throws JSQLParserException { String sql = "select a,b as a1,c from test"; Select select = (Select) parserManager.parse(new StringReader(sql)); - final AddAliasesVisitor instance = new AddAliasesVisitor(); - select.accept(instance); + final AddAliasesVisitor instance = new AddAliasesVisitor<>(); + select.accept(instance, null); assertEquals("SELECT a AS A2, b AS a1, c AS A3 FROM test", select.toString()); } @@ -49,8 +49,8 @@ public void testVisit_PlainSelect_duplicates() throws JSQLParserException { public void testVisit_PlainSelect_expression() throws JSQLParserException { String sql = "select 3+4 from test"; Select select = (Select) parserManager.parse(new StringReader(sql)); - final AddAliasesVisitor instance = new AddAliasesVisitor(); - select.accept(instance); + final AddAliasesVisitor instance = new AddAliasesVisitor<>(); + select.accept(instance, null); assertEquals("SELECT 3 + 4 AS A1 FROM test", select.toString()); } @@ -62,8 +62,8 @@ public void testVisit_PlainSelect_expression() throws JSQLParserException { public void testVisit_SetOperationList() throws JSQLParserException { String sql = "select 3+4 from test union select 7+8 from test2"; Select setOpList = (Select) parserManager.parse(new StringReader(sql)); - final AddAliasesVisitor instance = new AddAliasesVisitor(); - setOpList.accept(instance); + final AddAliasesVisitor instance = new AddAliasesVisitor<>(); + setOpList.accept(instance, null); assertEquals("SELECT 3 + 4 AS A1 FROM test UNION SELECT 7 + 8 AS A1 FROM test2", setOpList.toString()); diff --git a/src/test/java/net/sf/jsqlparser/util/ConnectExpressionsVisitorTest.java b/src/test/java/net/sf/jsqlparser/util/ConnectExpressionsVisitorTest.java index 7f3902368..712e1950f 100644 --- a/src/test/java/net/sf/jsqlparser/util/ConnectExpressionsVisitorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/ConnectExpressionsVisitorTest.java @@ -23,19 +23,19 @@ public class ConnectExpressionsVisitorTest { - private CCJSqlParserManager parserManager = new CCJSqlParserManager(); + private final CCJSqlParserManager parserManager = new CCJSqlParserManager(); @Test public void testVisit_PlainSelect_concat() throws JSQLParserException { String sql = "select a,b,c from test"; Select select = (Select) parserManager.parse(new StringReader(sql)); - ConnectExpressionsVisitor instance = new ConnectExpressionsVisitor() { + ConnectExpressionsVisitor instance = new ConnectExpressionsVisitor<>() { @Override protected BinaryExpression createBinaryExpression() { return new Concat(); } }; - select.accept(instance); + select.accept(instance, null); assertEquals("SELECT a || b || c AS expr FROM test", select.toString()); } @@ -44,13 +44,13 @@ protected BinaryExpression createBinaryExpression() { public void testVisit_PlainSelect_addition() throws JSQLParserException { String sql = "select a,b,c from test"; Select select = (Select) parserManager.parse(new StringReader(sql)); - ConnectExpressionsVisitor instance = new ConnectExpressionsVisitor("testexpr") { + ConnectExpressionsVisitor instance = new ConnectExpressionsVisitor<>("testexpr") { @Override protected BinaryExpression createBinaryExpression() { return new Addition(); } }; - select.accept(instance); + select.accept(instance, null); assertEquals("SELECT a + b + c AS testexpr FROM test", select.toString()); } diff --git a/src/test/java/net/sf/jsqlparser/util/RandomUtils.java b/src/test/java/net/sf/jsqlparser/util/RandomUtils.java index 23beb02a7..dfd527999 100644 --- a/src/test/java/net/sf/jsqlparser/util/RandomUtils.java +++ b/src/test/java/net/sf/jsqlparser/util/RandomUtils.java @@ -69,7 +69,8 @@ public static void pushObjects(List obj) { /** * @param * @param type - * @return a random non-null value for given type or null if not supported. + * @return a random non-null value for given type or null if not + * supported. */ public static T getRandomValueForType(Class type) { Object value = null; @@ -125,14 +126,18 @@ public static T getRandomValueForType(Class type) { if (type.isEnum()) { @SuppressWarnings("unchecked") EnumSet enums = EnumSet.allOf(type.asSubclass(Enum.class)); - value = new ArrayList<>(enums).get(RandomUtils.RANDOM.nextInt(enums.size())); + value = new ArrayList<>(enums) + .get(RandomUtils.RANDOM.nextInt(enums.size())); } else { try { value = type.getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException - | InvocationTargetException | NoSuchMethodException | SecurityException e) { + } catch (InstantiationException | IllegalAccessException + | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException + | SecurityException e) { // cannot get default instance with empty constructor - LOG.log(Level.WARNING, "cannot get default instance with reflection for type " + type); + LOG.log(Level.WARNING, + "cannot get default instance with reflection for type " + type); } } } diff --git a/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java b/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java index df6bca701..07dec9f07 100644 --- a/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java +++ b/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java @@ -30,13 +30,15 @@ */ public class ReflectionTestUtils { - public static final Predicate GETTER_METHODS = m -> !void.class.isAssignableFrom(m.getReturnType()) - && m.getParameterCount() == 0 - && (m.getName().startsWith("get") || m.getName().startsWith("is")); + public static final Predicate GETTER_METHODS = + m -> !void.class.isAssignableFrom(m.getReturnType()) + && m.getParameterCount() == 0 + && (m.getName().startsWith("get") || m.getName().startsWith("is")); - public static final Predicate SETTER_METHODS = m -> void.class.isAssignableFrom(m.getReturnType()) - && m.getParameterCount() == 1 - && m.getName().startsWith("set"); + public static final Predicate SETTER_METHODS = + m -> void.class.isAssignableFrom(m.getReturnType()) + && m.getParameterCount() == 1 + && m.getName().startsWith("set"); public static final Predicate CHAINING_METHODS = m -> m.getDeclaringClass() .isAssignableFrom(m.getReturnType()) @@ -51,21 +53,27 @@ public class ReflectionTestUtils { * * * @param objs - * @param testMethodFilter - additional filter to skip some methods (by returning false). - * Default-Filters: null {@link #notDeclaredInObjectClass(Method)}, - * {@link #GETTER_METHODS}, {@link #SETTER_METHODS}, - * {@link #CHAINING_METHODS} + * @param testMethodFilter - additional filter to skip some methods (by returning + * false). Default-Filters: null {@link #notDeclaredInObjectClass(Method)}, + * {@link #GETTER_METHODS}, {@link #SETTER_METHODS}, {@link #CHAINING_METHODS} */ @SafeVarargs - public static void testGetterSetterChaining(List objs, Predicate... testMethodFilter) { + public static void testGetterSetterChaining(List objs, + Predicate... testMethodFilter) { RandomUtils.pushObjects(objs); objs.forEach(o -> { - testMethodInvocation(o, ReflectionTestUtils::anyReturnType, ReflectionTestUtils::reflectiveNonNullArgs, - ArrayUtils.insert(0, testMethodFilter, GETTER_METHODS, ReflectionTestUtils::notDeclaredInObjectClass)); - testMethodInvocation(o, ReflectionTestUtils::noReturnTypeValid, ReflectionTestUtils::reflectiveNonNullArgs, - ArrayUtils.insert(0, testMethodFilter, SETTER_METHODS, ReflectionTestUtils::notDeclaredInObjectClass)); - testMethodInvocation(o, ReflectionTestUtils::returnTypeThis, ReflectionTestUtils::reflectiveNonNullArgs, - ArrayUtils.insert(0, testMethodFilter, CHAINING_METHODS, ReflectionTestUtils::notDeclaredInObjectClass)); + testMethodInvocation(o, ReflectionTestUtils::anyReturnType, + ReflectionTestUtils::reflectiveNonNullArgs, + ArrayUtils.insert(0, testMethodFilter, GETTER_METHODS, + ReflectionTestUtils::notDeclaredInObjectClass)); + testMethodInvocation(o, ReflectionTestUtils::noReturnTypeValid, + ReflectionTestUtils::reflectiveNonNullArgs, + ArrayUtils.insert(0, testMethodFilter, SETTER_METHODS, + ReflectionTestUtils::notDeclaredInObjectClass)); + testMethodInvocation(o, ReflectionTestUtils::returnTypeThis, + ReflectionTestUtils::reflectiveNonNullArgs, + ArrayUtils.insert(0, testMethodFilter, CHAINING_METHODS, + ReflectionTestUtils::notDeclaredInObjectClass)); }); } @@ -117,10 +125,11 @@ private static boolean noReturnTypeValid(Object returnValue, Method m) { * @param methodFilters */ @SafeVarargs - public static void testMethodInvocation(Object object, BiPredicate returnTypeCheck, + public static void testMethodInvocation(Object object, + BiPredicate returnTypeCheck, Function argsFunction, Predicate... methodFilters) { - log(Level.INFO, "testing methods of class " + object.getClass()); + log(Level.FINE, "testing methods of class " + object.getClass()); for (Method m : object.getClass().getMethods()) { boolean testMethod = true; for (Predicate f : methodFilters) { @@ -131,13 +140,14 @@ public static void testMethodInvocation(Object object, BiPredicate returnValue try { Object returnValue = method.invoke(object, argsFunction.apply(method)); if (!void.class.isAssignableFrom(method.getReturnType())) { - assertTrue(returnValueCheck.test(returnValue, method), "unexpected return-value with type " + returnValue.getClass() + " for method " - + method.toGenericString()); + assertTrue(returnValueCheck.test(returnValue, method), + "unexpected return-value with type " + returnValue.getClass() + + " for method " + + method.toGenericString()); } } catch (TestAbortedException tae) { - log(Level.INFO, "skip methods " + method.toGenericString() + ", detail: " + tae.getMessage()); + log(Level.INFO, + "skip methods " + method.toGenericString() + ", detail: " + tae.getMessage()); } } diff --git a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java index a1ee09040..44a27624c 100644 --- a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java +++ b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java @@ -9,6 +9,16 @@ */ package net.sf.jsqlparser.util; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.OracleHint; import net.sf.jsqlparser.parser.CCJSqlParserUtil; @@ -21,14 +31,6 @@ import net.sf.jsqlparser.test.TestUtils; import org.junit.jupiter.api.Test; -import java.util.Set; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - public class TablesNamesFinderTest { @Test @@ -52,6 +54,14 @@ public void testGetTablesWithXor() throws Exception { assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1"); } + @Test + public void testGetTablesWithPreWhere() throws Exception { + String sqlStr = + "SELECT * FROM MY_TABLE1 PREWHERE ID IN (SELECT ID FROM MY_TABLE2)"; + assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1", + "MY_TABLE2"); + } + @Test public void testGetTablesWithStmt() throws Exception { String sqlStr = @@ -105,6 +115,25 @@ public void testGetTablesFromInsertValues() throws Exception { assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1"); } + @Test + public void testGetTablesFromOracleInsertAll() throws Exception { + String sqlStr = + "INSERT ALL INTO MY_TABLE1 (a) VALUES (1) INTO MY_TABLE2 (a) VALUES (2) SELECT * FROM dual"; + assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1", + "MY_TABLE2", "dual"); + } + + @Test + public void testGetTablesFromOracleInsertAllWhenElse() throws Exception { + String sqlStr = + "INSERT ALL WHEN EXISTS (SELECT 1 FROM CHECK_TABLE c WHERE c.id = s.id) " + + "THEN INTO MY_TABLE1 (a) VALUES (a) " + + "ELSE INTO MY_TABLE2 (a) VALUES (a) " + + "SELECT a, id FROM SOURCE_TABLE s"; + assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("MY_TABLE1", + "MY_TABLE2", "CHECK_TABLE", "SOURCE_TABLE"); + } + @Test public void testGetTablesFromReplace() throws Exception { String sqlStr = "REPLACE INTO MY_TABLE1 (a) VALUES ((SELECT a from MY_TABLE2 WHERE a = 1))"; @@ -150,12 +179,19 @@ public void testInsertSelect() throws Exception { } @Test - public void testCreateSelect() throws Exception { + public void testCreateTableSelect() throws Exception { String sqlStr = "CREATE TABLE mytable AS SELECT mycolumn FROM mytable2"; assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("mytable", "mytable2"); } + @Test + public void testCreateViewSelect() throws Exception { + String sqlStr = "CREATE VIEW mytable AS SELECT mycolumn FROM mytable2"; + assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("mytable", + "mytable2"); + } + @Test public void testInsertSubSelect() throws JSQLParserException { String sqlStr = @@ -176,12 +212,13 @@ public void testOracleHint() throws JSQLParserException { String sql = "select --+ HINT\ncol2 from mytable"; PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sql); final OracleHint[] holder = new OracleHint[1]; - TablesNamesFinder tablesNamesFinder = new TablesNamesFinder() { + TablesNamesFinder tablesNamesFinder = new TablesNamesFinder() { @Override - public void visit(OracleHint hint) { - super.visit(hint); + public Void visit(OracleHint hint, K parameters) { + super.visit(hint, parameters); holder[0] = hint; + return null; } }; @@ -193,7 +230,7 @@ public void visit(OracleHint hint) { public void testGetTablesIssue194() throws Exception { String sql = "SELECT 1"; Statement statement = TestUtils.assertSqlCanBeParsedAndDeparsed(sql, true); - TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); + TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); Set tableList = tablesNamesFinder.getTables(statement); assertEquals(0, tableList.size()); } @@ -470,6 +507,13 @@ void testOtherSources() throws JSQLParserException { assertThat(tables).containsExactly("Datetimes"); } + @Test + void testLockStatement() throws JSQLParserException { + String sqlStr = "LOCK TABLE A IN EXCLUSIVE MODE"; + Set tables = TablesNamesFinder.findTablesOrOtherSources(sqlStr); + assertThat(tables).containsExactly("A"); + } + @Test void testSubqueryAliasesIssue1987() throws JSQLParserException { String sqlStr = "select * from (select * from a) as a1, b;"; @@ -495,6 +539,236 @@ void testSubqueryAliasesIssue1987() throws JSQLParserException { tables = TablesNamesFinder.findTables(sqlStr); assertThat(tables).containsExactlyInAnyOrder("a", "b"); assertThat(tables).doesNotContain("a1"); + + sqlStr = "select (a_alias.col1), b_alias.col2\n" + + "from b b_alias, a as a_alias, c join b on c.id = b.id\n" + + "where b_alias.id = a_alias.id and c.id = b_alias.id"; + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("a", "b", "c"); + + sqlStr = "with\n" + + "temp1 as (( select * from b )),\n" + + "temp2 as ( select (((temp1_alias1.id))) from temp1 temp1_alias1 )\n" + + "select a_alias.col1, temp1_alias2.col2\n" + + "from temp1 temp1_alias2, a as a_alias, temp2 join c c_alias on c_alias.id = temp2.id\n" + + + "where c.id = temp1_alias2.id"; + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("a", "b", "c"); + + sqlStr = "select a.id, (select max(val) from e) as maxval\n" + + "from a, (select * from b, (select * from c) c_alias) as bc_nested\n" + + " where a.id in ( select id from bc_nested join (select * from d) d_alias on bc_nested.id = d_alias.id ) \n" + + + " and a.max > (select max(val) from bc_nested, f) and a.desc like 'abc'"; + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("a", "b", "c", "d", "e", "f"); + + sqlStr = " select (select max(val) from e) as maxval, id\n" + + " from (select * from b, (select * from c) c_alias) as bc_nested, a\n" + + " where a.max > (select max(val) from bc_nested, f) and \n" + + " a.id in ( select id from (select * from d) d_alias join bc_nested on bc_nested.id = d_alias.id )"; + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("a", "b", "c", "d", "e", "f"); + + sqlStr = "select a.id, bc_nested.id\n" + + " from (select * from b, (select * from c) c_alias) as bc_nested, a\n" + + " where a.id in (((\n" + + " select id from d join \n" + + " (select * from bc_nested join \n" + + " (select * from e) e_alias on bc_nested.id = e_alias.id\n" + + " ) bc_nested_alias \n" + + " on bc_nested_alias.id = d.id\n" + + " )))"; + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("a", "b", "c", "d", "e"); + + sqlStr = "select id\n" + + "from (select * from c, (select * from b) b_alias) as bc_nested, a\n" + + "where a.id in (\n" + + "select id from (select * from d \n" + + "join (select * from e) e_alias on d.id = e_alias.id) bc_nested_alias\n" + + "join bc_nested on bc_nested_alias.id = bc_nested.id\n" + + ")"; + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("a", "b", "c", "d", "e"); + + sqlStr = "with\n" + + " temp1 as (\n" + + " select a1.id as id, b.content as content from a a1\n" + + " join b on a1.id = b.id\n" + + " ),\n" + + " temp2 as (\n" + + " select b.id as id, b.value as value from b, c cross join temp1 where\n" + + " b.id = c.id and b.value = \"b.value\"\n" + + " )\n" + + "select temp1.id, ( select tid from d where cid = 29974 ) as tid \n" + + "from ( select tid from e, (select * from f) where cid = 29974) e_alias, temp1 cross join temp2\n" + + + "where exist ( select * from e, e_alias where e.test = dtest.test ) and temp1.max = (select max(column_1) from g)"; + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("a", "b", "c", "d", "e", "f", "g"); + } + + @Test + void testSubqueryAliasesIssue2035() throws JSQLParserException { + String sqlStr = "SELECT * FROM (SELECT * FROM A) AS A \n" + + "JOIN B ON A.a = B.a \n" + + "JOIN C ON A.a = C.a;"; + Set tables = TablesNamesFinder.findTablesOrOtherSources(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("A", "B", "C"); + + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("B", "C"); + } + + @Test + void testTableRenamingIssue2028() throws JSQLParserException { + List IGNORE_SCHEMAS = + Arrays.asList("mysql", "information_schema", "performance_schema"); + final String prefix = "test_"; + + //@formatter:off + String sql = + "UPDATE table_1 a\n" + + "SET a.a1 = ( SELECT b1\n" + + " FROM table_2 b\n" + + " WHERE b.xx = 'xx' )\n" + + " , a.a2 = ( SELECT b2\n" + + " FROM table_2 b\n" + + " WHERE b.yy = 'yy' )\n" + + ";"; + String expected = + "UPDATE test_table_1 a\n" + + "SET a.a1 = ( SELECT b1\n" + + " FROM test_table_2 b\n" + + " WHERE b.xx = 'xx' )\n" + + " , a.a2 = ( SELECT b2\n" + + " FROM test_table_2 b\n" + + " WHERE b.yy = 'yy' )\n" + + ";"; + //@formatter:on + + TablesNamesFinder finder = new TablesNamesFinder<>() { + @Override + public Void visit(Table table, S context) { + String schemaName = table.getSchemaName(); + if (schemaName != null && IGNORE_SCHEMAS.contains(schemaName.toLowerCase())) { + return super.visit(table, context); + } + String originTableName = table.getName(); + table.setName(prefix + originTableName); + if (originTableName.startsWith("`")) { + table.setName("`" + prefix + originTableName.replace("`", "") + "`"); + } + return super.visit(table, context); + } + }; + finder.init(false); + + Statement statement = CCJSqlParserUtil.parse(sql); + statement.accept(finder); + + TestUtils.assertStatementCanBeDeparsedAs(statement, expected, true); + } + + @Test + void testAlterTableIssue2062() throws JSQLParserException { + String sqlStr = "ALTER TABLE the_cool_db.the_table\n" + + " ADD test VARCHAR (40)\n" + + ";"; + Set tables = TablesNamesFinder.findTablesOrOtherSources(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("the_cool_db.the_table"); + + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("the_cool_db.the_table"); + } + + @Test + void testInsertTableIssue() throws JSQLParserException { + String sqlStr = "INSERT INTO the_cool_db.the_table\n" + + " VALUES ( 'something' ) \n" + + ";"; + Set tables = TablesNamesFinder.findTablesOrOtherSources(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("the_cool_db.the_table"); + + tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("the_cool_db.the_table"); + } + + @Test + void testIssue2183() throws JSQLParserException { + String sqlStr = "SELECT\n" + + "\tsubscriber_id,\n" + + "\tsum(1) OVER (PARTITION BY subscriber_id\n" + + "ORDER BY\n" + + "\tstat_time ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS stop_id\n" + + "FROM\n" + + "\t(\n" + + "\tSELECT\n" + + "\t\tsubscriber_id,\n" + + "\t\tstat_time\n" + + "\tFROM\n" + + "\t\tlocation_subscriber AS mid2 WINDOW w AS (PARTITION BY subscriber_id\n" + + "\tORDER BY\n" + + "\t\tstat_time ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING ) )"; + Set tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("location_subscriber"); + } + + @Test + void testIssue2305() throws JSQLParserException { + String sqlStr = "SELECT tbl.fk_id\n" + + " , tbl.etape\n" + + "FROM ( tbl\n" + + " JOIN ( SELECT tbl_1.fk_id\n" + + " , Max( tbl_1.date1 ) AS max_1\n" + + " FROM tbl tbl_1\n" + + " GROUP BY tbl_1.fk_id ) sub2\n" + + " ON ( ( ( sub2.fk_id = tbl.fk_id )\n" + + " AND ( sub2.max_1 = tbl.date1 ) ) ) )\n" + + ";"; + Set tables = TablesNamesFinder.findTables(sqlStr); + assertThat(tables).containsExactlyInAnyOrder("tbl"); } -} + @Test + void assertWithItemWithFunctionDeclarationDoesNotThrowException() throws JSQLParserException { + String sqlStr = + "WITH FUNCTION my_with_item(param1 INT) RETURNS INT RETURN param1 + 1 SELECT * FROM my_table;"; + assertThatCode(() -> TablesNamesFinder.findTables(sqlStr)) + .doesNotThrowAnyException(); + } + + @Test + void assertWithItemWithFunctionDeclarationReturnsTableInSelect() throws JSQLParserException { + String sqlStr = + "WITH FUNCTION my_with_item(param1 INT) RETURNS INT RETURN param1 + 1 SELECT * FROM my_table;"; + assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactly("my_table"); + } + + @Test + void testNestedTablesInJsonObject() throws JSQLParserException { + String sqlStr = "select JSON_OBJECT(\n" + + " t1.*, \n" + + " nested1 : (SELECT JSON_OBJECT(tn2.*) FROM table2 tn2 WHERE tn2.fk = t1.pk), \n" + + " nested2 : (SELECT JSON_OBJECT(tn3.*) FROM table3 tn3 WHERE tn3.fk = t1.pk)\n" + + " )\n" + + "FROM table1 t1;"; + + assertThat(TablesNamesFinder.findTables(sqlStr)).containsExactlyInAnyOrder("table1", + "table2", "table3"); + } + + @Test + void testJsonTable() throws JSQLParserException { + String sqlStr = "SELECT * FROM JSON_TABLE(" + + "(SELECT json_column FROM table_with_json), '$.jsonPath' COLUMNS( id FOR ORDINALITY ))"; + + Set tables = TablesNamesFinder.findTables(sqlStr); + + assertThat(tables).containsExactly("table_with_json"); + + } + +} diff --git a/src/test/java/net/sf/jsqlparser/util/cnfexpression/CNFTest.java b/src/test/java/net/sf/jsqlparser/util/cnfexpression/CNFTest.java index d7b1f288d..cb67e9ca7 100644 --- a/src/test/java/net/sf/jsqlparser/util/cnfexpression/CNFTest.java +++ b/src/test/java/net/sf/jsqlparser/util/cnfexpression/CNFTest.java @@ -20,18 +20,19 @@ public class CNFTest { /** - * The purpose of this method is to check when there is a Not Operator at the root. Which means the root must be - * switched. + * The purpose of this method is to check when there is a Not Operator at the root. Which means + * the root must be switched. * * Here is the expression tree: * - * NOT | ( ) | AND / \ ( ) ( ) | | OR OR / \ / \ - * < = != >= / \ / \ / \ / \ 1.2 2.3 3.5 4.6 1.1 2.5 8.0 7.2 + * NOT | ( ) | AND / \ ( ) ( ) | | OR OR / \ / \ < = != >= / \ / \ / \ / \ 1.2 2.3 3.5 4.6 1.1 + * 2.5 8.0 7.2 * * Here is the converted expression tree: * - * AND / \ AND ( ) / \ | AND ( ) OR / \ | / \ ( ) ( ) OR NOT NOT | | / \ | | OR OR NOT NOT = >= / \ / \ | | / \ / \ - * NOT NOT NOT NOT = != 3.5 4.6 8.0 7.2 | | | | / \ / \ < != < >= / \ / \ / \ / \ 1.2 2.3 1.1 2.5 1.2 2.3 8.0 7.2 + * AND / \ AND ( ) / \ | AND ( ) OR / \ | / \ ( ) ( ) OR NOT NOT | | / \ | | OR OR NOT NOT = >= + * / \ / \ | | / \ / \ NOT NOT NOT NOT = != 3.5 4.6 8.0 7.2 | | | | / \ / \ < != < >= / \ / \ / + * \ / \ 1.2 2.3 1.1 2.5 1.2 2.3 8.0 7.2 * */ @Test @@ -40,249 +41,133 @@ public void test1() throws Exception { "NOT ((1.2 < 2.3 OR 3.5 = 4.6) AND (1.1 <> 2.5 OR 8.0 >= 7.2))"); Expression expected = CCJSqlParserUtil.parseCondExpression( "(NOT 1.2 < 2.3 OR NOT 1.1 <> 2.5) AND (NOT 1.2 < 2.3 OR NOT 8.0 >= 7.2) AND" - + " (NOT 3.5 = 4.6 OR NOT 1.1 <> 2.5) AND (NOT 3.5 = 4.6 OR NOT 8.0 >= 7.2)"); + + " (NOT 3.5 = 4.6 OR NOT 1.1 <> 2.5) AND (NOT 3.5 = 4.6 OR NOT 8.0 >= 7.2)"); Expression result = CNFConverter.convertToCNF(expr); assertEquals(expected.toString(), result.toString()); } /** - * The purpose is to test the double negation law. As you can see when you build the tree, there will be two Not - * Operators together on the line. It is there when we use the double negation law. + * The purpose is to test the double negation law. As you can see when you build the tree, there + * will be two Not Operators together on the line. It is there when we use the double negation + * law. * - * Here is the expression tree: ( ) | OR / \ ( ) ( ) | | NOT AND | / \ ( ) LIKE = | / \ / \ OR S.A "%%%" S.B "orz" / - * \ NOT < - * | / \ - * >= 3.3 4.5 / \ 1.1 2.3 + * Here is the expression tree: ( ) | OR / \ ( ) ( ) | | NOT AND | / \ ( ) LIKE = | / \ / \ OR + * S.A "%%%" S.B "orz" / \ NOT < | / \ >= 3.3 4.5 / \ 1.1 2.3 * * Here is the converted expression tree: * - * AND / \ AND ( ) / \ | AND ( ) OR / \ | / \ ( ) ( ) OR NOT = | | / \ | / \ OR OR NOT LIKE < S.B "orz" - * / \ / \ | / \ / \ - * >= LIKE >= = < S.A "%%%" 3.3 4.5 / \ / \ / \ / \ 1.1 2.3 S.A "%%%" 1.1 2.3 S.B "orz" + * AND / \ AND ( ) / \ | AND ( ) OR / \ | / \ ( ) ( ) OR NOT = | | / \ | / \ OR OR NOT LIKE < + * S.B "orz" / \ / \ | / \ / \ >= LIKE >= = < S.A "%%%" 3.3 4.5 / \ / \ / \ / \ 1.1 2.3 S.A + * "%%%" 1.1 2.3 S.B "orz" * */ @Test public void test2() throws Exception { Expression expr = CCJSqlParserUtil.parseCondExpression( "((NOT (NOT 1.1 >= 2.3 OR 3.3 < 4.5)) OR " - + "(S.A LIKE '\"%%%\"' AND S.B = '\"orz\"'))"); + + "(S.A LIKE '\"%%%\"' AND S.B = '\"orz\"'))"); Expression expected = CCJSqlParserUtil.parseCondExpression( - "(1.1 >= 2.3 OR S.A LIKE '\"%%%\"') AND (1.1 >= 2.3 OR S.B = '\"orz\"')" - + " AND (NOT 3.3 < 4.5 OR S.A LIKE '\"%%%\"') AND (NOT 3.3 < 4.5 OR S.B = '\"orz\"')"); + "(1.1 >= 2.3 OR S.A LIKE '\"%%%\"') AND (1.1 >= 2.3 OR S.B = '\"orz\"') AND (NOT 3.3 < 4.5 OR S.A LIKE '\"%%%\"') AND (NOT 3.3 < 4.5 OR S.B = '\"orz\"')"); Expression result = CNFConverter.convertToCNF(expr); assertEquals(expected.toString(), result.toString()); } /** - * This is the case when we test a more complex tree structure, Notice you could see the amount of line to build up - * the CNF tree. You could tell how complicated the CNF could be. + * This is the case when we test a more complex tree structure, Notice you could see the amount + * of line to build up the CNF tree. You could tell how complicated the CNF could be. * - * OR / \ ( ) ( ) | | AND OR / \ / \ >= <= ( ) NOT / \ / \ | | 7.0 8.0 9.0 10.0 AND OR / \ / \ ( ) = != ( ) | / \ / - * \ | AND 11.0 12.0 13.0 14.0 AND / \ / \ < > = ( ) - * / \ / \ / \ | - * 7.0 8.0 9.0 10.0 15.0 16.0 OR / \ = > / \ / \ 17.0 18.0 19.0 20.0 + * OR / \ ( ) ( ) | | AND OR / \ / \ >= <= ( ) NOT / \ / \ | | 7.0 8.0 9.0 10.0 AND OR / \ / \ ( + * ) = != ( ) | / \ / \ | AND 11.0 12.0 13.0 14.0 AND / \ / \ < > = ( ) / \ / \ / \ | 7.0 8.0 + * 9.0 10.0 15.0 16.0 OR / \ = > / \ / \ 17.0 18.0 19.0 20.0 * * Here is the converted expression tree: * - * AND / \ AND ( ) / \ | AND ( ) part18 / \ | AND ( ) part17 / \ | AND ( ) part16 / \ | AND ( ) part15 / \ | AND ( ) - * part14 / \ | AND ( ) part13 / \ | AND ( ) part12 / \ | AND ( ) part11 / \ | AND ( ) part10 / \ | AND ( ) part9 / - * \ | AND ( ) part8 / \ | AND ( ) part7 / \ | AND ( ) part6 / \ | AND ( ) part5 / \ | AND ( ) part4 / \ | ( ) ( ) - * part3 | | part1 part2 - * - * part1: OR / \ OR NOT / \ | >= < != - * / \ / \ / \ - * 3.0 4.0 7.0 8.0 13.0 14.0 - * - * part2: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 17.0 18.0 - * / \ / \ / \ - * 3.0 4.0 7.0 8.0 15.0 16.0 - * - * part3: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 19.0 20.0 - * / \ / \ / \ - * 3.0 4.0 7.0 8.0 15.0 16.0 - * - * part4: OR - * / \ - * OR NOT - * / \ | - * >= < != - * / \ / \ / \ - * 3.0 4.0 9.0 10.0 13.0 14.0 - * - * part5: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 17.0 18.0 - * / \ / \ / \ - * 3.0 4.0 9.0 10.0 15.0 16.0 - * - * part6: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 19.0 20.0 - * / \ / \ / \ - * 3.0 4.0 9.0 10.0 15.0 16.0 - * - * part7: OR - * / \ - * OR NOT - * / \ | - * >= < != - * / \ / \ / \ - * 3.0 4.0 11.0 12.0 13.0 14.0 - * - * part8: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 17.0 18.0 - * / \ / \ / \ - * 3.0 4.0 11.0 12.0 15.0 16.0 - * - * part9: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 19.0 20.0 - * / \ / \ / \ - * 3.0 4.0 11.0 12.0 15.0 16.0 - * - * part10: OR - * / \ - * OR NOT - * / \ | - * >= < != - * / \ / \ / \ - * 5.0 6.0 7.0 8.0 13.0 14.0 - * - * part11: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 17.0 18.0 - * / \ / \ / \ - * 5.0 6.0 7.0 8.0 15.0 16.0 - * - * part12: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 19.0 20.0 - * / \ / \ / \ - * 5.0 6.0 7.0 8.0 15.0 16.0 - * - * part13: OR - * / \ - * OR NOT - * / \ | - * >= < != - * / \ / \ / \ - * 5.0 6.0 9.0 10.0 13.0 14.0 - * - * part14: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 17.0 18.0 - * / \ / \ / \ - * 5.0 6.0 9.0 10.0 15.0 16.0 - * - * part15: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 19.0 20.0 - * / \ / \ / \ - * 5.0 6.0 9.0 10.0 15.0 16.0 - * - * part16: OR - * / \ - * OR NOT - * / \ | - * >= < != - * / \ / \ / \ - * 5.0 6.0 11.0 12.0 13.0 14.0 - * - * part17: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 17.0 18.0 - * / \ / \ / \ - * 5.0 6.0 11.0 12.0 15.0 16.0 - * - * part18: OR - * / \ - * OR NOT - * / \ | - * OR NOT = - * / \ | / \ - * >= < = 19.0 20.0 / \ / \ / \ 5.0 6.0 11.0 12.0 15.0 16.0 + * AND / \ AND ( ) / \ | AND ( ) part18 / \ | AND ( ) part17 / \ | AND ( ) part16 / \ | AND ( ) + * part15 / \ | AND ( ) part14 / \ | AND ( ) part13 / \ | AND ( ) part12 / \ | AND ( ) part11 / + * \ | AND ( ) part10 / \ | AND ( ) part9 / \ | AND ( ) part8 / \ | AND ( ) part7 / \ | AND ( ) + * part6 / \ | AND ( ) part5 / \ | AND ( ) part4 / \ | ( ) ( ) part3 | | part1 part2 + * + * part1: OR / \ OR NOT / \ | >= < != / \ / \ / \ 3.0 4.0 7.0 8.0 13.0 14.0 + * + * part2: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 17.0 18.0 / \ / \ / \ 3.0 4.0 7.0 8.0 + * 15.0 16.0 + * + * part3: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 19.0 20.0 / \ / \ / \ 3.0 4.0 7.0 8.0 + * 15.0 16.0 + * + * part4: OR / \ OR NOT / \ | >= < != / \ / \ / \ 3.0 4.0 9.0 10.0 13.0 14.0 + * + * part5: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 17.0 18.0 / \ / \ / \ 3.0 4.0 9.0 10.0 + * 15.0 16.0 + * + * part6: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 19.0 20.0 / \ / \ / \ 3.0 4.0 9.0 10.0 + * 15.0 16.0 + * + * part7: OR / \ OR NOT / \ | >= < != / \ / \ / \ 3.0 4.0 11.0 12.0 13.0 14.0 + * + * part8: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 17.0 18.0 / \ / \ / \ 3.0 4.0 11.0 12.0 + * 15.0 16.0 + * + * part9: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 19.0 20.0 / \ / \ / \ 3.0 4.0 11.0 12.0 + * 15.0 16.0 + * + * part10: OR / \ OR NOT / \ | >= < != / \ / \ / \ 5.0 6.0 7.0 8.0 13.0 14.0 + * + * part11: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 17.0 18.0 / \ / \ / \ 5.0 6.0 7.0 8.0 + * 15.0 16.0 + * + * part12: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 19.0 20.0 / \ / \ / \ 5.0 6.0 7.0 8.0 + * 15.0 16.0 + * + * part13: OR / \ OR NOT / \ | >= < != / \ / \ / \ 5.0 6.0 9.0 10.0 13.0 14.0 + * + * part14: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 17.0 18.0 / \ / \ / \ 5.0 6.0 9.0 10.0 + * 15.0 16.0 + * + * part15: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 19.0 20.0 / \ / \ / \ 5.0 6.0 9.0 10.0 + * 15.0 16.0 + * + * part16: OR / \ OR NOT / \ | >= < != / \ / \ / \ 5.0 6.0 11.0 12.0 13.0 14.0 + * + * part17: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 17.0 18.0 / \ / \ / \ 5.0 6.0 11.0 12.0 + * 15.0 16.0 + * + * part18: OR / \ OR NOT / \ | OR NOT = / \ | / \ >= < = 19.0 20.0 / \ / \ / \ 5.0 6.0 11.0 12.0 + * 15.0 16.0 * */ @Test public void test3() throws Exception { Expression expr = CCJSqlParserUtil.parseCondExpression( "(3.0 >= 4.0 AND 5.0 <= 6.0) OR " - + "(((7.0 < 8.0 AND 9.0 > 10.0) AND 11.0 = 12.0) OR " - + "NOT (13.0 <> 14.0 OR (15.0 = 16.0 AND (17.0 = 18.0 OR 19.0 > 20.0))))"); + + "(((7.0 < 8.0 AND 9.0 > 10.0) AND 11.0 = 12.0) OR " + + "NOT (13.0 <> 14.0 OR (15.0 = 16.0 AND (17.0 = 18.0 OR 19.0 > 20.0))))"); Expression expected = CCJSqlParserUtil.parseCondExpression( "(3.0 >= 4.0 OR 7.0 < 8.0 OR NOT 13.0 <> 14.0) AND " - + "(3.0 >= 4.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " - + "(3.0 >= 4.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " - + "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 13.0 <> 14.0) AND " - + "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " - + "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " - + "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 13.0 <> 14.0) AND " - + "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " - + "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " - + "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 13.0 <> 14.0) AND " - + "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " - + "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " - + "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 13.0 <> 14.0) AND " - + "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " - + "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " - + "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 13.0 <> 14.0) AND " - + "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " - + "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0)"); + + "(3.0 >= 4.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " + + "(3.0 >= 4.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " + + "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 13.0 <> 14.0) AND " + + "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " + + "(3.0 >= 4.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " + + "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 13.0 <> 14.0) AND " + + "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " + + "(3.0 >= 4.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " + + "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 13.0 <> 14.0) AND " + + "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " + + "(5.0 <= 6.0 OR 7.0 < 8.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " + + "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 13.0 <> 14.0) AND " + + "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " + + "(5.0 <= 6.0 OR 9.0 > 10.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0) AND " + + "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 13.0 <> 14.0) AND " + + "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 17.0 = 18.0) AND " + + "(5.0 <= 6.0 OR 11.0 = 12.0 OR NOT 15.0 = 16.0 OR NOT 19.0 > 20.0)"); Expression result = CNFConverter.convertToCNF(expr); assertEquals(expected.toString(), result.toString()); } /** - * This is the case when we test a very simple tree structure that has neither AND operator or OR operator. + * This is the case when we test a very simple tree structure that has neither AND operator or + * OR operator. * * Here is the expression tree: * @@ -302,31 +187,25 @@ public void test4() throws Exception { } /** - * This is the case when we test the tree that only contains AND operator without having an OR operator. + * This is the case when we test the tree that only contains AND operator without having an OR + * operator. * - * Here is the original expression tree: NOT | ( ) | OR / \ ( ) ( ) | | NOT OR | / \ AND LIKE = / \ / \ / \ > < S.C "%%" S.D {t '12:04:34'} - * / \ / \ - * S.A 3.5 S.B 4 + * Here is the original expression tree: NOT | ( ) | OR / \ ( ) ( ) | | NOT OR | / \ AND LIKE = + * / \ / \ / \ > < S.C "%%" S.D {t '12:04:34'} / \ / \ S.A 3.5 S.B 4 * * Here is the converted expression tree: * - * AND - * / \ - * AND = - * / \ / \ - * AND NOT LIKE S.D {t '12:04:34'} - * / \ / \ - * > < S.C "%%" / \ / \ S.A 3.5 S.B 4 + * AND / \ AND = / \ / \ AND NOT LIKE S.D {t '12:04:34'} / \ / \ > < S.C "%%" / \ / \ S.A 3.5 + * S.B 4 * */ @Test public void test5() throws Exception { Expression expr = CCJSqlParserUtil.parseCondExpression( "NOT ((NOT (S.A > 3.5 AND S.B < 4)) OR " - + "(S.C LIKE '\"%%\"' OR S.D = {t '12:04:34'}))"); + + "(S.C LIKE '\"%%\"' OR S.D = {t '12:04:34'}))"); Expression expected = CCJSqlParserUtil.parseCondExpression( - "S.A > 3.5 AND S.B < 4 AND NOT S.C LIKE '\"%%\"' " - + "AND NOT S.D = {t '12:04:34'}"); + "S.A > 3.5 AND S.B < 4 AND NOT S.C LIKE '\"%%\"' AND NOT S.D = {t '12:04:34'}"); Expression result = CNFConverter.convertToCNF(expr); assertEquals(expected.toString(), result.toString()); } @@ -335,65 +214,63 @@ public void test5() throws Exception { public void testStackOverflowIssue1576() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseCondExpression( "((3.0 >= 4.0 AND 5.0 <= 6.0) OR " - + "(7.0 < 8.0 AND 9.0 > 10.0) OR " - + "(11.0 = 11.0 AND 19.0 > 20.0) OR " - + "(17.0 = 14.0 AND 19.0 > 17.0) OR " - + "(17.0 = 18.0 AND 20.0 > 20.0) OR " - + "(17.0 = 16.0 AND 19.0 > 20.0) OR " - + "(17.0 = 18.0 AND 19.0 > 20.0) OR " - + "(17.0 = 18.0 AND 19.0 > 20.0) OR " - + "(17.0 = 22.0 AND 19.0 > 20.0) OR " - + "(18.0 = 18.0 AND 22.0 > 20.0) OR " - + "(17.0 = 18.0 AND 19.0 > 20.0) OR " - + "(18.0 = 18.0 AND 22.0 > 20.0) OR " - + "(18.0 = 19.0 AND 22.0 > 20.0) OR " - + "(17.0 = 18.0 AND 19.0 > 20.0))" - ); + + "(7.0 < 8.0 AND 9.0 > 10.0) OR " + + "(11.0 = 11.0 AND 19.0 > 20.0) OR " + + "(17.0 = 14.0 AND 19.0 > 17.0) OR " + + "(17.0 = 18.0 AND 20.0 > 20.0) OR " + + "(17.0 = 16.0 AND 19.0 > 20.0) OR " + + "(17.0 = 18.0 AND 19.0 > 20.0) OR " + + "(17.0 = 18.0 AND 19.0 > 20.0) OR " + + "(17.0 = 22.0 AND 19.0 > 20.0) OR " + + "(18.0 = 18.0 AND 22.0 > 20.0) OR " + + "(17.0 = 18.0 AND 19.0 > 20.0) OR " + + "(18.0 = 18.0 AND 22.0 > 20.0) OR " + + "(18.0 = 19.0 AND 22.0 > 20.0) OR " + + "(17.0 = 18.0 AND 19.0 > 20.0))"); Expression result = CNFConverter.convertToCNF(expr); assertThat(result).asString().hasSize(3448827); } - - + + @Test @Disabled public void testStackOverflowIssue1576_veryLarge() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseCondExpression( "((3.0 >= 4.0 AND 5.0 <= 6.0) OR " - + "(7.0 < 8.0 AND 9.0 > 10.0) OR " - + "(11.0 = 11.0 AND 19.0 > 20.0) OR " - + "(17.0 = 14.0 AND 19.0 > 17.0) OR " - + "(17.0 = 18.0 AND 20.0 > 20.0) OR " - + "(17.0 = 16.0 AND 19.0 > 20.0) OR " - + "(17.0 = 18.0 AND 19.0 > 20.0) OR " - + "(17.0 = 18.0 AND 19.0 > 20.0) OR " - + "(17.0 = 22.0 AND 19.0 > 20.0) OR " - + "(18.0 = 18.0 AND 22.0 > 20.0) OR " - + "(17.0 = 18.0 AND 19.0 > 20.0) OR " - + "(18.0 = 18.0 AND 22.0 > 20.0) OR " - + "(18.0 = 19.0 AND 22.0 > 20.0) OR " - + "(117.0 = 22.0 AND 19.0 > 20.0) OR " - + "(118.0 = 18.0 AND 22.0 > 20.0) OR " - + "(117.0 = 18.0 AND 19.0 > 20.0) OR " - //+ "(118.0 = 18.0 AND 22.0 > 20.0) OR " - //+ "(118.0 = 19.0 AND 22.0 > 20.0) OR " - + "(17.0 = 18.0 AND 19.0 > 20.0))" - ); + + "(7.0 < 8.0 AND 9.0 > 10.0) OR " + + "(11.0 = 11.0 AND 19.0 > 20.0) OR " + + "(17.0 = 14.0 AND 19.0 > 17.0) OR " + + "(17.0 = 18.0 AND 20.0 > 20.0) OR " + + "(17.0 = 16.0 AND 19.0 > 20.0) OR " + + "(17.0 = 18.0 AND 19.0 > 20.0) OR " + + "(17.0 = 18.0 AND 19.0 > 20.0) OR " + + "(17.0 = 22.0 AND 19.0 > 20.0) OR " + + "(18.0 = 18.0 AND 22.0 > 20.0) OR " + + "(17.0 = 18.0 AND 19.0 > 20.0) OR " + + "(18.0 = 18.0 AND 22.0 > 20.0) OR " + + "(18.0 = 19.0 AND 22.0 > 20.0) OR " + + "(117.0 = 22.0 AND 19.0 > 20.0) OR " + + "(118.0 = 18.0 AND 22.0 > 20.0) OR " + + "(117.0 = 18.0 AND 19.0 > 20.0) OR " + // + "(118.0 = 18.0 AND 22.0 > 20.0) OR " + // + "(118.0 = 19.0 AND 22.0 > 20.0) OR " + + "(17.0 = 18.0 AND 19.0 > 20.0))"); Expression result = CNFConverter.convertToCNF(expr); assertThat(result).asString().hasSize(33685499); } - + @Test public void testStackOverflowIssue1576_2() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseCondExpression( "((3.0 >= 4.0 AND 5.0 <= 6.0) OR " - + "(7.0 < 8.0 AND 9.0 > 10.0) OR " - + "(11.0 = 11.0 AND 19.0 > 20.0) OR " - + "(17.0 = 14.0 AND 19.0 > 17.0) OR " - + "(17.0 = 18.0 AND 20.0 > 20.0) OR " - + "(17.0 = 16.0 AND 19.0 > 20.0))" - ); + + "(7.0 < 8.0 AND 9.0 > 10.0) OR " + + "(11.0 = 11.0 AND 19.0 > 20.0) OR " + + "(17.0 = 14.0 AND 19.0 > 17.0) OR " + + "(17.0 = 18.0 AND 20.0 > 20.0) OR " + + "(17.0 = 16.0 AND 19.0 > 20.0))"); Expression result = CNFConverter.convertToCNF(expr); - assertThat(result).asString().isEqualTo("(3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0)"); + assertThat(result).asString().isEqualTo( + "(3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (3.0 >= 4.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 7.0 < 8.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 11.0 = 11.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 17.0 = 14.0 OR 20.0 > 20.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 17.0 = 18.0 OR 19.0 > 20.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 17.0 = 16.0) AND (5.0 <= 6.0 OR 9.0 > 10.0 OR 19.0 > 20.0 OR 19.0 > 17.0 OR 20.0 > 20.0 OR 19.0 > 20.0)"); } } diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java index 0979a4884..05b9e6bf5 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java @@ -13,7 +13,7 @@ import net.sf.jsqlparser.parser.CCJSqlParserDefaultVisitor; import net.sf.jsqlparser.parser.CCJSqlParserTreeConstants; import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import net.sf.jsqlparser.parser.SimpleNode; +import net.sf.jsqlparser.parser.Node; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.create.view.CreateView; @@ -33,11 +33,11 @@ public class CreateViewDeParserTest { public void testUseExtrnalExpressionDeparser() throws JSQLParserException { StringBuilder b = new StringBuilder(); SelectDeParser selectDeParser = new SelectDeParser(); - selectDeParser.setBuffer(b); + selectDeParser.setBuilder(b); ExpressionDeParser expressionDeParser = new ExpressionDeParser(selectDeParser, b) { @Override - public void visit(Column tableColumn) { + public StringBuilder visit(Column tableColumn, K parameters) { final Table table = tableColumn.getTable(); String tableName = null; if (table != null) { @@ -48,30 +48,31 @@ public void visit(Column tableColumn) { } } if (tableName != null && !tableName.isEmpty()) { - getBuffer().append("\"").append(tableName).append("\"").append("."); + getBuilder().append("\"").append(tableName).append("\"").append("."); } - getBuffer().append("\"").append(tableColumn.getColumnName()).append("\""); + getBuilder().append("\"").append(tableColumn.getColumnName()).append("\""); + return builder; } }; selectDeParser.setExpressionVisitor(expressionDeParser); CreateViewDeParser instance = new CreateViewDeParser(b, selectDeParser); - CreateView vc = (CreateView) CCJSqlParserUtil. - parse("CREATE VIEW test AS SELECT a, b FROM mytable"); + CreateView vc = + (CreateView) CCJSqlParserUtil.parse("CREATE VIEW test AS SELECT a, b FROM mytable"); instance.deParse(vc); assertEquals("CREATE VIEW test AS SELECT a, b FROM mytable", vc.toString()); - assertEquals("CREATE VIEW test AS SELECT \"a\", \"b\" FROM mytable", instance.getBuffer(). - toString()); + assertEquals("CREATE VIEW test AS SELECT \"a\", \"b\" FROM mytable", + instance.getBuilder().toString()); } @Test public void testCreateViewASTNode() throws JSQLParserException { String sql = "CREATE VIEW test AS SELECT a, b FROM mytable"; final StringBuilder b = new StringBuilder(sql); - SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql); + Node node = (Node) CCJSqlParserUtil.parseAST(sql); node.dump("*"); assertEquals(CCJSqlParserTreeConstants.JJTSTATEMENT, node.getId()); @@ -79,7 +80,7 @@ public void testCreateViewASTNode() throws JSQLParserException { int idxDelta = 0; @Override - public Object visit(SimpleNode node, Object data) { + public Object visit(Node node, Object data) { if (CCJSqlParserTreeConstants.JJTCOLUMN == node.getId()) { b.insert(node.jjtGetFirstToken().beginColumn - 1 + idxDelta, '"'); idxDelta++; diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/ExecuteDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/ExecuteDeParserTest.java index 83ef5b102..90727d19c 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/ExecuteDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/ExecuteDeParserTest.java @@ -36,7 +36,7 @@ public class ExecuteDeParserTest { public void setUp() { buffer = new StringBuilder(); expressionVisitor = new ExpressionDeParser(); - expressionVisitor.setBuffer(buffer); + expressionVisitor.setBuilder(buffer); executeDeParser = new ExecuteDeParser(expressionVisitor, buffer); } @@ -45,7 +45,7 @@ public void shouldDeParseExecute() { Execute execute = new Execute(); String name = "name"; - ParenthesedExpressionList expressions = new ParenthesedExpressionList(); + ParenthesedExpressionList expressions = new ParenthesedExpressionList<>(); expressions.add(new JdbcParameter()); expressions.add(new JdbcParameter()); @@ -71,12 +71,12 @@ public void shouldUseProvidedExpressionVisitorWhenDeParsingExecute() { expressions.add(expression1); expressions.add(expression2); - ExpressionList exprList = new ExpressionList().addExpressions(expressions); + ExpressionList exprList = new ExpressionList<>().addExpressions(expressions); execute.withName(name).withExprList(exprList); executeDeParser.deParse(execute); - then(expression1).should().accept(expressionVisitor); - then(expression2).should().accept(expressionVisitor); + then(expression1).should().accept(expressionVisitor, null); + then(expression2).should().accept(expressionVisitor, null); } } diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java index 15c74e520..dd0df1fe0 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java @@ -38,7 +38,7 @@ public class ExpressionDeParserTest { private ExpressionDeParser expressionDeParser; @Mock - private SelectVisitor selectVisitor; + private SelectVisitor selectVisitor; private StringBuilder buffer; @@ -55,7 +55,7 @@ public void setUp() { public void shouldDeParseSimplestAnalyticExpression() { AnalyticExpression analyticExpression = new AnalyticExpression(); analyticExpression.setName("name"); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name() OVER ()", buffer.toString()); } @@ -67,9 +67,9 @@ public void shouldDeParseAnalyticExpressionWithExpression() { analyticExpression.setName("name"); analyticExpression.setExpression(expression); - will(appendToBuffer("expression")).given(expression).accept(expressionDeParser); + will(appendToBuffer("expression")).given(expression).accept(expressionDeParser, null); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name(expression) OVER ()", buffer.toString()); } @@ -84,10 +84,10 @@ public void shouldDeParseAnalyticExpressionWithOffset() { analyticExpression.setExpression(expression); analyticExpression.setOffset(offset); - will(appendToBuffer("expression")).given(expression).accept(expressionDeParser); - will(appendToBuffer("offset")).given(offset).accept(expressionDeParser); + will(appendToBuffer("expression")).given(expression).accept(expressionDeParser, null); + will(appendToBuffer("offset")).given(offset).accept(expressionDeParser, null); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name(expression, offset) OVER ()", buffer.toString()); } @@ -104,11 +104,11 @@ public void shouldDeParseAnalyticExpressionWithDefaultValue() { analyticExpression.setOffset(offset); analyticExpression.setDefaultValue(defaultValue); - will(appendToBuffer("expression")).given(expression).accept(expressionDeParser); - will(appendToBuffer("offset")).given(offset).accept(expressionDeParser); - will(appendToBuffer("default value")).given(defaultValue).accept(expressionDeParser); + will(appendToBuffer("expression")).given(expression).accept(expressionDeParser, null); + will(appendToBuffer("offset")).given(offset).accept(expressionDeParser, null); + will(appendToBuffer("default value")).given(defaultValue).accept(expressionDeParser, null); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name(expression, offset, default value) OVER ()", buffer.toString()); } @@ -120,7 +120,7 @@ public void shouldDeParseAnalyticExpressionWithAllColumns() { analyticExpression.setName("name"); analyticExpression.setAllColumns(true); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name(*) OVER ()", buffer.toString()); } @@ -133,9 +133,9 @@ public void shouldDeParseComplexAnalyticExpressionWithKeep() { analyticExpression.setName("name"); analyticExpression.setKeep(keep); - will(appendToBuffer("keep")).given(keep).accept(expressionDeParser); + will(appendToBuffer("keep")).given(keep).accept(expressionDeParser, null); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name() keep OVER ()", buffer.toString()); } @@ -143,21 +143,21 @@ public void shouldDeParseComplexAnalyticExpressionWithKeep() { @Test public void shouldDeParseComplexAnalyticExpressionWithPartitionExpressionList() { AnalyticExpression analyticExpression = new AnalyticExpression(); - ExpressionList partitionExpressionList = new ExpressionList(); + ExpressionList partitionExpressionList = new ExpressionList<>(); Expression partitionExpression1 = mock(Expression.class); Expression partitionExpression2 = mock(Expression.class); - analyticExpression.setName("name"); - analyticExpression.setPartitionExpressionList(partitionExpressionList); partitionExpressionList.add(partitionExpression1); partitionExpressionList.add(partitionExpression2); + analyticExpression.setName("name"); + analyticExpression.setPartitionExpressionList(partitionExpressionList); will(appendToBuffer("partition expression 1")).given(partitionExpression1) - .accept(expressionDeParser); + .accept(expressionDeParser, null); will(appendToBuffer("partition expression 2")).given(partitionExpression2) - .accept(expressionDeParser); + .accept(expressionDeParser, null); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name() OVER (PARTITION BY partition expression 1, partition expression 2 )", buffer.toString()); @@ -180,7 +180,7 @@ public void shouldDeParseAnalyticExpressionWithOrderByElements() { will(appendToBuffer("order by element 2")).given(orderByDeParser) .deParseElement(orderByElement2); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name() OVER (ORDER BY order by element 1, order by element 2)", buffer.toString()); @@ -206,7 +206,7 @@ public void shouldDeParseAnalyticExpressionWithWindowElement() { .deParseElement(orderByElement2); given(windowElement.toString()).willReturn("window element"); - expressionDeParser.visit(analyticExpression); + expressionDeParser.visit(analyticExpression, null); assertEquals("name() OVER (ORDER BY order by element 1, order by element 2 window element)", buffer.toString()); diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java index 4248ef494..23b3927e6 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java @@ -88,9 +88,9 @@ public void shouldUseProvidedDeparsersWhenDeParsingDelete() { statementDeParser.visit(delete); - then(where).should().accept(expressionDeParser); - then(orderByElement1Expression).should().accept(expressionDeParser); - then(orderByElement2Expression).should().accept(expressionDeParser); + then(where).should().accept(expressionDeParser, null); + then(orderByElement1Expression).should().accept(expressionDeParser, null); + then(orderByElement2Expression).should().accept(expressionDeParser, null); } @Test @@ -108,7 +108,7 @@ public void shouldUseProvidedDeparsersWhenDeParsingInsert() { duplicateUpdateSets.add(new UpdateSet(duplicateUpdateColumn2, duplicateUpdateExpression2)); PlainSelect select = mock(PlainSelect.class); - List withItemsList = new ArrayList(); + List> withItemsList = new ArrayList>(); WithItem withItem1 = spy(new WithItem()); WithItem withItem2 = spy(new WithItem()); ParenthesedSelect withItem1SubSelect = mock(ParenthesedSelect.class); @@ -125,34 +125,34 @@ public void shouldUseProvidedDeparsersWhenDeParsingInsert() { statementDeParser.visit(insert.withWithItemsList(withItemsList)); - then(withItem1).should().accept((SelectVisitor) selectDeParser); - then(withItem2).should().accept((SelectVisitor) selectDeParser); - then(select).should().accept(selectDeParser); - then(duplicateUpdateExpression1).should().accept(expressionDeParser); - then(duplicateUpdateExpression1).should().accept(expressionDeParser); + then(withItem1).should().accept((SelectVisitor) selectDeParser, null); + then(withItem2).should().accept((SelectVisitor) selectDeParser, null); + then(select).should().accept((SelectVisitor) selectDeParser, null); + then(duplicateUpdateExpression1).should().accept(expressionDeParser, null); + then(duplicateUpdateExpression2).should().accept(expressionDeParser, null); } - @Test - @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") - public void shouldUseProvidedDeParsersWhenDeParsingSelect() { - WithItem withItem1 = spy(new WithItem()); - withItem1.setSelect(mock(ParenthesedSelect.class)); - WithItem withItem2 = spy(new WithItem()); - withItem2.setSelect(mock(ParenthesedSelect.class)); - - List withItemsList = new ArrayList(); - withItemsList.add(withItem1); - withItemsList.add(withItem2); - - PlainSelect plainSelect = mock(PlainSelect.class); - plainSelect.setWithItemsList(withItemsList); - - statementDeParser.visit(plainSelect); - - // then(withItem1).should().accept((SelectVisitor) selectDeParser); - // then(withItem2).should().accept((SelectVisitor) selectDeParser); - then(plainSelect).should().accept(selectDeParser); - } + // @Test + // @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") + // public void shouldUseProvidedDeParsersWhenDeParsingSelect() { + // WithItem withItem1 = spy(new WithItem<>()); + // withItem1.setSelect(mock(ParenthesedSelect.class)); + // WithItem withItem2 = spy(new WithItem<>()); + // withItem2.setSelect(mock(ParenthesedSelect.class)); + // + // List> withItemsList = new ArrayList>(); + // withItemsList.add(withItem1); + // withItemsList.add(withItem2); + // + // PlainSelect plainSelect = mock(PlainSelect.class); + // plainSelect.setWithItemsList(withItemsList); + // + // statementDeParser.visit(plainSelect); + // + // // then(withItem1).should().accept((SelectVisitor) selectDeParser); + // // then(withItem2).should().accept((SelectVisitor) selectDeParser); + // then(plainSelect).should().accept((SelectVisitor) selectDeParser, null); + // } @Test @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") @@ -182,13 +182,13 @@ public void shouldUseProvidedDeParsersWhenDeParsingUpdateNotUsingSelect() { statementDeParser.visit(update); - then(expressionDeParser).should().visit(column1); - then(expressionDeParser).should().visit(column2); - then(expression1).should().accept(expressionDeParser); - then(expression2).should().accept(expressionDeParser); - then(where).should().accept(expressionDeParser); - then(orderByElement1Expression).should().accept(expressionDeParser); - then(orderByElement2Expression).should().accept(expressionDeParser); + then(expressionDeParser).should().visit(column1, null); + then(expressionDeParser).should().visit(column2, null); + then(expression1).should().accept(expressionDeParser, null); + then(expression2).should().accept(expressionDeParser, null); + then(where).should().accept(expressionDeParser, null); + then(orderByElement1Expression).should().accept(expressionDeParser, null); + then(orderByElement2Expression).should().accept(expressionDeParser, null); } @Test @@ -221,18 +221,18 @@ public void shouldUseProvidedDeParsersWhenDeParsingUpdateUsingSelect() { statementDeParser.visit(update); - then(expressionDeParser).should().visit(column1); - then(expressionDeParser).should().visit(column2); - then(where).should().accept(expressionDeParser); - then(orderByElement1Expression).should().accept(expressionDeParser); - then(orderByElement2Expression).should().accept(expressionDeParser); + then(expressionDeParser).should().visit(column1, null); + then(expressionDeParser).should().visit(column2, null); + then(where).should().accept(expressionDeParser, null); + then(orderByElement1Expression).should().accept(expressionDeParser, null); + then(orderByElement2Expression).should().accept(expressionDeParser, null); } @Test @SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert") public void shouldUseProvidedDeParserWhenDeParsingExecute() { Execute execute = new Execute(); - ExpressionList expressions = new ExpressionList(); + ExpressionList expressions = new ExpressionList<>(); Expression expression1 = mock(Expression.class); Expression expression2 = mock(Expression.class); @@ -242,8 +242,8 @@ public void shouldUseProvidedDeParserWhenDeParsingExecute() { statementDeParser.visit(execute); - then(expression1).should().accept(expressionDeParser); - then(expression2).should().accept(expressionDeParser); + then(expression1).should().accept(expressionDeParser, null); + then(expression2).should().accept(expressionDeParser, null); } @Test @@ -251,14 +251,14 @@ public void shouldUseProvidedDeParserWhenDeParsingExecute() { public void shouldUseProvidedDeParserWhenDeParsingSetStatement() { String name = "name"; Expression expression = mock(Expression.class); - ExpressionList expressions = new ExpressionList(); + ExpressionList expressions = new ExpressionList<>(); expressions.add(expression); SetStatement setStatement = new SetStatement(name, expressions); statementDeParser.visit(setStatement); - then(expression).should().accept(expressionDeParser); + then(expression).should().accept(expressionDeParser, null); } // private Matcher replaceDeParserWithDeParsers(final @@ -289,7 +289,7 @@ public void shouldUseProvidedDeparsersWhenDeParsingUpsertWithExpressionList() { Expression duplicateUpdateExpression1 = mock(Expression.class); Expression duplicateUpdateExpression2 = mock(Expression.class); PlainSelect select = mock(PlainSelect.class); - List withItemsList = new ArrayList(); + List> withItemsList = new ArrayList>(); WithItem withItem1 = spy(new WithItem()); WithItem withItem2 = spy(new WithItem()); ParenthesedSelect withItem1SubSelect = mock(ParenthesedSelect.class); @@ -309,9 +309,9 @@ public void shouldUseProvidedDeparsersWhenDeParsingUpsertWithExpressionList() { statementDeParser.visit(upsert); - then(select).should().accept(selectDeParser); - then(duplicateUpdateExpression1).should().accept(expressionDeParser); - then(duplicateUpdateExpression1).should().accept(expressionDeParser); + then(select).should().accept((SelectVisitor) selectDeParser, null); + then(duplicateUpdateExpression1).should().accept(expressionDeParser, null); + then(duplicateUpdateExpression1).should().accept(expressionDeParser, null); } @Test @@ -327,21 +327,21 @@ public void shouldUseProvidedDeparsersWhenDeParsingIfThenStatement() public void testIssue1500AllColumns() throws JSQLParserException { String sqlStr = "select count(*) from some_table"; PlainSelect selectBody = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); - selectBody.accept(new SelectDeParser()); + selectBody.accept((SelectVisitor) new SelectDeParser(), null); } @Test public void testIssue1836() throws JSQLParserException { String sqlStr = "TABLE columns ORDER BY column_name LIMIT 10 OFFSET 10;"; TableStatement tableStatement = (TableStatement) CCJSqlParserUtil.parse(sqlStr); - tableStatement.accept(tableStatementDeParser); + tableStatement.accept(tableStatementDeParser, null); } @Test public void testIssue1500AllTableColumns() throws JSQLParserException { String sqlStr = "select count(a.*) from some_table a"; PlainSelect selectBody = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); - selectBody.accept(new SelectDeParser()); + selectBody.accept((SelectVisitor) new SelectDeParser(), null); } @Test @@ -354,19 +354,21 @@ public void testIssue1608DeparseValueList() throws JSQLParserException { StringBuilder builder = new StringBuilder(); ExpressionDeParser expressionDeParser = new ExpressionDeParser() { @Override - public void visit(StringValue stringValue) { - buffer.append("?"); + public StringBuilder visit(StringValue stringValue, K parameters) { + builder.append("?"); + return null; } @Override - public void visit(LongValue longValue) { - buffer.append("?"); + public StringBuilder visit(LongValue longValue, K parameters) { + builder.append("?"); + return null; } }; SelectDeParser selectDeParser = new SelectDeParser(expressionDeParser, builder); expressionDeParser.setSelectVisitor(selectDeParser); - expressionDeParser.setBuffer(builder); + expressionDeParser.setBuilder(builder); StatementDeParser statementDeParser = new StatementDeParser(expressionDeParser, selectDeParser, builder); diff --git a/src/test/java/net/sf/jsqlparser/util/validation/ValidationTestAsserts.java b/src/test/java/net/sf/jsqlparser/util/validation/ValidationTestAsserts.java index 46696bff7..491d4ce0d 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/ValidationTestAsserts.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/ValidationTestAsserts.java @@ -31,7 +31,8 @@ public class ValidationTestAsserts { * @param errors * @param feature */ - public static void assertNotSupported(Collection errors, Feature... feature) { + public static void assertNotSupported(Collection errors, + Feature... feature) { assertEquals(toSet(f -> f + " not supported.", feature), toErrorsSet(errors)); } @@ -39,7 +40,8 @@ public static void assertNotSupported(Collection errors, Fe * @param errors * @param feature */ - public static void assertNotAllowed(Collection errors, Feature... feature) { + public static void assertNotAllowed(Collection errors, + Feature... feature) { assertEquals(toSet(f -> f + " not allowed.", feature), toErrorsSet(errors)); } @@ -48,9 +50,11 @@ public static void assertNotAllowed(Collection errors, Feat * @param checkForExists * @param names */ - public static void assertMetadata(Collection errors, boolean checkForExists, String... names) { + public static void assertMetadata(Collection errors, + boolean checkForExists, String... names) { assertEquals(Stream.of(names).map( - f -> String.format("%s does %sexist.", f, checkForExists ? "not " : "")).collect(Collectors.toSet()), + f -> String.format("%s does %sexist.", f, checkForExists ? "not " : "")) + .collect(Collectors.toSet()), toErrorsSet(errors)); } @@ -60,7 +64,8 @@ public static void assertMetadata(Collection errors, boolea */ public static void assertErrorsSize(Collection errors, int size) { assertNotNull(errors); - assertEquals(size, errors.size(), String.format("Expected %d errors, but got: %s", size, errors.toString())); + assertEquals(size, errors.size(), + String.format("Expected %d errors, but got: %s", size, errors.toString())); } /** @@ -79,7 +84,8 @@ public static void assertErrorsSize(Map errors, int size) { * @param statementCount * @param versions */ - public static void validateNoErrors(String sql, int statementCount, ValidationCapability... versions) { + public static void validateNoErrors(String sql, int statementCount, + ValidationCapability... versions) { Validation validation = new Validation( // Arrays.asList(versions), sql); List errors = validation.validate(); @@ -113,7 +119,8 @@ public static List validate(String sql, int statementCount, int public static void validateMetadata(String sql, int statementCount, int errorCount, DatabaseMetaDataValidation allowed, boolean exists, String... names) { - validateMetadata(sql, statementCount, errorCount, Collections.singleton(allowed), exists, names); + validateMetadata(sql, statementCount, errorCount, Collections.singleton(allowed), exists, + names); } /** @@ -136,11 +143,13 @@ public static void validateMetadata(String sql, int statementCount, int errorCou * @param errorCount * @param allowed - the allowed feature * @param features - the features not allowed, assert errormessages against - * {@link #assertNotAllowed(Collection, Feature...)} + * {@link #assertNotAllowed(Collection, Feature...)} */ - public static void validateNotAllowed(String sql, int statementCount, int errorCount, FeaturesAllowed allowed, + public static void validateNotAllowed(String sql, int statementCount, int errorCount, + FeaturesAllowed allowed, Feature... features) { - validateNotAllowed(sql, statementCount, errorCount, Collections.singleton(allowed), features); + validateNotAllowed(sql, statementCount, errorCount, Collections.singleton(allowed), + features); } /** @@ -149,7 +158,7 @@ public static void validateNotAllowed(String sql, int statementCount, int errorC * @param errorCount * @param allowed - the allowed features * @param features - the features not allowed, assert errormessages against - * {@link #assertNotAllowed(Collection, Feature...)} + * {@link #assertNotAllowed(Collection, Feature...)} */ public static void validateNotAllowed(String sql, int statementCount, int errorCount, Collection allowed, @@ -159,23 +168,21 @@ public static void validateNotAllowed(String sql, int statementCount, int errorC } /** - * @param sql - * @param statementCount - * @param errorCount - * @param supported - the supported features - * @param features - the features not supported, assert errormessages against null null {@link #assertNotSupported(Collection, Feature...) + * @param sql @param statementCount @param errorCount @param supported - the supported + * features @param features - the features not supported, assert errormessages against null null + * {@link #assertNotSupported(Collection, Feature...) */ - public static void validateNotSupported(String sql, int statementCount, int errorCount, Version supported, + public static void validateNotSupported(String sql, int statementCount, int errorCount, + Version supported, Feature... features) { - validateNotSupported(sql, statementCount, errorCount, Collections.singleton(supported), features); + validateNotSupported(sql, statementCount, errorCount, Collections.singleton(supported), + features); } /** - * @param sql - * @param statementCount - * @param errorCount - * @param supported - the supported features - * @param features - the features not supported, assert errormessages against null null {@link #assertNotSupported(Collection, Feature...) + * @param sql @param statementCount @param errorCount @param supported - the supported + * features @param features - the features not supported, assert errormessages against null null + * {@link #assertNotSupported(Collection, Feature...) */ public static void validateNotSupported(String sql, int statementCount, int errorCount, Collection supported, Feature... features) { diff --git a/src/test/java/net/sf/jsqlparser/util/validation/ValidationUtilTest.java b/src/test/java/net/sf/jsqlparser/util/validation/ValidationUtilTest.java index 28f5f03d4..15b86ba77 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/ValidationUtilTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/ValidationUtilTest.java @@ -19,7 +19,8 @@ public class ValidationUtilTest extends ValidationTestAsserts { @Test public void testMap() { assertEquals(Arrays.asList("col2", "col1"), - ValidationUtil.map(Arrays.asList(new Column("col2"), new Column("col1")), Column::getColumnName)); + ValidationUtil.map(Arrays.asList(new Column("col2"), new Column("col1")), + Column::getColumnName)); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java b/src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java index 8e821cea6..7c21680f0 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/metadata/DatabaseMetaDataValidationTest.java @@ -32,7 +32,8 @@ public void setupDatabase() throws SQLException { .prepareStatement( "CREATE TABLE mytable (id bigint, ref bigint, description varchar(100), active boolean);") .execute(); - connection.prepareStatement("CREATE TABLE mysecondtable (id bigint, description varchar(100), active boolean);") + connection.prepareStatement( + "CREATE TABLE mysecondtable (id bigint, description varchar(100), active boolean);") .execute(); connection.prepareStatement("CREATE VIEW myview AS SELECT * FROM mytable").execute(); } @@ -40,7 +41,8 @@ public void setupDatabase() throws SQLException { @Test public void testValidationAlterTable() throws JSQLParserException, SQLException { String sql = "ALTER TABLE mytable ADD price numeric(10,5) not null"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors connection.prepareStatement(sql).execute(); validateMetadata(sql, 1, 1, meta.clearCache(), false, "price"); // column exists @@ -49,56 +51,68 @@ public void testValidationAlterTable() throws JSQLParserException, SQLException @Test public void testValidationAlterTableAlterColumn() throws JSQLParserException, SQLException { String sql = "ALTER TABLE mytable ALTER COLUMN description SET NOT NULL"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } @Test public void testValidationMetadataInsert() throws JSQLParserException, SQLException { String sql = "INSERT INTO mytable (id, description, active) VALUES (1, 'test', 1)"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } @Test - public void testValidationMetadataSelectWithColumnsAndAlias() throws JSQLParserException, SQLException { - String sql = "SELECT * FROM mytable t JOIN mysecondtable t2 WHERE t.ref = t2.id AND t.id = ?"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + public void testValidationMetadataSelectWithColumnsAndAlias() + throws JSQLParserException, SQLException { + String sql = + "SELECT * FROM mytable t JOIN mysecondtable t2 WHERE t.ref = t2.id AND t.id = ?"; + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } @Test public void testValidationMetadataUpdate() throws JSQLParserException, SQLException { String sql = "UPDATE mytable t SET t.ref = 2 WHERE t.id = 1"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } @Test public void testValidationMetadataDelete() throws JSQLParserException, SQLException { String sql = "DELETE FROM mytable t WHERE t.id = 1 and ref = 2"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } @Test public void testValidationMetadataDeleteError() throws JSQLParserException, SQLException { String sql = "DELETE FROM mytable t WHERE t.id = 1 and x.ref = 2"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateMetadata(sql, 1, 1, meta, true, "x.ref"); } @Test public void testValidationMetadataSelectWithColumns() throws JSQLParserException, SQLException { - String sql = "SELECT * FROM mytable JOIN mysecondtable WHERE mytable.ref = mysecondtable.id AND mysecondtable.id = ?"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + String sql = + "SELECT * FROM mytable JOIN mysecondtable WHERE mytable.ref = mysecondtable.id AND mysecondtable.id = ?"; + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } @Test - public void testValidationMetadataSelectWithoutColumns() throws JSQLParserException, SQLException { + public void testValidationMetadataSelectWithoutColumns() + throws JSQLParserException, SQLException { String sql = String.format("SELECT * FROM %s.public.mytable", databaseName); - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); sql = String.format("SELECT * FROM public.mytable", databaseName); validateNoErrors(sql, 1, DatabaseType.H2, meta.clearCache()); @@ -109,32 +123,37 @@ public void testValidationMetadataSelectWithoutColumns() throws JSQLParserExcept @Test public void testValidationDropView3Parts() throws JSQLParserException, SQLException { String sql = String.format("DROP VIEW %s.public.myview", databaseName); - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE, - false); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE, + false); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } @Test public void testValidationDropView2Parts() throws JSQLParserException, SQLException { String sql = "DROP VIEW public.myview"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE, - false); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE, + false); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } @Test public void testValidationDropViewDoesNotExist() throws JSQLParserException, SQLException { String sql = "DROP VIEW public.anotherView"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE, - false); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE, + false); // view does not exist validateMetadata(sql, 1, 1, meta, true, String.format("public.anotherView", databaseName)); } @Test - public void testValidationMetadataSelectWithColumnsAndAlias2() throws JSQLParserException, SQLException { + public void testValidationMetadataSelectWithColumnsAndAlias2() + throws JSQLParserException, SQLException { String sql = "select my.id from mytable as my"; - JdbcDatabaseMetaDataCapability meta = new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); + JdbcDatabaseMetaDataCapability meta = + new JdbcDatabaseMetaDataCapability(connection, NamesLookup.UPPERCASE); validateNoErrors(sql, 1, DatabaseType.H2, meta); // no errors } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterSequenceValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterSequenceValidatorTest.java index 6bc379b11..54db97c35 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterSequenceValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterSequenceValidatorTest.java @@ -17,12 +17,14 @@ public class AlterSequenceValidatorTest extends ValidationTestAsserts { - private static final DatabaseType DATABASES_SUPPORTING_SEQUENCES[] = new DatabaseType[]{DatabaseType.ORACLE, - DatabaseType.SQLSERVER, DatabaseType.MARIADB, DatabaseType.POSTGRESQL, DatabaseType.H2}; + private static final DatabaseType DATABASES_SUPPORTING_SEQUENCES[] = new DatabaseType[] { + DatabaseType.ORACLE, + DatabaseType.SQLSERVER, DatabaseType.MARIADB, DatabaseType.POSTGRESQL, DatabaseType.H2}; @Test public void testValidatorAlterSequence() throws JSQLParserException { - for (String sql : Arrays.asList("ALTER SEQUENCE my_seq", "ALTER SEQUENCE my_seq INCREMENT BY 1", + for (String sql : Arrays.asList("ALTER SEQUENCE my_seq", + "ALTER SEQUENCE my_seq INCREMENT BY 1", "ALTER SEQUENCE my_seq START WITH 10", "ALTER SEQUENCE my_seq MAXVALUE 5", "ALTER SEQUENCE my_seq NOMAXVALUE", "ALTER SEQUENCE my_seq MINVALUE 5", "ALTER SEQUENCE my_seq NOMINVALUE", "ALTER SEQUENCE my_seq CYCLE", diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterValidatorTest.java index bbb444c08..f2aef4e40 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterValidatorTest.java @@ -28,6 +28,12 @@ public void testAlterTableAddColumn_ColumnKeyWordImplicit() throws JSQLParserExc validateNoErrors(sql, 1, DatabaseType.DATABASES); } + @Test + public void testAlterTableAddFunctionalIndex() throws JSQLParserException { + String sql = "ALTER TABLE PPK_OLPN ADD INDEX fAdd ((b + c))"; + validateNoErrors(sql, 1, DatabaseType.DATABASES); + } + @Test public void testAlterTablePrimaryKey() throws JSQLParserException { validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id)", 1, DatabaseType.DATABASES); @@ -35,44 +41,54 @@ public void testAlterTablePrimaryKey() throws JSQLParserException { @Test public void testAlterTablePrimaryKeyDeferrable() throws JSQLParserException { - validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) DEFERRABLE", 1, DatabaseType.DATABASES); + validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) DEFERRABLE", 1, + DatabaseType.DATABASES); } @Test public void testAlterTablePrimaryKeyNotDeferrable() throws JSQLParserException { - validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) NOT DEFERRABLE", 1, DatabaseType.DATABASES); + validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) NOT DEFERRABLE", 1, + DatabaseType.DATABASES); } @Test public void testAlterTablePrimaryKeyValidate() throws JSQLParserException { - validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) VALIDATE", 1, DatabaseType.DATABASES); + validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) VALIDATE", 1, + DatabaseType.DATABASES); } @Test public void testAlterTablePrimaryKeyNoValidate() throws JSQLParserException { - validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) NOVALIDATE", 1, DatabaseType.DATABASES); + validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) NOVALIDATE", 1, + DatabaseType.DATABASES); } @Test public void testAlterTablePrimaryKeyDeferrableValidate() throws JSQLParserException { - validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) DEFERRABLE VALIDATE", 1, DatabaseType.DATABASES); + validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) DEFERRABLE VALIDATE", 1, + DatabaseType.DATABASES); } @Test public void testAlterTablePrimaryKeyDeferrableDisableNoValidate() throws JSQLParserException { - validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) DEFERRABLE DISABLE NOVALIDATE", 1, + validateNoErrors("ALTER TABLE animals ADD PRIMARY KEY (id) DEFERRABLE DISABLE NOVALIDATE", + 1, DatabaseType.DATABASES); } @Test public void testAlterTableUniqueKey() throws JSQLParserException { - validateNoErrors("ALTER TABLE `schema_migrations` ADD UNIQUE KEY `unique_schema_migrations` (`version`)", 1, + validateNoErrors( + "ALTER TABLE `schema_migrations` ADD UNIQUE KEY `unique_schema_migrations` (`version`)", + 1, DatabaseType.DATABASES); } @Test public void testAlterTableForgeignKey() throws JSQLParserException { - validateNoErrors("ALTER TABLE test ADD FOREIGN KEY (user_id) REFERENCES ra_user (id) ON DELETE CASCADE", 1, + validateNoErrors( + "ALTER TABLE test ADD FOREIGN KEY (user_id) REFERENCES ra_user (id) ON DELETE CASCADE", + 1, DatabaseType.DATABASES); } @@ -110,13 +126,17 @@ public void testAlterTableForgeignKey2() throws JSQLParserException { @Test public void testAlterTableForgeignKey3() throws JSQLParserException { - validateNoErrors("ALTER TABLE test ADD FOREIGN KEY (user_id) REFERENCES ra_user (id) ON DELETE RESTRICT", 1, + validateNoErrors( + "ALTER TABLE test ADD FOREIGN KEY (user_id) REFERENCES ra_user (id) ON DELETE RESTRICT", + 1, DatabaseType.DATABASES); } @Test public void testAlterTableForgeignKey4() throws JSQLParserException { - validateNoErrors("ALTER TABLE test ADD FOREIGN KEY (user_id) REFERENCES ra_user (id) ON DELETE SET NULL", 1, + validateNoErrors( + "ALTER TABLE test ADD FOREIGN KEY (user_id) REFERENCES ra_user (id) ON DELETE SET NULL", + 1, DatabaseType.DATABASES); } @@ -127,7 +147,8 @@ public void testAlterTableDropColumn() throws JSQLParserException { @Test public void testAlterTableAlterColumnDropNotNullIssue918() throws JSQLParserException { - validateNoErrors("ALTER TABLE \"user_table_t\" ALTER COLUMN name DROP NOT NULL", 1, DatabaseType.DATABASES); + validateNoErrors("ALTER TABLE \"user_table_t\" ALTER COLUMN name DROP NOT NULL", 1, + DatabaseType.DATABASES); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterViewValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterViewValidatorTest.java index 516b5ba26..ae15be835 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterViewValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/AlterViewValidatorTest.java @@ -22,14 +22,16 @@ public class AlterViewValidatorTest extends ValidationTestAsserts { @Test public void testValidateAlterView() throws JSQLParserException { for (String sql : Arrays.asList("ALTER VIEW myview AS SELECT * FROM mytab")) { - validateNoErrors(sql, 1, DatabaseType.MARIADB, DatabaseType.MYSQL, DatabaseType.SQLSERVER); + validateNoErrors(sql, 1, DatabaseType.MARIADB, DatabaseType.MYSQL, + DatabaseType.SQLSERVER); } } @Test public void testValidateAlterViewNotSupported() throws JSQLParserException { for (String sql : Arrays.asList("REPLACE VIEW myview(a, b) AS SELECT a, b FROM mytab")) { - for (DatabaseType type : Arrays.asList(DatabaseType.MARIADB, DatabaseType.MYSQL, DatabaseType.SQLSERVER)) { + for (DatabaseType type : Arrays.asList(DatabaseType.MARIADB, DatabaseType.MYSQL, + DatabaseType.SQLSERVER)) { validateNotSupported(sql, 1, 1, type, Feature.alterViewReplace); } } @@ -40,7 +42,8 @@ public void testValidateAlterViewNotAllowed() throws JSQLParserException { validateNotAllowed("ALTER VIEW myview AS SELECT * FROM mytab", 1, 1, FeaturesAllowed.CREATE.copy().add(FeaturesAllowed.SELECT), Feature.alterView); validateNotAllowed("REPLACE VIEW myview(a, b) AS SELECT a, b FROM mytab", 1, 1, - FeaturesAllowed.CREATE.copy().add(FeaturesAllowed.SELECT), Feature.alterView, Feature.alterViewReplace); + FeaturesAllowed.CREATE.copy().add(FeaturesAllowed.SELECT), Feature.alterView, + Feature.alterViewReplace); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidatorTest.java index 754f8ad94..ae3d9fe53 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidatorTest.java @@ -22,7 +22,8 @@ public class CreateIndexValidatorTest extends ValidationTestAsserts { @Test public void testValidateCreateIndex() throws JSQLParserException { for (String sql : Arrays.asList( - "CREATE INDEX idx_american_football_action_plays_1 ON american_football_action_plays USING btree (play_type)")) { + "CREATE INDEX idx_american_football_action_plays_1 ON american_football_action_plays USING btree (play_type)", + "CREATE INDEX idx_func ON american_football_action_plays ((play_type + 1))")) { validateNoErrors(sql, 1, DatabaseType.DATABASES); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateSequenceValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateSequenceValidatorTest.java index 8746938d0..7685c3024 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateSequenceValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateSequenceValidatorTest.java @@ -19,8 +19,9 @@ public class CreateSequenceValidatorTest extends ValidationTestAsserts { - private static final DatabaseType DATABASES_SUPPORTING_SEQUENCES[] = new DatabaseType[]{DatabaseType.ORACLE, - DatabaseType.SQLSERVER, DatabaseType.MARIADB, DatabaseType.POSTGRESQL, DatabaseType.H2}; + private static final DatabaseType DATABASES_SUPPORTING_SEQUENCES[] = new DatabaseType[] { + DatabaseType.ORACLE, + DatabaseType.SQLSERVER, DatabaseType.MARIADB, DatabaseType.POSTGRESQL, DatabaseType.H2}; @Test public void testValidateCreateSequence() throws JSQLParserException { diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateTableValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateTableValidatorTest.java index 784a8c6d9..61b5f9e34 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateTableValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateTableValidatorTest.java @@ -33,13 +33,15 @@ public void testValidationDropNotAllowed() throws JSQLParserException { @Test public void testValidationCreateTableWithIndex() throws JSQLParserException { - String sql = "CREATE TABLE test_descending_indexes (c1 INT, c2 INT, INDEX idx1 (c1 ASC, c2 DESC))"; + String sql = + "CREATE TABLE test_descending_indexes (c1 INT, c2 INT, INDEX idx1 (c1 ASC, c2 DESC))"; validateNoErrors(sql, 1, DatabaseType.DATABASES); } @Test public void testValidationCreateTableWithIndex2() throws JSQLParserException { - String sql = "CREATE TABLE TABLE1 (COLUMN1 VARCHAR2 (15), COLUMN2 VARCHAR2 (15), CONSTRAINT P_PK PRIMARY KEY (COLUMN1) USING INDEX TABLESPACE \"T_INDEX\") TABLESPACE \"T_SPACE\""; + String sql = + "CREATE TABLE TABLE1 (COLUMN1 VARCHAR2 (15), COLUMN2 VARCHAR2 (15), CONSTRAINT P_PK PRIMARY KEY (COLUMN1) USING INDEX TABLESPACE \"T_INDEX\") TABLESPACE \"T_SPACE\""; validateNoErrors(sql, 1, DatabaseType.DATABASES); } @@ -51,7 +53,8 @@ public void testValidationCreateTableFromSelect() throws JSQLParserException { @Test public void testValidationCreateTableForeignKeyPrimaryKey() throws JSQLParserException { - String sql = "CREATE TABLE test (id INT UNSIGNED NOT NULL AUTO_INCREMENT, string VARCHAR (20), user_id INT UNSIGNED, PRIMARY KEY (id), FOREIGN KEY (user_id) REFERENCES ra_user(id))"; + String sql = + "CREATE TABLE test (id INT UNSIGNED NOT NULL AUTO_INCREMENT, string VARCHAR (20), user_id INT UNSIGNED, PRIMARY KEY (id), FOREIGN KEY (user_id) REFERENCES ra_user(id))"; validateNoErrors(sql, 1, DatabaseType.DATABASES); } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/DeleteValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/DeleteValidatorTest.java index b09a0a479..6cd2f3375 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/DeleteValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/DeleteValidatorTest.java @@ -29,13 +29,15 @@ public void testValidationDelete() throws JSQLParserException { @Test public void testValidationDeleteNotAllowed() throws JSQLParserException { String sql = "DELETE FROM tab2 t2 WHERE t2.criteria = ?;"; - validateNotAllowed(sql, 1, 1, FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.JDBC), Feature.delete); + validateNotAllowed(sql, 1, 1, FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.JDBC), + Feature.delete); } @Test public void testValidationDeleteSupportedAndNotSupported() throws JSQLParserException { String sql = "DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2 WHERE a1.id = a2.id;"; - validateNotSupported(sql, 1, 1, Arrays.asList(DatabaseType.H2), Feature.deleteTables, Feature.deleteJoin); + validateNotSupported(sql, 1, 1, Arrays.asList(DatabaseType.H2), Feature.deleteTables, + Feature.deleteJoin); validateNoErrors(sql, 1, DatabaseType.MARIADB, DatabaseType.MYSQL); } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/ExecuteValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/ExecuteValidatorTest.java index 835773e71..b2ae89c65 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/ExecuteValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/ExecuteValidatorTest.java @@ -28,21 +28,25 @@ public void testValidationExecute() throws Exception { @Test public void testValidationExec() throws Exception { for (String sql : Arrays.asList("EXEC myproc 'a', 2, 'b'", "EXEC procedure @param = 1", - "EXEC procedure @param = 'foo'", "EXEC procedure @param = 'foo', @param2 = 'foo2'")) { + "EXEC procedure @param = 'foo'", + "EXEC procedure @param = 'foo', @param2 = 'foo2'")) { validateNoErrors(sql, 1, DatabaseType.SQLSERVER); } } @Test public void testValidationCall() throws Exception { - for (String sql : Arrays.asList("CALL myproc 'a', 2, 'b'", "CALL BAR.FOO", "CALL myproc ('a', 2, 'b')")) { - validateNoErrors(sql, 1, DatabaseType.MARIADB, DatabaseType.POSTGRESQL, DatabaseType.MYSQL); + for (String sql : Arrays.asList("CALL myproc 'a', 2, 'b'", "CALL BAR.FOO", + "CALL myproc ('a', 2, 'b')")) { + validateNoErrors(sql, 1, DatabaseType.MARIADB, DatabaseType.POSTGRESQL, + DatabaseType.MYSQL); } } @Test public void testValidationCallNotSupported() throws Exception { - for (String sql : Arrays.asList("CALL myproc 'a', 2, 'b'", "CALL BAR.FOO", "CALL myproc ('a', 2, 'b')")) { + for (String sql : Arrays.asList("CALL myproc 'a', 2, 'b'", "CALL BAR.FOO", + "CALL myproc ('a', 2, 'b')")) { validateNotSupported(sql, 1, 1, DatabaseType.SQLSERVER, Feature.executeCall); } } @@ -50,22 +54,27 @@ public void testValidationCallNotSupported() throws Exception { @Test public void testValidationExecuteNotAllowed() throws Exception { for (String sql : Arrays.asList("EXECUTE myproc 'a', 2, 'b'")) { - validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.execute, Feature.executeExecute); + validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.execute, + Feature.executeExecute); } } @Test public void testValidationExecNotAllowed() throws Exception { for (String sql : Arrays.asList("EXEC myproc 'a', 2, 'b'", "EXEC procedure @param = 1", - "EXEC procedure @param = 'foo'", "EXEC procedure @param = 'foo', @param2 = 'foo2'")) { - validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.execute, Feature.executeExec); + "EXEC procedure @param = 'foo'", + "EXEC procedure @param = 'foo', @param2 = 'foo2'")) { + validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.execute, + Feature.executeExec); } } @Test public void testValidationCallNotAllowed() throws Exception { - for (String sql : Arrays.asList("CALL myproc 'a', 2, 'b'", "CALL BAR.FOO", "CALL myproc ('a', 2, 'b')")) { - validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.execute, Feature.executeCall); + for (String sql : Arrays.asList("CALL myproc 'a', 2, 'b'", "CALL BAR.FOO", + "CALL myproc ('a', 2, 'b')")) { + validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.execute, + Feature.executeCall); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidatorTest.java index af8b48d79..94429af53 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidatorTest.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.util.validation.validator; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.util.validation.ValidationTestAsserts; import net.sf.jsqlparser.util.validation.feature.DatabaseType; import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed; @@ -17,7 +18,8 @@ public class ExpressionValidatorTest extends ValidationTestAsserts { - private static final FeaturesAllowed EXPRESSIONS = FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.EXPRESSIONS); + private static final FeaturesAllowed EXPRESSIONS = + FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.EXPRESSIONS); @Test public void testAddition() { @@ -50,13 +52,16 @@ public void testEquals() { @Test public void testParenthesis() { - validateNoErrors("SELECT CASE WHEN ((a = b) OR b = c) AND (d <> a) AND d <> c THEN c ELSE d END", 1, + validateNoErrors( + "SELECT CASE WHEN ((a = b) OR b = c) AND (d <> a) AND d <> c THEN c ELSE d END", 1, EXPRESSIONS); } @Test public void testMatches() throws JSQLParserException { - validateNoErrors("SELECT * FROM team WHERE team.search_column @@ to_tsquery('new & york & yankees')", 1, + validateNoErrors( + "SELECT * FROM team WHERE team.search_column @@ to_tsquery('new & york & yankees')", + 1, EXPRESSIONS); } @@ -111,7 +116,8 @@ public void testJdbcParameter() { @Test public void testJdbcNamedParameter() { - validateNoErrors("SELECT func (:param1, :param2) ", 1, EXPRESSIONS.copy().add(FeaturesAllowed.JDBC)); + validateNoErrors("SELECT func (:param1, :param2) ", 1, + EXPRESSIONS.copy().add(FeaturesAllowed.JDBC)); } @Test @@ -145,6 +151,12 @@ public void testIsNull() { validateNoErrors("SELECT * FROM tab t WHERE t.col IS NOT NULL", 1, EXPRESSIONS); } + @Test + public void testIsUnknown() { + validateNoErrors("SELECT * FROM tab t WHERE t.col IS UNKNOWN", 1, EXPRESSIONS); + validateNoErrors("SELECT * FROM tab t WHERE t.col IS NOT UNKNOWN", 1, EXPRESSIONS); + } + @Test public void testLike() { validateNoErrors("SELECT * FROM tab t WHERE t.col LIKE '%search for%'", 1, EXPRESSIONS); @@ -153,13 +165,16 @@ public void testLike() { @Test public void testExists() { - validateNoErrors("SELECT * FROM tab t WHERE EXISTS (select 1 FROM tab2 t2 WHERE t2.id = t.id)", 1, + validateNoErrors( + "SELECT * FROM tab t WHERE EXISTS (select 1 FROM tab2 t2 WHERE t2.id = t.id)", 1, EXPRESSIONS); } @Test public void testInterval() throws JSQLParserException { - validateNoErrors("SELECT DATE_ADD(start_date, INTERVAL duration MINUTE) AS end_datetime FROM appointment", 1, + validateNoErrors( + "SELECT DATE_ADD(start_date, INTERVAL duration MINUTE) AS end_datetime FROM appointment", + 1, EXPRESSIONS); validateNoErrors("SELECT 5 + INTERVAL '3 days'", 1, EXPRESSIONS); @@ -181,6 +196,12 @@ public void testRlike() throws JSQLParserException { EXPRESSIONS); } + @Test + public void testRegexpLike() throws JSQLParserException { + validateNoErrors("SELECT * FROM mytable WHERE first_name REGEXP_LIKE '^Ste(v|ph)en$'", 1, + EXPRESSIONS); + } + @Test public void testSimilarTo() throws JSQLParserException { validateNoErrors( @@ -190,19 +211,35 @@ public void testSimilarTo() throws JSQLParserException { @Test public void testOneColumnFullTextSearchMySQL() throws JSQLParserException { - validateNoErrors("SELECT MATCH (col1) AGAINST ('test' IN NATURAL LANGUAGE MODE) relevance FROM tbl", 1, + validateNoErrors( + "SELECT MATCH (col1) AGAINST ('test' IN NATURAL LANGUAGE MODE) relevance FROM tbl", + 1, EXPRESSIONS); } + @Test + public void testFullTextSearchAgainstFunctionRequiresJdbcFeature() throws JSQLParserException { + validateNotAllowed( + "SELECT * FROM commodity WHERE MATCH (name) AGAINST (concat('',?,'') IN BOOLEAN MODE)", + 1, + 1, + EXPRESSIONS, + Feature.jdbcParameter); + } + @Test public void testAnalyticFunctionFilter() throws JSQLParserException { - validateNoErrors("SELECT COUNT(*) FILTER (WHERE name = 'Raj') OVER (PARTITION BY name ) FROM table", 1, + validateNoErrors( + "SELECT COUNT(*) FILTER (WHERE name = 'Raj') OVER (PARTITION BY name ) FROM table", + 1, EXPRESSIONS); } @Test public void testAtTimeZoneExpression() throws JSQLParserException { - validateNoErrors("SELECT DATE(date1 AT TIME ZONE 'UTC' AT TIME ZONE 'australia/sydney') AS another_date FROM mytbl", 1, + validateNoErrors( + "SELECT DATE(date1 AT TIME ZONE 'UTC' AT TIME ZONE 'australia/sydney') AS another_date FROM mytbl", + 1, EXPRESSIONS); } @@ -224,9 +261,13 @@ public void testJsonFunctionExpression() throws JSQLParserException { @Test public void testJsonAggregartFunctionExpression() throws JSQLParserException { - validateNoErrors("SELECT JSON_ARRAYAGG( a FORMAT JSON ABSENT ON NULL ) FILTER( WHERE name = 'Raj' ) OVER( PARTITION BY name ) FROM mytbl", 1, + validateNoErrors( + "SELECT JSON_ARRAYAGG( a FORMAT JSON ABSENT ON NULL ) FILTER( WHERE name = 'Raj' ) OVER( PARTITION BY name ) FROM mytbl", + 1, EXPRESSIONS); - validateNoErrors("SELECT JSON_OBJECT( KEY 'foo' VALUE bar FORMAT JSON, 'foo':bar, 'foo':bar ABSENT ON NULL) FROM mytbl", 1, + validateNoErrors( + "SELECT JSON_OBJECT( KEY 'foo' VALUE bar FORMAT JSON, 'foo':bar, 'foo':bar ABSENT ON NULL) FROM mytbl", + 1, EXPRESSIONS); } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/GrantValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/GrantValidatorTest.java index b466c8ae5..d3151b303 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/GrantValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/GrantValidatorTest.java @@ -21,7 +21,8 @@ public class GrantValidatorTest extends ValidationTestAsserts { @Test public void testValidateGrant() throws JSQLParserException { - for (String sql : Arrays.asList("GRANT SELECT ON t1 TO u", "GRANT SELECT, INSERT ON t1 TO u, u2", + for (String sql : Arrays.asList("GRANT SELECT ON t1 TO u", + "GRANT SELECT, INSERT ON t1 TO u, u2", "GRANT role1 TO u, u2", "GRANT SELECT, INSERT, UPDATE, DELETE ON T1 TO ADMIN_ROLE", "GRANT ROLE_1 TO TEST_ROLE_1, TEST_ROLE_2")) { validateNoErrors(sql, 1, DatabaseType.DATABASES); @@ -30,7 +31,8 @@ public void testValidateGrant() throws JSQLParserException { @Test public void testValidateGrantNotAllowed() throws JSQLParserException { - for (String sql : Arrays.asList("GRANT SELECT ON t1 TO u", "GRANT SELECT, INSERT ON t1 TO u, u2", + for (String sql : Arrays.asList("GRANT SELECT ON t1 TO u", + "GRANT SELECT, INSERT ON t1 TO u, u2", "GRANT role1 TO u, u2", "GRANT SELECT, INSERT, UPDATE, DELETE ON T1 TO ADMIN_ROLE", "GRANT ROLE_1 TO TEST_ROLE_1, TEST_ROLE_2")) { validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.grant); diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/GroupByValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/GroupByValidatorTest.java index b8baeb20a..1a4078ce0 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/GroupByValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/GroupByValidatorTest.java @@ -25,7 +25,8 @@ public void testValidationSelectGroupBy() { @Test public void testValidationHaving() throws JSQLParserException { - String sql = "SELECT MAX(tab1.b) FROM tab1 WHERE a > 34 GROUP BY tab1.b HAVING MAX(tab1.b) > 56"; + String sql = + "SELECT MAX(tab1.b) FROM tab1 WHERE a > 34 GROUP BY tab1.b HAVING MAX(tab1.b) > 56"; validateNoErrors(sql, 1, DatabaseType.DATABASES); } @@ -34,7 +35,8 @@ public void testGroupingSets() throws JSQLParserException { for (String sql : Arrays.asList( "SELECT COL_1, COL_2, COL_3, COL_4, COL_5, COL_6 FROM TABLE_1 GROUP BY GROUPING SETS ((COL_1, COL_2, COL_3, COL_4), (COL_5, COL_6))", "SELECT COL_1 FROM TABLE_1 GROUP BY GROUPING SETS (COL_1)")) { - validateNoErrors(sql, 1, DatabaseType.ORACLE, DatabaseType.POSTGRESQL, DatabaseType.SQLSERVER); + validateNoErrors(sql, 1, DatabaseType.ORACLE, DatabaseType.POSTGRESQL, + DatabaseType.SQLSERVER); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/LimitValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/LimitValidatorTest.java index e90172a38..553e04758 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/LimitValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/LimitValidatorTest.java @@ -28,7 +28,8 @@ public void testValidationLimitAndOffset() throws JSQLParserException { for (String sql : Arrays.asList("SELECT * FROM mytable WHERE mytable.col = 9 LIMIT 3", "SELECT * FROM mytable WHERE mytable.col = 9 LIMIT ? OFFSET 3", "SELECT * FROM mytable WHERE mytable.col = 9 OFFSET ?")) { - validateNoErrors(sql, 1, DatabaseType.MARIADB, DatabaseType.MYSQL, DatabaseType.POSTGRESQL); + validateNoErrors(sql, 1, DatabaseType.MARIADB, DatabaseType.MYSQL, + DatabaseType.POSTGRESQL); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/MergeValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/MergeValidatorTest.java index ec37c4fec..ddf62f946 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/MergeValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/MergeValidatorTest.java @@ -33,7 +33,8 @@ public void testValidateMergeNotAllowed() throws JSQLParserException { for (String sql : Arrays.asList( "MERGE INTO a USING dual ON (col3 = ? AND col1 = ? AND col2 = ?) WHEN NOT MATCHED THEN INSERT (col1, col2, col3, col4) VALUES (?, ?, ?, ?) WHEN MATCHED THEN UPDATE SET col4 = col4 + ?", "MERGE INTO a USING dual ON (col3 = ? AND col1 = ? AND col2 = ?) WHEN MATCHED THEN UPDATE SET col4 = col4 + ? WHEN NOT MATCHED THEN INSERT (col1, col2, col3, col4) VALUES (?, ?, ?, ?)")) { - validateNotAllowed(sql, 1, 1, FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.JDBC), Feature.merge); + validateNotAllowed(sql, 1, 1, FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.JDBC), + Feature.merge); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/SetStatementValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/SetStatementValidatorTest.java index 49dbc9082..96b85493c 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/SetStatementValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/SetStatementValidatorTest.java @@ -19,8 +19,10 @@ public class SetStatementValidatorTest extends ValidationTestAsserts { @Test public void testValidateSet() throws JSQLParserException { - for (String sql : Arrays.asList("SET statement_timeout = 0; SET deferred_name_resolution true;", - "SET tester 5; SET v = 1, c = 3;", "SET standard_conforming_strings = on;SET statement_timeout = 0")) { + for (String sql : Arrays.asList( + "SET statement_timeout = 0; SET deferred_name_resolution true;", + "SET tester 5; SET v = 1, c = 3;", + "SET standard_conforming_strings = on;SET statement_timeout = 0")) { validateNoErrors(sql, 2, DatabaseType.POSTGRESQL); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/ShowIndexStatementValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/ShowIndexStatementValidatorTest.java index ee9469460..26b62d382 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/ShowIndexStatementValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/ShowIndexStatementValidatorTest.java @@ -19,9 +19,9 @@ import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed; /** -* -* @author Jayant Kumar Yadav -*/ + * + * @author Jayant Kumar Yadav + */ public class ShowIndexStatementValidatorTest extends ValidationTestAsserts { @@ -32,11 +32,11 @@ public void testValidationShowIndex() throws Exception { } } - + @Test public void testValidationShowIndexNotAllowed() throws Exception { for (String sql : Arrays.asList("SHOW INDEX FROM mydatabase")) { validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.showIndex); } } -} \ No newline at end of file +} diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/ShowTablesStatementValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/ShowTablesStatementValidatorTest.java index c237ea3ab..b61bd1d8a 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/ShowTablesStatementValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/ShowTablesStatementValidatorTest.java @@ -20,16 +20,20 @@ public class ShowTablesStatementValidatorTest extends ValidationTestAsserts { @Test public void testValidationShowTables() throws Exception { - for (String sql : Arrays.asList("SHOW TABLES", "SHOW EXTENDED FULL TABLES", "SHOW EXTENDED TABLES FROM db_name", - "SHOW FULL TABLES IN db_name", "SHOW TABLES LIKE '%FOO%'", "SHOW TABLES WHERE table_name = 'FOO'")) { + for (String sql : Arrays.asList("SHOW TABLES", "SHOW EXTENDED FULL TABLES", + "SHOW EXTENDED TABLES FROM db_name", + "SHOW FULL TABLES IN db_name", "SHOW TABLES LIKE '%FOO%'", + "SHOW TABLES WHERE table_name = 'FOO'")) { validateNoErrors(sql, 1, DatabaseType.MARIADB, DatabaseType.MYSQL); } } @Test public void testValidationShowTablesNotAllowed() throws Exception { - for (String sql : Arrays.asList("SHOW TABLES", "SHOW EXTENDED FULL TABLES", "SHOW EXTENDED TABLES FROM db_name", - "SHOW FULL TABLES IN db_name", "SHOW TABLES LIKE '%FOO%'", "SHOW TABLES WHERE table_name = 'FOO'")) { + for (String sql : Arrays.asList("SHOW TABLES", "SHOW EXTENDED FULL TABLES", + "SHOW EXTENDED TABLES FROM db_name", + "SHOW FULL TABLES IN db_name", "SHOW TABLES LIKE '%FOO%'", + "SHOW TABLES WHERE table_name = 'FOO'")) { validateNotAllowed(sql, 1, 1, FeaturesAllowed.DML, Feature.showTables); } } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/UpdateValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/UpdateValidatorTest.java index bdcfd25dc..ef8564376 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/UpdateValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/UpdateValidatorTest.java @@ -27,7 +27,8 @@ public void testValidationUpdate() throws JSQLParserException { @Test public void testValidationUpdateNotAllowed() throws JSQLParserException { String sql = "UPDATE tab1 SET ref = ? WHERE id = ?;"; - validateNotAllowed(sql, 1, 1, FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.JDBC), Feature.update); + validateNotAllowed(sql, 1, 1, FeaturesAllowed.SELECT.copy().add(FeaturesAllowed.JDBC), + Feature.update); } @Test @@ -38,13 +39,15 @@ public void testUpdateWithFrom() throws JSQLParserException { @Test public void testUpdateMultiTable() throws JSQLParserException { - String sql = "UPDATE T1, T2 SET T1.C2 = T2.C2, T2.C3 = 'UPDATED' WHERE T1.C1 = T2.C1 AND T1.C2 < 10"; + String sql = + "UPDATE T1, T2 SET T1.C2 = T2.C2, T2.C3 = 'UPDATED' WHERE T1.C1 = T2.C1 AND T1.C2 < 10"; validateNoErrors(sql, 1, DatabaseType.MYSQL, DatabaseType.MARIADB); } @Test public void testUpdateWithSelect() throws JSQLParserException { - String sql = "UPDATE mytable t1 SET (col1, col2, col3) = (SELECT a, b, c FROM mytable2 t2 WHERE t2.id = t1.id)"; + String sql = + "UPDATE mytable t1 SET (col1, col2, col3) = (SELECT a, b, c FROM mytable2 t2 WHERE t2.id = t1.id)"; validateNoErrors(sql, 1, DatabaseType.ORACLE); } @@ -56,7 +59,8 @@ public void testUpdateWithReturningAll() throws JSQLParserException { @Test public void testUpdateWithReturningList() throws JSQLParserException { - String sql = "UPDATE tablename SET col = 'thing' WHERE id = 1 RETURNING col_1, col_2, col_3"; + String sql = + "UPDATE tablename SET col = 'thing' WHERE id = 1 RETURNING col_1, col_2, col_3"; validateNoErrors(sql, 1, DatabaseType.POSTGRESQL, DatabaseType.ORACLE); } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/UseStatementValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/UseStatementValidatorTest.java index 6715d7d83..e8bf0c44f 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/UseStatementValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/UseStatementValidatorTest.java @@ -18,7 +18,8 @@ public class UseStatementValidatorTest extends ValidationTestAsserts { @Test public void testValidateUse() throws JSQLParserException { - validateNoErrors("USE my_schema", 1, DatabaseType.SQLSERVER, DatabaseType.MARIADB, DatabaseType.MYSQL); + validateNoErrors("USE my_schema", 1, DatabaseType.SQLSERVER, DatabaseType.MARIADB, + DatabaseType.MYSQL); } } diff --git a/src/test/resources/net/sf/jsqlparser/performance.sql b/src/test/resources/net/sf/jsqlparser/performance.sql new file mode 100644 index 000000000..d83065643 --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/performance.sql @@ -0,0 +1,2110 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2025 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +-- complex-lateral-select-request.txt +SELECT +O.ORDERID, +O.CUSTNAME, +OL.LINETOTAL, +OC.ORDCHGTOTAL, +OT.TAXTOTAL +FROM +ORDERS O, +LATERAL ( +SELECT +SUM(NETAMT) AS LINETOTAL +FROM +ORDERLINES LINES +WHERE +LINES.ORDERID=O.ORDERID +) AS OL, +LATERAL ( +SELECT +SUM(CHGAMT) AS ORDCHGTOTAL +FROM +ORDERCHARGES CHARGES +WHERE +LINES.ORDERID=O.ORDERID +) AS OC, +LATERAL ( +SELECT +SUM(TAXAMT) AS TAXTOTAL +FROM +ORDERTAXES TAXES +WHERE +TAXES.ORDERID=O.ORDERID +) AS OT +; + +-- large-sql-issue-235.txt +SELECT + 'CR' AS `^CR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -3) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -3) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^P3Q TRR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -2) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -2) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^P2Q TRR`, + (1 - (SUM((CASE + WHEN (`tbl`.`AS` = 'Cancelled') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = -1) THEN 1 + ELSE 0 + END) + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN (CASE + WHEN (ROUND((((((period_diff(date_format(`tbl`.`OCD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) <= -1) THEN 1 + ELSE 0 + END) + ELSE 0 + END)))) AS `^PQ TRR`, + (1 - (SUM((CASE + WHEN ((ROUND((((((period_diff(date_format(`tbl`.`CD`, + '%Y%m'), + date_format(SUBTIME(CURRENT_TIMESTAMP(), + 25200), + '%Y%m')) + month(SUBTIME(CURRENT_TIMESTAMP(), + 25200))) - MONTH('2012-02-01')) - 1) / 3) - ROUND((((month(SUBTIME(CURRENT_TIMESTAMP(), + 25200)) - MONTH('2012-02-01')) - 1) / 3)))) = 0) + AND (`tbl`.`AS` = 'Cancelled')) THEN 1 + ELSE 0 + END)) / SUM((CASE + WHEN (`tbl`.`AS` = 'Active') THEN 1 + ELSE 0 + END)))) AS `^CQ TRR` + FROM + `tbl` + GROUP BY + 'CR' LIMIT 25000 +; + +-- large-sql-issue-566.txt +SELECT "CAMPAIGNID","TARGET_SOURCE","NON_INDV_TYPE","GROUP_SPONSOR","SEGMNTS","COUNTRY_CD","TARGET_STATE","TARGET_CITY","TARGET_ZIP","SIC_CLASS","NAICS_CLASS","GENDER_CD","OCCUPATION","CREDIT_SCORE","MARITAL_STATUS","IMPORT_ID","BIRTH_DT","STATUS" + FROM ( + SELECT + X.CAMPAIGNID, + X.FIELDNAME, + CASE WHEN Y.VALUE IS NULL THEN 'ALL' + ELSE Y.VALUE END AS VALUE + FROM + --CREATES A CARTESIAN JOIN TO COMBINE ALL CHARACTERISTICS WITH CAMPAIGN + (SELECT + CAMPAIGNID, + FIELDNAME + FROM CAMPAIGN + CROSS JOIN (SELECT DISTINCT FIELDNAME + FROM FIELDCRITERIA)) X + LEFT JOIN + --RETURNS ALL AVAILABLE CAMPAIGN CHARACTERISTS + ( + SELECT + CAMPAIGNID, + FIELDNAME, + (CASE FIELDNAME + WHEN U'BUSINESSTYPE' THEN D.DISPLAYVALUE + WHEN U'LEADTARGETSOURCE' THEN E.DISPLAYVALUE + ELSE VALUE END) AS VALUE + FROM FIELDCRITERIA A, STRINGFIELDCRITERIA_VALUE B + LEFT JOIN (SELECT + B.CODE, + B.DISPLAYVALUE, + LOOKUPNAME + FROM LOOKUPLIST A, LOOKUPVALUE B + WHERE A.ID = B.LOOKUPLIST_ID AND LOOKUPNAME = 'NONINDIVIDUALTYPE') D ON B.VALUE = D.CODE + LEFT JOIN (SELECT + B.CODE, + B.DISPLAYVALUE, + LOOKUPNAME + FROM LOOKUPLIST A, LOOKUPVALUE B + WHERE A.ID = B.LOOKUPLIST_ID AND LOOKUPNAME = 'LEADTARGETSOURCE') E ON B.VALUE = E.CODE + , + CAMPAIGN C + WHERE A.ID = B.FIELD_CRITERIA_ID + AND A.CRITERIA_ID = C.ID + ) Y ON X.CAMPAIGNID = Y.CAMPAIGNID AND X.FIELDNAME = Y.FIELDNAME + ) + PIVOT (MAX(VALUE) + FOR FIELDNAME + IN + ('LEADTARGETSOURCE' AS TARGET_SOURCE, 'BUSINESSTYPE' AS NON_INDV_TYPE, 'GROUPSPONSOR' AS GROUP_SPONSOR, 'SEGMENTS' AS SEGMNTS, 'COUNTRYCD' AS COUNTRY_CD, 'STATEPROVCD' AS TARGET_STATE, + 'CITY' AS TARGET_CITY, 'POSTALCODE' AS TARGET_ZIP, 'SICCLASSIFICATION' AS SIC_CLASS, 'NAICSCLASSIFICATION' AS NAICS_CLASS, 'GENDERCD' AS GENDER_CD, 'OCCUPATION' AS OCCUPATION, 'CREDITSCORE' AS CREDIT_SCORE, + 'MARITALSTATUSCD' AS MARITAL_STATUS, 'IMPORTID' AS IMPORT_ID, 'BIRTHDATE' AS BIRTH_DT, 'STATUS' AS STATUS)) +; + +-- large-sql-issue-923.txt +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + CLM.STATUS_C, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + EPPCL.PRODUCT_TYPE, + CLM.SERVICE_START_DATE, + CLM.SERVICE_END_DATE, + CLM.DATE_RECEIVED, + CLM_CS.NAME, + CLM.STATUS_DATE, + CLM_APSTS.ABBR, + CLM_CF.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + GRP.PLAN_GRP_NAME, + SERREN_2.NPI, + SERREN.PROV_NAME, + D_VTN.TAX_ID, + VENCLM.VENDOR_NAME, + (CLM.TOT_BILLED_AMT), + (CLM.TOT_NET_PAYABLE), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME), + POS.CITY, + POS_ST.ABBR, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + POS_TYPE.NAME, + POS.POS_CODE, + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END, + CLM_MAP5.INTERNAL_ID, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLAIM_FORMAT CLM_CF RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_FORMAT_C=CLM_CF.CLAIM_FORMAT_C) + LEFT OUTER JOIN ZC_CLM_STATUS CLM_CS ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN ZC_CLM_AP_STAT CLM_APSTS ON (CLM.AP_STS_C=CLM_APSTS.AP_STS_C) + LEFT OUTER JOIN CLARITY_POS POS ON (CLM.LOC_ID=POS.POS_ID) + LEFT OUTER JOIN ZC_POS_TYPE POS_TYPE ON (POS.POS_TYPE_C=POS_TYPE.POS_TYPE_C) + LEFT OUTER JOIN ZC_STATE POS_ST ON (POS.STATE_C=POS_ST.STATE_C AND POS_ST.INTERNAL_ID >= 0 AND POS_ST.INTERNAL_ID <= 51) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN AP_CLAIM AOC ON (CLM.ORIG_ADJST_CLM_ID=AOC.CLAIM_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP5 ON (AOC.CLAIM_ID=CLM_MAP5.CID AND AOC.CM_LOG_OWNER_ID=CLM_MAP5.CM_LOG_OWNER_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END BETWEEN (CASE + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ) Like 't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) AND (CASE + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ) Like't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) + AND + ( + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:7,Optional) + ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:9,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:13) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + EOB_CODE.ROUTE_FROM_DISC_C, + EOB_CODE.MNEMONIC +FROM + ZC_POS_TYPE CLMPOS RIGHT OUTER JOIN AP_CLAIM_PX CLD ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END BETWEEN (CASE + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ) Like 't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized From Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) AND (CASE + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='t' THEN + trunc(sysdate) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ) Like't-%' THEN + trunc(sysdate)-to_number(Substr(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),3,3)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb' THEN + TRUNC(sysdate, 'IW')-1 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='wb-1' THEN + TRUNC(sysdate, 'IW')-8 + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we' THEN + NEXT_DAY(TRUNC(sysdate,'IW'),'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='we-1' THEN + NEXT_DAY(TRUNC(sysdate,'IW')-8,'SATURDAY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb' THEN + trunc(sysdate,'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me' THEN + trunc(last_day(sysdate)) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-1' THEN + trunc(trunc(sysdate, 'MM') - 1, 'MM') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-1' THEN + (trunc(sysdate, 'MM') - 1) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='mb-2' THEN + add_months(trunc(sysdate, 'MM'), - 2) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='me-2' THEN + (last_day(add_months (sysdate,-2))) + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb' THEN + trunc(sysdate,'YY') + WHEN ( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) )='yb-1' THEN + trunc(trunc(sysdate, 'YY') - 1, 'YY') + else + TO_DATE(( @Prompt(Enter Claim Finalized Thru Date:§(relative or absolute date§)) ),'MM/dd/yyyy') +END) + AND + ( + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:7,Optional) + ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:9,Optional) + AND + EOB_CODE.CODE_TYPE_C IN ( 2 ) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:13) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME +FROM + CLARITY_EOB_CODE EOB_CODE +WHERE + EOB_CODE.CODE_TYPE_C = 2 +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + EAP.PROC_CODE, + CLM_CS.NAME, + CLM.STATUS_DATE, + CKR.CHECK_STATUS_C, + CLM_APSTS.ABBR, + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + EOB_CODE2.MNEMONIC, + EOB_CODE2.CODE_TYPE_C, + EOB_CODE.CODE_TYPE_C, + EOB_CODE2.EOB_CODE_NAME, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLM_STATUS CLM_CS RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN ZC_CLM_AP_STAT CLM_APSTS ON (CLM.AP_STS_C=CLM_APSTS.AP_STS_C) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN CLARITY_EAP EAP ON (CLD.PROC_ID=EAP.PROC_ID) + LEFT OUTER JOIN AP_CLAIM_PX_EOBS CLD_EOB ON (CLD.TX_ID=CLD_EOB.TX_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE2 ON (CLD_EOB.EOB_CODE_ID=EOB_CODE2.EOB_CODE_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN ( + SELECT + PRV_SPEC.PROV_ID PROV_ID, + PRV_SPEC.SPECIALTY_C SPECIALTY_C +FROM + CLARITY_SER_SPEC PRV_SPEC +WHERE LINE=1 +group by PROV_ID,SPECIALTY_C + ) D_PRV_SPEC ON (SERREN.PROV_ID=D_PRV_SPEC.PROV_ID) + LEFT OUTER JOIN ZC_SPECIALTY ZC_SPEC ON (D_PRV_SPEC.SPECIALTY_C=ZC_SPEC.SPECIALTY_C) + LEFT OUTER JOIN CLARITY_SER_ADDR SERRENADDR ON (SERREN.PROV_ID=SERRENADDR.PROV_ID) + LEFT OUTER JOIN ZC_STATE SERRENST ON (SERRENADDR.STATE_C=SERRENST.STATE_C AND SERRENST.INTERNAL_ID >= 0 AND SERRENST.INTERNAL_ID <= 51) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + CLM.STATUS_C = 3 + AND + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END Is Null + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:7,Optional) + AND + ( + EOB_CODE2.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim Line (CLD)\Claim Line EOB\Eob Code Id (CLD)\Mnemonic (CLD)',Multi,Free,Persistent,,User:8,Optional) + OR + EOB_CODE.MNEMONIC IN @Prompt('Enter Claim Denial Code(s) or Leave Blank for All:','A','Claim EOB (EOB)\Eob Code Id (CLM_EOB)\Mnemonic (EOB_CODE)',Multi,Free,Persistent,,User:9,Optional) + ) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:10,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:11,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:12,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,{'Original Claim'},User:13) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +--END-- +SELECT DISTINCT + CLM_MAP_1.INTERNAL_ID, + CLD.LINE, + CLM.ACCT_NUM_WITH_VEN +, + CLM_CF.NAME, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + VENCLM.VENDOR_NAME, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + SERREN.PROV_NAME, + EAP.PROC_CODE, + CLM.TYPE_OF_BILL, + CLM_CS.NAME, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end), + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end), + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end), + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CLM.DATE_RECEIVED, + CLM.SERVICE_END_DATE, + WQ.WORKQUEUE_NAME, + CLM.SERVICE_START_DATE, + CLD.POS_TYPE_C, + CLMPOS.NAME, + POS.POS_NAME, + sum(coalesce(CLD.OVERRIDE_ALLD_AMT,CLD.ALLOWED_AMT,0)), + CLD.NET_PAYABLE, + sum(coalesce(CLD.OVRD_COPAY,CLD.COPAYMENT,0)), + sum(coalesce(CLD.OVRD_COINS,CLD.COINSURANCE,0)), + sum(CLD.BILLED_AMT), + EAFMAP.INTERNAL_ID, + sum(coalesce(CLD.OVRD_DEDUCTIBLE,CLD.DEDUCTIBLE,0)), + SUM(CLD.PRIM_PAT_PORTION), + sum(CLD.PRIM_INS_AMOUNT), + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST, + CLD.BILLED_AMT +FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE, ZC_CLAIM_FORMAT CLM_CF RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM.CLAIM_FORMAT_C=CLM_CF.CLAIM_FORMAT_C) + LEFT OUTER JOIN ZC_CLM_STATUS CLM_CS ON (CLM.STATUS_C=CLM_CS.STATUS_C) + LEFT OUTER JOIN PATIENT PAT ON (PAT.PAT_ID=CLM.PAT_ID) + LEFT OUTER JOIN CLARITY_POS POS ON (CLM.LOC_ID=POS.POS_ID) + LEFT OUTER JOIN EAF_MAP EAFMAP ON (EAFMAP.CID=POS.POS_ID AND POS.CM_LOG_OWNER_ID=EAFMAP.CM_LOG_OWNER_ID) + LEFT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EOB_CODE EOB_CODE ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + LEFT OUTER JOIN COVERAGE COVCL ON (CLM.COVERAGE_ID=COVCL.COVERAGE_ID) + LEFT OUTER JOIN PLAN_GRP GRP ON (GRP.PLAN_GRP_ID=COVCL.PLAN_GRP_ID) + LEFT OUTER JOIN ZC_REGION_CODE ZC_REG_CD ON (GRP.CUR_REGION_CODE_C=ZC_REG_CD.REGION_CODE_C) + LEFT OUTER JOIN CLARITY_LOB LOBCL ON (CLM.CLM_LOB_ID=LOBCL.LOB_ID) + LEFT OUTER JOIN ( + (SELECT + CLM.CLAIM_ID + FROM AP_CLAIM CLM + WHERE + CLM.CLAIM_ID NOT IN +(SELECT CLAIM_ID +FROM AP_CLAIM_CHANGE_HX HX +LEFT OUTER JOIN ECI_BASIC ECI ON HX.CM_LOG_OWNER_ID =ECI.INSTANCE_ID +WHERE((UPPER(DEPLYMNT_DESC) LIKE '%NP%' AND CHANGE_HX_USER_ID NOT IN ( '161NCALTAP3','161NCALTAP1')) --NCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%CO%' AND CHANGE_HX_USER_ID NOT IN ( '140194','44323593','44323592')) --CO +OR (UPPER(DEPLYMNT_DESC) LIKE '%SP%' AND CHANGE_HX_USER_ID NOT IN ( '1501001006','1501001005','150119165')) --SCAL +OR (UPPER(DEPLYMNT_DESC) LIKE '%MA%' AND CHANGE_HX_USER_ID NOT IN ( '170100056','1213117','19012093','17017391')) --MAS +OR (UPPER(DEPLYMNT_DESC) LIKE '%NW%' AND CHANGE_HX_USER_ID NOT IN ( '19012093','19012091')) --NW +OR (UPPER(DEPLYMNT_DESC) LIKE '%HI%' AND CHANGE_HX_USER_ID NOT IN ( '130HI50101','130HI50100')) --HI +OR (UPPER(DEPLYMNT_DESC) LIKE '%GA%' AND CHANGE_HX_USER_ID NOT IN('2001','200EDIUSER')) -- GA +) ) +AND (CLM.STATUS_C IN (3, 4, 5) +AND CLM.ORIG_REV_CLM_ID IS NULL +AND CLM.ORIG_ADJST_CLM_ID IS NULL)) + ) D_AA_INDICATOR ON (D_AA_INDICATOR.CLAIM_ID=CLM.CLAIM_ID) + LEFT OUTER JOIN CLARITY_EPP EPPCL ON (CLM.PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN CLARITY_EPP_2 EPPCL_2 ON (EPPCL_2.BENEFIT_PLAN_ID=EPPCL.BENEFIT_PLAN_ID) + LEFT OUTER JOIN ZC_PROD_TYPE ZC_PRD_TYP ON (EPPCL_2.PROD_TYPE_C=ZC_PRD_TYP.PROD_TYPE_C) + LEFT OUTER JOIN AP_CLAIM_PX CLD ON (CLM.CLAIM_ID=CLD.CLAIM_ID) + LEFT OUTER JOIN ZC_POS_TYPE CLMPOS ON (CLD.POS_TYPE_C=CLMPOS.POS_TYPE_C) + LEFT OUTER JOIN CLARITY_EAP EAP ON (CLD.PROC_ID=EAP.PROC_ID) + LEFT OUTER JOIN AP_CLAIM_2 CLM2 ON (CLM.CLAIM_ID=CLM2.CLAIM_ID) + LEFT OUTER JOIN ZC_CLM_TRAIT_3 CLM_TRAIT ON (CLM2.CLM_TRAIT_3_C=CLM_TRAIT.CLM_TRAIT_3_C) + LEFT OUTER JOIN ZC_CLM_TRAIT_4 CLM_TRAIT_4 ON (CLM2.CLM_TRAIT_4_C=CLM_TRAIT_4.CLM_TRAIT_4_C +) + LEFT OUTER JOIN ZC_CLM_TRAIT_2 CLM_TRAIT_2 ON (CLM2.CLM_TRAIT_2_C=CLM_TRAIT_2.CLM_TRAIT_2_C) + LEFT OUTER JOIN CLARITY_SER SERREN ON (CLM.PROV_ID=SERREN.PROV_ID) + LEFT OUTER JOIN CLARITY_SER_2 SERREN_2 ON (SERREN.PROV_ID=SERREN_2.PROV_ID) + LEFT OUTER JOIN ( + SELECT + PRV_SPEC.PROV_ID PROV_ID, + PRV_SPEC.SPECIALTY_C SPECIALTY_C +FROM + CLARITY_SER_SPEC PRV_SPEC +WHERE LINE=1 +group by PROV_ID,SPECIALTY_C + ) D_PRV_SPEC ON (SERREN.PROV_ID=D_PRV_SPEC.PROV_ID) + LEFT OUTER JOIN ZC_SPECIALTY ZC_SPEC ON (D_PRV_SPEC.SPECIALTY_C=ZC_SPEC.SPECIALTY_C) + LEFT OUTER JOIN CLARITY_SER_ADDR SERRENADDR ON (SERREN.PROV_ID=SERRENADDR.PROV_ID) + LEFT OUTER JOIN ZC_STATE SERRENST ON (SERRENADDR.STATE_C=SERRENST.STATE_C AND SERRENST.INTERNAL_ID >= 0 AND SERRENST.INTERNAL_ID <= 51) + LEFT OUTER JOIN CLARITY_VENDOR VENCLM ON (VENCLM.VENDOR_ID=CLM.VENDOR_ID) + LEFT OUTER JOIN ( + select t1.vendor_id,t1.line,t1.TAX_ID +from vendor_tax_id t1 , +(select vendor_id,max(line) as line from vendor_tax_id group by vendor_id) t2 Where t1.vendor_id=t2.vendor_id and t1.line=t2.line +group by t1.vendor_id,t1.line,t1.TAX_ID + ) D_VTN ON (VENCLM.VENDOR_ID=D_VTN.VENDOR_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT VENDOR_ID, PLACE_OF_SERVICE_ID FROM VENDOR_POS +WHERE PLACE_OF_SERVICE_ID IN (SELECT POS_ID FROM CLARITY_POS WHERE POS_NAME LIKE '%VISITING MEM%') +union all +SELECT distinct + t1.vendor_id + ,999 as PLACE_OF_SERVICE_ID +from + vendor_tax_id t1 inner join + ( + select vendor_id, + max(line) as line + from vendor_tax_id + group by vendor_id + ) t2 on t1.vendor_id=t2.vendor_id + and t1.line=t2.line +WHERE + t1.TAX_ID = '811559375' + ) D_VM ON (D_VM.VENDOR_ID=VENCLM.VENDOR_ID) + LEFT OUTER JOIN CLM_MAP CLM_MAP_1 ON (CLM.CLAIM_ID=CLM_MAP_1.CID AND CLM.CM_LOG_OWNER_ID=CLM_MAP_1.CM_LOG_OWNER_ID) + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,PAT_LIABILITY +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,CASE WHEN MAX(EOB.ROUTE_FROM_DISC_C)=2 THEN 'Yes' ELSE + 'No' + END AS PAT_LIABILITY + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_PX_EOBS CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + GROUP BY CLM_EOB.CLAIM_ID,EOB.ROUTE_FROM_DISC_C,EOB.MNEMONIC,RMC.RMC_EXTERNAL_ID,RMK.ABBR + ) +GROUP BY CLAIM_ID,PAT_LIABILITY + ) LISTAGG_DTL_INFO ON (CLM.CLAIM_ID=LISTAGG_DTL_INFO.CLAIM_ID) + LEFT OUTER JOIN ( + SELECT DISTINCT CLM.CLAIM_ID FROM ( + select DISTINCT min(owner) AS + CLARITY_DATABASE +FROM +ALL_VIEWS WHERE VIEW_NAME LIKE 'AP_CLAIM' + And OWNER Like 'HCCL%' + ) D_CLARITY_DATABASE + , CLARITY_EOB_CODE EOB_CODE + RIGHT OUTER JOIN AP_CLAIM_EOB_CODE CLM_EOB ON (EOB_CODE.EOB_CODE_ID=CLM_EOB.EOB_CODE_ID) + RIGHT OUTER JOIN AP_CLAIM CLM ON (CLM_EOB.CLAIM_ID=CLM.CLAIM_ID) + WHERE + ( ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('SC','NC') AND EOB_CODE.MNEMONIC IN ('CI134','CLP38','CLI36') AND CLM_EOB.ENTRY_DATE >=TO_DATE ('2017-12-15' ,'YYYY-MM-DD')) + ) "LEGACY_ADJST" ON (CLM.CLAIM_ID="LEGACY_ADJST"."CLAIM_ID") + LEFT OUTER JOIN ( + SELECT +CLAIM_ID +,LISTAGG(MNEMONIC,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS CODE_LIST +,LISTAGG(REMIT_CD,', ') WITHIN GROUP ( ORDER BY MNEMONIC) AS REMIT_CODE_LIST +FROM (SELECT DISTINCT + CLM_EOB.CLAIM_ID + ,EOB.MNEMONIC + ,RMC.RMC_EXTERNAL_ID||'/'||RMK.ABBR AS REMIT_CD + FROM + AP_CLAIM_EOB_CODE CLM_EOB, + CLARITY_EOB_CODE EOB, + CLARITY_RMC RMC, + ZC_REMARK_CODE RMK + WHERE + CLM_EOB.EOB_CODE_ID=EOB.EOB_CODE_ID + AND EOB.REMIT_CODE_ID=RMC.REMIT_CODE_ID(+) + AND EOB.REMARK_CODE_C=RMK.REMARK_CODE_C(+) + AND CLM_EOB.RESOLUTION_DATE IS NULL + --1 IS PEND CODE 2 IS DENIAL CODE 3 IS INFO CODE + AND EOB.CODE_TYPE_C=3 + ) +GROUP BY CLAIM_ID + ) LISTAGG_HDR_INFO ON (CLM.CLAIM_ID=LISTAGG_HDR_INFO.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_WQ_ITEM WQI ON (CLM.CLAIM_ID=WQI.CLAIM_ID) + LEFT OUTER JOIN AP_CLAIM_WQ WQ ON (WQI.WORKQUEUE_ID=WQ.WORKQUEUE_ID) + LEFT OUTER JOIN AP_CLAIM_CHECK CLM_CHK ON (CLM.CLAIM_ID=CLM_CHK.CLAIM_ID) + LEFT OUTER JOIN AP_CHECK CKR ON (CLM_CHK.CHECK_ID=CKR.CHECK_ID) +WHERE +( COALESCE(CLM.WORKFLOW_C,0) IN @Prompt(P_WorkflowTypeInclude) and COALESCE(CLM_TRAIT_4.NAME,'CCA') In @Prompt(P_CCA-TPMG) ) + AND + ( + coalesce(EPPCL.PRODUCT_TYPE ,ZC_PRD_TYP.NAME) IN @Prompt('Enter Product Type or Leave Blank for All:','A','Claim Header (CLM)\Claim Header IDs (CLM)\Benefit Plan Id (CLM)\Product Type',Multi,Free,Persistent,,User:1,Optional) + AND + nvl(LOBCL.LOB_NAME,'UNKNOWN') LIKE @Prompt('Enter Line of Business or Leave Blank for All:','A','Claim Header (CLM)\Line Of Business (CLM)\Line Of Business Name (CLM)',Mono,Free,Persistent,,User:2,Optional) + AND + SERREN.PROV_NAME LIKE @Prompt('Enter Provider Name or Leave Blank for All:','A','Provider (PRV)\Rendering (SERREN)\Prov Name (SERREN)',Mono,Free,Persistent,,User:3,Optional) + AND + SERREN_2.NPI LIKE @Prompt('Enter Provider ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:4,Optional) + AND + D_VTN.TAX_ID LIKE @Prompt('Enter Vendor Tax ID or Leave Blank for All:','A',,Mono,Free,Persistent,,User:5,Optional) + AND + VENCLM.VENDOR_NAME LIKE @Prompt('Enter Vendor Name or Leave Blank for All:','A','Claim Header Vendor (VENCLM)\Vendor Name (VENCLM)',Mono,Free,Persistent,,User:6,Optional) + AND + GRP.PLAN_GRP_NAME LIKE @Prompt('Enter Plan Group Name or Leave Blank for All:','A','Plan / Group (GRP)\Plan Grp Name (GRP)',Mono,Free,Persistent,,User:0,Optional) + AND + ( + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ) IN ( '77','76' ) + OR + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end) IN ( '77','76' ) + ) + AND + ( + CLM.STATUS_C = 3 + OR + CLD.STATUS_C = 1 + ) + AND + EOB_CODE.MNEMONIC IN ( 'CED12','CED44' ) + AND + CLMPOS.NAME IN @Prompt('Enter POS Type(s) or Leave Blank for All:','A','Claim Line (CLD)\Pos Type C (CLD)\Name (CLMPOS)',Multi,Free,Persistent,,User:7,Optional) + AND + NVL(CLM_TRAIT.NAME,'KFHP') IN @Prompt('Enter ANIC Claim Trait or Leave Blank for All:','A','Claim Header (CLM)\Company Code (CLM)',Multi,Free,Persistent,,User:8,Optional) + AND + nvl(CLM2.DENTAL_INFO_YN,'N') IN @Prompt('Enter Dental Indicator (Y/N):','A','Claim Header (CLM)\Dental Info Yn (CLM2)',Multi,Free,Persistent,{'N'},User:9,Optional) + AND + CLM.ADJST_CLM_ID Is Null + AND + ZC_REG_CD.NAME IN @Prompt('Enter CO Service Area Name:','A','Plan / Group (GRP)\Current Region Code C (GRP)\Current Region Code Name (GRP)',Multi,Free,Persistent,,User:10,Optional) + AND + CASE +WHEN CLM.ORIG_REV_CLM_ID IS NOT NULL + THEN 'Reversal Claim' +WHEN (CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NULL) OR ("LEGACY_ADJST"."CLAIM_ID" IS NOT NULL) + THEN 'Adjusted / Revised Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NOT NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND CLM.ADJST_CLM_ID IS NOT NULL + THEN 'Multiple Adj Interim Claim' +WHEN CLM.ORIG_ADJST_CLM_ID IS NULL AND CLM.ORIG_REV_CLM_ID IS NULL AND "LEGACY_ADJST"."CLAIM_ID" IS NULL + THEN 'Original Claim' +ELSE NULL +END IN @Prompt('Enter Claim Adjudication Type:','A','Claim Header (CLM)\Clm Adj Type (CLM)\Clm Adj Type Desc (CLM)',Multi,Free,Persistent,,User:11) + AND + ( ( CASE +WHEN D_VM.PLACE_OF_SERVICE_ID IS NOT NULL THEN 'Y' ELSE 'N' +END ) in @Prompt(Visiting Member) OR ( 'ALL') IN @Prompt(Visiting Member) ) + ) +GROUP BY + CLM_MAP_1.INTERNAL_ID, + CLD.LINE, + CLM.ACCT_NUM_WITH_VEN +, + CLM_CF.NAME, + CASE +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NC','SC') AND +CLM_TRAIT_2.ABBR='CAP' +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) IN ('NW') AND + (UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM SUNNYSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM WESTSIDE%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANNW REGIONAL LAB%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM CLINIC%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'CARE ESSENTIALS BY ANTHEM NW%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM HOSPITALS%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'HI' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%HAWAII PERMANENTE MEDICAL GROUP' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%HOSPITAL%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION HEALTH PLAN INC%') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'CO' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%COLORADO PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC FRANKLIN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'KASC LONETREE%') +Then 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'MAS' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%INTRGNL AN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN OF THE MID-ATLANTIC STATES%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%MID ATLANTIC PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR upper(VENCLM.VENDOR_NAME) = 'ANTHEM MID ATLANTIC') +THEN 'Internal' +WHEN ( case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end ) = 'GA' AND +(UPPER(VENCLM.VENDOR_NAME) LIKE '%ANTHEM FOUNDATION HEALTH PLAN%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE '%PERMANENTE MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FOUNDATION MEDICAL GROUP%' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'PMG VENDOR' +OR UPPER(VENCLM.VENDOR_NAME) LIKE 'ANTHEM FAMILY CHIROPRACTI%') +THEN 'Internal' +ELSE 'External' +END, + VENCLM.VENDOR_NAME, + nvl(LOBCL.LOB_NAME,'UNKNOWN'), + SERREN.PROV_NAME, + EAP.PROC_CODE, + CLM.TYPE_OF_BILL, + CLM_CS.NAME, + ZC_SPEC.NAME, + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME, + (case when length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) = 0 or length(substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1))) Is Null then CLD.MODIFIERS else substr(CLD.MODIFIERS, 0,instr(CLD.MODIFIERS, ',',1,1)-1) end), + (case when length(CLD.MODIFIERS) > 3 then substr(CLD.MODIFIERS,4,2) else '0' end), + (case when length(CLD.MODIFIERS) > 6 then substr(CLD.MODIFIERS,7,2) else '0' end), + (case when length(CLD.MODIFIERS) > 9 then substr(CLD.MODIFIERS,10,2) else '0' end ), + CASE + WHEN CLM.AP_STS_C=3 THEN CKR.AP_RUN_DATE +END, + CLM.DATE_RECEIVED, + CLM.SERVICE_END_DATE, + WQ.WORKQUEUE_NAME, + CLM.SERVICE_START_DATE, + CLD.POS_TYPE_C, + CLMPOS.NAME, + POS.POS_NAME, + CLD.NET_PAYABLE, + EAFMAP.INTERNAL_ID, + TRUNC((sysdate-( PAT.BIRTH_DATE ))/365,0), + Upper(SERRENADDR.CITY), + SERRENST.ABBR, + case + when D_AA_INDICATOR.CLAIM_ID is null +then 'Not AA' +else 'AA' end, + ZC_REG_CD.NAME, + case when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLHI%' then 'HI' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNW%' then 'NW' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLMA%' then 'MAS' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLSC%' then 'SC' +when D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLNC%' then 'NC' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLCO%' then 'CO' +When D_CLARITY_DATABASE.CLARITY_DATABASE like '%HCCLGA%' then 'GA' +else 'Contact BO Developers' end, + LISTAGG_DTL_INFO.CODE_LIST, + LISTAGG_HDR_INFO.CODE_LIST, + CLD.BILLED_AMT +--END-- +SELECT DISTINCT + EOB_CODE.MNEMONIC, + EOB_CODE.EOB_CODE_NAME +FROM + CLARITY_EOB_CODE EOB_CODE +WHERE + EOB_CODE.CODE_TYPE_C = 3 +; + +-- large-sql-with-issue-265.txt +with cross_items as +(select i_item_sk ss_item_sk +from item, +(select iss.i_brand_id brand_id +,iss.i_class_id class_id +,iss.i_category_id category_id +from store_sales +,item iss +,date_dim d1 +where ss_item_sk = iss.i_item_sk +and ss_sold_date_sk = d1.d_date_sk +and d1.d_year between 1999 AND 1999 + 2 +intersect +select ics.i_brand_id +,ics.i_class_id +,ics.i_category_id +from catalog_sales +,item ics +,date_dim d2 +where cs_item_sk = ics.i_item_sk +and cs_sold_date_sk = d2.d_date_sk +and d2.d_year between 1999 AND 1999 + 2 +intersect +select iws.i_brand_id +,iws.i_class_id +,iws.i_category_id +from web_sales +,item iws +,date_dim d3 +where ws_item_sk = iws.i_item_sk +and ws_sold_date_sk = d3.d_date_sk +and d3.d_year between 1999 AND 1999 + 2) x +where i_brand_id = brand_id +and i_class_id = class_id +and i_category_id = category_id +), +avg_sales as +(select avg(quantitylist_price) average_sales +from (select ss_quantity quantity +,ss_list_price list_price +from store_sales +,date_dim +where ss_sold_date_sk = d_date_sk +and d_year between 1999 and 2001 +union all +select cs_quantity quantity +,cs_list_price list_price +from catalog_sales +,date_dim +where cs_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select ws_quantity quantity +,ws_list_price list_price +from web_sales +,date_dim +where ws_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2) x) +select channel, i_brand_id,i_class_id,i_category_id,sum(sales), sum(number_sales) +from( +select 'store' channel, i_brand_id,i_class_id +,i_category_id,sum(ss_quantityss_list_price) sales +, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantityss_list_price) > (select average_sales from avg_sales) +union all +select 'catalog' channel, i_brand_id,i_class_id,i_category_id, sum(cs_quantitycs_list_price) sales, count() number_sales +from catalog_sales +,item +,date_dim +where cs_item_sk in (select ss_item_sk from cross_items) +and cs_item_sk = i_item_sk +and cs_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(cs_quantitycs_list_price) > (select average_sales from avg_sales) +union all +select 'web' channel, i_brand_id,i_class_id,i_category_id, sum(ws_quantityws_list_price) sales , count() number_sales +from web_sales +,item +,date_dim +where ws_item_sk in (select ss_item_sk from cross_items) +and ws_item_sk = i_item_sk +and ws_sold_date_sk = d_date_sk +and d_year = 1998+2 +and d_moy = 11 +group by i_brand_id,i_class_id,i_category_id +having sum(ws_quantityws_list_price) > (select average_sales from avg_sales) +) y +group by rollup (channel, i_brand_id,i_class_id,i_category_id) +order by channel,i_brand_id,i_class_id,i_category_id +limit 100; +with cross_items as +(select i_item_sk ss_item_sk +from item, +(select iss.i_brand_id brand_id +,iss.i_class_id class_id +,iss.i_category_id category_id +from store_sales +,item iss +,date_dim d1 +where ss_item_sk = iss.i_item_sk +and ss_sold_date_sk = d1.d_date_sk +and d1.d_year between 1999 AND 1999 + 2 +intersect +select ics.i_brand_id +,ics.i_class_id +,ics.i_category_id +from catalog_sales +,item ics +,date_dim d2 +where cs_item_sk = ics.i_item_sk +and cs_sold_date_sk = d2.d_date_sk +and d2.d_year between 1999 AND 1999 + 2 +intersect +select iws.i_brand_id +,iws.i_class_id +,iws.i_category_id +from web_sales +,item iws +,date_dim d3 +where ws_item_sk = iws.i_item_sk +and ws_sold_date_sk = d3.d_date_sk +and d3.d_year between 1999 AND 1999 + 2) x +where i_brand_id = brand_id +and i_class_id = class_id +and i_category_id = category_id +), +avg_sales as +(select avg(quantitylist_price) average_sales +from (select ss_quantity quantity +,ss_list_price list_price +from store_sales +,date_dim +where ss_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select cs_quantity quantity +,cs_list_price list_price +from catalog_sales +,date_dim +where cs_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2 +union all +select ws_quantity quantity +,ws_list_price list_price +from web_sales +,date_dim +where ws_sold_date_sk = d_date_sk +and d_year between 1998 and 1998 + 2) x) +select * from +(select 'store' channel, i_brand_id,i_class_id,i_category_id +,sum(ss_quantityss_list_price) sales, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_week_seq = (select d_week_seq +from date_dim +where d_year = 1998 + 1 +and d_moy = 12 +and d_dom = 16) +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantityss_list_price) > (select average_sales from avg_sales)) this_year, +(select 'store' channel, i_brand_id,i_class_id +,i_category_id, sum(ss_quantityss_list_price) sales, count() number_sales +from store_sales +,item +,date_dim +where ss_item_sk in (select ss_item_sk from cross_items) +and ss_item_sk = i_item_sk +and ss_sold_date_sk = d_date_sk +and d_week_seq = (select d_week_seq +from date_dim +where d_year = 1998 +and d_moy = 12 +and d_dom = 16) +group by i_brand_id,i_class_id,i_category_id +having sum(ss_quantity*ss_list_price) > (select average_sales from avg_sales)) last_year +where this_year.i_brand_id= last_year.i_brand_id +and this_year.i_class_id = last_year.i_class_id +and this_year.i_category_id = last_year.i_category_id +order by this_year.channel, this_year.i_brand_id, this_year.i_class_id, this_year.i_category_id +limit 100; + + +-- performanceIssue1397.sql +SELECT "TABLE1"."LABEL" , + (CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) AS "SEGMENT", + (CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q1 000 - Small Amps', 'Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 000 - Upper Reddle Alt')) THEN '000 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 000 - Entry Amps', 'Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 000 - Waterproof Speakers', 'Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 000 - Small Amps', 'Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 000 - Campery', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 000 - Fires - Smooth')) THEN '000 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 000 - Small Amps', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 000 - Upper Reddle Alt')) THEN '000 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 000 - Entry Amps', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Small Amps', 'Registration Q4 000 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Campery', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Fires - Smooth')) THEN '000 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 001 - Small Amps', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 001 - Upper Reddle Alt')) THEN '001 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 001 - Entry Amps', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Small Amps', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Campery', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Fires - Smooth')) THEN '001 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 001 - Small Amps', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 001 - Upper Reddle Alt')) THEN '001 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 001 - Entry Amps', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Small Amps', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 001 - Campery', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 001 - Fires - Smooth')) THEN '001 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 002 - Small Amps', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 002 - Upper Reddle Alt')) THEN '002 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q2 002 - Entry Amps', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Small Amps', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Wagon', 'Registration Q2 002 - Campery', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Fires - Smooth')) THEN '002 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 002 - Small Amps', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 002 - Upper Reddle Alt')) THEN '002 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 002 - Entry Amps', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Small Amps', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 002 - Campery', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 002 - Fires - Smooth')) THEN '002 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 005 - Small Amps', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 005 - Upper Reddle Alt')) THEN '005 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Entry Amps', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Small Amps', 'Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 005 - Campers Amps', 'Registration Q2 005 - Campery', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q2 005 - Fires - Smooth')) THEN '005 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 005 - Entry Amps', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Small Amps', 'Registration Q4 005 - Camper Yeah - Entry Alt', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 005 - Campers Amps', 'Registration Q4 005 - Campery', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 005 - Fires - Smooth')) THEN '005 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 006 - Small Amps', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 006 - Upper Reddle Alt')) THEN '006 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 006 - Small Amps', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q3 006 - Upper Reddle Alt')) THEN '006 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Entry Amps', 'Registration Q4 006 - Fullsize Amp Alt', 'Registration Q4 006 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Small', 'Registration Q4 006 - Red-Junk - Waterproof', 'Registration Q4 006 - Near-Entry Waterproof', 'Registration Q4 006 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Fullsize', 'Registration Q4 006 - Small Amps', 'Registration Q4 006 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Small', 'Registration Q4 006 - Camper Wagon', 'Registration Q4 006 - Campers Amps', 'Registration Q4 006 - Campery', 'Registration Q4 006 - Upper Reddle Alt', 'Registration Q4 006 - Fires - Smooth')) THEN '006 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 2021 - Small Amps', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q1 2021 - Upper Reddle Alt')) THEN '2021 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q2 2021 - Redsize Amps', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Small Amps', 'Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Wagon', 'Registration Q2 2021 - Campers Amps', 'Registration Q2 2021 - Campery', 'Registration Q2 2021 - Fires - Smooth')) THEN '2021 Q2' ELSE "TABLE1"."DESCRIPTION" END) AS "Study_Quarter/Year", + COUNT(DISTINCT "TABLE2"."ID") AS "ctd:ID:ok" +FROM "SCHEMA1"."TABLE2" "TABLE2" + INNER JOIN "SCHEMA1"."TABLE1" "TABLE1" ON ("TABLE2"."ID" = "TABLE1"."ID") +WHERE (((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) >= 'Alternative Capacitor Devices') AND ((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample')) THEN 'Alternative Capacitor Devices' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 005 - Camper Yeah - Entry Alt')) THEN 'Entry Alt Propane' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q2 000 - Entry Amps', 'Registration Q2 001 - Entry Amps', 'Registration Q2 002 - Entry Amps', 'Registration Q2 005 - Entry Amps', 'Registration Q4 000 - Entry Amps', 'Registration Q4 001 - Entry Amps', 'Registration Q4 002 - Entry Amps', 'Registration Q4 005 - Entry Amps', 'Registration Q4 006 - Entry Amps')) THEN 'Entry Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 006 - Fullsize Amp Alt')) THEN 'Fullsize Amp Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Purple Device Makes - 450 Ratings')) THEN 'Purple Device Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American')) THEN 'Purple Device Makes Non-Waterproof - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Speakers')) THEN 'Waterproof Speakers' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Makes - 450 Ratings')) THEN 'Waterproof Makes' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Redsize')) THEN 'Waterproof Propane Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 006 - Waterproof Propane Small')) THEN 'Waterproof Propane Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 006 - Red-Junk - Waterproof')) THEN 'Red-Junk Waterproof' WHEN ("TABLE1"."DESCRIPTION" = 'Registration Q2 2021 - Redsize Amps') THEN 'Redsize Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 006 - Near-Entry Waterproof')) THEN 'Near-Entry Waterproof' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Smooth')) THEN 'Home Theaters - Smooth' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 006 - Home Theaters - Fullsize')) THEN 'Home Theaters - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full')) THEN 'Home Theaters - Fullsize - Half Full' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Small Amps', 'Registration Q1 001 - Small Amps', 'Registration Q1 002 - Small Amps', 'Registration Q1 005 - Small Amps', 'Registration Q1 006 - Small Amps', 'Registration Q1 2021 - Small Amps', 'Registration Q2 000 - Small Amps', 'Registration Q2 001 - Small Amps', 'Registration Q2 002 - Small Amps', 'Registration Q2 005 - Small Amps', 'Registration Q2 2021 - Small Amps', 'Registration Q3 000 - Small Amps', 'Registration Q3 001 - Small Amps', 'Registration Q3 002 - Small Amps', 'Registration Q3 006 - Small Amps', 'Registration Q4 000 - Small Amps', 'Registration Q4 001 - Small Amps', 'Registration Q4 002 - Small Amps', 'Registration Q4 005 - Small Amps', 'Registration Q4 006 - Small Amps')) THEN 'Small Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Small-Entry Amps - Any-American')) THEN 'Small-Entry Amps - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Entry Alt')) THEN 'Camper Yeah - Entry Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Fullsize')) THEN 'Camper Yeah - Fullsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Redsize')) THEN 'Camper Yeah - Redsize' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 006 - Camper Yeah - Small')) THEN 'Camper Yeah - Small' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Camper Yeah - Small - Any-American')) THEN 'Camper Yeah - Small - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt')) THEN 'Camper Yeah Premium Redsize Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Camper Wagon', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 2021 - Camper Wagon', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 006 - Camper Wagon')) THEN 'Camper Wagon' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Campers Amps', 'Registration Q2 2021 - Campers Amps', 'Registration Q4 005 - Campers Amps', 'Registration Q4 006 - Campers Amps')) THEN 'Campers Amps' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Campery', 'Registration Q2 001 - Campery', 'Registration Q2 002 - Campery', 'Registration Q2 005 - Campery', 'Registration Q2 2021 - Campery', 'Registration Q4 000 - Campery', 'Registration Q4 001 - Campery', 'Registration Q4 002 - Campery', 'Registration Q4 005 - Campery', 'Registration Q4 006 - Campery')) THEN 'Campery' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Upper Reddle Alt', 'Registration Q1 001 - Upper Reddle Alt', 'Registration Q1 002 - Upper Reddle Alt', 'Registration Q1 005 - Upper Reddle Alt', 'Registration Q1 006 - Upper Reddle Alt', 'Registration Q1 2021 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q3 000 - Upper Reddle Alt', 'Registration Q3 001 - Upper Reddle Alt', 'Registration Q3 002 - Upper Reddle Alt', 'Registration Q3 006 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 006 - Upper Reddle Alt')) THEN 'Upper Reddle Alt' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Upper Reddle Alt - Any-American')) THEN 'Upper Reddle Alt - Any-American' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Fires - Smooth', 'Registration Q2 001 - Fires - Smooth', 'Registration Q2 002 - Fires - Smooth', 'Registration Q2 005 - Fires - Smooth', 'Registration Q2 2021 - Fires - Smooth', 'Registration Q4 000 - Fires - Smooth', 'Registration Q4 001 - Fires - Smooth', 'Registration Q4 002 - Fires - Smooth', 'Registration Q4 005 - Fires - Smooth', 'Registration Q4 006 - Fires - Smooth')) THEN 'Fires - Smooth' ELSE "TABLE1"."DESCRIPTION" END) <= 'Fires - Smooth') AND ((CASE WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 000 - Entry Amps', 'Registration Q1 000 - Purple Device Makes - 450 Ratings', 'Registration Q1 000 - Small Amps', 'Registration Q1 000 - Camper Yeah - Small', 'Registration Q1 000 - Upper Reddle Alt')) THEN '000 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 000 - Entry Alt Propane', 'Registration Q2 000 - Entry Amps', 'Registration Q2 000 - Fullsize Amp Alt', 'Registration Q2 000 - Purple Device Makes - 450 Ratings', 'Registration Q2 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 000 - Waterproof Speakers', 'Registration Q2 000 - Waterproof Makes - 450 Ratings', 'Registration Q2 000 - Red-Junk - Waterproof', 'Registration Q2 000 - Near-Entry Waterproof', 'Registration Q2 000 - Home Theaters - Smooth', 'Registration Q2 000 - Home Theaters - Fullsize', 'Registration Q2 000 - Home Theaters - Fullsize - Half Full', 'Registration Q2 000 - Small Amps', 'Registration Q2 000 - Small-Entry Amps - Any-American', 'Registration Q2 000 - Camper Yeah - Redsize', 'Registration Q2 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q2 000 - Camper Yeah - Small', 'Registration Q2 000 - Camper Yeah - Small - Any-American', 'Registration Q2 000 - Campery', 'Registration Q2 000 - Upper Reddle Alt', 'Registration Q2 000 - Upper Reddle Alt - Any-American', 'Registration Q2 000 - Fires - Smooth')) THEN '000 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 000 - Small Amps', 'Registration Q3 000 - Camper Yeah - Small', 'Registration Q3 000 - Upper Reddle Alt')) THEN '000 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 000 - Alternative Capacitor Devices', 'Registration Q4 000 - Entry Alt Propane', 'Registration Q4 000 - Entry Amps', 'Registration Q4 000 - Fullsize Amp Alt', 'Registration Q4 000 - Purple Device Makes - 450 Ratings', 'Registration Q4 000 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q4 000 - Waterproof Speakers', 'Registration Q4 000 - Waterproof Makes - 450 Ratings', 'Registration Q4 000 - Red-Junk - Waterproof', 'Registration Q4 000 - Near-Entry Waterproof', 'Registration Q4 000 - Home Theaters - Smooth', 'Registration Q4 000 - Home Theaters - Fullsize', 'Registration Q4 000 - Home Theaters - Fullsize - Half Full', 'Registration Q4 000 - Small Amps', 'Registration Q4 000 - Small-Entry Amps - Any-American', 'Registration Q4 000 - Camper Yeah - Redsize', 'Registration Q4 000 - Camper Yeah - Premium Redsize Alt', 'Registration Q4 000 - Camper Yeah - Small', 'Registration Q4 000 - Camper Yeah - Small - Any-American', 'Registration Q4 000 - Campery', 'Registration Q4 000 - Upper Reddle Alt', 'Registration Q4 000 - Upper Reddle Alt - Any-American', 'Registration Q4 000 - Fires - Smooth')) THEN '000 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 001 - Small Amps', 'Registration Q1 001 - Camper Yeah - Small', 'Registration Q1 001 - Upper Reddle Alt')) THEN '001 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 001 - Entry Alt Propane', 'Registration Q2 001 - Entry Amps', 'Registration Q2 001 - Fullsize Amp Alt', 'Registration Q2 001 - Purple Device Makes - 450 Ratings', 'Registration Q2 001 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 001 - Waterproof Speakers', 'Registration Q2 001 - Waterproof Makes - 450 Ratings', 'Registration Q2 001 - Waterproof Propane Redsize', 'Registration Q2 001 - Waterproof Propane Small', 'Registration Q2 001 - Red-Junk - Waterproof', 'Registration Q2 001 - Near-Entry Waterproof', 'Registration Q2 001 - Home Theaters - Smooth', 'Registration Q2 001 - Home Theaters - Fullsize', 'Registration Q2 001 - Home Theaters - Fullsize - Half Full', 'Registration Q2 001 - Small Amps', 'Registration Q2 001 - Small-Entry Amps - Any-American', 'Registration Q2 001 - Camper Yeah - Redsize', 'Registration Q2 001 - Camper Yeah - Small', 'Registration Q2 001 - Camper Yeah - Small - Any-American', 'Registration Q2 001 - Campery', 'Registration Q2 001 - Upper Reddle Alt', 'Registration Q2 001 - Upper Reddle Alt - Any-American', 'Registration Q2 001 - Fires - Smooth')) THEN '001 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 001 - Small Amps', 'Registration Q3 001 - Camper Yeah - Small', 'Registration Q3 001 - Upper Reddle Alt')) THEN '001 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 001 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 001 - Entry Alt Propane', 'Registration Q4 001 - Entry Amps', 'Registration Q4 001 - Fullsize Amp Alt', 'Registration Q4 001 - Purple Device Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Speakers', 'Registration Q4 001 - Waterproof Makes - 450 Ratings', 'Registration Q4 001 - Waterproof Propane Redsize', 'Registration Q4 001 - Waterproof Propane Small', 'Registration Q4 001 - Red-Junk - Waterproof', 'Registration Q4 001 - Near-Entry Waterproof', 'Registration Q4 001 - Home Theaters - Smooth', 'Registration Q4 001 - Home Theaters - Fullsize', 'Registration Q4 001 - Home Theaters - Fullsize - Half Full', 'Registration Q4 001 - Small Amps', 'Registration Q4 001 - Camper Yeah - Redsize', 'Registration Q4 001 - Camper Yeah - Small', 'Registration Q4 001 - Campery', 'Registration Q4 001 - Upper Reddle Alt', 'Registration Q4 001 - Fires - Smooth')) THEN '001 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 002 - Small Amps', 'Registration Q1 002 - Camper Yeah - Small', 'Registration Q1 002 - Upper Reddle Alt')) THEN '002 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 002 - Entry Alt Propane', 'Registration Q2 002 - Entry Amps', 'Registration Q2 002 - Fullsize Amp Alt', 'Registration Q2 002 - Purple Device Makes - 450 Ratings', 'Registration Q2 002 - Purple Device Makes Non-Waterproof - Any-American', 'Registration Q2 002 - Waterproof Speakers', 'Registration Q2 002 - Waterproof Makes - 450 Ratings', 'Registration Q2 002 - Waterproof Propane Redsize', 'Registration Q2 002 - Waterproof Propane Small', 'Registration Q2 002 - Red-Junk - Waterproof', 'Registration Q2 002 - Near-Entry Waterproof', 'Registration Q2 002 - Home Theaters - Smooth', 'Registration Q2 002 - Home Theaters - Fullsize', 'Registration Q2 002 - Home Theaters - Fullsize - Half Full', 'Registration Q2 002 - Small Amps', 'Registration Q2 002 - Small-Entry Amps - Any-American', 'Registration Q2 002 - Camper Yeah - Redsize', 'Registration Q2 002 - Camper Yeah - Small', 'Registration Q2 002 - Camper Yeah - Small - Any-American', 'Registration Q2 002 - Camper Wagon', 'Registration Q2 002 - Campery', 'Registration Q2 002 - Upper Reddle Alt', 'Registration Q2 002 - Upper Reddle Alt - Any-American', 'Registration Q2 002 - Fires - Smooth')) THEN '002 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 002 - Small Amps', 'Registration Q3 002 - Camper Yeah - Small', 'Registration Q3 002 - Upper Reddle Alt')) THEN '002 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 002 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 002 - Entry Alt Propane', 'Registration Q4 002 - Entry Amps', 'Registration Q4 002 - Fullsize Amp Alt', 'Registration Q4 002 - Purple Device Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Speakers', 'Registration Q4 002 - Waterproof Makes - 450 Ratings', 'Registration Q4 002 - Waterproof Propane Redsize', 'Registration Q4 002 - Waterproof Propane Small', 'Registration Q4 002 - Red-Junk - Waterproof', 'Registration Q4 002 - Near-Entry Waterproof', 'Registration Q4 002 - Home Theaters - Smooth', 'Registration Q4 002 - Home Theaters - Fullsize', 'Registration Q4 002 - Home Theaters - Fullsize - Half Full', 'Registration Q4 002 - Small Amps', 'Registration Q4 002 - Camper Yeah - Redsize', 'Registration Q4 002 - Camper Yeah - Small', 'Registration Q4 002 - Camper Wagon', 'Registration Q4 002 - Campery', 'Registration Q4 002 - Upper Reddle Alt', 'Registration Q4 002 - Fires - Smooth')) THEN '002 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 005 - Small Amps', 'Registration Q1 005 - Camper Yeah - Small', 'Registration Q1 005 - Upper Reddle Alt')) THEN '005 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 005 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 005 - Entry Amps', 'Registration Q2 005 - Fullsize Amp Alt', 'Registration Q2 005 - Purple Device Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Speakers', 'Registration Q2 005 - Waterproof Makes - 450 Ratings', 'Registration Q2 005 - Waterproof Propane Redsize', 'Registration Q2 005 - Waterproof Propane Small', 'Registration Q2 005 - Red-Junk - Waterproof', 'Registration Q2 005 - Near-Entry Waterproof', 'Registration Q2 005 - Home Theaters - Smooth', 'Registration Q2 005 - Home Theaters - Fullsize', 'Registration Q2 005 - Home Theaters - Fullsize - Half Full', 'Registration Q2 005 - Small Amps', 'Registration Q2 005 - Camper Yeah - Entry Alt', 'Registration Q2 005 - Camper Yeah - Redsize', 'Registration Q2 005 - Camper Yeah - Small', 'Registration Q2 005 - Camper Wagon', 'Registration Q2 005 - Campers Amps', 'Registration Q2 005 - Campery', 'Registration Q2 005 - Upper Reddle Alt', 'Registration Q2 005 - Fires - Smooth')) THEN '005 Q2' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 005 - Entry Amps', 'Registration Q4 005 - Fullsize Amp Alt', 'Registration Q4 005 - Purple Device Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Speakers', 'Registration Q4 005 - Waterproof Makes - 450 Ratings', 'Registration Q4 005 - Waterproof Propane Redsize', 'Registration Q4 005 - Waterproof Propane Small', 'Registration Q4 005 - Red-Junk - Waterproof', 'Registration Q4 005 - Near-Entry Waterproof', 'Registration Q4 005 - Home Theaters - Smooth', 'Registration Q4 005 - Home Theaters - Fullsize', 'Registration Q4 005 - Home Theaters - Fullsize - Half Full', 'Registration Q4 005 - Small Amps', 'Registration Q4 005 - Camper Yeah - Entry Alt', 'Registration Q4 005 - Camper Yeah - Redsize', 'Registration Q4 005 - Camper Yeah - Small', 'Registration Q4 005 - Camper Wagon', 'Registration Q4 005 - Campers Amps', 'Registration Q4 005 - Campery', 'Registration Q4 005 - Upper Reddle Alt', 'Registration Q4 005 - Fires - Smooth')) THEN '005 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 006 - Small Amps', 'Registration Q1 006 - Camper Yeah - Small', 'Registration Q1 006 - Upper Reddle Alt')) THEN '006 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q3 006 - Small Amps', 'Registration Q3 006 - Camper Yeah - Small', 'Registration Q3 006 - Upper Reddle Alt')) THEN '006 Q3' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q4 006 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q4 006 - Entry Amps', 'Registration Q4 006 - Fullsize Amp Alt', 'Registration Q4 006 - Purple Device Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Speakers', 'Registration Q4 006 - Waterproof Makes - 450 Ratings', 'Registration Q4 006 - Waterproof Propane Redsize', 'Registration Q4 006 - Waterproof Propane Small', 'Registration Q4 006 - Red-Junk - Waterproof', 'Registration Q4 006 - Near-Entry Waterproof', 'Registration Q4 006 - Home Theaters - Smooth', 'Registration Q4 006 - Home Theaters - Fullsize', 'Registration Q4 006 - Small Amps', 'Registration Q4 006 - Camper Yeah - Entry Alt', 'Registration Q4 006 - Camper Yeah - Fullsize', 'Registration Q4 006 - Camper Yeah - Redsize', 'Registration Q4 006 - Camper Yeah - Small', 'Registration Q4 006 - Camper Wagon', 'Registration Q4 006 - Campers Amps', 'Registration Q4 006 - Campery', 'Registration Q4 006 - Upper Reddle Alt', 'Registration Q4 006 - Fires - Smooth')) THEN '006 Q4' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q1 2021 - Small Amps', 'Registration Q1 2021 - Camper Yeah - Small', 'Registration Q1 2021 - Upper Reddle Alt')) THEN '2021 Q1' WHEN ("TABLE1"."DESCRIPTION" IN ('Registration Q2 2021 - Alternative Capacitor Devices - Stuff Sample', 'Registration Q2 2021 - Fullsize Amp Alt', 'Registration Q2 2021 - Purple Device Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Speakers', 'Registration Q2 2021 - Waterproof Makes - 450 Ratings', 'Registration Q2 2021 - Waterproof Propane Redsize', 'Registration Q2 2021 - Red-Junk - Waterproof', 'Registration Q2 2021 - Redsize Amps', 'Registration Q2 2021 - Near-Entry Waterproof', 'Registration Q2 2021 - Home Theaters - Smooth', 'Registration Q2 2021 - Home Theaters - Fullsize', 'Registration Q2 2021 - Home Theaters - Fullsize - Half Full', 'Registration Q2 2021 - Small Amps', 'Registration Q2 2021 - Camper Yeah - Fullsize', 'Registration Q2 2021 - Camper Yeah - Redsize', 'Registration Q2 2021 - Camper Yeah - Small', 'Registration Q2 2021 - Camper Wagon', 'Registration Q2 2021 - Campers Amps', 'Registration Q2 2021 - Campery', 'Registration Q2 2021 - Fires - Smooth')) THEN '2021 Q2' ELSE "TABLE1"."DESCRIPTION" END) = '2021 Q2') AND ((CASE WHEN ("TABLE1"."CODE" = 'No Answer') THEN 0 ELSE 1 END) <> 0) AND ("TABLE1"."DESCRIPTION" = 'Familiar With (G1)')) +GROUP BY 1, + 2, + 3 +; + +-- simple_parsing.txt +sELect g.*, A.K from B, KLJ as A; + +select * from TABLE_A; + +select * from TABLE_A; + +select * from TABLE_A LIMIT 34; + +select * from TABLE_A LIMIT ?; + +select * from TABLE_A LIMIT 34,?; + +select * from TABLE_A LIMIT ?,?; + +select * from TABLE_A LIMIT ? OFFSET 3; + +select * from TABLE_A LIMIT ? OFFSET ?; + +select * from TABLE_A LIMIT ALL OFFSET ?; + +select * from TABLE_A LIMIT ALL OFFSET 3; + +select * from TABLE_A OFFSET 3; + +select A,sdf,sch.tab.col from TABLE_A; + +select k, * from K as skldjfl where i=0; + +select MAX(k+2), COUNT(*), MYCOL from K; + +SELECT * FROM TA2 LEFT JOIN O USING (col1, col2) +where D.OasSD = 'asdf' And (kj >= 4 OR l < 'sdf'); + +seLECT my as KIO, lio aS +NE fRom TA2 LEFT OUter JOIN O as TA3 +where D.OasSD = 'asdf' And (kj >= 4 OR l < 'sdf'); + +select * from a +INNer Join TAB_2 ON i.o = p.l whEre 'sdf'>'asdf' AND + ( + OL<>? + OR + L NOT IN (SELECT * FROM KJSD) + ); + +select * from k where L IS NOT NUll; + +(select sdf from sdfd) UNION (select * from k); + +update mytab set jk=das, d=kasd+asd/d+3 where KL>= ds OR (k not in (SELECT K from KS)); + +insert into tabName VALUES ('sdgf', ?, ?); + +insert into myschama.tabName2 (col1, col2, col3) VALUES ('sdgf', ?, ?); + +delete from jk; + +delete from asdff where INI = 94 OR (ASD>9 AND (SELECT MAX(ID) from myt) > ?); + +select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ON ( id ) * FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id))); + +(select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ( id ) FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id)))) UNION ( SELECT wct_workflows.workflow_id as +id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' or wct_audit_entry.privilege = 'C' ) and wct_audit_entry.outcome += 't' and wct_audit_entry.transaction_id = +wct_transaction.transaction_id and wct_transaction.user_id = 164 and +p= 'asd'); + +select * from ( SELECT intermediate.id as id , intermediate.date as +date FROM ( SELECT DISTINCT ( id ) FROM ( SELECT +wct_workflows.workflow_id as id , wct_transaction.date as date FROM +wct_audit_entry , wct_transaction , wct_workflows WHERE +( wct_audit_entry.privilege = 'W' or wct_audit_entry.privilege = +'C' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.active_version_id ))) UNION SELECT wct_workflows.workflow_id as +id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' or wct_audit_entry.privilege = 'C' ) and wct_audit_entry.outcome += 't' and wct_audit_entry.transaction_id = +wct_transaction.transaction_id and wct_transaction.user_id = 164 and +afdf= ( select wct_audit_entry.object_id from wct_audit_entry , +wct_workflow_archive where wct_audit_entry.object_id = +wct_workflow_archive.archive_id and wct_workflows.workflow_id = +wct_workflow_archive.workflow_id ) +UNION SELECT wct_workflows.workflow_id +as id , wct_transaction.date as date FROM wct_audit_entry , +wct_transaction , wct_workflows WHERE ( wct_audit_entry.privilege = +'W' OR wct_audit_entry.privilege = 'E' OR wct_audit_entry.privilege = +'A' ) and wct_audit_entry.outcome = 't' and +wct_audit_entry.transaction_id = wct_transaction.transaction_id and +wct_transaction.user_id = 164 and wct_audit_entry.object_id = +wct_workflows.workflow_id UNION SELECT * FROM interm2 , wct_workflow_docs WHERE +interm2.id = wct_workflow_docs.document_id ORDER BY id , date DESC +; + +replace df set ki='oasdf', dsd=asd+dd; + +(select sdf from sdfd) UNION (select * from k) ORDER BY 1,2; + +(select sdf from sdfd) UNION (select * from k) ORDER BY 1,asd.sd ; + +(select sdf from sdfd) UNION (select * from k) UNION (select * from k2) LIMIT 0,2; + +select sdf from sdfd UNION select * from k join j on k.p = asdf.f; + +select * from ( select persistence_dynamic_ot.pdl_id , +acs_objects.default_domain_class as attribute0 , +acs_objects.object_type as attribute1 , acs_objects.display_name +as attribute2 , persistence_dynamic_ot.dynamic_object_type as +attribute3 , persistence_dynamic_ot.pdl_file as attribute4 from +persistence_dynamic_ot , acs_objects where +persistence_dynamic_ot.pdl_id = acs_objects.object_id ); + +SELECT * FROM table1 WHERE column1 > ALL (SELECT column2 FROM table1); + +INSERT INTO mytable (col1, col2, col3) SELECT * FROM mytable2; + +insert into foo ( x ) select a from b; + +select (case when a > 0 then b + a else 0 end) p from mytable; + +SELECT BTI.*, BTI_PREDECESSOR.objid AS predecessor_objid, BTI_PREDECESSOR.item_id +AS predecessor_item_id, BTIT_PREDECESSOR.bt_item_type_key AS predecessor_type_key, +CAT.catalog_key, S.objid AS state_objid, S.state_key, S.is_init_state, +S.is_final_state, mlS.name AS state, BTIT.bt_item_type_key, BTP.bt_processor_key, +mlBTP.name AS bt_processor_name , CU.objid AS cust_user_objid , CU.title AS +cust_user_title , CU.firstname AS cust_user_firstname , CU.lastname AS +cust_user_lastname , CU.salutation2pv AS cust_user_salutation2pv , PV_CU.name_option +AS cust_user_salutation , A_CU.email AS cust_user_email , '' AS use_option_field, +'' AS use_readerlist , BTI_QUOTATION.quotation_type2pv , BTI_QUOTATION.is_mandatory +AS quotation_is_mandatory , BTI_QUOTATION.is_multiple AS quotation_is_multiple +, BTI_QUOTATION.expiration_datetime AS quotation_expiration_datetime , +BTI_QUOTATION.hint_internal AS quotation_hint_internal , BTI_QUOTATION.hint_external +AS quotation_hint_external , BTI_QUOTATION.filter_value AS quotation_filter_value +, BTI_QUOTATION.email_cc AS quotation_email_cc , BTI_QUOTATION.notification1_datetime +AS notification1_datetime , BTI_QUOTATION.notification2_datetime AS +notification2_datetime , BTI_RFQ.filter_value AS request_for_quotation_filter_value +FROM tBusinessTransactionItem BTI LEFT OUTER JOIN tBusinessTransactionItem_Quotation +BTI_QUOTATION ON BTI_QUOTATION.this2business_transaction_item = BTI.objid LEFT +OUTER JOIN tBusinessTransactionItem_RequestForQuotation BTI_RFQ ON +BTI_RFQ.this2business_transaction_item = BTI.objid LEFT OUTER JOIN +tBusinessTransactionItem BTI_PREDECESSOR ON BTI_PREDECESSOR.objid += BTI.predecessor2bt_item, tBusinessTransactionItemType BTIT_PREDECESSOR +, tBusinessTransactionItemType BTIT, tBusinessTransactionProcessor BTP, +mltBusinessTransactionProcessor mlBTP, tLanguagePriority LP_BTP, tState S, mltState +mlS, tLanguagePriority LP_S, tCatalog CAT +, tBusinessTransactionItem2BusinessTransaction BTI2BT , +tBusinessTransactionItem2SessionCart BTI2SC , tSessionCart SC , tCustUser CU_MASTER +, tCustUser CU , tPopValue PV_CU , tAddress A_CU , tAddress2CustUser A2CU WHERE +BTI.objid <> -1 AND BTI_PREDECESSOR.this2bt_item_type = BTIT_PREDECESSOR.objid +AND BTI.this2bt_item_type = BTIT.objid AND BTI.this2bt_processor = BTP.objid +AND mlBTP.this2master = BTP.objid AND mlBTP.this2language = LP_BTP.item2language +AND LP_BTP.master2language = 0 AND LP_BTP.this2shop = 0 AND LP_BTP.priority += (SELECT MIN(LP_BTP2.priority) FROM tLanguagePriority LP_BTP2, +mltBusinessTransactionProcessor mlBTP2 WHERE LP_BTP2.master2language = 0 AND +LP_BTP2.this2shop = 0 AND LP_BTP2.item2language = mlBTP2.this2language +AND mlBTP2.this2master = BTP.objid ) AND BTI.this2catalog = CAT.objid AND S.objid += BTI.bt_item2state AND mlS.this2master = S.objid AND mlS.this2language += LP_S.item2language AND LP_S.master2language = 0 AND LP_S.this2shop = 0 AND +LP_S.priority = (SELECT MIN(LP_S2.priority) FROM tLanguagePriority LP_S2, mltState +mlS2 WHERE LP_S2.master2language = 0 AND LP_S2.this2shop = 0 AND LP_S2.item2language += mlS2.this2language AND mlS2.this2master = S.objid ) AND BTI.objid += BTI2BT.this2business_transaction_item AND CU_MASTER.objid = 1101 AND +CU.this2customer = CU_MASTER.this2customer AND SC.this2custuser = CU.objid AND +BTI.objid = BTI2SC.this2business_transaction_item AND BTI.bt_item2state = 6664 +AND BTI2SC.is_master_cart_item = 1 AND BTI2SC.this2session_cart = SC.objid AND +EXISTS (SELECT NULL FROM tBusinessTransaction BT, tBusinessTransactionType BTT +WHERE BT.objid = BTI2BT.this2business_transaction AND BTT.objid = BT.this2bt_type +AND BTT.business_transaction_type_key = 'order:master_cart') AND PV_CU.objid += CU.salutation2pv AND A2CU.this2custuser = CU.objid AND A2CU.is_billing_default += 1 AND A2CU.this2address = A_CU.objid ORDER BY BTI.dbobj_create_datetime DESC; + +WITH +DINFO (DEPTNO, AVGSALARY, EMPCOUNT) AS +(SELECT OTHERS.WORKDEPT, AVG(OTHERS.SALARY), COUNT(*) +FROM EMPLOYEE OTHERS +GROUP BY OTHERS.WORKDEPT +), +DINFOMAX AS +(SELECT MAX(AVGSALARY) AS AVGMAX FROM DINFO) +SELECT THIS_EMP.EMPNO, THIS_EMP.SALARY, +DINFO.AVGSALARY, DINFO.EMPCOUNT, DINFOMAX.AVGMAX +FROM EMPLOYEE THIS_EMP, DINFO, DINFOMAX +WHERE THIS_EMP.JOB = 'SALESREP' +AND THIS_EMP.WORKDEPT = DINFO.DEPTNO; + +select * from Person where deptname='it' AND NOT (age=24); + +select * from unnest(array[4,5,6]) with ordinality; + diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql index 77ace598b..e554a530f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql @@ -20,4 +20,5 @@ select time_id, product --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:07 AM ---@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Apr 6, 2024, 7:38:53 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Apr 6, 2024, 7:38:53 AM +--@FAILURE: Encountered: / "by", at line 14, column 39, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql index 03cd17602..95aa905a1 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql @@ -16,4 +16,5 @@ select times.time_id, product, quantity from inventory ---@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "by", at line 11, column 14, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql index 6e1f00c92..707109e43 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query07.sql @@ -47,4 +47,8 @@ where a.cluster_id = b.id order by prob desc, cl_id asc, conf desc, attr asc, val asc ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 36, column 15, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 +--@FAILURE: Encountered: / "(", at line 36, column 15, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 +--@FAILURE: Encountered: / "using", at line 36, column 45, in lexical state DEFAULT. recorded first on 12 Mar 2026, 20:27:52 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 13 Mar 2026, 20:40:43 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query09.sql index b60a7eef1..90ef12721 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query09.sql @@ -21,4 +21,5 @@ from ) ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql index 4ec094ba7..4d1b143f8 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql @@ -27,4 +27,5 @@ from where scn > :2 --@FAILURE: Encountered unexpected token: "group" "GROUP" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Mar 25, 2023, 9:30:55 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Mar 25, 2023, 9:30:55 AM +--@FAILURE: Encountered: / "group", at line 25, column 2, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql index 01b37d44b..6821142a6 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql @@ -15,4 +15,6 @@ from where "rm".a-interval:"sys_b_07" day(:"sys_b_08") to second(:"sys_b_09") ) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 +--@FAILURE: Encountered: / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql index c30472e1e..dbe06b95c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql @@ -10,4 +10,5 @@ update customers_demo set cust_address_ntab = cust_address_ntab multiset union cust_address_ntab ---@FAILURE: Encountered unexpected token: "multiset" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "multiset" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "multiset", at line 11, column 43, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql index 487c15997..52ce45bd2 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql @@ -12,4 +12,6 @@ multiset except distinct cust_address2_ntab multiset_except from customers_demo --@FAILURE: Encountered unexpected token: "except" "EXCEPT" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "distinct" "DISTINCT" recorded first on Mar 25, 2023, 9:18:30 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "distinct" "DISTINCT" recorded first on Mar 25, 2023, 9:18:30 AM +--@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Feb 8, 2025, 6:46:21 AM +--@FAILURE: Encountered: / "cust_address2_ntab", at line 11, column 26, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset14.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset14.sql index c1c16572c..8b675ab39 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset14.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset14.sql @@ -13,4 +13,6 @@ from customers_demo order by customer_id --@FAILURE: Encountered unexpected token: "intersect" "INTERSECT" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "all" "ALL" recorded first on Mar 25, 2023, 9:18:30 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "all" "ALL" recorded first on Mar 25, 2023, 9:18:30 AM +--@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Feb 8, 2025, 6:46:21 AM +--@FAILURE: Encountered: / "cust_address2_ntab", at line 11, column 24, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset15.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset15.sql index 689791df4..7ccc1491f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset15.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset15.sql @@ -13,4 +13,5 @@ from customers_demo order by customer_id --@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Mar 25, 2023, 9:18:30 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Mar 25, 2023, 9:18:30 AM +--@FAILURE: Encountered: / "union", at line 11, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset34.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset34.sql index dd93d7fa7..e9d1debeb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset34.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset34.sql @@ -16,4 +16,6 @@ select deptno group by deptno ---@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "varchar2_ntt", at line 14, column 42, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset37.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset37.sql index 00d816581..946fbda98 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset37.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset37.sql @@ -18,4 +18,6 @@ select owner owner , object_type ---@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "varchar2_ntt", at line 15, column 42, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql index 038eb48b7..a72e776e8 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset38.sql @@ -12,4 +12,7 @@ select * multiset union distinct varchar2_ntt('b','c','d') ) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 11, column 18, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 11, column 18, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 +--@FAILURE: Encountered: / "union", at line 12, column 32, in lexical state DEFAULT. recorded first on 14 Mar 2026, 22:33:07 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset39.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset39.sql index dab664623..a98b02407 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset39.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset39.sql @@ -13,4 +13,5 @@ select varchar2_ntt('a','b','c') from dual --@FAILURE: Encountered unexpected token: "except" "EXCEPT" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Mar 25, 2023, 9:18:30 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "varchar2_ntt" recorded first on Mar 25, 2023, 9:18:30 AM +--@FAILURE: Encountered: / "except", at line 11, column 25, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql index 0e883ae44..eb7aed05f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cluster_set01.sql @@ -42,4 +42,8 @@ select a.probability prob, a.cluster_id cl_id, where a.cluster_id = b.id order by prob desc, cl_id asc, conf desc, attr asc, val asc ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 31, column 36, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 31, column 36, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 +--@FAILURE: Encountered: / "using", at line 31, column 66, in lexical state DEFAULT. recorded first on 12 Mar 2026, 20:27:52 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 13 Mar 2026, 20:40:43 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements01.sql index 0fce1148e..636556411 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements01.sql @@ -29,4 +29,5 @@ ); END ---@FAILURE: Encountered unexpected token: "PK_NAME" recorded first on May 27, 2022, 10:27:41 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "PK_NAME" recorded first on May 27, 2022, 10:27:41 PM +--@FAILURE: Encountered: / "PK_NAME", at line 11, column 9, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements02.sql index ec47ee889..227602a06 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements02.sql @@ -27,4 +27,5 @@ DECLARE END; END ---@FAILURE: Encountered unexpected token: "n_emp_id" recorded first on May 27, 2022, 10:29:48 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "n_emp_id" recorded first on May 27, 2022, 10:29:48 PM +--@FAILURE: Encountered: / "n_emp_id", at line 11, column 11, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements03.sql index b4f2d87e5..b35dc877b 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/compound_statements03.sql @@ -16,4 +16,6 @@ BEGIN --@FAILURE: Encountered unexpected token: "BEGIN" "BEGIN" recorded first on May 27, 2022, 10:29:48 PM --@FAILURE: Encountered unexpected token: ":" ":" recorded first on 9 Dec 2022, 14:03:29 ---@FAILURE: Encountered unexpected token: "INTO" "INTO" recorded first on 4 May 2023, 18:47:18 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "INTO" "INTO" recorded first on 4 May 2023, 18:47:18 +--@FAILURE: Encountered: / "INTO", at line 12, column 24, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / ":", at line 12, column 29, in lexical state DEFAULT. recorded first on 28 Mar 2026, 16:43:42 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql index 1406c1f8d..92d280776 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition06.sql @@ -22,4 +22,6 @@ and t1.sid(+)=t2.sid and ( ( t1.scode like 'mmm' and t2.scode like 'xax' ) ) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "is", at line 19, column 31, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql index 20c302deb..869624b94 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition11.sql @@ -15,4 +15,7 @@ and nvl(X.cid, '^') = nvl(Y.clientid (+), '^') and 0 = Lib.SKU(X.sid, nvl(Z.cid, '^')) ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 14, column 26, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 14, column 26, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition12.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition12.sql index afe20c6f8..94cbfadc4 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition12.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition12.sql @@ -19,4 +19,5 @@ where and "timestamp" <= 1298505600000 ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "not" "NOT" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition16.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition16.sql index dab84c3a9..6841847cc 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition16.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition16.sql @@ -11,4 +11,5 @@ select * from persons p where value(p) is of type(only employee_t) ---@FAILURE: Encountered unexpected token: "is" "IS" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "is" "IS" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "is", at line 11, column 23, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition17.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition17.sql index 551ed804a..04c130530 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition17.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition17.sql @@ -10,4 +10,5 @@ delete from table_name where current of cursor_name ---@FAILURE: Encountered unexpected token: "of" "OF" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "of" "OF" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "of", at line 11, column 15, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition18.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition18.sql index 6971b861d..acca5ff98 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition18.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/condition18.sql @@ -12,4 +12,5 @@ set c1 = 'x' where current of c_cur1 ---@FAILURE: Encountered unexpected token: "of" "OF" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "of" "OF" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "of", at line 12, column 15, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by01.sql index 1bded99ba..025c2734f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by01.sql @@ -27,4 +27,5 @@ from o connect by nocycle obj=prior link start with obj='a' ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 14, 2021 9:00:57 PM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 14, 2021 9:00:57 PM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by08.sql new file mode 100644 index 000000000..ca64e160e --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by08.sql @@ -0,0 +1,15 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2019 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +select t.*, connect_by_root t.id as root_id +from test t +start with t.id = 1 +connect by prior t.id = t.parent_id +order siblings by t.some_text +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Oct 2, 2024, 8:11:58 PM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by09.sql new file mode 100644 index 000000000..e29c601d6 --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by09.sql @@ -0,0 +1,15 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2019 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +select t.*, prior t.id parent_id +from test t +start with t.id = 1 +connect by prior t.id = t.parent_id +order siblings by t.some_text +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Oct 2, 2024, 8:14:31 PM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by10.sql new file mode 100644 index 000000000..f0001cf44 --- /dev/null +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/connect_by10.sql @@ -0,0 +1,15 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2019 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +select t.*, prior t.id as parent_id +from test t +start with t.id = 1 +connect by prior t.id = t.parent_id +order siblings by t.some_text +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Oct 2, 2024, 8:14:33 PM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql index c60faf151..1833b975f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql @@ -17,4 +17,6 @@ explain plan where location_id = 1700) --@FAILURE: Encountered unexpected token: "plan" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "set" "SET" recorded first on 2023年12月23日 下午1:38:33 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "set" "SET" recorded first on 2023年12月23日 下午1:38:33 +--@FAILURE: Encountered unexpected token: "plan" "PLAN" recorded first on 23 Aug 2024, 21:35:20 +--@FAILURE: Encountered: / "set", at line 11, column 5, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/flashback01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/flashback01.sql index 93b5eed0a..67ae61cda 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/flashback01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/flashback01.sql @@ -9,4 +9,5 @@ --- select value(p$) from "XDB"."XDB$SCHEMA" as of snapshot(:2) p$ where SYS_NC_OID$ = :1 ---@FAILURE: Encountered unexpected token: "snapshot" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "snapshot" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "snapshot", at line 10, column 64, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update07.sql index 2cb9519cc..ddd448b75 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update07.sql @@ -11,4 +11,6 @@ select employee_id from (select employee_id+1 as employee_id from employees) for update of a, b.c, d skip locked ---@FAILURE: Encountered unexpected token: "," "," recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "," "," recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / ",", at line 11, column 19, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Apr 11, 2026, 4:05:21 PM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update08.sql index ff5b7f79b..9408f4acf 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update08.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/for_update08.sql @@ -13,4 +13,6 @@ where (nvl(su.up,'n')='n' and su.ttype=:b0) for update of su.up order by su.d ---@FAILURE: select su.ttype,su.cid,su.s_id,sessiontimezone from sku su where(nvl(su.up,'n')='n' and su.ttype=:b0)order by su.d for update of su.up recorded first on 20 Apr 2024, 15:59:32 \ No newline at end of file +--@FAILURE: select su.ttype,su.cid,su.s_id,sessiontimezone from sku su where(nvl(su.up,'n')='n' and su.ttype=:b0)order by su.d for update of su.up recorded first on 20 Apr 2024, 15:59:32 +--@FAILURE: Encountered unexpected token: "order" "ORDER" recorded first on Feb 13, 2025, 10:16:06 AM +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Apr 11, 2026, 4:05:22 PM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql index 0156c4570..9375c7dbb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/function07.sql @@ -15,4 +15,9 @@ select cust_gender, count(*) as cnt, round(avg(age)) as avg_age order by cust_gender ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 12, column 20, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 12, column 20, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 +--@FAILURE: Encountered: / "cost", at line 12, column 39, in lexical state DEFAULT. recorded first on 12 Mar 2026, 20:27:52 +--@FAILURE: Encountered: / ",", at line 13, column 32, in lexical state DEFAULT. recorded first on 13 Mar 2026, 20:40:43 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 14 Mar 2026, 01:34:50 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/groupby18.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/groupby18.sql index 28e4d9533..6906eee22 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/groupby18.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/groupby18.sql @@ -17,4 +17,5 @@ from dimension_tab group by grouping sets(fact_1_id, fact_2_id), grouping sets(fact_3_id, fact_4_id) order by fact_1_id, fact_2_id, fact_3_id, fact_4_id ---@FAILURE: Encountered unexpected token: "," "," recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "," "," recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / ",", at line 17, column 45, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql index 2564f35d4..551491cf6 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert01.sql @@ -15,4 +15,5 @@ insert select object_id, created from all_objects --@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql index 3435fa022..21509acfb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert03.sql @@ -24,4 +24,5 @@ else select * from emp --@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on 11 Jan 2023, 21:07:10 +--@FAILURE: Encountered: / "insert", at line 11, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert04.sql index 0fbb8fe3f..9a2cdd3eb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert04.sql @@ -16,4 +16,6 @@ from airplanes --@FAILURE: Encountered unexpected token: "into" "INTO" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "ap_cust" recorded first on 24 Oct 2021, 16:56:39 ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 11, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert05.sql index a8c42ad20..ea11f57f9 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert05.sql @@ -19,4 +19,6 @@ select * from dual --@FAILURE: Encountered unexpected token: "into" "INTO" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "t" recorded first on 24 Oct 2021, 16:56:39 ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 11, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert06.sql index c9ff596c6..d39e7d398 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert06.sql @@ -23,4 +23,6 @@ else select * from emp --@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql index b2d203861..4b967e54c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql @@ -21,4 +21,6 @@ select program_id, delivered_date, customer_id, order_date from airplanes --@FAILURE: Encountered unexpected token: "when" "WHEN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert08.sql index 0dc47fba9..fed59f44e 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert08.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert08.sql @@ -15,4 +15,5 @@ where deptno < 30) values (98, 'travel', 'seattle') --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 11, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert09.sql index 6078d3305..932680a98 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert09.sql @@ -14,4 +14,5 @@ where deptno < 30 with check option) values (99, 'travel', 'seattle') --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert10.sql index 5c5934fc8..9ace88b05 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert10.sql @@ -14,4 +14,5 @@ insert into ( (1, 'morgan', 'dba', '1', 40) --@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "insert" "INSERT" recorded first on Mar 26, 2023, 6:59:20 PM +--@FAILURE: Encountered: / "insert", at line 10, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql index 3d173a1a4..df005b047 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval01.sql @@ -10,4 +10,6 @@ select (systimestamp - order_date) day(9) to second from orders where order_id = 2458 ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 10, column 39, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "(", at line 10, column 39, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval03.sql index 3e84e6285..80fec57aa 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/interval03.sql @@ -25,4 +25,5 @@ select ,interval :a day from dual ---@FAILURE: Encountered unexpected token: "second" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "second" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "second", at line 11, column 34, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/join05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/join05.sql index eaada8283..32c8d6c9a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/join05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/join05.sql @@ -16,4 +16,5 @@ select times.time_id, product, quantity from inventory ---@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered: / "by", at line 11, column 14, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/keywordasidentifier04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/keywordasidentifier04.sql index bea6452c2..17dd16d7f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/keywordasidentifier04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/keywordasidentifier04.sql @@ -13,4 +13,5 @@ union all (select null keep, null keep_until from v$backup_piece bp) ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on 3 Jun 2022, 18:48:09 \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 3 Jun 2022, 18:48:09 +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql index eeceac635..91875f0c0 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql @@ -10,4 +10,7 @@ select * from dual where 1 < > 2 and 1 ! = 2 and 1 ^ /*aaa */ = 2 ---@FAILURE: Encountered unexpected token: "=" "=" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "=" "=" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "^" "^" recorded first on Jul 11, 2024, 9:09:49 AM +--@FAILURE: Encountered: "^" / "^", at line 10, column 52, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@FAILURE: Encountered: / "! =", at line 10, column 40, in lexical state DEFAULT. recorded first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql index 409d8754d..7553cc27c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop01.sql @@ -17,4 +17,5 @@ begin end; --@FAILURE: Encountered unexpected token: "begin" "BEGIN" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "forall" recorded first on 9 Dec 2022, 14:03:29 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "forall" recorded first on 9 Dec 2022, 14:03:29 +--@FAILURE: Encountered: / "forall", at line 11, column 2, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql index 035af9ec2..e2642ee38 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/loop02.sql @@ -22,4 +22,5 @@ BEGIN END; --@FAILURE: Encountered unexpected token: "BEGIN" "BEGIN" recorded first on Aug 3, 2021, 7:20:07 AM ---@FAILURE: Encountered unexpected token: "<<" "<<" recorded first on 9 Dec 2022, 14:03:29 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "<<" "<<" recorded first on 9 Dec 2022, 14:03:29 +--@FAILURE: Encountered: "<<" / "<<", at line 11, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause01.sql index 9e9bbf4f1..b5c97067d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause01.sql @@ -26,4 +26,5 @@ order by country, prod, year ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "partition", at line 13, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause02.sql index fb6c23dd5..7b6212a3f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause02.sql @@ -24,4 +24,5 @@ select country, year, sale, csum ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 16, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause03.sql index 71877c2c0..1e685e0c2 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause03.sql @@ -23,4 +23,5 @@ select country,prod,year,s order by country, prod, year ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "partition", at line 13, column 5, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause04.sql index f974005e6..9b93ac699 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause04.sql @@ -23,4 +23,5 @@ select country, year, sale, csum ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 16, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause05.sql index 54c9c946d..9777def6a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause05.sql @@ -22,4 +22,5 @@ select country, year, sale, csum order by country, year ---@FAILURE: Encountered unexpected token: "model" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "model" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "model", at line 16, column 4, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause06.sql index 668b79e68..864e3932a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause06.sql @@ -19,4 +19,5 @@ model measures ( ( select dummy from dual ) as dummy ) rules ( ) ---@FAILURE: Encountered unexpected token: "model" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "model" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "model", at line 17, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause07.sql index 63e743a26..3b099255c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause07.sql @@ -20,4 +20,5 @@ model unique single reference order by group_2 ---@FAILURE: Encountered unexpected token: "unique" "UNIQUE" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "unique" "UNIQUE" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "unique", at line 16, column 7, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause08.sql index 75839d349..9760d9a88 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause08.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause08.sql @@ -20,4 +20,5 @@ model order by key ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered: / "dimension", at line 17, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause09.sql index 0380a3fc1..6703cfd79 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause09.sql @@ -24,4 +24,5 @@ model order by key ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 17, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause10.sql index 20d123c6d..a0ab3a65a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause10.sql @@ -25,4 +25,5 @@ model order by key ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 17, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause11.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause11.sql index d58a51aa8..654a82923 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause11.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause11.sql @@ -18,4 +18,5 @@ dimension by (0 dim) (str_new [0] = regexp_replace (str_new[0], '(^|;)([^;]+;)(.*?;)?\2+', '\1\2\3')); ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "partition", at line 13, column 4, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause12.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause12.sql index 8201dcabe..62a290586 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause12.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause12.sql @@ -27,4 +27,5 @@ level3[any] = case when org_level[cv()] = 3 then ename [cv()] end, level4[any] = case when org_level[cv()] = 4 then ename [cv()] end ) --@FAILURE: Encountered unexpected token: "return" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:45 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:45 +--@FAILURE: Encountered: / "return", at line 16, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql index e9e35ce56..79e18fe7f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause13.sql @@ -31,4 +31,5 @@ level4[any] = case when org_level[cv()] = 4 then ename [cv()] end ))) --@FAILURE: Encountered unexpected token: "return" recorded first on Aug 3, 2021, 7:20:08 AM ---@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:44 \ No newline at end of file +--@FAILURE: Encountered unexpected token: "return" "RETURN" recorded first on 9 Dec 2023, 18:20:44 +--@FAILURE: Encountered: / "return", at line 20, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause14.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause14.sql index fa59dfcbc..4dbf9021a 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause14.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause14.sql @@ -16,4 +16,5 @@ model dt[ iteration_number+1 ] = dt[ iteration_number ]+1 ) ---@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "dimension" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "dimension", at line 13, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause15.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause15.sql index f158dcedb..6e9e355fe 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause15.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause15.sql @@ -29,4 +29,5 @@ select order by name, dt ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "partition", at line 19, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql index f17f8247c..156297664 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/model_clause16.sql @@ -38,4 +38,5 @@ select spf.*, nvl(a, ddr_a) as a, b, d, ) ---@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "partition" "PARTITION" recorded first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered: / "partition", at line 28, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/pivot10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/pivot10.sql index 6799342fc..64d904e15 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/pivot10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/pivot10.sql @@ -27,4 +27,5 @@ ) where d_t = 'p' ---@FAILURE: Encountered unexpected token: "pivot" "PIVOT" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "pivot" "PIVOT" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "pivot", at line 12, column 2, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring01.sql index 4d74dc0c1..9bb5986c7 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring01.sql @@ -24,4 +24,5 @@ where r.c1 = a.c2 order by reportlevel, eid ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring02.sql index af27afc76..f4d4ac541 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring02.sql @@ -26,4 +26,5 @@ from reports_to_101 order by reportlevel, eid ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring03.sql index 044df6fef..a7a8e63be 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring03.sql @@ -24,4 +24,5 @@ where reportlevel <= 1 order by reportlevel, eid ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql index 0c59307b5..4a66277a4 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql @@ -26,4 +26,7 @@ order by order1 ---@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:07 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:07 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "search", at line 22, column 3, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring05.sql index 15078f7d6..40b18d5ba 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring05.sql @@ -35,4 +35,5 @@ union select a from dual ---@FAILURE: Encountered unexpected token: "is" "IS" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "is" "IS" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: / "is", at line 33, column 9, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring10.sql index 610700c4a..8e26be25e 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring10.sql @@ -41,4 +41,7 @@ select root,lev,obj,link,path,cycle, from t ---@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "search", at line 33, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 +--@FAILURE: Encountered: / "cycle", at line 34, column 1, in lexical state DEFAULT. recorded first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring13.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring13.sql index 4013b85c5..6e46c7060 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring13.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring13.sql @@ -22,4 +22,7 @@ select lpad(' ',2*reportlevel)||emp_last emp_name, eid, mgr_id, hire_date, job_i from dup_hiredate order by order1 ---@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "search", at line 19, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 +--@FAILURE: Encountered: / "cycle", at line 20, column 1, in lexical state DEFAULT. recorded first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring14.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring14.sql index 06e937459..918c76b10 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring14.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring14.sql @@ -22,4 +22,7 @@ group by emp_last, eid, mgr_id, salary having max(mgrlevel) > 0 order by mgr_id nulls first, emp_last ---@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "search" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: Encountered: / "search", at line 18, column 1, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 8 Mar 2026, 18:41:51 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql index 1103dc931..9747a883c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/returning01.sql @@ -13,4 +13,6 @@ where job = :jobs(i) returning empno bulk collect into :empnos ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 12, column 18, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 +--@FAILURE: Encountered: / "(", at line 12, column 18, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:18 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/sample01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/sample01.sql index 96a881ecc..476db90de 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/sample01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/sample01.sql @@ -14,4 +14,5 @@ select 1 as c1 from "sys"."obj$" sample block (14.285714 , 1) seed (1) "o" --@FAILURE: Encountered unexpected token: "block" recorded first on Aug 3, 2021, 7:20:08 AM --@FAILURE: Encountered unexpected token: "block" "BLOCK" recorded first on Jul 12, 2023, 12:58:42 PM ---@FAILURE: Encountered unexpected token: "," "," recorded first on Jul 12, 2023, 1:30:58 PM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "," "," recorded first on Jul 12, 2023, 1:30:58 PM +--@FAILURE: Encountered: / ",", at line 12, column 58, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/string01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/string01.sql index 1e07ba58a..c61543e8c 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/string01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/string01.sql @@ -22,4 +22,5 @@ select from dual ---@FAILURE: Encountered unexpected token: "%" "%" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "%" "%" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "%" / "%", at line 17, column 17, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union01.sql index c50c5abf5..92f26c01d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union01.sql @@ -15,4 +15,5 @@ (select 'e', 'e' from dual) ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union02.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union02.sql index b0f719f00..cb360f7e2 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union02.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union02.sql @@ -12,4 +12,5 @@ union all (select distinct job_id from hr.job_history) ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union03.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union03.sql index 53ad59f0a..1c905ac03 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union03.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union03.sql @@ -14,4 +14,5 @@ union all ) ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union04.sql index 44c8392e3..c59339e6f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union04.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union04.sql @@ -53,4 +53,5 @@ union all select distinct job_id from hr.job_history ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union05.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union05.sql index 68c7857cc..28418174f 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union05.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union05.sql @@ -38,4 +38,5 @@ union all ) order by 1 asc, 2 asc ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql index 5eac6382d..73c100f6d 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql @@ -43,4 +43,6 @@ union order by 4,3,1 ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Feb 13, 2025, 10:16:06 AM +--@FAILURE: ((select "x"."r_no","x"."i_id","x"."ind","x"."item",'0' "o" from "x" where("x"."r_no"=:a))union(select "y"."r_no","y"."i_id","y"."ind","y"."item",'0' "o" from "y" where("y"."r_no"=:a)))union((select "y"."r_no","y"."i_id","y"."ind","y"."item",'1' "o" from "y" where("y"."r_no"=:a))union(select "x"."r_no","x"."i_id","x"."ind","x"."item",'1' "o" from "x" where("x"."r_no"=:a)))order by 4,3,1 recorded first on Aug 21, 2025, 7:56:53 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union07.sql index 47f09e09c..df489e122 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union07.sql @@ -51,4 +51,5 @@ select * from ( ) where rownum_ >= ? ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union08.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union08.sql index 5da67f266..9288439cb 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union08.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union08.sql @@ -13,4 +13,5 @@ select * from dual where exists ( (select * from dual) ) ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "exists" "EXISTS" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union09.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union09.sql index a19cc34a8..9cfdd6776 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union09.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union09.sql @@ -35,4 +35,5 @@ select * from ( ) where rownum >= 1 ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union10.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union10.sql index 0055acf05..2ecbb56f2 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union10.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union10.sql @@ -22,4 +22,5 @@ select as yes_no from dual ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql index 4a503456e..b65ff7c26 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql @@ -16,4 +16,7 @@ from warehouses, "rail" varchar2(6) path '/warehouse/railaccess') warehouse2 ---@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM \ No newline at end of file +--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM +--@FAILURE: Encountered: "(" / "(", at line 12, column 10, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:09 +--@FAILURE: Encountered: / "(", at line 12, column 10, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:18 +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on 14 Mar 2026, 01:34:50 \ No newline at end of file diff --git a/src/test/resources/simple_parsing.txt b/src/test/resources/simple_parsing.txt index 3f0670ee1..30e335a9e 100644 --- a/src/test/resources/simple_parsing.txt +++ b/src/test/resources/simple_parsing.txt @@ -208,4 +208,277 @@ FROM EMPLOYEE THIS_EMP, DINFO, DINFOMAX WHERE THIS_EMP.JOB = 'SALESREP' AND THIS_EMP.WORKDEPT = DINFO.DEPTNO -select * from Person where deptname='it' AND NOT (age=24) \ No newline at end of file +select * from Person where deptname='it' AND NOT (age=24) + +select * from unnest(array[4,5,6]) with ordinality; + +SELECT * FROM tbl WHERE +day BETWEEN + CAST(CAST((NOW() + INTERVAL '-30 day') AS date) AS timestamptz) +AND + CAST(CAST((NOW() + INTERVAL '-1 day') AS date) AS timestamptz); + +SELECT DATE_TRUNC('week',("schema"."tbl"."column" + INTERVAL '1 day')) FROM "schema"."tbl"; + +WITH + FUNCTION doubleup(x integer) + RETURNS integer + RETURN x * 2 +SELECT doubleup(21); + +WITH + FUNCTION doubleup(x integer) + RETURNS integer + RETURN x * 2, + FUNCTION doubleupplusone(x integer) + RETURNS integer + RETURN doubleup(x) + 1 +SELECT doubleupplusone(21); + +WITH + FUNCTION hello(name varchar) + RETURNS varchar + RETURN format('Hello %s!', 'name'), + FUNCTION bye(name varchar) + RETURNS varchar + RETURN format('Bye %s!', 'name') +SELECT hello('Finn') || ' and ' || bye('Joe'); + +WITH + FUNCTION takesArray(x array) + RETURNS double + RETURN x[1] + x[2] + x[3] +SELECT takesArray(array[1.0, 2.0, 3.0]); + +SELECT + id, + json_exists( + description, + 'lax $.children[*]?(@ > 10)' + ) AS children_above_ten +FROM customers; + +SELECT + id, + json_exists( + description, + 'strict $.children[2]?(@ > 10)' + UNKNOWN ON ERROR + ) AS child_3_above_ten +FROM customers; + +SELECT + id, + json_query( + description, + 'lax $.children' + ) AS children +FROM customers; + +SELECT + id, + json_query( + description, + 'lax $.children[*]' + WITHOUT ARRAY WRAPPER + NULL ON ERROR + ) AS children +FROM customers; + +SELECT + id, + json_query( + description, + 'lax $.children[last]' + WITH ARRAY WRAPPER + ) AS last_child +FROM customers; + +SELECT + id, + json_query( + description, + 'strict $.children[*]?(@ > 12)' + WITH ARRAY WRAPPER + EMPTY ARRAY ON EMPTY + ) AS children +FROM customers; + +SELECT + id, + json_query(description, 'strict $.comment' KEEP QUOTES) AS quoted_comment, + json_query(description, 'strict $.comment' OMIT QUOTES) AS unquoted_comment +FROM customers; + +SELECT id, json_value( + description, + 'lax $.comment' + RETURNING char(12) + ) AS comment +FROM customers; + +SELECT id, json_value( + description, + 'lax $.children[0]' + RETURNING tinyint + ) AS child +FROM customers; + +SELECT id, json_value( + description, + 'strict $.children[2]' + DEFAULT 'err' ON ERROR + ) AS child +FROM customers; + +SELECT id, json_value( + description, + 'lax $.children[2]' + DEFAULT 'missing' ON EMPTY + ) AS child +FROM customers; + +SELECT + * +FROM + json_table( + '[ + {"id":1,"name":"Africa","wikiDataId":"Q15"}, + {"id":2,"name":"Americas","wikiDataId":"Q828"}, + {"id":3,"name":"Asia","wikiDataId":"Q48"}, + {"id":4,"name":"Europe","wikiDataId":"Q51"} + ]', + 'strict $' COLUMNS ( + NESTED PATH 'strict $[*]' COLUMNS ( + id integer PATH 'strict $.id', + name varchar PATH 'strict $.name', + wiki_data_id varchar PATH 'strict $."wikiDataId"' + ) + ) + ); + +SELECT + * +FROM + json_table( + '[ + {"continent": "Asia", "countries": [ + {"name": "Japan", "population": 125.7}, + {"name": "Thailand", "population": 71.6} + ]}, + {"continent": "Europe", "countries": [ + {"name": "France", "population": 67.4}, + {"name": "Germany", "population": 83.2} + ]} + ]', + 'lax $' COLUMNS ( + NESTED PATH 'lax $[*]' COLUMNS ( + continent varchar PATH 'lax $.continent', + NESTED PATH 'lax $.countries[*]' COLUMNS ( + country varchar PATH 'lax $.name', + population double PATH 'lax $.population' + ) + ) + )); + +SELECT + * +FROM + JSON_TABLE( + '[]', + 'lax $' AS "root_path" + COLUMNS( + a varchar(1) PATH 'lax "A"', + NESTED PATH 'lax $[*]' AS "nested_path" + COLUMNS (b varchar(1) PATH 'lax "B"')) + PLAN ("root_path" OUTER "nested_path") + ); + +SELECT + * +FROM + JSON_TABLE( + '[]', + 'lax $' AS "root_path" + COLUMNS( + a varchar(1) PATH 'lax "A"', + NESTED PATH 'lax $[*]' AS "nested_path" + COLUMNS (b varchar(1) PATH 'lax "B"')) + PLAN ("root_path" INNER "nested_path") + ); + +SELECT json_array(true, 12e-1, 'text'); + +SELECT json_array( + '[ "text" ] ' FORMAT JSON, + X'5B0035005D00' FORMAT JSON ENCODING UTF16 + ); + +SELECT json_array( + json_query('{"key" : [ "value" ]}', 'lax $.key') + ); + +SELECT json_array( + DATE '2001-01-31', + UUID '12151fd2-7586-11e9-8f9e-2a86e4085a59' + ); + +SELECT json_array(); + +SELECT json_array(true, null, 1); + +SELECT json_array(true, null, 1 ABSENT ON NULL); + +SELECT json_array(true, null, 1 NULL ON NULL); + +SELECT json_array(true, 1 RETURNING VARCHAR(100)); + +SELECT json_array(true, 1 RETURNING VARBINARY); + +SELECT json_array(true, 1 RETURNING VARBINARY FORMAT JSON ENCODING UTF8); + +SELECT json_array(true, 1 RETURNING VARBINARY FORMAT JSON ENCODING UTF16); + +SELECT json_array(true, 1 RETURNING VARBINARY FORMAT JSON ENCODING UTF32); + +SELECT json_object('key1' : 1, 'key2' : true); + +SELECT json_object(KEY 'key1' VALUE 1, KEY 'key2' VALUE true); + +SELECT json_object('key1' VALUE 1, 'key2' VALUE true); + +SELECT json_object('x' : true, 'y' : 12e-1, 'z' : 'text'); + +SELECT json_object( + 'x' : '[ "text" ] ' FORMAT JSON, + 'y' : X'5B0035005D00' FORMAT JSON ENCODING UTF16 + ); + +SELECT json_object( + 'x' : json_query('{"key" : [ "value" ]}', 'lax $.key') + ); + +SELECT json_object( + 'x' : DATE '2001-01-31', + 'y' : UUID '12151fd2-7586-11e9-8f9e-2a86e4085a59' + ); + +SELECT json_object(); + +SELECT json_object('x' : null, 'y' : 1); + +SELECT json_object('x' : null, 'y' : 1 NULL ON NULL); + +SELECT json_object('x' : null, 'y' : 1 ABSENT ON NULL); + +SELECT json_object('x' : null, 'x' : 1 WITH UNIQUE KEYS); + +SELECT json_object('x' : 1 RETURNING VARCHAR(100)); + +SELECT json_object('x' : 1 RETURNING VARBINARY); + +SELECT json_object('x' : 1 RETURNING VARBINARY FORMAT JSON ENCODING UTF8); + +SELECT json_object('x' : 1 RETURNING VARBINARY FORMAT JSON ENCODING UTF16); + +SELECT json_object('x' : 1 RETURNING VARBINARY FORMAT JSON ENCODING UTF32); \ No newline at end of file