diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 89826d9e5..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "gradle" # Specify Gradle as the package manager - directory: "/" # Root directory of your project - schedule: - interval: "weekly" # Define how often Dependabot should check for updates - ignore: - - dependency-name: "se.bjurr.gitchangelog.git-changelog-gradle-plugin" - versions: ["*"] # This will ignore all versions for this specific plugin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 943bef7dd..4c12bac81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,84 +2,104 @@ name: CI Pipeline on: push: - branches: [ "master" ] + branches: [ "**" ] # Run on every commit to any branch pull_request: - branches: [ "master" ] + branches: [ "**" ] # Run for PRs from any branch workflow_dispatch: permissions: write-all jobs: gradle_check: - runs-on: ubuntu-latest + 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: Build with Gradle + + - name: Set up Gradle uses: gradle/actions/setup-gradle@main + - name: Run Gradle Check run: ./gradlew check maven_verify: - needs: gradle_check - runs-on: ubuntu-latest + name: Maven Verify + needs: gradle_check # ✅ Run only after Gradle check succeeds + runs-on: ${{ matrix.os }} + strategy: + matrix: +# currently Windows does not work w/ code page related issues +# 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' - cache: maven - server-id: sonatype-nexus-snapshots - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - - name: Build with Maven - run: mvn -B verify --file pom.xml -DdisableXmlReport=true -Djacoco.skip=true -Dpmd.skip=true - env: - MAVEN_USERNAME: ${{ secrets.OSSRHUSERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRHPASSWORD }} + + - name: Run Maven Verify + run: mvn --batch-mode verify gradle_publish: - needs: maven_verify + 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 xsltproc sphinx-common + run: sudo apt-get install -y xsltproc sphinx-common + - name: Install Python dependencies - run: pip install furo myst_parser sphinx-prompt sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments + run: pip install furo 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: Deploy Sphinx documentation + + - 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/README.md b/README.md index ed1b89d27..a3c2389fe 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# [JSqlParser 5.1 Website](https://jsqlparser.github.io/JSqlParser) drawing +# [JSqlParser 5.3 Website](https://jsqlparser.github.io/JSqlParser) drawing [![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://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) +[![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! @@ -69,13 +69,28 @@ JSQLParser-4.9 was the last JDK8 compatible version. JSQLParser-5.0 and later de Building JSQLParser-5.1 and newer with Gradle will depend on a JDK17 toolchain due to the used plugins. +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. + +```text +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 82.695 ± 2.841 ms/op +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 ...` | +| 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) | | diff --git a/build.gradle b/build.gradle index 1f0924c03..15e9e50e2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,11 @@ 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: '12.5' + classpath group: 'net.sf.saxon', name: 'Saxon-HE', version: 'latest.release' } } @@ -43,7 +45,7 @@ def getVersion = { boolean considerSnapshot -> commandLine "git", "--no-pager", "-C", project.projectDir, "describe", "--tags", "--always", "--dirty=-SNAPSHOT" }.standardOutput.asText.get().trim() - def pattern = /(?\d*)\.(?\d*)(\.(?\d*))?(-(?\d*)-(?[a-zA-Z\d]*))?/ + def pattern = /jsqlparser-(?\d*)\.(?\d*)(\.(?\d*))?(-(?\d*)-(?[a-zA-Z\d]*))?/ def matcher = versionStr =~ pattern if (matcher.find()) { @@ -72,14 +74,67 @@ version = getVersion( !System.getenv("RELEASE") ) group = 'com.github.jsqlparser' description = 'JSQLParser library' +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 ai.starlake.jsqltranspiler; + | + |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" } @@ -104,24 +159,42 @@ dependencies { 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' + ] } java { @@ -162,9 +235,13 @@ jar { "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" @@ -178,22 +255,32 @@ tasks.register('xmldoc', Javadoc) { ) source = sourceSets.main.allJava - include("**/javacc/net/sf/jsqlparser/parser/*.java" ) + // 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.manticore.tools.xmldoclet.XmlDoclet" title = "API $version" + options.addBooleanOption("rst", true) - options.addBooleanOption("withFloatingToc", Boolean.parseBoolean(System.getenv().getOrDefault("FLOATING_TOC", "true"))) + if (Boolean.parseBoolean(System.getProperty("FLOATING_TOC", "true"))) { + options.addBooleanOption("withFloatingToc", true) + } options.addStringOption("basePackage", "net.sf.jsqlparser") options.addStringOption("filename", outFile.getName()) - dependsOn(compileJava) doLast { copy { from rstFile - into "${projectDir}/src/site/sphinx/" + into layout.projectDirectory.dir("src/site/sphinx/").asFile } } } @@ -309,6 +396,7 @@ pmd { pmdMain { excludes = [ "build/generated/*" + , "**/net/sf/jsqlparser/parser/SimpleCharStream.java" ] } } @@ -318,6 +406,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' @@ -337,13 +436,6 @@ spotless { } } -tasks.withType(Checkstyle).configureEach { - reports { - xml.required = false - html.required = true - } - excludes = [ "**/module-info.java" ] -} tasks.register('renderRR') { dependsOn(compileJavacc) @@ -447,16 +539,16 @@ tasks.register('updateKeywords', JavaExec) { dependsOn(compileJava) } -task xslt(type: SaxonXsltTask) { +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 file('src/main/resources/rr/xhtml2rst.xsl') - parameters ( - "withFloatingToc": System.getenv().getOrDefault("FLOATING_TOC", "true"), + parameters( + "withFloatingToc": System.getProperty("FLOATING_TOC", "true"), "isSnapshot": Boolean.toString(version.endsWith("-SNAPSHOT")) ) @@ -512,7 +604,7 @@ publish { publishing { publications { - create("mavenJava", MavenPublication) { + mavenJava(MavenPublication) { artifactId = 'jsqlparser' from components.java @@ -567,8 +659,8 @@ publishing { repositories { maven { name = "ossrh" - def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/" + 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 { @@ -633,3 +725,11 @@ tasks.register('upload') { check { dependsOn jacocoTestCoverageVerification } + +jmh { + includes = ['.*JSQLParserBenchmark.*'] + warmupIterations = 2 + fork = 3 + iterations = 5 + timeOnIteration = '1s' +} diff --git a/pom.xml b/pom.xml index 98d67faa3..20f6b7066 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 5.2-SNAPSHOT + 5.4-SNAPSHOT JSQLParser library 2004 @@ -24,12 +24,52 @@ + + + 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 @@ -59,13 +99,13 @@ org.assertj assertj-core - [3.25.3,) + 3.27.3 test org.apache.commons commons-lang3 - [3.14.0,) + [3.18.0,) test @@ -82,6 +122,23 @@ 1.3 test + + + + org.openjdk.jmh + jmh-core + 1.37 + test + + + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + provided + + @@ -94,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/ + sonatype-nexus-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + false + true @@ -141,6 +200,7 @@ **/*Bean.java **/generated/*.java + **/net/sf/jsqlparser/parser/SimpleCharStream.java target/generated-sources @@ -173,7 +233,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.2.0 + 3.6.0 add-source @@ -192,16 +252,25 @@ maven-compiler-plugin - 3.10.1 + 3.14.0 11 11 true ${project.build.sourceEncoding} true - true - 128m 2000m + + -J-Xss4M + + true + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + + @@ -218,15 +287,25 @@ UTF-8 false - 1.8 + false + false + java + + + - net.java.dev.javacc - javacc - [7.0.13,) + org.javacc.generator + java + 8.1.0-SNAPSHOT + + + org.javacc + core + 8.1.0-SNAPSHOT @@ -304,7 +383,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.4.1 + 3.11.2 attach-javadocs @@ -326,7 +405,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.2 @@ -349,7 +428,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.2.5 + 3.5.2 false @@ -364,7 +443,7 @@ org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.11 @@ -383,7 +462,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.28.0 + 2.43.0 origin/master @@ -424,6 +503,15 @@ + + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 + true + + sonatype-nexus + + @@ -536,7 +624,7 @@ true true ${project.build.sourceDirectory} - **/module-info.java + **/module-info.java,**/net/sf/jsqlparser/parser/SimpleCharStream.java @@ -599,6 +687,7 @@ UTF-8 + UTF-8 6.55.0 10.14.0 diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 361504653..ada4bfdf4 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -27,6 +27,7 @@ exports net.sf.jsqlparser.statement.comment; exports net.sf.jsqlparser.statement.create.function; exports net.sf.jsqlparser.statement.create.index; + exports net.sf.jsqlparser.statement.create.policy; exports net.sf.jsqlparser.statement.create.procedure; exports net.sf.jsqlparser.statement.create.schema; exports net.sf.jsqlparser.statement.create.sequence; @@ -36,8 +37,11 @@ exports net.sf.jsqlparser.statement.delete; exports net.sf.jsqlparser.statement.drop; exports net.sf.jsqlparser.statement.execute; + exports net.sf.jsqlparser.statement.export; exports net.sf.jsqlparser.statement.grant; + exports net.sf.jsqlparser.statement.imprt; exports net.sf.jsqlparser.statement.insert; + exports net.sf.jsqlparser.statement.lock; exports net.sf.jsqlparser.statement.merge; exports net.sf.jsqlparser.statement.piped; exports net.sf.jsqlparser.statement.refresh; diff --git a/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java b/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java index f2a531ab6..0c0d11146 100644 --- a/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java @@ -60,7 +60,6 @@ public AnalyticExpression(Function function) { this.distinct = function.isDistinct(); this.unique = function.isUnique(); - ExpressionList list = function.getParameters(); if (list != null) { if (list.size() > 3) { @@ -117,16 +116,16 @@ public void setKeep(KeepExpression keep) { } public ExpressionList getPartitionExpressionList() { - return windowDef.partitionBy.getPartitionExpressionList(); + return windowDef.partitionBy; } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList, + public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) { - windowDef.partitionBy.setPartitionExpressionList(partitionExpressionList, brackets); + windowDef.partitionBy.setExpressions(partitionExpressionList, brackets); } public boolean isPartitionByBrackets() { diff --git a/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java b/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java index 98421e2bb..45c2fde6a 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java @@ -35,15 +35,26 @@ * @author are */ public class ConnectByPriorOperator extends ASTNodeAccessImpl implements Expression { - private final Column column; + private final Expression expression; + @Deprecated public ConnectByPriorOperator(Column column) { - this.column = Objects.requireNonNull(column, + this.expression = Objects.requireNonNull(column, "The COLUMN of the ConnectByPrior Operator must not be null"); } - public Column getColumn() { - return column; + public ConnectByPriorOperator(Expression column) { + this.expression = Objects.requireNonNull(column, + "The COLUMN of the ConnectByPrior Operator must not be null"); + } + + @Deprecated + public Expression getColumn() { + return getExpression(); + } + + public Expression getExpression() { + return expression; } @Override @@ -52,7 +63,7 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { } public StringBuilder appendTo(StringBuilder builder) { - builder.append("PRIOR ").append(column); + builder.append("PRIOR ").append(expression); return builder; } @@ -60,4 +71,4 @@ public StringBuilder appendTo(StringBuilder builder) { public String toString() { return appendTo(new StringBuilder()).toString(); } -} \ No newline at end of file +} diff --git a/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java b/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java index 6942f0787..776dc031e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java @@ -34,15 +34,26 @@ * @author are */ public class ConnectByRootOperator extends ASTNodeAccessImpl implements Expression { - private final Column column; + private final Expression expression; + @Deprecated public ConnectByRootOperator(Column column) { - this.column = Objects.requireNonNull(column, + this.expression = Objects.requireNonNull(column, "The COLUMN of the ConnectByRoot Operator must not be null"); } - public Column getColumn() { - return column; + public ConnectByRootOperator(Expression column) { + this.expression = Objects.requireNonNull(column, + "The EXPRESSION of the ConnectByRoot Operator must not be null"); + } + + @Deprecated + public Expression getColumn() { + return expression; + } + + public Expression getExpression() { + return expression; } @Override @@ -51,7 +62,7 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { } public StringBuilder appendTo(StringBuilder builder) { - builder.append("CONNECT_BY_ROOT ").append(column); + builder.append("CONNECT_BY_ROOT ").append(expression); return builder; } diff --git a/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java b/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java index 3510fe6d3..ccb15db4b 100644 --- a/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java @@ -39,7 +39,7 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { @Override public String toString() { - return type.name() + " " + value; + return type != null ? type.name() + " " + value : value; } public DateTimeLiteralExpression withValue(String value) { diff --git a/src/main/java/net/sf/jsqlparser/expression/DateUnitExpression.java b/src/main/java/net/sf/jsqlparser/expression/DateUnitExpression.java new file mode 100644 index 000000000..298cff0cc --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/DateUnitExpression.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.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.Objects; + +public class DateUnitExpression extends ASTNodeAccessImpl implements Expression { + + private final DateUnit type; + + public DateUnitExpression(DateUnit type) { + this.type = Objects.requireNonNull(type); + } + + public DateUnitExpression(String DateUnitStr) { + this.type = Objects.requireNonNull(DateUnit.from(DateUnitStr)); + } + + public DateUnit getType() { + return type; + } + + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return type.toString(); + } + + public enum DateUnit { + CENTURY, DECADE, YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND; + + public static DateUnit from(String UnitStr) { + return Enum.valueOf(DateUnit.class, UnitStr.toUpperCase()); + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index a87b4594a..f70021f83 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -61,11 +61,97 @@ 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.GroupByElement; +import net.sf.jsqlparser.statement.select.Limit; +import net.sf.jsqlparser.statement.select.OrderByElement; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.update.UpdateSet; + +import java.util.List; public interface ExpressionVisitor { + default T visitExpressions(ExpressionList expressions, S context) { + if (expressions != null) { + expressions.forEach(expression -> expression.accept(this, context)); + } + return null; + }; + + default T visitExpression(Expression expression, S context) { + if (expression != null) { + expression.accept(this, context); + } + return null; + } + + default T visitOrderBy(List orderByElements, S context) { + if (orderByElements != null) { + for (OrderByElement orderByElement : orderByElements) { + orderByElement.getExpression().accept(this, context); + } + } + return null; + } + + default T visitLimit(Limit limit, S context) { + if (limit != null && !limit.isLimitNull() && !limit.isLimitAll()) { + if (limit.getOffset() != null) { + limit.getOffset().accept(this, context); + } + if (limit.getRowCount() != null) { + limit.getRowCount().accept(this, context); + } + if (limit.getByExpressions() != null) { + limit.getByExpressions().accept(this, context); + } + } + return null; + } + + default T visitPreferringClause(PreferringClause preferringClause, S context) { + if (preferringClause != null) { + if (preferringClause.getPreferring() != null) { + preferringClause.getPreferring().accept(this, context); + } + if (preferringClause.getPartitionBy() != null) { + for (Expression expression : preferringClause.getPartitionBy()) { + expression.accept(this, context); + } + } + } + return null; + } + + default T visitUpdateSets(List updateSets, S context) { + if (updateSets != null) { + for (UpdateSet updateSet : updateSets) { + for (Column column : updateSet.getColumns()) { + column.accept(this, context); + } + for (Expression value : updateSet.getValues()) { + value.accept(this, context); + } + } + } + return null; + } + + default T visit(GroupByElement groupBy, S context) { + if (groupBy != null) { + for (Expression expression : groupBy.getGroupByExpressionList()) { + expression.accept(this, context); + } + if (!groupBy.getGroupingSets().isEmpty()) { + for (ExpressionList expressionList : groupBy.getGroupingSets()) { + expressionList.accept(this, context); + } + } + } + return null; + } + T visit(BitwiseRightShift bitwiseRightShift, S context); default void visit(BitwiseRightShift bitwiseRightShift) { @@ -566,6 +652,14 @@ default void visit(JsonFunction jsonFunction) { this.visit(jsonFunction, null); } + default T visit(JsonTableFunction jsonTableFunction, S context) { + return visit((Function) jsonTableFunction, context); + } + + default void visit(JsonTableFunction jsonTableFunction) { + this.visit(jsonTableFunction, null); + } + T visit(ConnectByRootOperator connectByRootOperator, S context); default void visit(ConnectByRootOperator connectByRootOperator) { @@ -693,4 +787,12 @@ default void visit(Inverse inverse) { T visit(CosineSimilarity cosineSimilarity, S context); T visit(FromQuery fromQuery, S context); + + T visit(DateUnitExpression dateUnitExpression, S context); + + T visit(PostgresNamedFunctionParameter postgresNamedFunctionParameter, S context); + + default void visit(PostgresNamedFunctionParameter postgresNamedFunctionParameter) { + this.visit(postgresNamedFunctionParameter, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index 3be6d1348..ad0d1b974 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -84,17 +84,26 @@ public class ExpressionVisitorAdapter private SelectVisitor selectVisitor; + public ExpressionVisitorAdapter(SelectVisitor selectVisitor) { + this.selectVisitor = selectVisitor; + } + + public ExpressionVisitorAdapter() { + this.selectVisitor = null; + } + public SelectVisitor getSelectVisitor() { return selectVisitor; } - public void setSelectVisitor(SelectVisitor selectVisitor) { + public ExpressionVisitorAdapter setSelectVisitor(SelectVisitor selectVisitor) { this.selectVisitor = selectVisitor; + return this; } @Override public T visit(NullValue nullValue, S context) { - return visitExpression(nullValue, context); + return applyExpression(nullValue, context); } @Override @@ -121,47 +130,47 @@ public T visit(SignedExpression signedExpression, S context) { @Override public T visit(JdbcParameter jdbcParameter, S context) { - return visitExpression(jdbcParameter, context); + return applyExpression(jdbcParameter, context); } @Override public T visit(JdbcNamedParameter jdbcNamedParameter, S context) { - return visitExpression(jdbcNamedParameter, context); + return applyExpression(jdbcNamedParameter, context); } @Override public T visit(DoubleValue doubleValue, S context) { - return visitExpression(doubleValue, context); + return applyExpression(doubleValue, context); } @Override public T visit(LongValue longValue, S context) { - return visitExpression(longValue, context); + return applyExpression(longValue, context); } @Override public T visit(DateValue dateValue, S context) { - return visitExpression(dateValue, context); + return applyExpression(dateValue, context); } @Override public T visit(TimeValue timeValue, S context) { - return visitExpression(timeValue, context); + return applyExpression(timeValue, context); } @Override public T visit(TimestampValue timestampValue, S context) { - return visitExpression(timestampValue, context); + return applyExpression(timestampValue, context); } @Override public T visit(StringValue stringValue, S context) { - return visitExpression(stringValue, context); + return applyExpression(stringValue, context); } @Override public T visit(BooleanValue booleanValue, S context) { - return visitExpression(booleanValue, context); + return applyExpression(booleanValue, context); } @Override @@ -308,7 +317,7 @@ public T visit(ContainedBy containedBy, S context) { @Override public T visit(Column column, S context) { - return visitExpression(column, context); + return applyExpression(column, context); } @Override @@ -352,7 +361,7 @@ public T visit(MemberOfExpression memberOfExpression, S context) { @Override public T visit(AnyComparisonExpression anyComparisonExpression, S context) { - return visitExpression(anyComparisonExpression, context); + return applyExpression(anyComparisonExpression, context); } @Override @@ -481,7 +490,7 @@ public T visit(BitwiseLeftShift bitwiseLeftShift, S context) { return visitBinaryExpression(bitwiseLeftShift, context); } - protected T visitExpression(Expression expression, S context) { + protected T applyExpression(Expression expression, S context) { return null; } @@ -522,12 +531,12 @@ public T visit(JsonOperator jsonOperator, S context) { @Override public T visit(UserVariable userVariable, S context) { - return visitExpression(userVariable, context); + return applyExpression(userVariable, context); } @Override public T visit(NumericBind numericBind, S context) { - return visitExpression(numericBind, context); + return applyExpression(numericBind, context); } @Override @@ -592,22 +601,22 @@ public T visit(UnPivot unpivot, S context) { @Override public T visit(AllColumns allColumns, S context) { - return visitExpression(allColumns, context); + return applyExpression(allColumns, context); } @Override public T visit(AllTableColumns allTableColumns, S context) { - return visitExpression(allTableColumns, context); + return applyExpression(allTableColumns, context); } @Override public T visit(FunctionAllColumns functionAllColumns, S context) { - return visitExpression(functionAllColumns, context); + return applyExpression(functionAllColumns, context); } @Override public T visit(AllValue allValue, S context) { - return visitExpression(allValue, context); + return applyExpression(allValue, context); } @Override @@ -627,27 +636,27 @@ public T visit(RowGetExpression rowGetExpression, S context) { @Override public T visit(HexValue hexValue, S context) { - return visitExpression(hexValue, context); + return applyExpression(hexValue, context); } @Override public T visit(OracleHint hint, S context) { - return visitExpression(hint, context); + return applyExpression(hint, context); } @Override public T visit(TimeKeyExpression timeKeyExpression, S context) { - return visitExpression(timeKeyExpression, context); + return applyExpression(timeKeyExpression, context); } @Override public T visit(DateTimeLiteralExpression dateTimeLiteralExpression, S context) { - return visitExpression(dateTimeLiteralExpression, context); + return applyExpression(dateTimeLiteralExpression, context); } @Override public T visit(NextValExpression nextValExpression, S context) { - return visitExpression(nextValExpression, context); + return applyExpression(nextValExpression, context); } @Override @@ -713,12 +722,40 @@ public T visit(JsonAggregateFunction jsonAggregateFunction, S context) { @Override public T visit(JsonFunction jsonFunction, S context) { ArrayList subExpressions = new ArrayList<>(); + for (JsonKeyValuePair keyValuePair : jsonFunction.getKeyValuePairs()) { + if (keyValuePair.getKey() instanceof Expression) { + subExpressions.add((Expression) keyValuePair.getKey()); + } + if (keyValuePair.getValue() instanceof Expression) { + subExpressions.add((Expression) keyValuePair.getValue()); + } + } for (JsonFunctionExpression expr : jsonFunction.getExpressions()) { subExpressions.add(expr.getExpression()); } + if (jsonFunction.getInputExpression() != null) { + subExpressions.add(jsonFunction.getInputExpression().getExpression()); + } + if (jsonFunction.getJsonPathExpression() != null) { + subExpressions.add(jsonFunction.getJsonPathExpression()); + } + subExpressions.addAll(jsonFunction.getPassingExpressions()); + if (jsonFunction.getOnEmptyBehavior() != null + && jsonFunction.getOnEmptyBehavior().getExpression() != null) { + subExpressions.add(jsonFunction.getOnEmptyBehavior().getExpression()); + } + if (jsonFunction.getOnErrorBehavior() != null + && jsonFunction.getOnErrorBehavior().getExpression() != null) { + subExpressions.add(jsonFunction.getOnErrorBehavior().getExpression()); + } return visitExpressions(jsonFunction, context, subExpressions); } + @Override + public T visit(JsonTableFunction jsonTableFunction, S context) { + return visitExpressions(jsonTableFunction, context, jsonTableFunction.getAllExpressions()); + } + @Override public T visit(ConnectByRootOperator connectByRootOperator, S context) { return connectByRootOperator.getColumn().accept(this, context); @@ -734,6 +771,11 @@ public T visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S return oracleNamedFunctionParameter.getExpression().accept(this, context); } + @Override + public T visit(PostgresNamedFunctionParameter postgresNamedFunctionParameter, S context) { + return postgresNamedFunctionParameter.getExpression().accept(this, context); + } + @Override public T visit(GeometryDistance geometryDistance, S context) { return visitBinaryExpression(geometryDistance, context); @@ -831,4 +873,9 @@ public T visit(FromQuery fromQuery, S context) { return null; } + @Override + public T visit(DateUnitExpression dateUnitExpression, S context) { + return null; + } + } diff --git a/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java b/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java index 50e557933..a64d8eb27 100644 --- a/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java +++ b/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java @@ -51,17 +51,17 @@ public FilterOverImpl withOrderByElements(List orderByElements) return this; } - public ExpressionList getPartitionExpressionList() { - return partitionBy.getPartitionExpressionList(); + public ExpressionList getPartitionExpressionList() { + return partitionBy; } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList, + public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) { - partitionBy.setPartitionExpressionList(partitionExpressionList, brackets); + partitionBy.setExpressions(partitionExpressionList, brackets); } public boolean isPartitionByBrackets() { diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java index 4422c1beb..aee8e7bf3 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java @@ -13,22 +13,147 @@ 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 { + public enum JsonOnResponseBehaviorType { + ERROR, NULL, DEFAULT, EMPTY_ARRAY, EMPTY_OBJECT, TRUE, FALSE, UNKNOWN + } + + public enum JsonWrapperType { + WITHOUT, WITH + } + + public enum JsonWrapperMode { + CONDITIONAL, UNCONDITIONAL + } + + public enum JsonQuotesType { + KEEP, OMIT + } + + 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_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: + // this should never happen + } + return builder; + } + + @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; + + 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; } @@ -57,6 +182,118 @@ 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 boolean isEmpty() { return keyValuePairs.isEmpty(); } @@ -114,6 +351,19 @@ public JsonFunction withType(String 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); @@ -123,17 +373,22 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { public StringBuilder append(StringBuilder builder) { switch (functionType) { case OBJECT: - appendObject(builder); - break; case POSTGRES_OBJECT: - appendPostgresObject(builder); - break; case MYSQL_OBJECT: - appendMySqlObject(builder); + 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 } @@ -148,35 +403,38 @@ public StringBuilder appendObject(StringBuilder builder) { if (i > 0) { builder.append(", "); } - if (keyValuePair.isUsingValueKeyword()) { - if (keyValuePair.isUsingKeyKeyword()) { - builder.append("KEY "); - } - 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"); - } + 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"); + builder.append(" ABSENT ON NULL"); break; default: // this should never happen } } + } + private void appendUniqueKeys(StringBuilder builder) { if (uniqueKeysType != null) { switch (uniqueKeysType) { case WITH: @@ -189,71 +447,140 @@ public StringBuilder appendObject(StringBuilder builder) { // this should never happen } } + } - builder.append(" ) "); + @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 appendPostgresObject(StringBuilder builder) { - builder.append("JSON_OBJECT( "); - for (JsonKeyValuePair keyValuePair : keyValuePairs) { - builder.append(keyValuePair.getKey()); - if (keyValuePair.getValue() != null) { - builder.append(", ").append(keyValuePair.getValue()); - } + public StringBuilder appendValue(StringBuilder builder) { + builder.append("JSON_VALUE("); + appendValueOrQueryPrefix(builder); + + if (returningType != null) { + builder.append(" RETURNING ").append(returningType); } - builder.append(" ) "); + appendOnResponseClause(builder, onEmptyBehavior, "EMPTY"); + appendOnResponseClause(builder, onErrorBehavior, "ERROR"); + + 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++; + @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(" ) "); + builder.append(")"); return builder; } @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) - public StringBuilder appendArray(StringBuilder builder) { - builder.append("JSON_ARRAY( "); - int i = 0; + public StringBuilder appendExists(StringBuilder builder) { + builder.append("JSON_EXISTS("); + appendValueOrQueryPrefix(builder); + appendOnResponseClause(builder, onErrorBehavior, "ERROR"); + builder.append(")"); + return builder; + } - for (JsonFunctionExpression expr : expressions) { - if (i > 0) { + private void appendValueOrQueryPrefix(StringBuilder builder) { + if (inputExpression != null) { + inputExpression.append(builder); + } + + if (jsonPathExpression != null) { + if (inputExpression != null) { builder.append(", "); } - expr.append(builder); - i++; + builder.append(jsonPathExpression); } - 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 + if (!passingExpressions.isEmpty()) { + builder.append(" PASSING "); + boolean comma = false; + for (Expression passingExpression : passingExpressions) { + if (comma) { + builder.append(", "); + } else { + comma = true; + } + builder.append(passingExpression); } } - builder.append(") "); + } - return builder; + 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 diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java index 5df7ad310..738c09fc2 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java @@ -21,6 +21,7 @@ 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"); @@ -43,8 +44,28 @@ public JsonFunctionExpression withUsingFormatJson(boolean 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 43a33aab6..ebd497e79 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java @@ -14,7 +14,19 @@ * @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 82c8a355a..18fb4752d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java @@ -20,16 +20,28 @@ public class JsonKeyValuePair implements Serializable { private final Object key; private final Object value; - private boolean usingKeyKeyword = false; - private boolean usingValueKeyword = false; + 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.usingValueKeyword = usingValueKeyword; + this.separator = + Objects.requireNonNull(separator, "The KeyValuePairSeparator must not be NULL"); } public boolean isUsingKeyKeyword() { @@ -45,19 +57,45 @@ public JsonKeyValuePair withUsingKeyKeyword(boolean usingKeyKeyword) { return this; } + /** + * Use {@link #getSeparator()} + */ + @Deprecated public boolean isUsingValueKeyword() { - return usingValueKeyword; + return separator == JsonKeyValuePairSeparator.VALUE; } + /** + * Use {@link #setSeparator(JsonKeyValuePairSeparator)} + */ + @Deprecated public void setUsingValueKeyword(boolean usingValueKeyword) { - this.usingValueKeyword = 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; } @@ -71,6 +109,19 @@ public JsonKeyValuePair withUsingFormatJson(boolean 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; @@ -102,17 +153,21 @@ public Object getValue() { } 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 (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; 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..b7f5d0149 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonTableFunction.java @@ -0,0 +1,704 @@ +/*- + * #%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 { + 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, EMPTY + } + + 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 JsonFunction.JsonWrapperType wrapperType; + private JsonFunction.JsonWrapperMode wrapperMode; + private boolean array; + + 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; + + 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 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 String encoding; + private Expression pathExpression; + private JsonTableWrapperClause wrapperClause; + private JsonTableQuotesClause quotesClause; + private JsonFunction.JsonOnResponseBehavior onEmptyBehavior; + private JsonFunction.JsonOnResponseBehavior onErrorBehavior; + + public String getColumnName() { + return columnName; + } + + public JsonTableValueColumnDefinition setColumnName(String columnName) { + this.columnName = columnName; + 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; + } + + @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(); + } + + builder.append(" ").append(dataType); + if (formatJson) { + builder.append(" FORMAT JSON"); + if (encoding != null) { + builder.append(" ENCODING ").append(encoding); + } + } + if (pathExpression != null) { + builder.append(" PATH ").append(pathExpression); + } + if (wrapperClause != null) { + builder.append(" ").append(wrapperClause); + } + if (quotesClause != null) { + builder.append(" ").append(quotesClause); + } + if (onEmptyBehavior != null) { + builder.append(" ").append(onEmptyBehavior).append(" ON EMPTY"); + } + if (onErrorBehavior != null) { + builder.append(" ").append(onErrorBehavior).append(" ON ERROR"); + } + 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(); + } + } + + private Expression jsonInputExpression; + private Expression jsonPathExpression; + private String pathName; + private final List passingClauses = new ArrayList<>(); + private JsonTableColumnsClause columnsClause; + private JsonTablePlanClause planClause; + private JsonTableOnErrorClause onErrorClause; + + public JsonTableFunction() { + setName("JSON_TABLE"); + } + + 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 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).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; + } + } + builder.append(" ").append(columnsClause); + if (planClause != null) { + builder.append(" ").append(planClause); + } + if (onErrorClause != null) { + builder.append(" ").append(onErrorClause); + } + builder.append(")"); + return builder.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java b/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java index 243975029..6ad41e994 100644 --- a/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java @@ -14,29 +14,39 @@ 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, + @Deprecated + public void setPartitionExpressionList(ExpressionList partitionExpressionList, + boolean brackets) { + setExpressions(partitionExpressionList, brackets); + } + + public PartitionByClause setExpressions(ExpressionList partitionExpressionList, boolean brackets) { - this.partitionExpressionList = partitionExpressionList; + 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, + b.append(PlainSelect.getStringList(this, true, brackets)); b.append(" "); } @@ -46,7 +56,9 @@ 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 index 08ebb71a7..2db468dbb 100644 --- a/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java @@ -21,12 +21,12 @@ public PreferringClause(Expression preferring) { this.preferring = preferring; } - public void setPartitionExpressionList(ExpressionList expressionList, + public void setPartitionExpressionList(ExpressionList expressionList, boolean brackets) { if (this.partitionBy == null) { this.partitionBy = new PartitionByClause(); } - partitionBy.setPartitionExpressionList(expressionList, brackets); + partitionBy.setExpressions(expressionList, brackets); } public void toStringPreferring(StringBuilder b) { 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/StringValue.java b/src/main/java/net/sf/jsqlparser/expression/StringValue.java index ec77f54a9..a16536fab 100644 --- a/src/main/java/net/sf/jsqlparser/expression/StringValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/StringValue.java @@ -24,6 +24,7 @@ public final class StringValue extends ASTNodeAccessImpl implements Expression { Arrays.asList("N", "U", "E", "R", "B", "RB", "_utf8", "Q"); private String value = ""; private String prefix = null; + private String quoteStr = "'"; public StringValue() { // empty constructor @@ -35,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) { @@ -68,6 +74,15 @@ 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; @@ -87,7 +102,7 @@ public T accept(ExpressionVisitor expressionVisitor, S 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/TranscodingFunction.java b/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java index 343579e29..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; } @@ -87,14 +114,16 @@ public T accept(ExpressionVisitor expressionVisitor, S 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/UserVariable.java b/src/main/java/net/sf/jsqlparser/expression/UserVariable.java index ece2bd13a..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,7 +32,15 @@ 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 diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java b/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java index a5df35aa6..60760baee 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java @@ -51,13 +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, + public void setPartitionExpressionList(ExpressionList partitionExpressionList, boolean brackets) { - partitionBy.setPartitionExpressionList(partitionExpressionList, brackets); + partitionBy.setExpressions(partitionExpressionList, brackets); } public String getWindowName() { 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 1cd997216..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,6 +22,8 @@ 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; @@ -55,6 +57,24 @@ public void setNot(boolean b) { not = b; } + public boolean isUsingSymmetric() { + return usingSymmetric; + } + + public Between setUsingSymmetric(boolean usingSymmetric) { + this.usingSymmetric = usingSymmetric; + return this; + } + + public boolean isUsingAsymmetric() { + return usingAsymmetric; + } + + public Between setUsingAsymmetric(boolean usingAsymmetric) { + this.usingAsymmetric = usingAsymmetric; + return this; + } + @Override public T accept(ExpressionVisitor expressionVisitor, S context) { return expressionVisitor.visit(this, context); @@ -62,7 +82,9 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { @Override public String toString() { - return leftExpression + " " + (not ? "NOT " : "") + "BETWEEN " + betweenExpressionStart + return leftExpression + " " + (not ? "NOT " : "") + "BETWEEN " + + (usingSymmetric ? "SYMMETRIC " : "") + (usingAsymmetric ? "ASYMMETRIC " : "") + + betweenExpressionStart + " AND " + betweenExpressionEnd; } 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 2abbae1db..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); @@ -96,12 +96,12 @@ public String toString() { @Override - public SimpleNode getASTNode() { + public Node getASTNode() { return node; } @Override - public void setASTNode(SimpleNode node) { + public void setASTNode(Node node) { this.node = node; } 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 fb26ff2c2..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,18 +49,18 @@ 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()); diff --git a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java index a39ac7e32..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); } @@ -83,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) { @@ -95,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 50d583194..bdb25eeb4 100644 --- a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java +++ b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java @@ -40,7 +40,6 @@ @SuppressWarnings("PMD.CyclomaticComplexity") public final class CCJSqlParserUtil { public final static Logger LOGGER = Logger.getLogger(CCJSqlParserUtil.class.getName()); - public final static int ALLOWED_NESTING_DEPTH = 10; static { LOGGER.setLevel(Level.OFF); @@ -50,7 +49,7 @@ 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); @@ -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 6e6019a64..19e1ad471 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -56,6 +56,7 @@ public class ParserKeywordsUtils { {"CHECK", RESTRICTED_SQL2016}, {"CONNECT", RESTRICTED_ALIAS}, {"CONNECT_BY_ROOT", RESTRICTED_JSQLPARSER}, + {"CSV", RESTRICTED_JSQLPARSER}, {"PRIOR", RESTRICTED_JSQLPARSER}, {"CONSTRAINT", RESTRICTED_SQL2016}, {"CREATE", RESTRICTED_ALIAS}, @@ -63,14 +64,18 @@ public class ParserKeywordsUtils { {"CURRENT", RESTRICTED_JSQLPARSER}, {"DEFAULT", RESTRICTED_ALIAS}, {"DISTINCT", RESTRICTED_SQL2016}, + {"DISTINCTROW", RESTRICTED_SQL2016}, {"DOUBLE", RESTRICTED_ALIAS}, {"ELSE", RESTRICTED_JSQLPARSER}, + {"ERRORS", RESTRICTED_JSQLPARSER}, {"EXCEPT", RESTRICTED_SQL2016}, {"EXCLUDES", RESTRICTED_JSQLPARSER}, {"EXISTS", RESTRICTED_SQL2016}, {"EXTEND", RESTRICTED_JSQLPARSER}, {"FALSE", RESTRICTED_SQL2016}, + {"FBV", RESTRICTED_JSQLPARSER}, {"FETCH", RESTRICTED_SQL2016}, + {"FILE", RESTRICTED_JSQLPARSER}, {"FINAL", RESTRICTED_JSQLPARSER}, {"FOR", RESTRICTED_SQL2016}, {"FORCE", RESTRICTED_SQL2016}, @@ -86,6 +91,7 @@ public class ParserKeywordsUtils { {"IIF", RESTRICTED_ALIAS}, {"IGNORE", RESTRICTED_ALIAS}, {"ILIKE", RESTRICTED_SQL2016}, + {"IMPORT", RESTRICTED_JSQLPARSER}, {"IN", RESTRICTED_SQL2016}, {"INCLUDES", RESTRICTED_JSQLPARSER}, {"INNER", RESTRICTED_SQL2016}, @@ -115,18 +121,22 @@ public class ParserKeywordsUtils { {"OVERWRITE ", RESTRICTED_JSQLPARSER}, {"PIVOT", RESTRICTED_JSQLPARSER}, {"PREFERRING", RESTRICTED_JSQLPARSER}, + {"PREWHERE", RESTRICTED_JSQLPARSER}, {"PRIOR", RESTRICTED_ALIAS}, {"PROCEDURE", RESTRICTED_ALIAS}, {"PUBLIC", RESTRICTED_ALIAS}, + {"RETURNS", RESTRICTED_JSQLPARSER}, {"RETURNING", RESTRICTED_JSQLPARSER}, {"RIGHT", RESTRICTED_SQL2016}, {"SAMPLE", RESTRICTED_ALIAS}, + {"SCRIPT", RESTRICTED_JSQLPARSER}, {"SEL", RESTRICTED_ALIAS}, {"SELECT", RESTRICTED_ALIAS}, {"SEMI", RESTRICTED_JSQLPARSER}, {"SET", RESTRICTED_JSQLPARSER}, {"SOME", RESTRICTED_JSQLPARSER}, {"START", RESTRICTED_JSQLPARSER}, + {"STATEMENT", RESTRICTED_JSQLPARSER}, {"TABLES", RESTRICTED_ALIAS}, {"TOP", RESTRICTED_SQL2016}, {"TRAILING", RESTRICTED_SQL2016}, @@ -146,6 +156,7 @@ public class ParserKeywordsUtils { {"VALUE", RESTRICTED_JSQLPARSER}, {"VALUES", RESTRICTED_SQL2016}, {"VARYING", RESTRICTED_JSQLPARSER}, + {"VERIFY", RESTRICTED_JSQLPARSER}, {"WHEN", RESTRICTED_SQL2016}, {"WHERE", RESTRICTED_SQL2016}, {"WINDOW", RESTRICTED_SQL2016}, diff --git a/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java b/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java index b96578e01..c10c568a6 100644 --- a/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java +++ b/src/main/java/net/sf/jsqlparser/parser/SimpleCharStream.java @@ -2,29 +2,30 @@ * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2019 JSQLParser + * Copyright (C) 2004 - 2025 JSQLParser * %% * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ +/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 8.0.0 */ package net.sf.jsqlparser.parser; -import java.io.IOException; +/** + * An implementation of interface CharStream, where the stream is assumed to contain only ASCII + * characters (without unicode processing). + */ -@SuppressWarnings({"PMD.MethodNamingConventions", "PMD.CyclomaticComplexity"}) public class SimpleCharStream { - /** * Whether parser is static. */ - @SuppressWarnings("checkstyle:constantname") public static final boolean staticFlag = false; /** * Position in buffer. */ public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; + protected int[] bufline; + protected int[] bufcolumn; protected int column = 0; protected int line = 1; protected boolean prevCharIsCR = false; @@ -40,52 +41,30 @@ public class SimpleCharStream { int bufsize; int available; int tokenBegin; - private boolean isStringProvider; /** - * Constructor - * - * @param dstream - * @param startline - * @param startcolumn - * @param buffersize + * Constructor. */ - public SimpleCharStream(Provider dstream, int startline, - int startcolumn, int buffersize) { + public SimpleCharStream(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 { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; } /** - * Constructor - * - * @param dstream - * @param startline - * @param startcolumn + * Constructor. */ - public SimpleCharStream(Provider dstream, int startline, - int startcolumn) { + public SimpleCharStream(Provider dstream, int startline, int startcolumn) { this(dstream, startline, startcolumn, 4096); } /** - * Constructor - * - * @param dstream + * Constructor. */ public SimpleCharStream(Provider dstream) { this(dstream, 1, 1, 4096); @@ -103,10 +82,10 @@ public final int getAbsoluteTokenBegin() { return absoluteTokenBegin; } - protected void ExpandBuff(boolean wrapAround) throws IOException { + protected void ExpandBuff(boolean wrapAround) { char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; + int[] newbufline = new int[bufsize + 2048]; + int[] newbufcolumn = new int[bufsize + 2048]; try { if (wrapAround) { @@ -136,16 +115,17 @@ protected void ExpandBuff(boolean wrapAround) throws IOException { maxNextCharInd = bufpos -= tokenBegin; } } catch (Throwable t) { - throw new IOException("Errow expanding the buffer.", t); + throw new Error(t.getMessage()); } + bufsize += 2048; available = bufsize; tokenBegin = 0; } - protected void FillBuff() throws IOException { - if (!isStringProvider && maxNextCharInd == available) { + protected void FillBuff() throws java.io.IOException { + if (maxNextCharInd == available) { if (available == bufsize) { if (tokenBegin > 2048) { bufpos = maxNextCharInd = 0; @@ -166,23 +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) { @@ -194,15 +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; } @@ -230,7 +199,7 @@ protected void UpdateLineColumn(char c) { break; case '\t': column--; - column += tabSize - (column % tabSize); + column += tabSize - column % tabSize; break; default: break; @@ -240,21 +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; @@ -263,7 +221,8 @@ public char readChar() throws IOException { } totalCharsRead++; - return readChar(bufpos); + + return buffer[bufpos]; } if (++bufpos >= maxNextCharInd) { @@ -272,53 +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]; @@ -326,8 +287,6 @@ public int getBeginLine() { /** * Backup a number of characters. - * - * @param amount */ public void backup(int amount) { @@ -340,30 +299,17 @@ public void backup(int amount) { /** * Reinitialise. - * - * @param dstream - * @param startline - * @param startcolumn - * @param buffersize */ - public void ReInit(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]; - } + + 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; @@ -372,72 +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 */ 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; @@ -454,12 +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; @@ -471,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; @@ -484,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; } } } @@ -508,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/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java index 75b5c78a5..d786f5170 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -792,6 +792,36 @@ public enum Feature { * 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; 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 da5ddd2b0..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,7 +19,7 @@ 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 @@ -64,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/schema/Column.java b/src/main/java/net/sf/jsqlparser/schema/Column.java index 2aa0994cd..1c1427c86 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Column.java +++ b/src/main/java/net/sf/jsqlparser/schema/Column.java @@ -16,6 +16,7 @@ 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; /** @@ -28,6 +29,10 @@ public class Column extends ASTNodeAccessImpl implements Expression, MultiPartNa private String commentText; private ArrayConstructor arrayConstructor; private String tableDelimiter = "."; + private int oldOracleJoinSyntax = SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN; + + // holds the physical table when resolved against an actual schema information + private Table resolvedTable = null; public Column() {} @@ -50,7 +55,8 @@ public Column(List nameParts, List delimiters) { } public Column(String columnName) { - this(null, columnName); + this(); + setColumnName(columnName); } public ArrayConstructor getArrayConstructor() { @@ -128,8 +134,56 @@ public String getUnquotedColumnName() { return MultiPartName.unquote(columnName); } - public void setColumnName(String string) { - columnName = string; + 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() { @@ -140,6 +194,14 @@ 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); @@ -193,6 +255,7 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { @Override public String toString() { return getFullyQualifiedName(true) + + (oldOracleJoinSyntax != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN ? "(+)" : "") + (commentText != null ? " /* " + commentText + "*/ " : ""); } @@ -216,6 +279,11 @@ public Column withTableDelimiter(String delimiter) { return this; } + public Column withOldOracleJoinSyntax(int oldOracleJoinSyntax) { + this.setOldOracleJoinSyntax(oldOracleJoinSyntax); + return this; + } + public String getCommentText() { return commentText; } @@ -223,4 +291,26 @@ public String getCommentText() { 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/MultiPartName.java b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java index e2d985bc1..ce954780d 100644 --- a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java +++ b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java @@ -9,10 +9,12 @@ */ 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 @@ -27,10 +29,32 @@ static String unquote(String quotedIdentifier) { } static boolean isQuoted(String identifier) { - return identifier!=null && LEADING_TRAILING_QUOTES_PATTERN.matcher(identifier).find(); + 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/Sequence.java b/src/main/java/net/sf/jsqlparser/schema/Sequence.java index 2f813c1d7..083122434 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Sequence.java +++ b/src/main/java/net/sf/jsqlparser/schema/Sequence.java @@ -158,7 +158,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()); @@ -189,8 +189,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/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 066326a88..1de14a8a5 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.schema; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -17,6 +18,7 @@ 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; @@ -27,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; @@ -44,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; @@ -56,6 +62,9 @@ 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() {} /** @@ -70,6 +79,10 @@ public Table(String name) { setName(name); } + public Table(String name, boolean splitNamesOnDelimiter) { + setName(name, splitNamesOnDelimiter); + } + public Table(String schemaName, String name) { setSchemaName(schemaName); setName(name); @@ -157,7 +170,49 @@ public String getUnquotedSchemaName() { } public Table setSchemaName(String schemaName) { - this.setIndex(SCHEMA_IDX, 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; } @@ -193,12 +248,20 @@ public void setName(String name) { .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); } @@ -230,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++) { @@ -290,6 +366,15 @@ public T accept(IntoTableVisitor intoTableVisitor, S context) { return intoTableVisitor.visit(this, context); } + public String getTimeTravel() { + return timeTravelStr; + } + + public Table setTimeTravel(String timeTravelStr) { + this.timeTravelStr = timeTravelStr; + return this; + } + @Override public Pivot getPivot() { return pivot; @@ -342,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); } @@ -400,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/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/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/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/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/FBVColumn.java b/src/main/java/net/sf/jsqlparser/statement/FBVColumn.java new file mode 100644 index 000000000..a1846efd9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/FBVColumn.java @@ -0,0 +1,98 @@ +/*- + * #%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 net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.StringValue; + +public class FBVColumn { + private boolean precedesComma; + private String key; + private Expression value; + private String stringValue; + + private FBVColumn(String key, Expression value) { + this.key = key; + this.value = value; + this.stringValue = null; + } + + public FBVColumn(String key, String value) { + this.key = key; + this.value = null; + this.stringValue = value; + } + + public FBVColumn(String key, StringValue value) { + this(key, (Expression) value); + } + + public FBVColumn(String key, LongValue value) { + this(key, (Expression) value); + } + + public boolean precedesComma() { + return precedesComma; + } + + public void setPrecedesComma(boolean precedesComma) { + this.precedesComma = precedesComma; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Expression getValue() { + return value; + } + + public void setValue(String value) { + this.stringValue = value; + this.value = null; + } + + private void setValue(Expression value) { + this.value = value; + this.stringValue = null; + } + + public void setValue(StringValue value) { + setValue((Expression) value); + } + + public void setValue(LongValue value) { + setValue((Expression) value); + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (precedesComma) { + sql.append(", "); + } + + sql.append(key); + sql.append(" = "); + if (stringValue != null) { + sql.append(stringValue); + } else { + sql.append(value); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/FileOption.java b/src/main/java/net/sf/jsqlparser/statement/FileOption.java new file mode 100644 index 000000000..ff91f571b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/FileOption.java @@ -0,0 +1,85 @@ +/*- + * #%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 net.sf.jsqlparser.expression.LongValue; +import net.sf.jsqlparser.expression.StringValue; + +public class FileOption { + private String key; + private Expression value; + private String stringValue; + + private FileOption(String key, Expression value) { + this.key = key; + this.value = value; + this.stringValue = null; + } + + public FileOption(String key, String value) { + this.key = key; + this.value = null; + this.stringValue = value; + } + + public FileOption(String key) { + this(key, (Expression) null); + } + + public FileOption(String key, StringValue value) { + this(key, (Expression) value); + } + + public FileOption(String key, LongValue 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; + } + + public void setValue(String value) { + this.stringValue = value; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(key); + if (value != null || stringValue != null) { + sql.append(" = "); + if (stringValue != null) { + sql.append(stringValue); + } else { + sql.append(value); + } + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/FileSourceDestination.java b/src/main/java/net/sf/jsqlparser/statement/FileSourceDestination.java new file mode 100644 index 000000000..d5a79ed8f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/FileSourceDestination.java @@ -0,0 +1,133 @@ +/*- + * #%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.statement.select.PlainSelect; + +import java.io.Serializable; +import java.util.List; +import java.util.Objects; + +public abstract class FileSourceDestination implements Serializable { + private SourceDestinationType type; + private List connectionFileDefinitions; + private Boolean local; + private Boolean secure; + private List csvColumns; + private List fbvColumns; + private List fileOptions; + private CertificateVerification certificateVerification; + + protected SourceDestinationType getType() { + return type; + } + + protected void setType(SourceDestinationType type) { + this.type = type; + } + + public List getConnectionFileDefinitions() { + return connectionFileDefinitions; + } + + public void setConnectionFileDefinitions( + List connectionFileDefinitions) { + this.connectionFileDefinitions = connectionFileDefinitions; + } + + 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 List getCSVColumns() { + return csvColumns; + } + + public void setCSVColumns(List csvColumns) { + this.csvColumns = csvColumns; + } + + public List getFBVColumns() { + return fbvColumns; + } + + public void setFBVColumns(List fbvColumns) { + this.fbvColumns = fbvColumns; + } + + public List getFileOptions() { + return fileOptions; + } + + public void setFileOptions(List fileOptions) { + this.fileOptions = fileOptions; + } + + public CertificateVerification getCertificateVerification() { + return certificateVerification; + } + + public void setCertificateVerification(CertificateVerification certificateVerification) { + this.certificateVerification = certificateVerification; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (local != null) { + if (local) { + sql.append("LOCAL "); + } + + if (Objects.requireNonNullElse(secure, false)) { + sql.append("SECURE "); + } + } + + sql.append(type); + if (connectionFileDefinitions != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, connectionFileDefinitions, false, false); + } + + if (csvColumns != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, csvColumns, true, true); + } else if (fbvColumns != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, fbvColumns, false, true); + } + + if (fileOptions != null) { + sql.append(" "); + PlainSelect.appendStringListTo(sql, fileOptions, false, false); + } + + if (certificateVerification != null) { + sql.append(" "); + sql.append(certificateVerification); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/FileType.java b/src/main/java/net/sf/jsqlparser/statement/FileType.java new file mode 100644 index 000000000..7ea1535f9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/FileType.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.statement; + +public class FileType implements SourceDestinationType { + private final Kind fileType; + + public FileType(String fileType) { + this.fileType = Kind.valueOf(fileType.toUpperCase()); + } + + private enum Kind { + CSV, FBV + } + + @Override + public String toString() { + return fileType.toString(); + } +} 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/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/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/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/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index e8be0a5cb..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; @@ -27,9 +28,12 @@ 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; @@ -323,4 +327,35 @@ default void visit(ParenthesedUpdate parenthesedUpdate) { 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); + } + } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index 0e6ab8698..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; @@ -27,12 +32,27 @@ 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; @@ -40,8 +60,48 @@ 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 { + 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<>(); + } + + 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 T visit(Comment comment, S context) { @@ -57,56 +117,137 @@ public T visit(Commit commit, S context) { @Override public T visit(Select select, S context) { - - return null; + return select.accept(selectVisitor, context); } @Override 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 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 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 null; + return update.getUpdate().accept(this, context); } @Override 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 T visit(Drop drop, S context) { + if (drop.getType().equalsIgnoreCase("table")) { + fromItemVisitor.visitFromItem(drop.getName(), context); + } + // @todo: handle schemas return null; } @Override public T visit(Truncate truncate, S context) { - - return null; + return truncate.getTable().accept(fromItemVisitor, context); } @Override @@ -122,13 +263,11 @@ public T visit(CreateSchema createSchema, S context) { @Override public T visit(CreateTable createTable, S context) { - - return null; + return createTable.getTable().accept(fromItemVisitor, context); } @Override public T visit(CreateView createView, S context) { - return null; } @@ -152,6 +291,18 @@ public T visit(Execute execute, S context) { return null; } + @Override + public T visit(LockStatement lock, S context) { + + return null; + } + + @Override + public T visit(CreatePolicy createPolicy, S context) { + + return null; + } + @Override public T visit(SetStatement set, S context) { @@ -166,7 +317,12 @@ public T visit(ResetStatement reset, S context) { @Override 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; } @@ -308,4 +464,14 @@ public T visit(UnsupportedStatement unsupportedStatement, S context) { public T visit(RefreshMaterializedViewStatement materializedView, S context) { return null; } + + @Override + 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/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/AlterExpression.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java index 372d9c790..336d66b44 100644 --- a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java @@ -856,6 +856,14 @@ public String toString() { } else { 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(" "); } 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 839685b1a..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, 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; + 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/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/schema/CreateSchema.java b/src/main/java/net/sf/jsqlparser/statement/create/schema/CreateSchema.java index ea4cdc64d..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 @@ -21,6 +21,7 @@ public class CreateSchema implements Statement { private String authorization; + private String catalogName = null; private String schemaName; private List schemaPath; private List statements = new ArrayList<>(); @@ -59,6 +60,15 @@ public void setAuthorization(String authorization) { this.authorization = authorization; } + public String getCatalogName() { + return catalogName; + } + + public CreateSchema setCatalogName(String catalogName) { + this.catalogName = catalogName; + return this; + } + /** * The name of the schema * @@ -119,7 +129,12 @@ public String toString() { 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/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/delete/Delete.java b/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java index 3072d9872..4e0f45ffe 100644 --- a/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java +++ b/src/main/java/net/sf/jsqlparser/statement/delete/Delete.java @@ -17,6 +17,7 @@ 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; @@ -29,6 +30,7 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static java.util.stream.Collectors.joining; @@ -38,7 +40,7 @@ public class Delete implements Statement { 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; @@ -157,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() { @@ -228,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(", "))); } @@ -273,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; @@ -364,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); @@ -405,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/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/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 c2f6faed0..6c53346d8 100644 --- a/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java +++ b/src/main/java/net/sf/jsqlparser/statement/insert/Insert.java @@ -9,6 +9,7 @@ */ package net.sf.jsqlparser.statement.insert; +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; @@ -52,8 +53,13 @@ public class Insert implements Statement { private OutputClause outputClause; private InsertConflictTarget conflictTarget; private InsertConflictAction conflictAction; + private InsertDuplicateAction duplicateAction; + private Alias rowAlias; public List getDuplicateUpdateSets() { + if (duplicateAction != null) { + return duplicateAction.getUpdateSets(); + } return duplicateUpdateSets; } @@ -62,7 +68,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; } @@ -157,7 +169,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() { @@ -329,11 +342,14 @@ public String toString() { if (setUpdateSets != null && !setUpdateSets.isEmpty()) { sql.append("SET "); sql = 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) { @@ -392,4 +408,20 @@ 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; + } } 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/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/MergeInsert.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java index be0d4bb2f..7e33db8b0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java +++ b/src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java @@ -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/MergeOperationVisitor.java b/src/main/java/net/sf/jsqlparser/statement/merge/MergeOperationVisitor.java index fef9682fe..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,6 +9,8 @@ */ package net.sf.jsqlparser.statement.merge; +import java.util.Collection; + public interface MergeOperationVisitor { T visit(MergeDelete mergeDelete, S context); @@ -16,4 +18,11 @@ public interface MergeOperationVisitor { 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 546b44604..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 { + private ExpressionVisitor expressionVisitor; + + public MergeOperationVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter<>(); + } + + public MergeOperationVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + } + + public MergeOperationVisitorAdapter(SelectVisitorAdapter selectVisitorAdapter) { + this.expressionVisitor = selectVisitorAdapter.getExpressionVisitor(); + } + @Override 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/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 a16320822..c38dd140b 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/ExceptOp.java @@ -13,38 +13,13 @@ public class ExceptOp extends SetOperation { - private boolean distinct; - private boolean all; - public ExceptOp() { - super(SetOperationType.EXCEPT); - } - - public boolean isAll() { - return all; - } - - public void setAll(boolean all) { - this.all = all; - } - - public boolean isDistinct() { - return distinct; - } - - public void setDistinct(boolean distinct) { - this.distinct = distinct; + this(""); } - @Override - public String toString() { - String allDistinct = ""; - if (isAll()) { - allDistinct = " ALL"; - } else if (isDistinct()) { - allDistinct = " DISTINCT"; - } - return super.toString() + allDistinct; + public ExceptOp(String modifier) { + super(SetOperationType.EXCEPT); + this.modifier = modifier; } public ExceptOp withDistinct(boolean distinct) { @@ -56,4 +31,9 @@ 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/ForMode.java b/src/main/java/net/sf/jsqlparser/statement/select/ForMode.java index 846faf9ed..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,7 +20,10 @@ public enum ForMode { NO_KEY_UPDATE("NO KEY UPDATE"), - KEY_SHARE("KEY SHARE"); + KEY_SHARE("KEY SHARE"), + + // 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"); private final String value; 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 0d97c4e4b..ed4432003 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java @@ -10,10 +10,39 @@ 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; +import java.util.Collection; +import java.util.List; + public interface FromItemVisitor { + default T visitFromItem(FromItem fromItem, S context) { + if (fromItem != null) { + fromItem.accept(this, context); + } + return null; + } + + default T visitTables(List
tables, S context) { + if (tables != null) { + for (Table table : tables) { + table.accept(this, context); + } + } + return null; + } + + default T visitJoins(Collection joins, S context) { + if (joins != null) { + for (Join join : joins) { + join.getFromItem().accept(this, context); + } + } + return null; + } + T visit(Table tableName, S context); default void visit(Table tableName) { @@ -68,5 +97,11 @@ 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); } 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 1ea920707..783b614f2 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java @@ -9,28 +9,96 @@ */ 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 { + 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 T visit(Table table, S context) { + 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 T visit(ParenthesedSelect select, S context) { - - return null; + return select.getPlainSelect().accept(selectVisitor, context); } @Override public T visit(LateralSubSelect lateralSubSelect, S context) { - - return null; + return lateralSubSelect.getPlainSelect().accept(selectVisitor, context); } @Override @@ -41,36 +109,43 @@ public T visit(TableFunction tableFunction, S context) { @Override public T visit(ParenthesedFromItem fromItem, S context) { - - return null; + return fromItem.getFromItem().accept(this, context); } @Override 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 null; + return plainSelect.accept(selectVisitor, context); } @Override 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 T visit(TableStatement tableStatement, S context) { + public T visit(Import imprt, S context) { return null; } - @Override public T visit(FromQuery fromQuery, S context) { - return null; + return fromQuery.accept(selectVisitor, 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 a708fe720..63b6b479d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/GroupByElement.java @@ -35,23 +35,23 @@ public T accept(GroupByVisitor groupByVisitor, S context) { return groupByVisitor.visit(this, context); } - public ExpressionList getGroupByExpressionList() { + public ExpressionList getGroupByExpressionList() { return groupByExpressions; } @Deprecated - public ExpressionList getGroupByExpressions() { + public ExpressionList getGroupByExpressions() { return groupByExpressions; } - public void setGroupByExpressions(ExpressionList 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.add(groupByExpression); } @@ -64,7 +64,7 @@ public void setGroupingSets(List> groupingSets) { this.groupingSets = groupingSets; } - public void addGroupingSet(ExpressionList list) { + public void addGroupingSet(ExpressionList list) { this.groupingSets.add(list); } @@ -79,12 +79,12 @@ public String toString() { } 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)); @@ -99,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; } @@ -127,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/IntersectOp.java b/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java index 02233a694..dd027d5ff 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/IntersectOp.java @@ -13,37 +13,13 @@ public class IntersectOp extends SetOperation { - private boolean distinct; - private boolean all; - public IntersectOp() { - super(SetOperationType.INTERSECT); - } - public boolean isAll() { - return all; - } - - public void setAll(boolean all) { - this.all = all; - } - - public boolean isDistinct() { - return distinct; + this(""); } - 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 IntersectOp(String modifier) { + super(SetOperationType.INTERSECT); + this.modifier = modifier; } public IntersectOp withDistinct(boolean distinct) { @@ -55,4 +31,9 @@ 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/Join.java b/src/main/java/net/sf/jsqlparser/statement/select/Join.java index 898804de0..191465e27 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Join.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Join.java @@ -35,8 +35,11 @@ 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 KSQLJoinWindow joinWindow; @@ -149,6 +152,24 @@ public Join withApply(boolean apply) { return this; } + /** + * 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; + } + /** * Whether is a "SEMI" join * @@ -167,6 +188,48 @@ public Join withSemi(boolean b) { return this; } + /** + * 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 an "ALL" join + * + * @return true if is an "ALL" join + */ + public boolean isAll() { + return all; + } + + 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 * @@ -277,10 +340,12 @@ public Join withCross(boolean cross) { /** * Returns the right item of the join */ + @Deprecated public FromItem getRightItem() { return fromItem; } + @Deprecated public void setRightItem(FromItem item) { fromItem = item; } @@ -400,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()) { @@ -427,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 : ""); 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 9257daa6d..ec5923a3f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Limit.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Limit.java @@ -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 e33ce1387..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,37 +12,13 @@ import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; public class MinusOp extends SetOperation { - private boolean distinct; - private boolean all; - public MinusOp() { - super(SetOperationType.MINUS); - } - public boolean isAll() { - return all; - } - - public void setAll(boolean all) { - this.all = all; - } - - public boolean isDistinct() { - return distinct; + this(""); } - 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 MinusOp(String modifier) { + super(SetOperationType.MINUS); + this.modifier = modifier; } public MinusOp withDistinct(boolean distinct) { @@ -54,4 +30,9 @@ 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/PivotVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/PivotVisitorAdapter.java index 6e7fce93f..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,8 +9,20 @@ */ 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 { + private final ExpressionVisitor expressionVisitor; + + public PivotVisitorAdapter() { + this.expressionVisitor = new ExpressionVisitorAdapter(); + } + + public PivotVisitorAdapter(ExpressionVisitor expressionVisitor) { + this.expressionVisitor = expressionVisitor; + } @Override public T visit(Pivot pivot, S context) { 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 8698e3152..87bae64eb 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/PlainSelect.java @@ -37,6 +37,7 @@ public class PlainSelect extends Select { private FromItem fromItem; private List lateralViews; private List joins; + private Expression preWhere; private Expression where; private GroupByElement groupBy; private Expression having; @@ -160,6 +161,14 @@ public void setWhere(Expression where) { this.where = where; } + public Expression getPreWhere() { + return preWhere; + } + + public void setPreWhere(Expression preWhere) { + this.preWhere = preWhere; + } + public PlainSelect withFromItem(FromItem item) { this.setFromItem(item); return this; @@ -569,6 +578,9 @@ 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); } @@ -597,6 +609,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); } @@ -669,6 +684,11 @@ public PlainSelect withWhere(Expression where) { return this; } + public PlainSelect withPreWhere(Expression preWhere) { + this.setPreWhere(preWhere); + return this; + } + public PlainSelect withOptimizeFor(OptimizeFor optimizeFor) { this.setOptimizeFor(optimizeFor); return this; @@ -767,6 +787,10 @@ 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()); } 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 1fc7a2322..a72ff0b70 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectItemVisitorAdapter.java @@ -10,11 +10,23 @@ 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 { + 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 null; + 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 94357bcd9..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,9 +9,24 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.statement.OutputClause; import net.sf.jsqlparser.statement.piped.FromQuery; +import java.util.List; + public interface SelectVisitor { + default T visitWithItems(List> withItemsList, S context) { + if (withItemsList != null) { + for (WithItem withItem : withItemsList) { + withItem.accept(this, context); + } + } + return null; + } + + default T visitOutputClause(OutputClause outputClause, S context) { + return null; + } T visit(ParenthesedSelect parenthesedSelect, S context); 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 462160e9f..f968f9015 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java @@ -9,18 +9,193 @@ */ 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 { + private final ExpressionVisitor expressionVisitor; + private final PivotVisitor pivotVisitor; + private final SelectItemVisitor selectItemVisitor; + private final FromItemVisitor fromItemVisitor; + + 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 T visit(ParenthesedSelect parenthesedSelect, S context) { - return parenthesedSelect.getSelect().accept(this, context); + 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 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 + @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); + } + + 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; } 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/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 ee58a9f4a..6cc0e3851 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Values.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Values.java @@ -35,7 +35,7 @@ public Values(ExpressionList expressions, Alias alias) { this.alias = alias; } - public ExpressionList getExpressions() { + public ExpressionList getExpressions() { return expressions; } 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/WithItem.java b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java index 2f464cb65..8789a6875 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/WithItem.java @@ -27,8 +27,9 @@ public class WithItem implements Serializable { private K statement; private Alias alias; private List> withItemList; + private WithFunctionDeclaration withFunctionDeclaration; private boolean recursive = false; - + private boolean usingNot = false; private boolean materialized = false; public WithItem(K statement, Alias alias) { @@ -90,6 +91,24 @@ 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 ...") * @@ -103,24 +122,46 @@ public void setWithItemList(List> withItemList) { this.withItemList = withItemList; } + public WithFunctionDeclaration getWithFunctionDeclaration() { + return withFunctionDeclaration; + } + + public void setWithFunctionDeclaration(WithFunctionDeclaration withFunctionDeclaration) { + this.withFunctionDeclaration = withFunctionDeclaration; + } + + public WithItem withWithFunctionDeclaration( + WithFunctionDeclaration withFunctionDeclaration) { + this.setWithFunctionDeclaration(withFunctionDeclaration); + return this; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); - 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 ? "," : ""); + 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(")"); + builder.append(" AS "); + if (materialized) { + builder.append(usingNot + ? "NOT MATERIALIZED " + : "MATERIALIZED "); + } + builder.append(statement); } - builder.append(" AS "); - builder.append(materialized ? "MATERIALIZED " : ""); - builder.append(statement); return builder.toString(); } @@ -130,7 +171,10 @@ public T accept(SelectVisitor selectVisitor, S context) { } public T accept(StatementVisitor statementVisitor, S context) { - return statement.accept(statementVisitor, context); + if (statement != null) { + return statement.accept(statementVisitor, context); + } + return null; } public WithItem withWithItemList(List> withItemList) { @@ -144,6 +188,13 @@ public WithItem withRecursive(boolean recursive, boolean 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) { List> collection = Optional.ofNullable(getWithItemList()).orElseGet(ArrayList::new); 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 6bb0376b9..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,11 +49,20 @@ 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; } @@ -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/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index ea9f1645b..e19524076 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -10,64 +10,7 @@ package net.sf.jsqlparser.util; 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.BooleanValue; -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.ConnectByPriorOperator; -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.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.JsonFunctionExpression; -import net.sf.jsqlparser.expression.KeepExpression; -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; -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; @@ -130,6 +73,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; @@ -146,6 +90,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; @@ -156,14 +101,18 @@ 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.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; @@ -315,8 +264,12 @@ public Set getTables(Expression expr) { @Override public Void visit(WithItem withItem, S context) { - otherItemNames.add(withItem.getAlias().getName()); - withItem.getSelect().accept((SelectVisitor) this, context); + if (withItem.getAlias() != null) { + otherItemNames.add(withItem.getAlias().getName()); + } + if (withItem.getSelect() != null) { + withItem.getSelect().accept((SelectVisitor) this, context); + } return null; } @@ -364,6 +317,9 @@ public Void visit(PlainSelect plainSelect, S context) { } visitJoins(plainSelect.getJoins(), context); + if (plainSelect.getPreWhere() != null) { + plainSelect.getPreWhere().accept(this, context); + } if (plainSelect.getWhere() != null) { plainSelect.getWhere().accept(this, context); } @@ -877,6 +833,11 @@ public Void visit(FromQuery fromQuery, S context) { return null; } + @Override + public Void visit(DateUnitExpression dateUnitExpression, S context) { + return null; + } + /** * Initializes table names collector. Important is the usage of Column instances to find table * names. This is only allowed for expression parsing, where a better place for tablenames could @@ -1007,9 +968,9 @@ public Void visit(MySQLGroupConcat groupConcat, S context) { public Void visit(Delete delete, S context) { visit(delete.getTable(), context); - if (delete.getUsingList() != null) { - for (Table using : delete.getUsingList()) { - visit(using, context); + if (delete.getUsingFromItemList() != null) { + for (FromItem usingFromItem : delete.getUsingFromItemList()) { + usingFromItem.accept(this, context); } } @@ -1031,6 +992,11 @@ 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) { @@ -1416,7 +1382,6 @@ private void visitJoins(List joins, S context) { } for (Join join : joins) { join.getFromItem().accept(this, context); - join.getRightItem().accept(this, context); for (Expression expression : join.getOnExpressions()) { expression.accept(this, context); } @@ -1747,9 +1712,52 @@ public Void visit(JsonAggregateFunction expression, S context) { @Override 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, 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(JsonTableFunction expression, S context) { + for (Expression jsonExpression : expression.getAllExpressions()) { + if (jsonExpression != null) { + jsonExpression.accept(this, context); + } + } return null; } @@ -1785,6 +1793,13 @@ public Void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, 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()) { @@ -1840,4 +1855,60 @@ public Void visit(GeometryDistance geometryDistance, S context) { 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/deparser/DeleteDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java index 23b5eb32b..2ab59ea14 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java @@ -78,9 +78,9 @@ public void deParse(Delete delete) { } builder.append(" ").append(delete.getTable().toString()); - if (delete.getUsingList() != null && !delete.getUsingList().isEmpty()) { + if (delete.getUsingFromItemList() != null && !delete.getUsingFromItemList().isEmpty()) { builder.append(" USING").append( - delete.getUsingList().stream().map(Table::toString) + delete.getUsingFromItemList().stream().map(Object::toString) .collect(joining(", ", " ", ""))); } if (delete.getJoins() != null) { 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 c93960539..d8fe4054f 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -23,6 +23,7 @@ import net.sf.jsqlparser.expression.ConnectByRootOperator; import net.sf.jsqlparser.expression.ConnectByPriorOperator; 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; @@ -38,6 +39,7 @@ 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.LambdaExpression; import net.sf.jsqlparser.expression.LongValue; @@ -51,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; @@ -182,6 +185,13 @@ public StringBuilder visit(Between between, S context) { } builder.append(" BETWEEN "); + + if (between.isUsingSymmetric()) { + builder.append("SYMMETRIC "); + } else if (between.isUsingAsymmetric()) { + builder.append("ASYMMETRIC "); + } + between.getBetweenExpressionStart().accept(this, context); builder.append(" AND "); between.getBetweenExpressionEnd().accept(this, context); @@ -635,7 +645,8 @@ public StringBuilder visit(StringValue stringValue, S context) { if (stringValue.getPrefix() != null) { builder.append(stringValue.getPrefix()); } - builder.append("'").append(stringValue.getValue()).append("'"); + builder.append(stringValue.getQuoteStr()).append(stringValue.getValue()) + .append(stringValue.getQuoteStr()); return builder; } @@ -685,14 +696,16 @@ public StringBuilder visit(Select select, S context) { @Override public StringBuilder visit(TranscodingFunction transcodingFunction, S context) { if (transcodingFunction.isTranscodeStyle()) { - builder.append("CONVERT( "); + builder.append(transcodingFunction.getKeyword()); + builder.append("( "); transcodingFunction.getExpression().accept(this, context); builder.append(" USING ") .append(transcodingFunction.getTranscodingName()) .append(" )"); } else { builder - .append("CONVERT( ") + .append(transcodingFunction.getKeyword()) + .append("( ") .append(transcodingFunction.getColDataType()) .append(", "); transcodingFunction.getExpression().accept(this, context); @@ -820,6 +833,9 @@ public StringBuilder visit(Column tableColumn, S context) { } builder.append(tableColumn.getColumnName()); + if (tableColumn.getOldOracleJoinSyntax() != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN) { + builder.append("(+)"); + } if (tableColumn.getArrayConstructor() != null) { tableColumn.getArrayConstructor().accept(this, context); @@ -1618,6 +1634,12 @@ public StringBuilder visit(JsonFunction expression, S context) { return builder; } + @Override + public StringBuilder visit(JsonTableFunction expression, S context) { + builder.append(expression); + return builder; + } + @Override public StringBuilder visit(ConnectByRootOperator connectByRootOperator, S context) { builder.append("CONNECT_BY_ROOT "); @@ -1819,4 +1841,18 @@ public StringBuilder visit(CosineSimilarity cosineSimilarity, S context) { 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/InsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java index a555f2ba7..41fd3fb22 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java @@ -12,6 +12,7 @@ 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.select.Select; import net.sf.jsqlparser.statement.select.SelectVisitor; @@ -29,8 +30,7 @@ public InsertDeParser() { } public InsertDeParser(ExpressionVisitor expressionVisitor, - SelectVisitor selectVisitor, - StringBuilder buffer) { + SelectVisitor selectVisitor, StringBuilder buffer) { super(buffer); this.expressionVisitor = expressionVisitor; this.selectVisitor = selectVisitor; @@ -113,11 +113,19 @@ public void deParse(Insert insert) { if (insert.getSetUpdateSets() != null) { builder.append(" SET "); deparseUpdateSets(insert.getSetUpdateSets(), builder, expressionVisitor); + if (insert.getRowAlias() != null) { + builder.append(" ").append(insert.getRowAlias()); + } } - if (insert.getDuplicateUpdateSets() != null) { + if (insert.getDuplicateAction() != null) { builder.append(" ON DUPLICATE KEY UPDATE "); - deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor); + 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 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 c14c9b9ab..bb6335d90 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -18,6 +18,7 @@ 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; @@ -286,6 +287,7 @@ public StringBuilder visit(PlainSelect plainSelect, S context) { builder.append(plainSelect.getKsqlWindow().toString()); } + deparsePreWhereClause(plainSelect); deparseWhereClause(plainSelect); if (plainSelect.getOracleHierarchical() != null) { @@ -393,10 +395,19 @@ protected void deparseWhereClause(PlainSelect plainSelect) { } } + 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 "); } @@ -446,25 +457,31 @@ public StringBuilder visit(SelectItem selectItem, S context) { @Override - public StringBuilder visit(Table tableName, S context) { - builder.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) { builder.append(alias); } - Pivot pivot = tableName.getPivot(); + if (table.getTimeTravelStrAfterAlias() != null) { + builder.append(" ").append(table.getTimeTravelStrAfterAlias()); + } + Pivot pivot = table.getPivot(); if (pivot != null) { pivot.accept(this, context); } - UnPivot unpivot = tableName.getUnPivot(); + UnPivot unpivot = table.getUnPivot(); if (unpivot != null) { unpivot.accept(this, context); } - MySQLIndexHint indexHint = tableName.getIndexHint(); + MySQLIndexHint indexHint = table.getIndexHint(); if (indexHint != null) { builder.append(indexHint); } - SQLServerHints sqlServerHints = tableName.getSqlServerHints(); + SQLServerHints sqlServerHints = table.getSqlServerHints(); if (sqlServerHints != null) { builder.append(sqlServerHints); } @@ -580,6 +597,12 @@ public void deparseJoin(Join join) { builder.append(" NATURAL"); } + if (join.isAny()) { + builder.append(" ANY"); + } else if (join.isAll()) { + builder.append(" ALL"); + } + if (join.isRight()) { builder.append(" RIGHT"); } else if (join.isFull()) { @@ -607,6 +630,9 @@ public void deparseJoin(Join join) { builder.append(" ").append(join.getJoinHint()); } builder.append(" JOIN "); + if (join.isFetch()) { + builder.append("FETCH "); + } } } @@ -708,21 +734,27 @@ public StringBuilder visit(SetOperationList list, S context) { @Override public StringBuilder visit(WithItem withItem, S context) { - 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("MATERIALIZED "); + 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()); + } else { + builder.append(withItem.getWithFunctionDeclaration().toString()); } - StatementDeParser statementDeParser = - new StatementDeParser((ExpressionDeParser) expressionVisitor, this, builder); - statementDeParser.deParse(withItem.getParenthesedStatement()); return builder; } @@ -794,6 +826,12 @@ public StringBuilder visit(Values values, S context) { return builder; } + @Override + public StringBuilder visit(Import imprt, S context) { + builder.append(imprt.toString()); + return builder; + } + @Override public void visit(Values values) { SelectVisitor.super.visit(values); @@ -889,6 +927,10 @@ public void visit(ParenthesedFromItem fromItem) { visit(fromItem, null); } + public void visit(Import imprt) { + visit(imprt, null); + } + private void deparseOptimizeFor(OptimizeFor optimizeFor) { builder.append(" OPTIMIZE FOR "); 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 b078b8716..751c4bf64 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java @@ -25,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; @@ -41,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; @@ -51,9 +53,12 @@ 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; @@ -201,6 +206,11 @@ public StringBuilder visit(ParenthesedDelete delete, S context) { 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()) { @@ -493,4 +503,28 @@ public ExpressionDeParser getExpressionDeParser() { public SelectDeParser getSelectDeParser() { return selectDeParser; } + + @Override + public StringBuilder visit(Import imprt, S context) { + builder.append(imprt.toString()); + return builder; + } + + @Override + public StringBuilder visit(Export export, S context) { + builder.append(export.toString()); + return builder; + } + + @Override + public StringBuilder visit(LockStatement lock, S context) { + builder.append(lock.toString()); + return builder; + } + + @Override + public StringBuilder visit(CreatePolicy createPolicy, S context) { + builder.append(createPolicy.toString()); + 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 0835284a4..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; @@ -78,9 +79,14 @@ public void deParse(Upsert upsert) { upsert.getSelect().accept((SelectVisitor) selectVisitor, null); } - if (upsert.getDuplicateUpdateSets() != null) { + if (upsert.getDuplicateAction() != null) { builder.append(" ON DUPLICATE KEY UPDATE "); - deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor); + if (ConflictActionType.DO_UPDATE + .equals(upsert.getDuplicateAction().getConflictActionType())) { + deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor); + } else { + upsert.getDuplicateAction().appendTo(builder); + } } } } 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 a4b27d765..48448ec9b 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 @@ -22,6 +22,7 @@ import net.sf.jsqlparser.expression.ConnectByRootOperator; import net.sf.jsqlparser.expression.ConnectByPriorOperator; 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; @@ -37,6 +38,7 @@ 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.LambdaExpression; import net.sf.jsqlparser.expression.LongValue; @@ -50,6 +52,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; @@ -525,6 +528,10 @@ public Void visit(ParenthesedSelect selectBody, S context) { @Override public Void visit(Column tableColumn, S context) { + if (tableColumn + .getOldOracleJoinSyntax() != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN) { + validateFeature(Feature.oracleOldJoinSyntax); + } validateName(NamedObject.column, tableColumn.getFullyQualifiedName()); return null; } @@ -1033,6 +1040,14 @@ public Void visit(JsonFunction expression, S context) { return null; } + @Override + public Void visit(JsonTableFunction expression, S context) { + for (Expression jsonExpression : expression.getAllExpressions()) { + validateOptionalExpression(jsonExpression, this); + } + return null; + } + @Override public Void visit(ConnectByRootOperator connectByRootOperator, S context) { connectByRootOperator.getColumn().accept(this, context); @@ -1051,6 +1066,13 @@ public Void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, return null; } + @Override + public Void visit(PostgresNamedFunctionParameter postgresNamedFunctionParameter, + S context) { + postgresNamedFunctionParameter.getExpression().accept(this, context); + return null; + } + @Override public Void visit(AllColumns allColumns, S context) { return null; @@ -1314,4 +1336,9 @@ 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/SelectValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java index 49367ddf0..36741ecd6 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 @@ -16,6 +16,7 @@ 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; @@ -118,6 +119,7 @@ public Void visit(PlainSelect plainSelect, S context) { // validateOptionalList(plainSelect.getSelectItems(), () -> this, SelectItem::accept, // context); + validateOptionalExpression(plainSelect.getPreWhere()); validateOptionalExpression(plainSelect.getWhere()); validateOptionalExpression(plainSelect.getOracleHierarchical()); @@ -360,6 +362,12 @@ public Void visit(Values values, S context) { 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, null); @@ -426,4 +434,8 @@ 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/StatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java index d8ce6078b..9e073a227 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java @@ -21,6 +21,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; @@ -38,6 +39,7 @@ import net.sf.jsqlparser.statement.comment.Comment; import net.sf.jsqlparser.statement.create.function.CreateFunction; import net.sf.jsqlparser.statement.create.index.CreateIndex; +import net.sf.jsqlparser.statement.create.policy.CreatePolicy; import net.sf.jsqlparser.statement.create.procedure.CreateProcedure; import net.sf.jsqlparser.statement.create.schema.CreateSchema; import net.sf.jsqlparser.statement.create.sequence.CreateSequence; @@ -49,9 +51,12 @@ 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; @@ -70,7 +75,6 @@ */ public class StatementValidator extends AbstractValidator implements StatementVisitor { - @Override public Void visit(CreateIndex createIndex, S context) { getValidator(CreateIndexValidator.class).validate(createIndex); @@ -112,6 +116,11 @@ 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) { @@ -380,6 +389,24 @@ 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); } @@ -556,4 +583,21 @@ 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/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 9ea68e0e4..800bc0b61 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -15,10 +15,11 @@ options { DEBUG_LOOKAHEAD = false; DEBUG_TOKEN_MANAGER = false; CACHE_TOKENS = false; + SINGLE_TREE_FILE = false; // 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,7 +27,7 @@ options { VISITOR = true; GRAMMAR_ENCODING = "UTF-8"; KEEP_LINE_COLUMN = true; - // USER_CHAR_STREAM = false; +// USER_CHAR_STREAM = false; } PARSER_BEGIN(CCJSqlParser) @@ -49,6 +50,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.*; @@ -68,6 +70,9 @@ 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; @@ -97,7 +102,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); } @@ -166,6 +171,46 @@ PARSER_END(CCJSqlParser) TOKEN_MGR_DECLS : { public FeatureConfiguration configuration = new FeatureConfiguration(); + // 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(); @@ -189,7 +234,9 @@ SKIP: TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ { - + +| +| | | | @@ -198,29 +245,38 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | +| | | | +| | | | | | +| | | | | | +| | +| | | | | | +| | +| | +| | | | @@ -232,6 +288,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | /* H2 casewhen function */ | +| | | | @@ -239,6 +296,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -246,6 +304,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -256,7 +315,9 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | +| | | | @@ -266,20 +327,25 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | +| +| | | | | | | +| | | | | | +| | | | @@ -287,16 +353,21 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | | | +| | +| | | | | /* Salesforce SOQL */ +| +| | | | @@ -305,8 +376,11 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| +| | | +| | | | @@ -333,6 +407,8 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| +| | | | @@ -342,9 +418,12 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | /* Salesforce SOQL */ | +| | | +| | +| | | | @@ -357,6 +436,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -367,12 +447,14 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | | | | +| | | | @@ -383,6 +465,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -398,10 +481,13 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | +| | | +| | | | @@ -411,6 +497,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -426,7 +513,9 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | "> +| | | @@ -437,6 +526,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -450,10 +540,12 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | | +| | | | @@ -468,6 +560,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -486,6 +579,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -493,11 +587,15 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | +| | | | +| | +| | | | @@ -517,14 +615,19 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | | | | +| | | +| +| +| | | | @@ -549,12 +652,14 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | | | | +| | | | @@ -574,6 +679,8 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| +| | | | @@ -600,6 +707,8 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | +| +| | | | @@ -614,6 +723,7 @@ TOKEN : /* Statement Separators */ TOKEN : /* Operators */ { " ()* "="> +| "> | )* "="> | )* ">"> | )* "="> @@ -640,7 +750,7 @@ TOKEN : /* Data Types */ | <#TYPE_BIT: "BISTRING"> | <#TYPE_BLOB: "BLOB" | "BYTEA" | | "VARBINARY" | > - | <#TYPE_BOOLEAN: "BOOLEAN" | "BOOL" > + | <#TYPE_BOOLEAN: | "BOOL" > | <#TYPE_ENUM: "ENUM" > | <#TYPE_MAP: "MAP" > | <#TYPE_DECIMAL: "DECIMAL" | "NUMBER" | "NUMERIC" > @@ -692,6 +802,7 @@ TOKEN: | | [ "$" , "#", "_" ] // Not SQL:2016 compliant! > | <#PART_LETTER: | | [ "$" , "#", "_" , "@" ] > +| ()? > // Unicode characters and categories are defined here: https://www.unicode.org/Public/UNIDATA/UnicodeData.txt // SQL:2016 states: @@ -723,7 +834,7 @@ TOKEN: | < S_CHAR_LITERAL: ( (["U","E","N","R","B"]|"RB"|"_utf8")? ( - ("'" ( | | ~["'", "\\"] )* "'") | ("'" ("''" | ~["'"])* "'") + ("'" ( | | ~["'", "\\"] )* "'") | ("'" ("''" | ~["'"])* "'" | "$$" (~["$"])* "$$") // Alternative Oracle Escape Modes | ("q'{" (~[])* "}'") | ("q'(" (~[])* ")'") @@ -738,33 +849,35 @@ 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 + * - , , , , , : Specific keywords treated as identifiers * * @return Token representing the identifier or keyword used as identifier */ @@ -796,6 +909,7 @@ Token KeywordOrIdentifier(): | tk = | tk = | tk = + | tk = ) { return tk; } } @@ -925,6 +1039,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; } } @@ -1090,7 +1210,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(); @@ -1101,857 +1221,1832 @@ 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(): -{ - Token tk; - Select select; - Table table; - List options; - ExplainStatement es; -} -{ - ( tk= | tk = ) +DBMSTableDestinationOption DBMSTableDestinationOption(): { + DBMSTableDestinationOption dbmsTableDestinationOption; + + Token token; + Token token2; + Token token3; +} { ( - LOOKAHEAD(3)( - options= ExplainStatementOptions() - select = Select( ) - { - es = new ExplainStatement(tk.image, select, options); - } - ) - | ( - table=Table( ) { es = new ExplainStatement(tk.image, table); } - ) + token = + | token = + ) { dbmsTableDestinationOption = new DBMSTableDestinationOption(token.image); } + | token = token2 = token3 = { dbmsTableDestinationOption = new DBMSTableDestinationOption(token.image + " " + token2.image, new StringValue(token3.image)); } ) + { - return es; + return dbmsTableDestinationOption; } } -/** - * 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; - } +List DBMSTableDestinationOptionList(): { + List dbmsTableDestinationOptions = new ArrayList(); + DBMSTableDestinationOption dbmsTableDestinationOption; +} { + ( LOOKAHEAD(2) dbmsTableDestinationOption = DBMSTableDestinationOption() { dbmsTableDestinationOptions.add(dbmsTableDestinationOption); } )+ + { + return dbmsTableDestinationOptions; + } } -/** - * 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; - } -} +DBMSSource DBMSSource() #DBMSSource: { + DBMSSource dbmsSource = new DBMSSource(); + DBMSType dbmsType; + ConnectionDefinition connectionDefinition; + Table table; + ExpressionList columns; + List statements; +} { + dbmsType = DBMSType() { dbmsSource.setSourceType(dbmsType); } -/** - * 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); - } - ) - | - ( - { option = new ExplainStatement.Option(ExplainStatement.OptionType.PLAN); } - [ { option = new ExplainStatement.Option(ExplainStatement.OptionType.PLAN_FOR); } ] + connectionDefinition = ConnectionDefinition() { dbmsSource.setConnectionDefinition(connectionDefinition); } - value=ExplainFormatOption() - { - option.setValue(value); - options.add(option); - } + ( + 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; -} -{ - [ LOOKAHEAD(2) { hasSchemaKeyword = true; } ] name = RelObjectNameExt() +DBMSType DBMSType(): { + DBMSType dbmsType; + Token tk1; + Token tk2 = null; +} { + ( + tk1= + | tk1= + | tk1= + [ "=" tk2=] + ) { dbmsType = new DBMSType(tk1.image, tk2 == null ? null : tk2.image); } { - return new UseStatement(name, hasSchemaKeyword); + return dbmsType; } } -Statement Show(): -{ - Statement statement; - List captureRest; -} -{ - +FileType FileType(): { + FileType fileType; + Token tk; +} { ( - 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); - } - } - ) + tk= + | tk= + ) { fileType = new FileType(tk.image); } { - return statement; + return fileType; } } -ShowColumnsStatement ShowColumns(): { - String tableName; -} -{ - tableName = RelObjectNameExt() +StringValue ImportExportStatement() #ImportExportStatement: { + StringValue statement; +} { + token = { - return new ShowColumnsStatement(tableName); + statement = new StringValue(token.image); + linkAST(statement, jjtThis); + return statement; } } -ShowIndexStatement ShowIndex(): { - String tableName; +List ImportExportStatementsList(): { + List statements = new ArrayList(); + StringValue statement; +} { + ( statement = ImportExportStatement() { statements.add(statement); } )+ + + { + return statements; + } } -{ - tableName = RelObjectNameExt() + +StringValue File() #File: { + Token token; +} { + token = { - return new ShowIndexStatement(tableName); + StringValue file = new StringValue(token.image); + linkAST(file, jjtThis); + return file; } } -Statement RefreshMaterializedView(): { - Table view = null; - boolean concurrently = false; - RefreshMode refreshMode = null; - List captureRest; +List FileList(): { + List files = new ArrayList(); + StringValue file; +} { + ( file = File() { files.add(file); } )+ + { + return files; + } } -{ - - [ 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); } ] - - [ - LOOKAHEAD(2) ( - { selectionMode = ShowTablesStatement.SelectionMode.FROM; } - | - { selectionMode = ShowTablesStatement.SelectionMode.IN; } + +CSVColumn CSVDestinationColumn(): { + 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)); }] + [ + + "=" + ( + 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 UpdateWithWithItems( List> withItems ): -{ - Update update; -} -{ - update = Update() { update.setWithItemsList( withItems ); - return update; -} +List CSVSourceColumnList(): { + List csvColumns = new ArrayList(); + CSVColumn csvColumn; +} { + csvColumn = CSVSourceColumn() { csvColumns.add(csvColumn); } + ( "," csvColumn = CSVSourceColumn() { csvColumns.add(csvColumn); } )* + { + return csvColumns; + } } -Update Update(): -{ - 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 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); } ] - - [ LOOKAHEAD(2) - fromItem=FromItem() - [ LOOKAHEAD(2) joins=JoinsList() ] ] - - [ where=WhereClause() { update.setWhere(where); } ] - [ preferringClause=PreferringClause() { update.setPreferringClause(preferringClause); } ] - - [ orderByElements = OrderByElements() { update.setOrderByElements(orderByElements); } ] - [ limit = PlainLimit() { update.setLimit(limit); } ] - [ returningClause = ReturningClause() { update.setReturningClause(returningClause); } ] +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 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; +FBVColumn FBVSourceColumn(): { + FBVColumn fbvColumn; - ExpressionList columns; - ExpressionListvalues; -} -{ + Token token; + Token token2; +} { ( - ( - 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= ) "=" 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); } ( - LOOKAHEAD(2) ( - "," - 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); } - ) - ) - ) + { precedesComma = false; } + ["," { precedesComma = true; }] + fbvColumn = FBVSourceColumn() { fbvColumn.setPrecedesComma(precedesComma); fbvColumns.add(fbvColumn); } )* + { + return fbvColumns; + } +} + +FileOption FileDestinationOption(): { + FileOption fileOption; + Token token; + Token token2; + Token token3; +} { + ( + ( 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 updateSets; + return fileOption; } } -List Partitions(): -{ - List partitions = new ArrayList(); - Column tableColumn; - Expression valueExpression = null; +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; +} { ( + ( 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) ( - tableColumn=Column() [ "=" valueExpression=Expression() ] - { partitions.add( new Partition (tableColumn, valueExpression)); } + 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)); } ) - - ( - LOOKAHEAD(2) ( - "," - tableColumn=Column() [ "=" valueExpression=Expression() ] - { partitions.add( new Partition (tableColumn, valueExpression)); } - ) - )* - { - return partitions; + return fileOption; } } -Insert InsertWithWithItems( List> withItems ): -{ - Insert insert; -} -{ - insert = Insert() { insert.setWithItemsList( withItems ); - return insert; -} +List FileSourceOptionList(): { + List fileOptions = new ArrayList(); + FileOption fileOption; +} { + ( LOOKAHEAD(2) fileOption = FileSourceOption() { fileOptions.add(fileOption); } )+ + { + return fileOptions; + } } -Insert Insert(): -{ - 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; - - List updateSets; - List duplicateUpdateSets; - - String name = null; - boolean useAs = false; - OutputClause outputClause = null; +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); }] - InsertConflictTarget conflictTarget = null; - InsertConflictAction conflictAction = null; -} -{ - { insert.setOracleHint(getOracleHint()); } + fileType = FileType() { fileDestination.setDestinationType(fileType); } + files = FileList() + { + connectionFileDefinitions = new ArrayList(); + connectionFileDefinitions.add(new ConnectionFileDefinition(files)); + } + ) + { fileDestination.setConnectionFileDefinitions(connectionFileDefinitions); } - [ - LOOKAHEAD(2) (tk = | tk = | tk = ) - { - if (tk!=null) - modifierPriority = InsertModifierPriority.from(tk.image); - } - ] - [ LOOKAHEAD(2) { modifierIgnore = true; }] - [ LOOKAHEAD(2) ( - { insert.setOverwrite(true); insert.setTableKeyword(true); } - | [ LOOKAHEAD(2) { insert.setTableKeyword(true); }] + [ + LOOKAHEAD(2) + "(" + ( + csvColumns = CSVDestinationColumnList() { fileDestination.setCSVColumns(csvColumns); } + | fbvColumns = FBVDestinationColumnList() { fileDestination.setFBVColumns(fbvColumns); } ) - ] table=Table() - [ LOOKAHEAD(2) "(" partitions=Partitions() ")" ] + ")" + ] - [ LOOKAHEAD(2) [ { useAs = true; } ] name=RelObjectNameWithoutValue() { table.setAlias(new Alias(name,useAs)); }] + [ LOOKAHEAD(2) fileOptions = FileDestinationOptionList() { fileDestination.setFileOptions(fileOptions); } ] - [ LOOKAHEAD(2) "(" columns=ColumnList() ")" ] + [ LOOKAHEAD(2) certificateVerification = CertificateVerification() { fileDestination.setCertificateVerification(certificateVerification); } ] - [ LOOKAHEAD(2) { insert.setOverriding(true); } ] + { + 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); }] - ( - { insert.setOnlyDefaultValues(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); - } - if (!partitions.isEmpty()) { - insert.setPartitions(partitions); + return certificateVerification; + } +} + +ScriptSourceDestination ScriptSourceDestination(): { + ScriptSourceDestination scriptSourceDestination = new ScriptSourceDestination(); + ConnectionDefinition connectionDefinition; + Table script; + String property; + StringValue value; + + 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); } - return insert.withWithItemsList(with) - .withSelect(select) - .withTable(table) - .withModifierPriority(modifierPriority) - .withModifierIgnore(modifierIgnore); + + + ( + LOOKAHEAD(2) + property = RelObjectNameWithoutValue() "=" token = { value = new StringValue(token.image); } + { + properties.add(property); + values.add(value); + } + )+ + ] + + { + return scriptSourceDestination; } } -InsertConflictTarget InsertConflictTarget(): -{ - String indexColumnName; - ArrayList indexColumnNames = new ArrayList(); - Expression indexExpression = null; - Expression whereExpression = null; - String constraintName = null ; +UserIdentification UserIdentification(): { + UserIdentification userIdentification = new UserIdentification(); + Token token; +} { + + token= { userIdentification.setUser(new StringValue(token.image)); } + + token= { userIdentification.setPassword(new StringValue(token.image)); } + + { + return userIdentification; + } } -{ - ( - ( - "(" - indexColumnName = RelObjectNameExt2() { indexColumnNames.add(indexColumnName); } - ( "," indexColumnName = RelObjectNameExt2() { indexColumnNames.add(indexColumnName); } )* -// | -// ( -// "(" indexExpression = Expression() ")" -// ) - ")" - [ whereExpression = WhereClause() ] - ) - | - ( - constraintName = RelObjectNameExt2() - ) +ConnectionDefinition ConnectionDefinition(): { + ConnectionDefinition connectionDefinition = new ConnectionDefinition(); + String connectionObjectName; + UserIdentification userIdentification; + CertificateVerification certificateVerification; + + Token token; +} { + + ( + connectionObjectName = RelObjectNameWithoutValue() { 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; + } +} + +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 = RelObjectNameWithoutValue() { connectionDefinition.setConnectionObjectName(connectionObjectName); } + | token = { connectionDefinition.setConnectionDefinition(new StringValue(token.image)); } + ) + + [ userIdentification = UserIdentification() { connectionDefinition.setUserIdentification(userIdentification); } ] + + { + return connectionDefinition; + } +} + +ConnectionDefinition ConnectionOrCloudConnectionDefinition(): { + ConnectionDefinition connectionDefinition; +} { + ( + LOOKAHEAD(2) connectionDefinition = CloudConnectionDefinition() + | connectionDefinition = ConnectionDefinition() ) + { + return connectionDefinition; + } +} - { return new InsertConflictTarget(indexColumnNames, indexExpression, whereExpression, constraintName); } +ErrorClause ErrorClause(): { + ErrorClause errorClause = new ErrorClause(); + ErrorDestination errorDestination; + Expression expression; + RejectClause rejectClause; + + Token token; +} { + ( + + 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); } + ) + + { + return errorClause; + } } -InsertConflictAction InsertConflictAction(): -{ - InsertConflictAction conflictAction; - Expression whereExpression = null; - List updateSets; +RejectClause RejectClause(): { + RejectClause rejectClause = new RejectClause(); +} { + + ( + token= { rejectClause.setLimit(new LongValue(token.image)); } + | + ) + + [ LOOKAHEAD(2) { rejectClause.setErrors(true); } ] + + { + return rejectClause; + } } -{ + +ErrorDestination ErrorDestination(): { + ErrorDestination errorDestination; +} { ( - LOOKAHEAD(2) ( - { conflictAction = new InsertConflictAction( ConflictActionType.DO_NOTHING ); } - ) - | - ( - { conflictAction = new InsertConflictAction( ConflictActionType.DO_UPDATE ); } - updateSets = UpdateSets() { conflictAction.setUpdateSets(updateSets); } - [ whereExpression = WhereClause() ] - ) + LOOKAHEAD(2) errorDestination = CSVFileDestination() + | errorDestination = Table() ) - { return conflictAction - .withWhereExpression(whereExpression); } + { + return errorDestination; + } } -OutputClause OutputClause(): -{ - List> selectItemList = null; - UserVariable tableVariable = null; - Table outputTable = null; - List columnList = null; +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); } + + { + return csvFileDestination; + } } -{ - - selectItemList = SelectItemsList() - [ - ( - tableVariable = UserVariable() - | - outputTable = Table() - ) - [ - LOOKAHEAD(2) columnList = ColumnsNamesList() - ] - ] +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 new OutputClause(selectItemList, tableVariable, outputTable, columnList); + return stmt; } } -Upsert Upsert(): +SessionStatement SessionStatement(): { - Upsert upsert = new Upsert(); - Table table = null; - ExpressionList columns; - List updateSets; - - Select select = null; - List duplicateUpdateSets; - Token tk = null; + SessionStatement sessionsStatement; + Token actionToken; + Token idToken = null; + String id = null; } { + ( | ) ( - { upsert.setUpsertType(UpsertType.UPSERT); } + actionToken = | - { upsert.setUpsertType(UpsertType.REPLACE); } + actionToken = | - ( - { upsert.setUpsertType(UpsertType.INSERT_OR_REPLACE); } - ) + actionToken = + | + actionToken = + | + actionToken = ) - [ LOOKAHEAD(2) { upsert.setUsingInto(true); } ] - - table=Table() { upsert.setTable(table); } - [ LOOKAHEAD(2) columns = ParenthesedColumnList() { upsert.setColumns(columns); } ] - ( + [ ( - - updateSets = UpdateSets() { upsert.setUpdateSets(updateSets); } - ) - | + idToken = + | + idToken = + | + idToken = + | + idToken = + ) { id = idToken.image; } + ( - select = Select() { upsert.setSelect(select); } - ) - ) + "." + ( + idToken = + | + idToken = + | + idToken = + | + idToken = + ) { id += "." + idToken.image; } + )? + ] + { + sessionsStatement = id!=null + ? new SessionStatement(actionToken.image, id) + : new SessionStatement(actionToken.image); + } + // options [ - - duplicateUpdateSets = UpdateSets() { upsert.setDuplicateUpdateSets(duplicateUpdateSets); } + 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 ); } + )* ] { - return upsert; + //linkAST(sessionsStatement,jjtThis); + return sessionsStatement; } } -Delete DeleteWithWithItems( List> withItems ): -{ - Delete delete; -} +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; } ] + ) + | + ( + name = IdentifierChain() + ["=" { useEqual=true; } ] + ) + ) + exp=Expression() + { + expList = new ExpressionList(); + expList.add(exp); + set = new SetStatement(name, expList) + .withUseEqual(useEqual) + .withEffectParameter(effectParameter); + } + + ( + { 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; } +} + +ResetStatement Reset(): { + String name; + ResetStatement reset; + Token all; +} +{ + ( LOOKAHEAD(2) {name = "Time Zone"; } | name = RelObjectName() | all = {name = all.image; } ) + { reset = new ResetStatement(name); return reset; } +} + +RenameTableStatement RenameTableStatement(): { + RenameTableStatement renameTableStatement; + Table oldName; + Table newName; + boolean usingTableKeyword=false; + boolean usesIfExistsKeyword=false; + String waitDirective = ""; + Token token; +} +{ + + [ LOOKAHEAD(2) { usingTableKeyword = true; } ] + [ LOOKAHEAD(2) { usesIfExistsKeyword = true; } ] + oldName = Table() + [ ( + token= { waitDirective = "WAIT " + token.image; } + | + { waitDirective = "NOWAIT"; } + ) ] + + newName = Table() + + { + renameTableStatement = new RenameTableStatement(oldName, newName, usingTableKeyword, usesIfExistsKeyword, waitDirective); + } + + ( + "," + oldName = Table() + + newName = Table() + { + renameTableStatement.addTableNames(oldName, newName); + } + )* + + { + return renameTableStatement; + } +} + +PurgeStatement PurgeStatement(): { + PurgeStatement purgeStatement = null; + Table table; + Index index; + Token tableSpaceToken; + Token userToken = null; +} +{ + + ( + 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); + } + ) + + { + return purgeStatement; + } +} + +DescribeStatement Describe(): { + Table table; + DescribeStatement stmt = new DescribeStatement(); + Token tk = null; +} { + (tk= | tk=) + table = Table() { stmt.setDescribeType(tk.image).setTable(table); } + { + return stmt; + } +} + +ExplainStatement Explain(): +{ + Token tk; + Select select; + Table table; + List options; + ExplainStatement es; +} +{ + ( tk= | tk = ) + ( + LOOKAHEAD(3)( + options= ExplainStatementOptions() + select = Select( ) + { + es = new ExplainStatement(tk.image, select, options); + } + ) + | + ( + table=Table( ) { es = new ExplainStatement(tk.image, table); } + ) + ) + { + 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; + } +} + +/** + * 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; + } +} + +/** + * 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); + } + ) + | + ( + { 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 = RelObjectNameExt() + { + return new UseStatement(name, hasSchemaKeyword); + } +} + +Statement Show(): +{ + Statement statement; + List captureRest; +} +{ + + ( + 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); + } + } + ) + { + return statement; + } +} + +ShowColumnsStatement ShowColumns(): { + String tableName; +} +{ + tableName = RelObjectNameExt() + { + return new ShowColumnsStatement(tableName); + } +} + +ShowIndexStatement ShowIndex(): { + String tableName; +} +{ + tableName = RelObjectNameExt() + { + return new ShowIndexStatement(tableName); + } +} + +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() + { + 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; } + | + { selectionMode = ShowTablesStatement.SelectionMode.IN; } + ) + 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; + } +} + +Values Values(): { + ExpressionList expressions; +} { + ( | ) + expressions = ExpressionList() + + { + return new Values(expressions); + } +} + +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); } + )* + ] + + { + return new ReturningClause(keyword.image, selectItems, dataItems); + } +} + +Update UpdateWithWithItems( List> withItems ): +{ + Update update; +} +{ + update = Update() { update.setWithItemsList( withItems ); + return update; +} +} + +Update Update(): +{ + 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 joins = null; + Limit limit = null; + List orderByElements; + boolean useColumnsBrackets = false; + ReturningClause returningClause; + Token tk = null; + UpdateModifierPriority modifierPriority = null; + boolean modifierIgnore = false; + + OutputClause outputClause = null; +} +{ + { 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); } ] + + [ LOOKAHEAD(2) + fromItem=FromItem() + [ LOOKAHEAD(2) joins=JoinsList() ] ] + + [ where=WhereClause() { update.setWhere(where); } ] + [ preferringClause=PreferringClause() { update.setPreferringClause(preferringClause); } ] + + [ orderByElements = OrderByElements() { update.setOrderByElements(orderByElements); } ] + [ limit = PlainLimit() { update.setLimit(limit); } ] + [ returningClause = ReturningClause() { update.setReturningClause(returningClause); } ] + + { + return update.withWithItemsList(with) + .withTable(table) + .withStartJoins(startJoins) + .withFromItem(fromItem) + .withJoins(joins) + .withModifierPriority(modifierPriority) + .withModifierIgnore(modifierIgnore); + } +} + +List UpdateSets(): +{ + ArrayList updateSets = new ArrayList(); + UpdateSet updateSet; + Column tableColumn; + Expression valueExpression; + + ExpressionList columns; + ExpressionListvalues; +} +{ + ( + ( + 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); } + ) + ) + ) + + ( + LOOKAHEAD(2) ( + "," + 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); } + ) + ) + ) + )* + + { + return updateSets; + } +} + +List Partitions(): +{ + List partitions = new ArrayList(); + Column tableColumn; + Expression valueExpression = null; +} +{ + ( + ( + tableColumn=Column() [ "=" valueExpression=Expression() ] + { partitions.add( new Partition (tableColumn, valueExpression)); } + ) + ) + + ( + LOOKAHEAD(2) ( + "," + tableColumn=Column() [ "=" valueExpression=Expression() ] + { partitions.add( new Partition (tableColumn, valueExpression)); } + ) + )* + + { + return partitions; + } +} + +Insert InsertWithWithItems( List> withItems ): +{ + Insert insert; +} +{ + insert = Insert() { insert.setWithItemsList( withItems ); + return insert; +} +} + +Insert Insert(): +{ + 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; + + 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; + + InsertDuplicateAction duplicateAction = null; +} +{ + { insert.setOracleHint(getOracleHint()); } + + [ + LOOKAHEAD(2) (tk = | tk = | tk = ) + { + if (tk!=null) + modifierPriority = InsertModifierPriority.from(tk.image); + } + ] + [ LOOKAHEAD(2) { modifierIgnore = true; }] + [ LOOKAHEAD(2) ( + { insert.setOverwrite(true); insert.setTableKeyword(true); } + | [ LOOKAHEAD(2) { insert.setTableKeyword(true); }] + ) + ] table=Table() + [ LOOKAHEAD(2) "(" partitions=Partitions() ")" ] + + [ LOOKAHEAD(2) [ { useAs = true; } ] name=RelObjectNameWithoutValue() { 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(2, { 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); } ] + + { + if (!columns.isEmpty()) { + insert.setColumns(columns); + } + if (!partitions.isEmpty()) { + insert.setPartitions(partitions); + } + return insert.withWithItemsList(with) + .withSelect(select) + .withTable(table) + .withModifierPriority(modifierPriority) + .withModifierIgnore(modifierIgnore); + } +} + +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() ")" +// ) + + ")" + [ whereExpression = WhereClause() ] + ) + | + ( + constraintName = RelObjectNameExt2() + ) + ) + + { return new InsertConflictTarget(indexColumnNames, indexExpression, whereExpression, constraintName); } +} + +InsertConflictAction InsertConflictAction(): +{ + InsertConflictAction conflictAction; + Expression whereExpression = null; + List updateSets; +} +{ + ( + 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); } +} + +InsertDuplicateAction InsertDuplicateAction(): +{ + InsertDuplicateAction duplicateAction; + Expression whereExpression = null; + List updateSets; +} +{ + ( + LOOKAHEAD(2) ( + { duplicateAction = new InsertDuplicateAction( ConflictActionType.NOTHING ); } + ) + | + ( + { duplicateAction = new InsertDuplicateAction( ConflictActionType.DO_UPDATE ); } + updateSets = UpdateSets() { duplicateAction.setUpdateSets(updateSets); } + [ whereExpression = WhereClause() ] + ) + ) + + { return duplicateAction + .withWhereExpression(whereExpression); } +} + + +OutputClause OutputClause(): +{ + List> selectItemList = null; + UserVariable tableVariable = null; + Table outputTable = null; + List columnList = null; +} +{ + + selectItemList = SelectItemsList() + [ + ( + tableVariable = UserVariable() + | + outputTable = Table() + ) + [ + LOOKAHEAD(2) columnList = ColumnsNamesList() + ] + ] + + { + return new OutputClause(selectItemList, tableVariable, outputTable, columnList); + } +} + +Upsert Upsert(): +{ + Upsert upsert = new Upsert(); + Table table = null; + ExpressionList columns; + List updateSets; + + Select select = null; + List duplicateUpdateSets; + InsertDuplicateAction duplicateAction = null; + Token tk = null; +} +{ + ( + { upsert.setUpsertType(UpsertType.UPSERT); } + | + { 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; + } +} + +Delete DeleteWithWithItems( List> withItems ): +{ + Delete delete; +} { delete = Delete() { delete.setWithItemsList( withItems ); return delete; @@ -1964,8 +3059,8 @@ Delete Delete(): Table table = null; List
tables = new ArrayList
(); List> with = null; - Table usingTable = null; - List
usingList = new ArrayList
(); + FromItem usingFromItem = null; + List usingFromItemList = new ArrayList(); List joins = null; Expression where = null; PreferringClause preferringClause = null; @@ -1991,8 +3086,8 @@ Delete Delete(): | ) { hasFrom = true; }] [ LOOKAHEAD(3) table=TableWithAlias() [ LOOKAHEAD(2) joins=JoinsList() ] ] - [ usingTable=TableWithAlias() { usingList.add(usingTable); } - ("," usingTable=TableWithAlias() { usingList.add(usingTable); } )*] + [ 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); } ] @@ -2007,7 +3102,7 @@ Delete Delete(): .withTables(tables) .withTable(table) .withHasFrom(hasFrom) - .withUsingList(usingList) + .withUsingFromItemList(usingFromItemList) .withModifierPriority(modifierPriority) .withModifierIgnore(modifierIgnore) .withModifierQuick(modifierQuick); @@ -2190,7 +3285,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | 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="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="IMPORT" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="KEY_BLOCK_SIZE" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATCH_ALL" | tk="MATCH_ANY" | tk="MATCH_PHRASE" | tk="MATCH_PHRASE_PREFIX" | tk="MATCH_REGEXP" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NAME" | 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="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PARALLEL" | tk="PARENT" | tk="PARSER" | tk="PARTITION" | tk="PARTITIONING" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PLUS" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="REBUILD" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="REMOVE" | tk="RENAME" | tk="REORGANIZE" | tk="REPAIR" | 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="SAFE_CAST" | 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="SPATIAL" | tk="STORED" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VIEW" | tk="VISIBLE" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALIGN" | tk="ALTER" | tk="ALWAYS" | tk="ANALYZE" | tk="APPEND_ONLY" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="ASYMMETRIC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="AZURE" | tk="BASE64" | tk="BEFORE" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOBSTORAGE" | tk="BLOCK" | tk="BOOLEAN" | tk="BRANCH" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CERTIFICATE" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="CLOUD" | tk="COALESCE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMENTS" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="CORRESPONDING" | tk="COSTS" | tk="COUNT" | tk="CREATED" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFAULTS" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DELIMIT" | tk="DELIMITER" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCARD" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DRIVER" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCODING" | tk="ENCRYPTION" | tk="END" | tk="ENFORCED" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXA" | tk="EXCHANGE" | tk="EXCLUDE" | tk="EXCLUDING" | tk="EXCLUSIVE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXPORT" | tk="EXTENDED" | tk="EXTRACT" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="IDENTIFIED" | tk="IDENTITY" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCLUDING" | tk="INCREMENT" | tk="INDEX" | tk="INFORMATION" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="INVISIBLE" | tk="ISNULL" | tk="JDBC" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="KEY_BLOCK_SIZE" | tk="KILL" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LEVEL" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW" | tk="LOW_PRIORITY" | tk="LTRIM" | tk="MATCH" | tk="MATCHED" | tk="MATCH_ALL" | tk="MATCH_ANY" | tk="MATCH_PHRASE" | tk="MATCH_PHRASE_PREFIX" | tk="MATCH_REGEXP" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODE" | tk="MODIFY" | tk="MOVEMENT" | tk="NAME" | tk="NAMES" | tk="NEVER" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NONE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="ORA" | tk="ORDINALITY" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PADDING" | tk="PARALLEL" | tk="PARENT" | tk="PARSER" | tk="PARTITION" | tk="PARTITIONING" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PLUS" | tk="POLICY" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="REBUILD" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REJECT" | tk="REMOTE" | tk="REMOVE" | tk="RENAME" | tk="REORGANIZE" | tk="REPAIR" | 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="RTRIM" | tk="SAFE_CAST" | tk="SAFE_CONVERT" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SECURITY" | 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="SPATIAL" | tk="STORED" | tk="STREAM" | tk="STRICT" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYMMETRIC" | tk="SYNONYM" | tk="SYSTEM" | tk="SYSTEM_TIME" | tk="SYSTEM_TIMESTAMP" | tk="SYSTEM_VERSION" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TRY_CONVERT" | tk="TUMBLING" | tk="TYPE" | tk="UNLIMITED" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VALIDATION" | tk="VERBOSE" | tk="VERSION" | tk="VIEW" | tk="VISIBLE" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) { return tk.image; } } @@ -2214,7 +3309,8 @@ String RelObjectNameWithoutStart() : { Token tk = null; String result = null; } { (result = RelObjectNameWithoutValue() | tk= | tk= | tk= - | tk= ) + | tk= + ) { return tk!=null ? tk.image : result; } } @@ -2263,17 +3359,20 @@ Table Table() #TableName : ObjectNames data = null; Token fileNameToken = null; Table table; + String timeTravelStr = null; } { ( - data = RelObjectNames() + data = RelObjectNames() [ LOOKAHEAD(2) timeTravelStr = TimeTravelBeforeAlias() ] { table = new Table(data.getNames()); + table.setTimeTravel(timeTravelStr); } | fileNameToken = { - table = new Table(fileNameToken.image); + // don't split name parts + table = new Table(fileNameToken.image, false); } ) @@ -2397,16 +3496,12 @@ Select Select() #Select: Alias alias = null; } { - ( - //@todo: avoid this expensive semantic look ahead - LOOKAHEAD( [ WithList() ] FromQuery()) ( - [ with=WithList() ] - select = FromQuery() - ) + [ with=WithList() ] + ( + LOOKAHEAD(3) select = FromQuery() | ( - [ with=WithList() ] ( LOOKAHEAD(3) select = PlainSelect() | @@ -2679,15 +3774,42 @@ LimitPipeOperator LimitPipeOperator(): } } +// see https://manticore-projects.com/SQL2016Parser/syntax_snapshot.html#corresponding-spec String SetOperationModifier(): { - Token token = null; - String modifier = null; + Token tk; + String modifier = ""; + String identifier; } { - ( token= | token= ) { modifier = token.image; } - [ ( { modifier+= " BY NAME"; } ) | ( { modifier+= " STRICT CORRESPONDING"; }) ] - + ( + LOOKAHEAD(2) ( + [ ( tk= | tk="DISTINCT") { modifier+=tk.image; } ] + { modifier+= " BY NAME"; } + [ + "MATCHING" { modifier+= " MATCHING"; } + "(" + identifier = RelObjectNameExt() { modifier+="(" + identifier; } + ("," identifier = RelObjectNameExt() { modifier+=", " + identifier; })* + ")" { modifier+=")"; } + ] + ) + | + ( + [ { modifier+= " STRICT"; } ] + { modifier+= " CORRESPONDING"; } + [ (tk= | tk="DISTINCT") { modifier+=tk.image; } ] + [ + { modifier+= " BY"; }[ (tk= | tk="DISTINCT") { modifier+=tk.image; } ] + "(" + identifier = RelObjectNameExt() { modifier+="(" + identifier; } + ("," identifier = RelObjectNameExt() { modifier+=", " + identifier;})* + ")" { modifier+=")"; } + ] + ) + | + ( tk= | tk= ) { modifier+=tk.image; } + ) { return modifier; } @@ -3008,6 +4130,7 @@ PlainSelect PlainSelect() #PlainSelect: List lateralViews = null; List joins = null; List> distinctOn = null; + Expression preWhere = null; Expression where = null; ForClause forClause = null; List orderByElements; @@ -3037,6 +4160,7 @@ PlainSelect PlainSelect() #PlainSelect: String windowName = null; WindowDefinition winDef; Table intoTempTable = null; + Distinct distinct; } { @@ -3059,11 +4183,13 @@ PlainSelect PlainSelect() #PlainSelect: | ( - { Distinct distinct = new Distinct(); plainSelect.setDistinct(distinct); } + { distinct = new Distinct(); plainSelect.setDistinct(distinct); } [ LOOKAHEAD(2) "ON" "(" distinctOn=SelectItemsList() { plainSelect.getDistinct().setOnSelectItems(distinctOn); } ")" ] ) | - { Distinct distinct = new Distinct(true); plainSelect.setDistinct(distinct); } + { distinct = new Distinct(); distinct.setUseDistinctRow(true); plainSelect.setDistinct(distinct); } + | + { distinct = new Distinct(true); plainSelect.setDistinct(distinct); } | { plainSelect.setMySqlSqlCalcFoundRows(true); } | @@ -3100,6 +4226,7 @@ PlainSelect PlainSelect() #PlainSelect: [ 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); } @@ -3141,6 +4268,8 @@ PlainSelect PlainSelect() #PlainSelect: | { 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() { plainSelect.setForUpdateTable(updateTable); } ] [ LOOKAHEAD() wait = Wait() { plainSelect.setWait(wait); } ] @@ -3173,6 +4302,7 @@ Select SetOperationList(Select select) #SetOperationList: { WithIsolation withIsolation = null; List(); List operations = new ArrayList(); + String modifier = null; } { @@ -3182,24 +4312,20 @@ Select SetOperationList(Select select) #SetOperationList: { ( LOOKAHEAD(2) ( ( - { UnionOp union = new UnionOp(); linkAST(union,jjtThis); operations.add(union); } - [ { union.setAll(true); } | { union.setDistinct(true); } [ ( ) | ( ) ] ] + [ modifier=SetOperationModifier() ] { UnionOp union = new UnionOp(modifier); linkAST(union,jjtThis); operations.add(union); } ) | ( - { IntersectOp intersect = new IntersectOp(); linkAST(intersect,jjtThis); operations.add(intersect); } - [ { intersect.setAll(true); } | { intersect.setDistinct(true); } [ ( ) | ( ) ] ] + [ modifier=SetOperationModifier() ] { IntersectOp intersect = new IntersectOp(modifier); linkAST(intersect,jjtThis); operations.add(intersect); } ) | ( - { MinusOp minus = new MinusOp(); linkAST(minus,jjtThis); operations.add(minus); } - [ { minus.setAll(true); } | { minus.setDistinct(true); } [ ( ) | ( ) ] ] + [ modifier=SetOperationModifier() ] { MinusOp minus = new MinusOp(); linkAST(minus,jjtThis); operations.add(minus); } ) | ( - { ExceptOp except = new ExceptOp(); linkAST(except,jjtThis); operations.add(except); } - [ { except.setAll(true); } | { except.setDistinct(true); } [ ( ) | ( ) ] ] + [ modifier=SetOperationModifier() ] { ExceptOp except = new ExceptOp(); linkAST(except,jjtThis); operations.add(except); } ) ) @@ -3264,33 +4390,91 @@ WithItem WithItem() #WithItem: { boolean recursive = false; boolean materialized = false; - String name; + boolean usingNot = false; + String name = null; List> selectItems = null; - ParenthesedStatement statement; + WithFunctionDeclaration withFunctionDeclaration = null; + ParenthesedStatement statement = null; + WithItem withItem; } { - [ LOOKAHEAD(2) { recursive = true; } ] - name=RelObjectName() - [ "(" selectItems=SelectItemsList() ")" ] - - [ LOOKAHEAD(2) { materialized = true; } ] - ( - LOOKAHEAD(2) statement = ParenthesedSelect() - | - LOOKAHEAD(2) statement = ParenthesedInsert() - | - LOOKAHEAD(2) statement = ParenthesedUpdate() + ( + LOOKAHEAD(2) + withFunctionDeclaration = WithFunctionDeclaration() + { + withItem = new WithItem().withWithFunctionDeclaration(withFunctionDeclaration); + } | - LOOKAHEAD(2) statement = ParenthesedDelete() + ( + [ 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); + } + ) ) { - WithItem withItem = new WithItem(statement, new Alias(name, false)); - return withItem - .withRecursive(recursive, materialized) - .withWithItemList(selectItems); + return withItem; } } +WithFunctionDeclaration WithFunctionDeclaration() #WithFunctionDeclaration: +{ + String functionName; + List parameters = new ArrayList(); + String returnType; + Expression returnExpression; + WithFunctionParameter parameter; +} +{ + functionName = RelObjectName() + "(" + [ parameter=WithFunctionParameter() { parameters.add(parameter); } + ( "," parameter=WithFunctionParameter() { parameters.add(parameter); } )* + ] + ")" + returnType = RelObjectName() + returnExpression = Expression() + { + return new WithFunctionDeclaration(functionName, parameters, returnType, returnExpression); + } +} + +WithFunctionParameter WithFunctionParameter() #WithFunctionParameter: +{ + String name; + String type = null; + String arrayType = null; +} +{ + name = RelObjectName() + ( + LOOKAHEAD(2) "<" arrayType = RelObjectName() ">" + | + type = RelObjectName() + ) + { + if (arrayType != null) { + type = "ARRAY<" + arrayType + ">"; + } + return new WithFunctionParameter(name, type); + } +} + List> ColumnSelectItemsList(): { List> selectItemsList = null; @@ -3361,7 +4545,12 @@ SelectItem SelectItem() #SelectItem: } } -AllColumns AllColumns(): +/** + * Parses the AllColumns-Pattern '*'. + * + * If the allowAdditions is true, it parses additional Keywords. + */ +AllColumns AllColumns(boolean allowAdditions): { ParenthesedExpressionList exceptColumns = null; List> replaceExpressions = null; @@ -3370,21 +4559,28 @@ AllColumns AllColumns(): } { "*" - [ LOOKAHEAD(2) ( tk= | tk= ) exceptColumns = ParenthesedColumnList() { exceptKeyword=tk.image; } ] - [ LOOKAHEAD(2) "(" replaceExpressions = SelectItemsList() ")" ] + // 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 new AllColumns(exceptColumns, replaceExpressions, exceptKeyword); } } -AllTableColumns AllTableColumns(): +/** + * Parses the AllTableColumns-Pattern 'table.*' + * + * If the allowAdditions is true, it parses additional Keywords. + */ +AllTableColumns AllTableColumns(boolean allowAdditions): { Table table = null; AllColumns allColumns; } { - table=Table() "." allColumns=AllColumns() + table=Table() "." allColumns=AllColumns(allowAdditions) { return new AllTableColumns(table, allColumns); } @@ -3671,16 +4867,31 @@ FromItem FromItem() #FromItem: 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(16) fromItem=TableFunction() | LOOKAHEAD(3) fromItem=Table() | - LOOKAHEAD(110) fromItem = ParenthesedFromItem() + LOOKAHEAD(ParenthesedFromItem()) fromItem = ParenthesedFromItem() | LOOKAHEAD(3, { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) ( fromItem=ParenthesedSelect() @@ -3690,10 +4901,16 @@ FromItem FromItem() #FromItem: | fromItem=LateralSubSelect() | + LOOKAHEAD(2, { Dialect.EXASOL.name().equals(getAsString(Feature.dialect)) }) fromItem=SubImport() { fromItem = new ParenthesedFromItem(fromItem); } + | LOOKAHEAD({ getAsBoolean(Feature.allowUnparenthesizedSubSelects) }) fromItem=Select() ) [ LOOKAHEAD(2) 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); } ] @@ -3760,17 +4977,18 @@ Join JoinerExpression() #JoinerExpression: } { [ { join.setGlobal(true); } ] + [ { join.setAny(true); } | { join.setAll(true); } ] [ { join.setNatural(true); } ] [ ( - { join.setLeft(true); } [ { join.setSemi(true); } | { join.setOuter(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.setOuter(true); } | { join.setAny(true); } | { join.setAll(true); } ] | { join.setInner(true); } ) @@ -3781,7 +4999,11 @@ Join JoinerExpression() #JoinerExpression: ] ( - ( [ joinHint=JoinHint() {join.setJoinHint(joinHint); } ] ) + ( + [ joinHint=JoinHint() {join.setJoinHint(joinHint); } ] + + [ { join.setFetch(true); } ] + ) | "," { join.setSimple(true); } ( { join.setOuter(true); } )? | @@ -3894,6 +5116,15 @@ Expression WhereClause(): { return retval; } } +Expression PreWhereClause(): +{ + Expression retval = null; +} +{ + retval=Expression() + { return retval; } +} + OracleHierarchicalExpression OracleHierarchicalQueryClause(): { OracleHierarchicalExpression result = new OracleHierarchicalExpression(); @@ -4157,9 +5388,11 @@ 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) ( @@ -4328,13 +5561,9 @@ WithIsolation WithIsolation(): JdbcParameter jdbc; } { - ( - //with (ur | cs | rs | rr) - - token= { withIsolation.setIsolation(token.image); } - - ) - { + + token= + { withIsolation.setIsolation(token.image); return withIsolation; } } @@ -4396,10 +5625,11 @@ Skip Skip(): { ( - 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)); } ] */ + token= { skip.setRowCount(Long.parseLong(token.image)); } + | + token= { skip.setVariable(token.image); } + | + jdbc = JdbcParameter() { skip.setJdbcParameter(jdbc); } ) { return skip; @@ -4507,7 +5737,7 @@ Expression AndExpression() : } { ( - LOOKAHEAD(814, {!interrupted}) left=Condition() + 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; } } @@ -4518,7 +5748,7 @@ Expression AndExpression() : { boolean useOperator = false; } ( | {useOperator=true;} ) ( - LOOKAHEAD(814, {!interrupted}) right=Condition() + 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; } } @@ -4544,7 +5774,7 @@ Expression Condition(): { [ LOOKAHEAD(2) ( { not=true; } | "!" { not=true; exclamationMarkNot=true; })] ( - LOOKAHEAD(814, {!interrupted}) result=RegularCondition() + LOOKAHEAD(RegularCondition(), {!interrupted}) result=RegularCondition() | result=SQLCondition() ) @@ -4613,7 +5843,7 @@ Expression RegularCondition() #RegularCondition: | "-#" { result = new JsonOperator("-#"); } | "<->" { result = new GeometryDistance("<->"); } | "<#>" { result = new GeometryDistance("<#>"); } - | "<=>" { result = new CosineSimilarity(); } + | { result = new CosineSimilarity(); } ) ( LOOKAHEAD(2) rightExpression=ComparisonItem() { oraclePrior = EqualsTo.ORACLE_PRIOR_END; } @@ -4647,7 +5877,7 @@ Expression SQLCondition(): { ( result=ExistsExpression() - | LOOKAHEAD( 814, {!interrupted}) result=OverlapsCondition() + | LOOKAHEAD( OverlapsCondition(), {!interrupted}) result=OverlapsCondition() | left = SimpleExpression() { result = left; } [ LOOKAHEAD(2) ( @@ -4695,7 +5925,7 @@ Expression InExpression(Expression leftExpression) #InExpression : ( LOOKAHEAD(2) token= { rightExpression = new StringValue(token.image); } | - rightExpression = Expression() + rightExpression = PrimaryExpression() ) { InExpression inExpression = new InExpression(leftExpression, rightExpression) @@ -4746,19 +5976,26 @@ Expression Between(Expression leftExpression) : { [ { result.setNot(true); }] + [ + LOOKAHEAD(2) ( + { result.setUsingSymmetric(true); } + | + { result.setUsingAsymmetric(true); } + ) + ] ( - LOOKAHEAD( 3 ) betweenExpressionStart = ParenthesedSelect() + LOOKAHEAD( ParenthesedSelect() ) betweenExpressionStart = ParenthesedSelect() | - LOOKAHEAD( 11 ) betweenExpressionStart = RegularCondition() + LOOKAHEAD( RegularCondition() ) betweenExpressionStart = RegularCondition() | betweenExpressionStart = SimpleExpression() ) ( - LOOKAHEAD( 3 ) betweenExpressionEnd = ParenthesedSelect() + LOOKAHEAD( ParenthesedSelect() ) betweenExpressionEnd = ParenthesedSelect() | - LOOKAHEAD( 11 ) betweenExpressionEnd = RegularCondition() + LOOKAHEAD( RegularCondition() ) betweenExpressionEnd = RegularCondition() | betweenExpressionEnd = SimpleExpression() ) @@ -4980,8 +6217,7 @@ ExpressionList SimpleExpressionList(): ( LOOKAHEAD(2, {!interrupted} ) "," ( - // @todo: Check hot to avoid this expensive look ahead - LOOKAHEAD( 6 ) expr=LambdaExpression() + LOOKAHEAD( 7 ) expr=LambdaExpression() | expr=SimpleExpression() ) @@ -5029,6 +6265,8 @@ ExpressionList ComplexExpressionList(): ( LOOKAHEAD(2) expr=OracleNamedFunctionParameter() | + LOOKAHEAD(2) expr=PostgresNamedFunctionParameter() + | expr=Expression() ) { @@ -5040,9 +6278,11 @@ ExpressionList ComplexExpressionList(): ( LOOKAHEAD(2) expr=OracleNamedFunctionParameter() | - // @todo: Check hot to avoid this expensive look ahead - LOOKAHEAD( 6 ) expr=LambdaExpression() - | expr=Expression() + LOOKAHEAD(2) expr=PostgresNamedFunctionParameter() + | + LOOKAHEAD(7) expr=LambdaExpression() + | + expr=Expression() ) { expressions.add(expr); } )* @@ -5348,130 +6588,457 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(2, {!interrupted}) retval=CharacterPrimary() - | LOOKAHEAD(5, {!interrupted}) retval=ImplicitCast() + | LOOKAHEAD(6, {!interrupted}) retval=ImplicitCast() | retval = JdbcParameter() - | LOOKAHEAD(2) retval =JdbcNamedParameter() + | LOOKAHEAD(2) retval =JdbcNamedParameter() + + | LOOKAHEAD(3) retval=UserVariable() + + | LOOKAHEAD(2, {!interrupted}) retval=NumericBind() + + | LOOKAHEAD(4 , {!interrupted}) retval=ExtractExpression() + + | LOOKAHEAD(3) retval=MySQLGroupConcat() + + | retval=XMLSerializeExpr() + + | LOOKAHEAD(3, { !interrupted}) retval = JsonFunction() + + | LOOKAHEAD(3, { !interrupted}) retval = JsonAggregateFunction() + + | LOOKAHEAD(3, { !interrupted}) retval = FullTextSearch() + + | LOOKAHEAD(2, {!interrupted}) retval= CastExpression() + + | LOOKAHEAD(16) 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(16) 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}) { 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); + } + ] - | LOOKAHEAD(3) retval=UserVariable() - | LOOKAHEAD(2, {!interrupted}) retval=NumericBind() + { + if (list.size() == 1) { + retval = new ParenthesedExpressionList( (Expression) list.getExpressions().get(0)); + } else { + retval = list; + } + } - | LOOKAHEAD(4 , {!interrupted}) retval=ExtractExpression() - | LOOKAHEAD(3) retval=MySQLGroupConcat() + // RowGet Expression + [ LOOKAHEAD(2) "." tmp=RelObjectNameExt() { retval = new RowGetExpression(retval, tmp); }] + ) + ) - | retval=XMLSerializeExpr() + [ + LOOKAHEAD(2) (token= | token= | token=) { retval = new CollateExpression(retval, token.image); } + ] - | LOOKAHEAD(3, { !interrupted}) retval = JsonFunction() + [ + LOOKAHEAD(2, { dateExpressionAllowed } ) retval = IntervalExpressionWithoutInterval(retval) + ] - | LOOKAHEAD(3, { !interrupted}) retval = JsonAggregateFunction() + [ LOOKAHEAD(2) retval = ArrayExpression(retval) ] - | LOOKAHEAD(3, { !interrupted}) retval = FullTextSearch() + ( LOOKAHEAD(2) "::" type=ColDataType() { + castExpr = new CastExpression(); + castExpr.setUseCastKeyword(false); + castExpr.setLeftExpression(retval); + castExpr.setColDataType(type); + retval=castExpr; + } + )* - | LOOKAHEAD(2, {!interrupted}) retval=CastExpression() + // Check for JSON operands + [ + LOOKAHEAD(2) ( + LOOKAHEAD(2) ( + token="->" + | + token=":" + | + token="->>" + | + token="#>" + | + token="#>>" + ) - | LOOKAHEAD(16) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ] + ( + LOOKAHEAD({getAsBoolean(Feature.allowComplexParsing) && !interrupted }) expression=Expression() + | + expression=SimpleExpression() + ) + { + jsonIdents.add(new AbstractMap.SimpleEntry(expression, token.image )); + } + )+ + retval = JsonExpression(retval, jsonIdents) + ] - | LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; } + ( LOOKAHEAD(2) timezoneRightExpr=PrimaryExpression() { + if (timezoneExpr == null) + timezoneExpr = new TimezoneExpression(); - | token= { retval = new DoubleValue(token.image); } + timezoneExpr.addTimezoneExpression(timezoneRightExpr); + } + )* - | token= { retval = new LongValue(token.image); } + { + 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; + } +} - | token= { retval = new HexValue(token.image); } +/* https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/img_text/hierarchical_query_clause.html - | LOOKAHEAD(3) retval=AllColumns() + { CONNECT BY [ NOCYCLE ] condition [ START WITH condition ] + | START WITH condition CONNECT BY [ NOCYCLE ] condition + } + */ - | LOOKAHEAD(16) retval=AllTableColumns() +ConnectByRootOperator ConnectByRootOperator() #ConnectByRootOperator: { + Expression expression; +} +{ + expression = Expression() + { + return new ConnectByRootOperator(expression); + } +} - | LOOKAHEAD(250) retval=FunctionAllColumns() +ConnectByPriorOperator ConnectByPriorOperator() #ConnectByPriorOperator: { + Expression expression; +} +{ + expression = Expression() + { + return new ConnectByPriorOperator(expression); + } +} - // support timestamp expressions - | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new TimeKeyExpression(token.image); } - | LOOKAHEAD(2, {!interrupted}) retval=DateTimeLiteralExpression() +NextValExpression NextValExpression() : { + ObjectNames data = null; + Token token; +} +{ + token= data = RelObjectNames() + { + return new NextValExpression(data.getNames(), token.image); + } +} - | LOOKAHEAD(3 , {!interrupted}) retval=StructType() +JdbcNamedParameter JdbcNamedParameter() : { + JdbcNamedParameter parameter = new JdbcNamedParameter(); + String name; + String namePart; +} +{ + (":" | "&" { parameter.setParameterCharacter("&"); } ) + name=IdentifierChain() + { + parameter.setName(name); + return parameter; + } +} - | LOOKAHEAD(3, {!interrupted}) [ "<" type=ColDataType() ">" ] retval=ArrayConstructor(true) { if (type!=null) ((ArrayConstructor) retval).setDataType(type); } +OracleNamedFunctionParameter OracleNamedFunctionParameter() : { + Token token = null; + String name = null; + Expression expression; +} +{ + ( name=RelObjectNameExt2() | token= ) + + expression=Expression() + { + return new OracleNamedFunctionParameter(name != null ? name : token.image, expression); + } +} - | LOOKAHEAD(3, {!interrupted}) retval=ArrayConstructor(false) +PostgresNamedFunctionParameter PostgresNamedFunctionParameter() : { + Token token = null; + String name = null; + Expression expression; +} +{ + ( name=RelObjectNameExt2() | token= ) + + expression=Expression() + { + return new PostgresNamedFunctionParameter(name != null ? name : token.image, expression); + } +} - | LOOKAHEAD(2, {!interrupted}) retval = NextValExpression() +UserVariable UserVariable() : { + Token tk; + String varName; +} +{ + tk = varName=IdentifierChain2(tk.image) + { + return new UserVariable(varName); + } +} - | retval=ConnectByRootOperator() +NumericBind NumericBind() : { + NumericBind var = new NumericBind(); + Token token; +} +{ + ":" token= + { + var.setBindId(Integer.valueOf(token.image)); + return var; + } +} - | retval=ConnectByPriorOperator() +DateTimeLiteralExpression DateTimeLiteralExpression() : { + DateTimeLiteralExpression expr = new DateTimeLiteralExpression(); + Token t; +} +{ + t= + { + expr.setType(DateTimeLiteralExpression.DateTime.from(t.image)); + } - | LOOKAHEAD(2, {!interrupted}) { retval = new AllValue(); } + ( t= | t= ) + { + expr.setValue(t.image); + return expr; + } +} - | LOOKAHEAD(2, {!interrupted}) retval=Column() +DateUnitExpression DateUnitExpression() : { + Token t; +} +{ + t= { return new DateUnitExpression( t.image ); } +} - | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new BooleanValue(token.image); } +RangeExpression RangeExpression(Expression startExpression): +{ + Expression endExpression; +} +{ + ":" endExpression = Expression() + { + return new RangeExpression(startExpression, endExpression); + } +} - | token= { retval = new StringValue(token.image); linkAST(retval,jjtThis); } +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); } - | "{d" token= "}" { retval = new DateValue(token.image); } + ( + "," + ( + LOOKAHEAD(3) exp = Expression() [ exp=RangeExpression(exp) ] + | + exp = ArrayConstructor(false) + ){ expList.add(exp); } + )* + ] + "]" + { return array; } +} - | "{t" token= "}" { retval = new TimeValue(token.image); } +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) ); + } - | "{ts" token= "}" { retval = new TimestampValue(token.image); } + ( + "," { parameterName=""; } - | LOOKAHEAD( 17 , { getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=Select() + [ LOOKAHEAD(2) parameterName = RelObjectName() ] + parameterType = ColDataType() + { + parameters.add( new AbstractMap.SimpleEntry(parameterName, parameterType) ); + } + )* - | LOOKAHEAD( 17 , { !getAsBoolean(Feature.allowUnparenthesizedSubSelects) && !interrupted } ) retval=ParenthesedSelect() + { + return parameters; + } +} +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() ")" + ) | ( - 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; - } - } + tk1= { keyword = tk1.image; } + "(" arguments = SelectItemsList() ")" + ) + | + ( + { arguments= new ArrayList>(); dialect = StructType.Dialect.DUCKDB;} + ( id = RelObjectNameExt2() | tk1= { id = tk1.image; } ) + expression = Expression() { arguments.add( new SelectItem( expression, id) ); } + ( + "," + ( id = RelObjectNameExt2() | tk1= { id = tk1.image; } ) + expression = Expression() { arguments.add( new SelectItem( expression, id) ); } + )* + - // RowGet Expression - [ LOOKAHEAD(2) "." tmp=RelObjectNameExt() { retval = new RowGetExpression(retval, tmp); }] + ( + LOOKAHEAD(2) "::" "(" parameters = StructParameters() ")" + )* ) ) + { + type = new StructType(dialect, keyword, parameters, arguments); + linkAST(type,jjtThis); + return type; + } +} - [ - LOOKAHEAD(2) token= { retval = new CollateExpression(retval, token.image); } - ] - - [ - LOOKAHEAD(2, { dateExpressionAllowed } ) retval = IntervalExpressionWithoutInterval(retval) - ] - - [ LOOKAHEAD(2) retval = ArrayExpression(retval) ] +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) "::" type=ColDataType() { - castExpr = new CastExpression(); - castExpr.setUseCastKeyword(false); - castExpr.setLeftExpression(retval); - castExpr.setColDataType(type); - retval=castExpr; + // 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); } - )* - // Check for JSON operands - [ - LOOKAHEAD(2) ( + ( LOOKAHEAD(2) ( token="->" | @@ -5485,426 +7052,655 @@ Expression PrimaryExpression() #PrimaryExpression: ) ( - LOOKAHEAD({getAsBoolean(Feature.allowComplexParsing) && !interrupted }) expression=Expression() + LOOKAHEAD({getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expression=Expression() | expression=SimpleExpression() ) { - jsonIdents.add(new AbstractMap.SimpleEntry(expression, token.image )); + result.addIdent( 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; + result.setExpression(expr); + return result; } } -ConnectByRootOperator ConnectByRootOperator() #ConnectByRootOperator: { - Column column; +JsonKeyValuePair JsonKeyValuePair(boolean isFirstEntry) : { + Token keyToken; + + boolean usingKeyKeyword = false; + boolean usingFormatJason = false; + String encoding = null; + boolean isWildcard = false; + + Object key = null; + Expression expression = null; + JsonFunctionExpression functionExpression; + + JsonKeyValuePairSeparator kvSeparator = JsonKeyValuePairSeparator.NOT_USED; } { - column = Column() + ( + // 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; } + ) + + // 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() + ] + + // Optional: FORMAT JSON [ ENCODING ... ] - Is not allowed with * or t1.* + [ + LOOKAHEAD(1, { !isWildcard } ) { usingFormatJason = true; } + [ encoding = JsonEncoding() ] + ] { - return new ConnectByRootOperator(column); - } + final JsonKeyValuePair keyValuePair = new JsonKeyValuePair( key, expression, usingKeyKeyword, kvSeparator ); + keyValuePair.setUsingFormatJson( usingFormatJason ); + keyValuePair.setEncoding(encoding); + return keyValuePair; + } } -ConnectByPriorOperator ConnectByPriorOperator() #ConnectByPriorOperator: { - Column column; +JsonFunction JsonObjectBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.OBJECT); + + JsonKeyValuePair keyValuePair; + ColDataType dataType; + String encoding; } { - column = Column() + ( "(" + ( + // 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); } ] + ] + ] + ")" ) { - return new ConnectByPriorOperator(column); + return result; } } +JsonFunction JsonArrayBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.ARRAY); -NextValExpression NextValExpression() : { - ObjectNames data = null; + Expression expression = null; + JsonFunctionExpression functionExpression; + ColDataType dataType; + String encoding; +} +{ + ( "(" + ( + LOOKAHEAD(2) ( + { result.setOnNullType( JsonAggregateOnNullType.NULL ); } + ) + | + expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } + + [ + LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } + [ encoding = JsonEncoding() { functionExpression.setEncoding(encoding); } ] + ] + ( + "," + expression=Expression() { functionExpression = new JsonFunctionExpression( expression ); result.add( functionExpression ); } + [ + LOOKAHEAD(2) { functionExpression.setUsingFormatJson( true ); } + [ encoding = JsonEncoding() { functionExpression.setEncoding(encoding); } ] + ] + )* + )* + + [ + { result.setOnNullType( JsonAggregateOnNullType.ABSENT ); } + ] + [ + dataType = ColDataType() { result.setReturningType(dataType); } + [ + { result.setReturningFormatJson(true); } + [ encoding = JsonEncoding() { result.setReturningEncoding(encoding); } ] + ] + ] + ")" ) + { + return result; + } +} + +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() : { - Token token = null; - String name = null; +JsonFunctionExpression JsonValueOrQueryInputExpression() : { Expression expression; + JsonFunctionExpression functionExpression; + String encoding; } { - ( name=RelObjectNameExt2() | token= ) - - expression=Expression() + expression = Expression() { functionExpression = new JsonFunctionExpression(expression); } + [ + { functionExpression.setUsingFormatJson(true); } + [ encoding = JsonEncoding() { functionExpression.setEncoding(encoding); } ] + ] { - return new OracleNamedFunctionParameter(name != null ? name : token.image, 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); + } + | + 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= + ( + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.ERROR); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.NULL); + } + | + token = + { + if (!token.image.equalsIgnoreCase("EMPTY")) { + throw new ParseException( + "Expected EMPTY, ERROR or NULL but found " + token.image); + } + } + ( + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.EMPTY_ARRAY); + } + | + JsonKeyword("OBJECT") + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.EMPTY_OBJECT); + } + ) + ) { - var.setBindId(Integer.valueOf(token.image)); - return var; + if (behavior != null) { + return behavior; + } } } -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; +JsonFunction.JsonOnResponseBehavior JsonExistsOnResponseBehavior() : { + JsonFunction.JsonOnResponseBehavior behavior = null; } { - ":" endExpression = Expression() + ( + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.TRUE); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.FALSE); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.UNKNOWN); + } + | + + { + behavior = new JsonFunction.JsonOnResponseBehavior( + JsonFunction.JsonOnResponseBehaviorType.ERROR); + } + ) { - return new RangeExpression(startExpression, endExpression); + return behavior; } } -ArrayConstructor ArrayConstructor(boolean arrayKeyword) : { - ExpressionList expList = new ExpressionList(); - ArrayConstructor array = new ArrayConstructor(expList, arrayKeyword); - Expression exp; -} { - "[" +JsonFunction JsonExistsBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.EXISTS); + JsonFunctionExpression inputExpression; + Expression expression; + JsonFunction.JsonOnResponseBehavior behavior; +} +{ + "(" + inputExpression = JsonValueOrQueryInputExpression() { result.setInputExpression(inputExpression); } + "," + expression = Expression() { result.setJsonPathExpression(expression); } + [ - ( - LOOKAHEAD(3) exp = Expression() [ exp=RangeExpression(exp) ] - | - exp = ArrayConstructor(false) - ) { expList.add(exp); } + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("PASSING") }) + JsonKeyword("PASSING") + expression = Expression() { result.addPassingExpression(expression); } + ( "," expression = Expression() { result.addPassingExpression(expression); } )* + ] - ( - "," - ( - LOOKAHEAD(3) exp = Expression() [ exp=RangeExpression(exp) ] - | - exp = ArrayConstructor(false) - ){ expList.add(exp); } - )* + [ + LOOKAHEAD( JsonExistsOnResponseBehavior() ) + behavior = JsonExistsOnResponseBehavior() + + { result.setOnErrorBehavior(behavior); } ] - "]" - { return array; } + ")" + { + return result; + } } -List> StructParameters(): -{ - String parameterName = ""; - ColDataType parameterType = null; - AbstractMap.SimpleEntry parameter = null; - List> parameters = new ArrayList>(); +JsonFunction JsonValueBody() : { + JsonFunction result = new JsonFunction(JsonFunctionType.VALUE); + JsonFunctionExpression inputExpression; + Expression expression; + ColDataType dataType; + JsonFunction.JsonOnResponseBehavior behavior; } { - [ LOOKAHEAD(2) parameterName = RelObjectName() ] - parameterType = ColDataType() - { - parameters.add( new AbstractMap.SimpleEntry(parameterName, parameterType) ); - } + "(" + inputExpression = JsonValueOrQueryInputExpression() { result.setInputExpression(inputExpression); } + "," + expression = Expression() { result.setJsonPathExpression(expression); } - ( - "," { parameterName=""; } + [ + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("PASSING") }) + JsonKeyword("PASSING") + expression = Expression() { result.addPassingExpression(expression); } + ( "," expression = Expression() { result.addPassingExpression(expression); } )* + ] - [ LOOKAHEAD(2) parameterName = RelObjectName() ] - parameterType = ColDataType() - { - parameters.add( new AbstractMap.SimpleEntry(parameterName, parameterType) ); - } - )* + [ dataType = ColDataType() { result.setReturningType(dataType); } ] + + [ + LOOKAHEAD( JsonValueOnResponseBehavior() ) + behavior = JsonValueOnResponseBehavior() + JsonKeyword("EMPTY") + { result.setOnEmptyBehavior(behavior); } + ] + [ + LOOKAHEAD( JsonValueOnResponseBehavior() ) + behavior = JsonValueOnResponseBehavior() + + { result.setOnErrorBehavior(behavior); } + ] + ")" { - return parameters; + return result; } } -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 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; } { - ( - 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;} + "(" + inputExpression = JsonValueOrQueryInputExpression() { result.setInputExpression(inputExpression); } + "," + expression = Expression() { result.setJsonPathExpression(expression); } - id = RelObjectName() expression = Expression() { arguments.add( new SelectItem( expression, id) ); } + [ + LOOKAHEAD({ getToken(1).kind == S_IDENTIFIER && getToken(1).image.equalsIgnoreCase("PASSING") }) + JsonKeyword("PASSING") + expression = Expression() { result.addPassingExpression(expression); } + ( "," expression = Expression() { result.addPassingExpression(expression); } )* + ] - ( - "," - id = RelObjectName() expression = Expression() { arguments.add( new SelectItem( expression, id) ); } - )* - + [ + dataType = ColDataType() { result.setReturningType(dataType); } + [ + { result.setReturningFormatJson(true); } + [ encoding = JsonEncoding() { result.setReturningEncoding(encoding); } ] + ] + ] - ( - LOOKAHEAD(2) "::" "(" parameters = StructParameters() ")" - )* + [ + ( + { 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 = + { + if (token.image.equalsIgnoreCase("CONDITIONAL")) { + result.setWrapperMode(JsonFunction.JsonWrapperMode.CONDITIONAL); + } else { + result.setWrapperMode(JsonFunction.JsonWrapperMode.UNCONDITIONAL); + } + } + ] + [ { result.setWrapperArray(true); } ] + JsonKeyword("WRAPPER") ) + ] - // don't parse this as an Struct, but rather use an Expressionlist - // | - // arguments = StructArguments() - ) - { - type = new StructType(dialect, keyword, parameters, arguments); - linkAST(type,jjtThis); - return type; - } -} + [ + LOOKAHEAD({ + getToken(1).kind == K_KEEP + || (getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("OMIT")) + }) + ( + { result.setQuotesType(JsonFunction.JsonQuotesType.KEEP); } + | + JsonKeyword("OMIT") { result.setQuotesType(JsonFunction.JsonQuotesType.OMIT); } + ) + JsonKeyword("QUOTES") + [ + JsonKeyword("SCALAR") + { result.setQuotesOnScalarString(true); } + ] + ] -JsonExpression JsonExpression(Expression expr, List> idents) : { - JsonExpression result = new JsonExpression(expr, idents); - Expression expression; - Token token=null; - ColDataType type = null; - CastExpression castExpr = null; -} -{ + [ + LOOKAHEAD( JsonQueryOnResponseBehavior() ) + behavior = JsonQueryOnResponseBehavior() + JsonKeyword("EMPTY") + { result.setOnEmptyBehavior(behavior); } + ] + + [ + LOOKAHEAD( JsonQueryOnResponseBehavior() ) + behavior = JsonQueryOnResponseBehavior() + + { result.setOnErrorBehavior(behavior); } + ] - // 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); + additionalReturningType = null; + additionalReturningFormatJson = false; + additionalReturningEncoding = null; + additionalWrapperType = null; + additionalWrapperMode = null; + additionalWrapperArray = false; + additionalQuotesType = null; + additionalQuotesOnScalarString = false; + additionalOnEmptyBehavior = null; + additionalOnErrorBehavior = null; } - - ( - LOOKAHEAD(2) ( - token="->" - | - token=":" - | - token="->>" - | - token="#>" + expression = Expression() + [ + additionalReturningType = ColDataType() + [ + { additionalReturningFormatJson = true; } + [ additionalReturningEncoding = JsonEncoding() ] + ] + ] + [ + ( + + { additionalWrapperType = JsonFunction.JsonWrapperType.WITHOUT; } + [ { additionalWrapperArray = true; } ] + JsonKeyword("WRAPPER") | - token="#>>" + + { 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")) + }) ( - LOOKAHEAD({getAsBoolean(Feature.allowComplexParsing) && !interrupted}) expression=Expression() + { additionalQuotesType = JsonFunction.JsonQuotesType.KEEP; } | - expression=SimpleExpression() + JsonKeyword("OMIT") { additionalQuotesType = JsonFunction.JsonQuotesType.OMIT; } ) - { - result.addIdent( expression, token.image ); + JsonKeyword("QUOTES") + [ + JsonKeyword("SCALAR") { additionalQuotesOnScalarString = true; } + ] + ] + [ + LOOKAHEAD( JsonQueryOnResponseBehavior() ) + additionalOnEmptyBehavior = JsonQueryOnResponseBehavior() + JsonKeyword("EMPTY") + ] + [ + 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; - - Object key = null; - Expression expression = null; - JsonFunctionExpression functionExpression; - + JsonFunction result; } { ( - ( - "(" { result.setType( JsonFunctionType.OBJECT ); } - ( - // SQL2016 compliant Syntax - LOOKAHEAD(2) ( - LOOKAHEAD(2) ( - "KEY" { usingKeyKeyword = true; } ( keyToken = { key = keyToken.image; } | key = Column() ) - ) - | - keyToken = { key = keyToken.image; } - | - key = Column() - ) - - ( LOOKAHEAD(2) - ( ":" | "," { result.setType( JsonFunctionType.POSTGRES_OBJECT ); } | "VALUE" { usingValueKeyword = true; } ) - ( - expression = Expression() - ) - [ { usingFormatJason = true; } ] - )? - { - if (expression !=null) { - keyValuePair = new JsonKeyValuePair( key, expression, usingKeyKeyword, usingValueKeyword ); - keyValuePair.setUsingFormatJson( usingFormatJason ); - result.add(keyValuePair); - } else { - result.setType( JsonFunctionType.POSTGRES_OBJECT ); - keyValuePair = new JsonKeyValuePair( key, null, false, false ); - result.add(keyValuePair); - } - } - - // --- Next Elements - ( "," { usingKeyKeyword = false; usingValueKeyword = false; } - ( - LOOKAHEAD(2) ( - "KEY" { usingKeyKeyword = true; } ( keyToken = { key = keyToken.image; } | key = Column() ) - ) - | - keyToken = { key = keyToken.image; } - | - key = Column() - ) - ( ":" | "," { result.setType( JsonFunctionType.MYSQL_OBJECT ); } | "VALUE" { usingValueKeyword = true; } ) - expression = Expression() { keyValuePair = new JsonKeyValuePair( key, 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 = JsonObjectBody() ) + | + ( result = JsonArrayBody() ) + | + ( + LOOKAHEAD({ + getToken(1).kind == S_IDENTIFIER + && getToken(1).image.equalsIgnoreCase("JSON_VALUE") + }) + JsonKeyword("JSON_VALUE") + result = JsonValueBody() ) | ( - { 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 ); } - ] - - ")" + 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; } @@ -6492,7 +8288,7 @@ Function SpecialStringFunctionWithNamedParameters() : "(" ( - LOOKAHEAD(6, { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() + LOOKAHEAD( NamedExpressionListExprFirst() , { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst() | expressionList=ExpressionList() ) @@ -6642,23 +8438,385 @@ XMLSerializeExpr XMLSerializeExpr(): { } } - -MySQLGroupConcat MySQLGroupConcat():{ - MySQLGroupConcat retval = new MySQLGroupConcat(); - ExpressionList expressionList = null; - List orderByList = null; - Token t; + +MySQLGroupConcat MySQLGroupConcat():{ + MySQLGroupConcat retval = new MySQLGroupConcat(); + ExpressionList expressionList = null; + List orderByList = null; + Token t; +} +{ + "(" + [ { retval.setDistinct(true); } ] + expressionList = ExpressionList() + [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ] + [ t= { retval.setSeparator(t.image); } ] + ")" + { + retval.setExpressionList(expressionList); + return retval; + } +} + +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); + } + | + 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() : { + JsonTableFunction.JsonTableWrapperClause wrapperClause = + new JsonTableFunction.JsonTableWrapperClause(); + 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(); } + [ { 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; + } + ( + JsonKeyword("ORDINALITY") + { valueColumnDefinition.setForOrdinality(true); } + | + dataType = ColDataType() { valueColumnDefinition.setDataType(dataType); } + [ + { valueColumnDefinition.setFormatJson(true); } + [ encoding = JsonEncoding() { valueColumnDefinition.setEncoding(encoding); } ] + ] + [ expression = Expression() { valueColumnDefinition.setPathExpression(expression); } ] + [ wrapperClause = JsonTableWrapperClause() { 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() + JsonKeyword("EMPTY") + { valueColumnDefinition.setOnEmptyBehavior(behavior); } + ] + [ + LOOKAHEAD( JsonValueOnResponseBehavior() ) + behavior = JsonValueOnResponseBehavior() + + { valueColumnDefinition.setOnErrorBehavior(behavior); } + ] + ) + ) + { + 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); + } + | + 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() : { + JsonTableFunction.JsonTableOnErrorClause onErrorClause = + new JsonTableFunction.JsonTableOnErrorClause(); + Token token; +} +{ + ( + { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.ERROR); } + | + token = + { + if (!token.image.equalsIgnoreCase("EMPTY")) { + throw new ParseException( + "Expected EMPTY or ERROR but found " + token.image); + } + onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.EMPTY); + } + ) + + { + if (onErrorClause.getType() != null) { + return onErrorClause; + } + } +} + +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; } { - "(" - [ { retval.setDistinct(true); } ] - expressionList = ExpressionList() - [ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ] - [ t= { retval.setSeparator(t.image); } ] + "(" + jsonInput = Expression() { + function.setJsonInputExpression(jsonInput); + } + "," + 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); } + )* + ] + columnsClause = JsonTableColumnsClause() { function.setColumnsClause(columnsClause); } + [ planClause = JsonTablePlanClause() { function.setPlanClause(planClause); } ] + [ onErrorClause = JsonTableOnErrorClause() { function.setOnErrorClause(onErrorClause); } ] ")" { - retval.setExpressionList(expressionList); - return retval; + return function; } } @@ -6666,12 +8824,20 @@ 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 @@ -6773,11 +8939,8 @@ ColumnDefinition ColumnDefinition(): { List parameter; } { columnName=RelObjectName() - - colDataType = ColDataType() - + colDataType=ColDataType() ( LOOKAHEAD(2) parameter=CreateParameter() { columnSpecs.addAll(parameter); } )* - { coldef = new ColumnDefinition(); coldef.setColumnName(columnName); @@ -6794,15 +8957,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(); } { [ LOOKAHEAD(2) { schema.setIfNotExists(true); } ] - [ ( tk= | tk=) { schema.setSchemaName(tk.image); } ] + [ + ( tk= | tk=) { schema.setSchemaName(tk.image); } + + ( + "." { schema.setCatalogName(tk.image); } + ( tk= | tk=) { schema.setSchemaName(tk.image); } + )? + ] + [ (tk= | tk=) { schema.setAuthorization(tk.image); } ] @@ -6947,10 +9116,11 @@ CreateTable CreateTable(boolean isUsingOrReplace): LOOKAHEAD(3) ( { tk=null; + tk3=null; idxSpec.clear(); } [ tk= ] - [ tk3= ] tk2= + [ tk3= | tk3= ] tk2= sk3=RelObjectName() colNames = ColumnNamesWithParamsList() ( parameter=CreateParameter() { idxSpec.addAll(parameter); } )* @@ -7105,12 +9275,12 @@ 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; } )+ ] [ @@ -7147,6 +9317,19 @@ ColDataType ColDataType(): } { ( + ( + + "(" + type = RelObjectNameExt2() + colDataType = ColDataType() { argumentsStringList.add( type + " " + colDataType.toString()); } + ( + "," + type = RelObjectNameExt2() + colDataType = ColDataType() { argumentsStringList.add( type + " " + colDataType.toString()); } + )* + ")" { colDataType = new ColDataType("STRUCT"); } + ) + | LOOKAHEAD(2) ( colDataType = DataType() ) @@ -7369,9 +9552,9 @@ List CreateParameter(): | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk= | 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); } @@ -7439,11 +9622,13 @@ String AList(): String ColumnsNamesListItem(): { Token tk = null; + Token sortDirection = null; String item = null; } { ( item = RelObjectName() ) [ LOOKAHEAD(2) "(" tk = ")" { item = item + "(" + tk.image + ")"; } ] + [ (sortDirection = | sortDirection = ) { item = item + " " + sortDirection.image; } ] { return item; } @@ -7542,8 +9727,15 @@ Drop Drop(): name = Table() { drop.setName(name); } [ LOOKAHEAD(2) funcArgs = FuncArgsList() ] - ((tk= | tk= | tk= | tk=) { dropArgs.add(tk.image); })* - + ( + ( + tk= | tk= | tk= + ) { dropArgs.add(tk.image); } + | + ( + name = Table() { dropArgs.add("ON"); dropArgs.add(name.toString()); } + ) + )* { if (dropArgs.size() > 0) { drop.setParameters(dropArgs); @@ -7897,7 +10089,11 @@ AlterExpression AlterExpression(): LOOKAHEAD(2) ( columnNames=ColumnsNamesList() { alterExp.setPkColumns(columnNames); }) constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] + [ + { alterExp.addParameters("USING"); } + [ { alterExp.addParameters("INDEX"); } ] + sk4=RelObjectName() { alterExp.addParameters(sk4); } + ] | LOOKAHEAD(2) ( (tk= { alterExp.setUk(true); } | tk=) @@ -8026,7 +10222,11 @@ AlterExpression AlterExpression(): | ( (( { alterExp.setUk(true); } | ) (tk= | tk=) { alterExp.setUkName(tk.image); } )? columnNames=ColumnsNamesList() { alterExp.setUkColumns(columnNames); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] + [ + { alterExp.addParameters("USING"); } + [ { alterExp.addParameters("INDEX"); } ] + sk4=RelObjectName() { alterExp.addParameters(sk4); } + ] [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] ) | @@ -8116,7 +10316,11 @@ AlterExpression AlterExpression(): alterExp.setIndex(index); } constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] + [ + { alterExp.addParameters("USING"); } + [ { alterExp.addParameters("INDEX"); } ] + sk4=RelObjectName() { alterExp.addParameters(sk4); } + ] [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] ) | @@ -8148,7 +10352,11 @@ AlterExpression AlterExpression(): alterExp.setIndex(index); } constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); } - [ sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }] + [ + { alterExp.addParameters("USING"); } + [ { alterExp.addParameters("INDEX"); } ] + sk4=RelObjectName() { alterExp.addParameters(sk4); } + ] [ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ] ) | @@ -8174,7 +10382,7 @@ AlterExpression AlterExpression(): { alterExp.setOperation(AlterOperation.CHANGE); } [ { alterExp.hasColumn(true); alterExp.setOptionalSpecifier("COLUMN"); } ] ( - (tk= | tk=) + (tk=KeywordOrIdentifier()) alterExpressionColumnDataType = AlterExpressionColumnDataType() { alterExp.withColumnOldName(tk.image).addColDataType(alterExpressionColumnDataType); } ) ) @@ -8208,7 +10416,7 @@ AlterExpression AlterExpression(): ( LOOKAHEAD(2) { alterExp.hasColumn(true); } )? [ { alterExp.setUsingIfExists(true); } ] // @todo: replace with a proper identifier - (tk= | tk= | tk=) { alterExp.setColumnName(tk.image); } + (tk=KeywordOrIdentifier() ) { alterExp.setColumnName(tk.image); } [ "INVALIDATE" { alterExp.addParameters("INVALIDATE"); } ] @@ -8251,7 +10459,19 @@ AlterExpression AlterExpression(): ) ) | - ( + LOOKAHEAD(5) ( + { + alterExp.setOperation(AlterOperation.FORCE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(5) ( + { + alterExp.setOperation(AlterOperation.NO_FORCE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(1) ( { alterExp.setOperation(AlterOperation.FORCE); } ) | @@ -8401,16 +10621,28 @@ AlterExpression AlterExpression(): ) ) | - ( - (tk = ) - (tk2 = ) { + + LOOKAHEAD(4) ( + { + alterExp.setOperation(AlterOperation.DISABLE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(2) ( + { alterExp.setOperation(AlterOperation.DISABLE_KEYS); } ) + | - ( - (tk = ) - (tk2 = ) { + LOOKAHEAD(4) ( + { + alterExp.setOperation(AlterOperation.ENABLE_ROW_LEVEL_SECURITY); + } + ) + | + LOOKAHEAD(2) ( + { alterExp.setOperation(AlterOperation.ENABLE_KEYS); } ) @@ -8692,57 +10924,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; } ) | ( @@ -8750,19 +10982,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() @@ -8940,93 +11172,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(): @@ -9081,6 +11328,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() { @@ -9161,6 +11410,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(); @@ -9291,6 +11579,17 @@ String IdentifierChain(): } } +String IdentifierChain2(String identifierChain): +{ + String part; +} +{ + ( LOOKAHEAD(2) "." part=RelObjectNameExt2() { identifierChain += "." + part; } )* + { + return identifierChain; + } +} + Expression CharacterPrimary(): { Expression expression; @@ -9320,6 +11619,7 @@ Expression CharacterPrimary(): TranscodingFunction TranscodingFunction() #TranscodingFunction : { + Token keywordToken; TranscodingFunction transcodingFunction; ColDataType colDataType; Expression expression; @@ -9327,14 +11627,15 @@ TranscodingFunction TranscodingFunction() #TranscodingFunction : Token style; } { - "(" + ( keywordToken= | keywordToken= | keywordToken= ) + "(" ( LOOKAHEAD(4) colDataType = ColDataType() "," expression = Expression() [ "," style = { transcodingName = style.image; } ] { - transcodingFunction = new TranscodingFunction(colDataType, expression, transcodingName); + transcodingFunction = new TranscodingFunction(keywordToken.image, colDataType, expression, transcodingName); } | ( @@ -9388,3 +11689,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/site/sphinx/_static/jmh_results.txt b/src/site/sphinx/_static/jmh_results.txt new file mode 100644 index 000000000..fac4a571f --- /dev/null +++ b/src/site/sphinx/_static/jmh_results.txt @@ -0,0 +1,25 @@ +-- Optimised LOOKAHEADS (replacing all syntactic lookahead by numeric lookaheads) +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 264.132 ± 9.636 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 415.744 ± 20.602 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 89.387 ± 1.916 ms/op +JSQLParserBenchmark.parseSQLStatements 5.0 avgt 15 68.810 ± 2.591 ms/op +JSQLParserBenchmark.parseSQLStatements 4.9 avgt 15 60.515 ± 1.650 ms/op +JSQLParserBenchmark.parseSQLStatements 4.8 avgt 15 60.002 ± 1.259 ms/op +JSQLParserBenchmark.parseSQLStatements 4.7 avgt 15 73.291 ± 3.049 ms/op + +-- Optimised LOOKAHEADS (replacing huge numeric lookaheads with syntactic lookaheads again) +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 249.408 ± 11.340 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 15 388.453 ± 13.149 ms/op + +-- Disable `FunctionAllColumns()` +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 + +-- Token Manipulation +JSQLParserBenchmark.parseSQLStatements latest avgt 30 78.287 ± 4.730 ms/op +JSQLParserBenchmark.parseSQLStatements 5.2 avgt 30 356.553 ± 24.823 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 30 86.815 ± 1.771 ms/op \ No newline at end of file diff --git a/src/site/sphinx/conf.py b/src/site/sphinx/conf.py index 29ab663cf..99e908d9e 100644 --- a/src/site/sphinx/conf.py +++ b/src/site/sphinx/conf.py @@ -4,7 +4,7 @@ needs_sphinx = '1.0' 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', ] issues_github_path = "JSQLParser/JSqlParser" diff --git a/src/site/sphinx/contribution.rst b/src/site/sphinx/contribution.rst index bfb3b3571..9793e8947 100644 --- a/src/site/sphinx/contribution.rst +++ b/src/site/sphinx/contribution.rst @@ -77,7 +77,22 @@ The JSQLParser is generated by ``JavaCC`` based on the provided Grammar. The Gra mvn verify - 7) Create your `GitHub Pull Request `_ + 7) Verify the performance and avoid any deterioration + + .. code-block:: shell + :caption: Gradle `check` Task + + gradle jmh + + .. code-block:: text + :caption: JMH performance results + + 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 + + 8) Create your `GitHub Pull Request `_ Manage Reserved Keywords ------------------------------ diff --git a/src/site/sphinx/keywords.rst b/src/site/sphinx/keywords.rst index 941d8d175..d80a92fb8 100644 --- a/src/site/sphinx/keywords.rst +++ b/src/site/sphinx/keywords.rst @@ -29,6 +29,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | CONNECT_BY_ROOT | Yes | Yes | +----------------------+-------------+-----------+ +| CSV | Yes | Yes | ++----------------------+-------------+-----------+ | PRIOR | Yes | Yes | +----------------------+-------------+-----------+ | CONSTRAINT | Yes | Yes | @@ -43,10 +45,14 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | DISTINCT | Yes | Yes | +----------------------+-------------+-----------+ +| DISTINCTROW | Yes | Yes | ++----------------------+-------------+-----------+ | DOUBLE | Yes | | +----------------------+-------------+-----------+ | ELSE | Yes | Yes | +----------------------+-------------+-----------+ +| ERRORS | Yes | Yes | ++----------------------+-------------+-----------+ | EXCEPT | Yes | Yes | +----------------------+-------------+-----------+ | EXCLUDES | Yes | Yes | @@ -57,8 +63,12 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | FALSE | Yes | Yes | +----------------------+-------------+-----------+ +| FBV | Yes | Yes | ++----------------------+-------------+-----------+ | FETCH | Yes | Yes | +----------------------+-------------+-----------+ +| FILE | Yes | Yes | ++----------------------+-------------+-----------+ | FINAL | Yes | Yes | +----------------------+-------------+-----------+ | FOR | Yes | Yes | @@ -89,6 +99,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | ILIKE | Yes | Yes | +----------------------+-------------+-----------+ +| IMPORT | Yes | Yes | ++----------------------+-------------+-----------+ | IN | Yes | Yes | +----------------------+-------------+-----------+ | INCLUDES | Yes | Yes | @@ -153,12 +165,16 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | PUBLIC | Yes | | +----------------------+-------------+-----------+ +| RETURNS | Yes | Yes | ++----------------------+-------------+-----------+ | RETURNING | Yes | Yes | +----------------------+-------------+-----------+ | RIGHT | Yes | Yes | +----------------------+-------------+-----------+ | SAMPLE | Yes | | +----------------------+-------------+-----------+ +| SCRIPT | Yes | Yes | ++----------------------+-------------+-----------+ | SEL | Yes | | +----------------------+-------------+-----------+ | SELECT | Yes | | @@ -171,6 +187,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | START | Yes | Yes | +----------------------+-------------+-----------+ +| STATEMENT | Yes | Yes | ++----------------------+-------------+-----------+ | TABLES | Yes | | +----------------------+-------------+-----------+ | TOP | Yes | Yes | @@ -209,6 +227,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | VARYING | Yes | Yes | +----------------------+-------------+-----------+ +| VERIFY | Yes | Yes | ++----------------------+-------------+-----------+ | WHEN | Yes | Yes | +----------------------+-------------+-----------+ | WHERE | Yes | Yes | 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/CastExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java index 806b6764a..f4e17c136 100644 --- a/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/CastExpressionTest.java @@ -104,4 +104,14 @@ 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); + } } 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/FunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java index 0433222d3..f977d558d 100644 --- a/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/FunctionTest.java @@ -108,4 +108,22 @@ void testSimpleFunctionIssue2059() throws JSQLParserException { 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); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java index c29af21f9..5fc72bea8 100644 --- a/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java @@ -41,6 +41,7 @@ void testIssue1792() throws JSQLParserException { @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()); @@ -48,6 +49,7 @@ void testSnowflakeGetOperator() throws JSQLParserException { @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()); diff --git a/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java b/src/test/java/net/sf/jsqlparser/expression/JsonFunctionTest.java index ef1335e6c..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.*; /** * @@ -66,15 +77,15 @@ public void testObjectBuilder() throws JSQLParserException { .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); + assertNotNull(keyValuePair3); + assertEquals(keyValuePair3, keyValuePair3); Assertions.assertNotEquals(keyValuePair3, f); Assertions.assertTrue(keyValuePair3.hashCode() != 0); @@ -94,7 +105,7 @@ public void testArrayBuilder() throws JSQLParserException { new JsonFunctionExpression(new NullValue()).withUsingFormatJson( true); - Assertions.assertEquals(expression1.toString(), expression2.toString()); + assertEquals(expression1.toString(), expression2.toString()); f.add(expression1); f.add(expression2); @@ -164,6 +175,62 @@ 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( @@ -222,6 +289,183 @@ public void testArrayWithNullExpressions() throws JSQLParserException { 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( @@ -262,29 +506,128 @@ 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)"; + "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()); + 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), + assertEquals(3, jsonFunction.getKeyValuePairs().size()); + assertEquals(new JsonKeyValuePair("'foo'", "bar", true, true), jsonFunction.getKeyValuePair(0)); jsonFunction.setOnNullType(JsonAggregateOnNullType.NULL); - Assertions.assertEquals(JsonAggregateOnNullType.ABSENT, + assertEquals(JsonAggregateOnNullType.ABSENT, jsonFunction.withOnNullType(JsonAggregateOnNullType.ABSENT).getOnNullType()); jsonFunction.setUniqueKeysType(JsonAggregateUniqueKeysType.WITH); - Assertions.assertEquals(JsonAggregateUniqueKeysType.WITH, jsonFunction + 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"; diff --git a/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java index d4b5ed86c..2e17ad1f0 100644 --- a/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/OracleHierarchicalExpressionTest.java @@ -1,3 +1,12 @@ +/*- + * #%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; 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/StringValueTest.java b/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java index 062f131aa..75f30b365 100644 --- a/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/StringValueTest.java @@ -10,7 +10,9 @@ 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.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -93,4 +95,12 @@ 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()); + } } diff --git a/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java b/src/test/java/net/sf/jsqlparser/expression/StructTypeTest.java index c6645b4c9..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); @@ -64,6 +63,12 @@ void testStructTypeConstructorDuckDB() throws JSQLParserException { 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/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/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/parser/ASTNodeAccessImplTest.java b/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java index b08f86a4d..088eb699b 100644 --- a/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/ASTNodeAccessImplTest.java @@ -47,7 +47,7 @@ void testGetWherePositionIssue1339() throws JSQLParserException { PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); Expression whereExpression = select.getWhere(); - final SimpleNode node = whereExpression.getASTNode(); + final Node node = whereExpression.getASTNode(); if (node != null) { Token token = node.jjtGetFirstToken(); Assertions.assertEquals(4, token.beginLine); diff --git a/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java b/src/test/java/net/sf/jsqlparser/parser/ParserKeywordsUtilsTest.java index 2c531e9e9..8acdee50e 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; @@ -141,21 +138,22 @@ 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(); + // JavaCCErrors.reInit(); + 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()); } @@ -205,9 +203,4 @@ void compareKeywordLists() throws Exception { } } - @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/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/TableTest.java b/src/test/java/net/sf/jsqlparser/schema/TableTest.java index 0f9ff2071..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; @@ -59,10 +60,8 @@ public void tableSetDatabaseIssue812() throws JSQLParserException { SelectDeParser deparser = new SelectDeParser(expressionDeParser, buffer) { @Override - public StringBuilder visit(Table tableName, S parameters) { - 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; } }; @@ -112,4 +111,22 @@ void testBigQueryFullQuotedName() throws JSQLParserException { 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/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/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/AlterTest.java b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java index 559517b9d..2e9566e0d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java @@ -9,22 +9,21 @@ */ package net.sf.jsqlparser.statement.alter; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; - +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; -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.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; @@ -43,10 +42,10 @@ 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 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 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 { @@ -249,6 +248,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"; @@ -455,6 +459,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( @@ -563,6 +572,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( @@ -2224,4 +2244,26 @@ public void testAlterTableAddIndexInvisible() throws JSQLParserException { 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/builder/ReflectionModelTest.java b/src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java index bff7ef05c..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; @@ -170,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(), @@ -211,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/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 db4e1984d..2ef0de36f 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateSequenceTest.java @@ -39,11 +39,21 @@ public void testCreateSequence_withIncrement() throws JSQLParserException { statement); } + @Test + public void testCreateSequence_withIncrementPostres() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("CREATE SEQUENCE db.schema.my_seq INCREMENT 1"); + } + @Test 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"); 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 6b2e67507..de3f389ab 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateTableTest.java @@ -219,6 +219,17 @@ 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 testCreateTableIfNotExists() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("CREATE TABLE IF NOT EXISTS animals (id INT NOT NULL)"); @@ -341,6 +352,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( @@ -1073,4 +1109,15 @@ void testUniqueAfterForeignKeyIssue2082() throws JSQLParserException { ", 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 5e100d125..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,6 +27,15 @@ 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"; 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 7981cc819..2b7bab5e9 100644 --- a/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/delete/DeleteTest.java @@ -25,7 +25,9 @@ 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; @@ -397,4 +399,19 @@ public void testDeleteWithSkylineKeywords() throws JSQLParserException { 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 a97eed829..a48b2fe7d 100644 --- a/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/drop/DropTest.java @@ -53,6 +53,16 @@ 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\"")); @@ -98,6 +108,7 @@ public void testDropMaterializedView() throws JSQLParserException { @Test public void testDropSchemaIssue855() throws JSQLParserException { assertSqlCanBeParsedAndDeparsed("DROP SCHEMA myschema"); + assertSqlCanBeParsedAndDeparsed("DROP SCHEMA unnamed.myschema"); } @Test 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/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 9323c440e..cd73f7dd8 100644 --- a/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java @@ -9,6 +9,20 @@ */ 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; @@ -34,21 +48,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.io.StringReader; -import java.util.List; - -import static junit.framework.Assert.assertNull; -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; - public class InsertTest { private final CCJSqlParserManager parserManager = new CCJSqlParserManager(); @@ -395,10 +394,23 @@ 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 @@ -917,4 +929,9 @@ void insertDemo() { 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/select/ClickHouseTest.java b/src/test/java/net/sf/jsqlparser/statement/select/ClickHouseTest.java index 72b8508df..39f7d8799 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/ClickHouseTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/ClickHouseTest.java @@ -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"; @@ -59,4 +99,21 @@ public void execute() throws Throwable { } }, "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()); + } } 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 index 2cb4b57fb..aad68683b 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/DuckDBTest.java @@ -25,4 +25,15 @@ void testFileTable() throws JSQLParserException { 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/NestedBracketsPerformanceTest.java b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java index b8b02dccd..acc510ec3 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/NestedBracketsPerformanceTest.java @@ -137,8 +137,7 @@ public void testRecursiveBracketExpressionIssue1019() { @Test @Timeout(2000) public void testRecursiveBracketExpressionIssue1019_2() throws JSQLParserException { - // Temporally set the maxDepth to be 6, was 8 before this - doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 8); + doIncreaseOfParseTimeTesting("IF(1=1, $1, 2)", "1", 10); } @Test @@ -531,8 +530,6 @@ void testIssue1983() throws JSQLParserException { "3,\n" + "4"; CCJSqlParserUtil.parse(sqlStr, parser -> parser - .withSquareBracketQuotation(false) - .withAllowComplexParsing(true) .withTimeOut(60000)); } 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 06d1e3d54..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,14 +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; @@ -102,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/SelectASTTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectASTTest.java index e12b51ed8..ddc578d26 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(); @@ -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)) { @@ -207,7 +207,7 @@ 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 */"); 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 cc0cbda66..6375210cc 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -58,6 +58,7 @@ 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.AbstractJSqlParser.Dialect; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; @@ -1058,6 +1059,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"; @@ -1188,6 +1210,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"; @@ -1776,10 +1804,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 @@ -2347,6 +2379,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)"; @@ -6174,6 +6219,8 @@ public void testSelectWithSkylineKeywords() throws JSQLParserException { } @Test + @Disabled + // see issue #2207 public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException { String sql = "SELECT (pg_stat_file('postgresql.conf')).*"; Statement statement = CCJSqlParserUtil.parse(sql); @@ -6192,6 +6239,8 @@ public void testSelectAllColumnsFromFunctionReturn() throws JSQLParserException } @Test + @Disabled + // see issue #2207 public void testSelectAllColumnsFromFunctionReturnWithMultipleParentheses() throws JSQLParserException { String sql = "SELECT ( ( ( pg_stat_file('postgresql.conf') ) )) . *"; @@ -6210,4 +6259,198 @@ public void testSelectAllColumnsFromFunctionReturnWithMultipleParentheses() 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/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/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..00224497f --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/select/WithItemTest.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.select; + +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); + } +} 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 1a342b42d..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(); + // 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); } } 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/test/AssortedFeatureTests.java b/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java index 07fdb858b..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; @@ -61,4 +65,54 @@ public void testIssue1608() throws JSQLParserException { "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/util/ReflectionTestUtils.java b/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java index 8be1c9275..07dec9f07 100644 --- a/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java +++ b/src/test/java/net/sf/jsqlparser/util/ReflectionTestUtils.java @@ -129,7 +129,7 @@ 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) { @@ -140,7 +140,7 @@ public static void testMethodInvocation(Object object, } } if (testMethod) { - log(Level.INFO, "testing method " + m.toGenericString()); + log(Level.FINE, "testing method " + m.toGenericString()); try { invoke(m, returnTypeCheck, argsFunction, object); } catch (Exception e) { diff --git a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java index 19a619c88..ff629a2e8 100644 --- a/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java +++ b/src/test/java/net/sf/jsqlparser/util/TablesNamesFinderTest.java @@ -26,6 +26,7 @@ import java.util.Set; 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; @@ -54,6 +55,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 = @@ -480,6 +489,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;"; @@ -681,5 +697,48 @@ void testIssue2183() throws JSQLParserException { 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"); + } +} 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 1a8f75d81..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; @@ -72,7 +72,7 @@ public StringBuilder visit(Column tableColumn, K parameters) { 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()); @@ -80,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/ExpressionDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java index 09ba90dc6..dd0df1fe0 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/ExpressionDeParserTest.java @@ -147,11 +147,11 @@ public void shouldDeParseComplexAnalyticExpressionWithPartitionExpressionList() 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, null); will(appendToBuffer("partition expression 2")).given(partitionExpression2) 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 1b129e6a2..23b3927e6 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java @@ -129,7 +129,7 @@ public void shouldUseProvidedDeparsersWhenDeParsingInsert() { then(withItem2).should().accept((SelectVisitor) selectDeParser, null); then(select).should().accept((SelectVisitor) selectDeParser, null); then(duplicateUpdateExpression1).should().accept(expressionDeParser, null); - then(duplicateUpdateExpression1).should().accept(expressionDeParser, null); + then(duplicateUpdateExpression2).should().accept(expressionDeParser, null); } // @Test 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..328f42a4e 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,6 @@ 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 \ 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 dee98af89..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 @@ -13,4 +13,5 @@ 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 ---@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Feb 8, 2025, 6:46:21 AM \ No newline at end of file +--@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 1822a3e2c..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 @@ -14,4 +14,5 @@ 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 ---@FAILURE: Encountered unexpected token: "cust_address2_ntab" recorded first on Feb 8, 2025, 6:46:21 AM \ No newline at end of file +--@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 1b4605011..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 @@ -17,4 +17,5 @@ select deptno deptno --@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 \ No newline at end of file +--@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 0de9ec128..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 @@ -19,4 +19,5 @@ select owner , object_type --@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 \ No newline at end of file +--@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..84086cffc 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,6 @@ 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 \ 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..d2ae24b1e 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,6 @@ 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 \ 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..dcedbdc18 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,5 @@ 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 \ 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..d6295170c 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,5 @@ 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 \ 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..2b4866121 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,6 @@ 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 \ 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/explain01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/explain01.sql index f58d9c7d0..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 @@ -18,4 +18,5 @@ explain plan --@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 ---@FAILURE: Encountered unexpected token: "plan" "PLAN" recorded first on 23 Aug 2024, 21:35:20 \ No newline at end of file +--@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..da5b94826 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,5 @@ 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 \ 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..aa451e33f 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,6 @@ 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 \ 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..16c4ef662 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,5 @@ 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 \ 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..c68c64fc2 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,5 @@ 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 \ 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..58eb0fb87 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,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 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/insert07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/insert07.sql index b2d203861..6122702ef 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,5 @@ 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 \ 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/lexer01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/lexer01.sql index bf0f6c5e9..6f9c540cd 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 @@ -11,4 +11,5 @@ 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 ---@FAILURE: Encountered unexpected token: "^" "^" recorded first on Jul 11, 2024, 9:09:49 AM \ No newline at end of file +--@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 \ 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_factoring04.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring04.sql index d9f54f9b1..0caeb5305 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 @@ -27,4 +27,5 @@ order by order1 --@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 \ No newline at end of file +--@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 \ 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 248f24eb3..8b2bd85af 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 @@ -42,4 +42,5 @@ select root,lev,obj,link,path,cycle, --@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 \ No newline at end of file +--@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 \ 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 58588003a..33e358d16 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 @@ -23,4 +23,5 @@ from dup_hiredate order by order1 --@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 \ No newline at end of file +--@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 \ 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 859eda67d..806075e17 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 @@ -23,4 +23,5 @@ 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 ---@FAILURE: Encountered unexpected token: "union" "UNION" recorded first on Feb 13, 2025, 10:16:06 AM \ No newline at end of file +--@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 \ 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/union06.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/union06.sql index c88c42aee..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 @@ -44,4 +44,5 @@ order by 4,3,1 --@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 \ No newline at end of file +--@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/xmltable01.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/xmltable01.sql index 4a503456e..3c7e35f56 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,6 @@ 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 \ No newline at end of file diff --git a/src/test/resources/simple_parsing.txt b/src/test/resources/simple_parsing.txt index 40824e8f2..30e335a9e 100644 --- a/src/test/resources/simple_parsing.txt +++ b/src/test/resources/simple_parsing.txt @@ -210,4 +210,275 @@ 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; \ No newline at end of file +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