diff --git a/.codacy.yml b/.codacy.yml new file mode 100644 index 000000000..d98077f4f --- /dev/null +++ b/.codacy.yml @@ -0,0 +1,3 @@ +--- +exclude_paths: + - "site/**" diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..5926aa29f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: https://paypal.me/wumpz diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..e79696ec8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,41 @@ +--- +name: @ SQL Parser Error +about: Create a report to help us improve +title: '[BUG] JSQLParser Version : RDBMS : failing feature description' +labels: 'Parser Error', 'Feature Request', 'Documentation', 'Java API', 'RDBMS support' +assignees: '' + +--- + + + +### Failing SQL Feature: + + +### SQL Example: + + +### Software Information: + + +### Tips: + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..9003b51e1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,31 @@ +--- +name: Feature request +about: Suggest an unsupported Statement or Expression +title: "[FEATURE] missing feature description" +labels: '' +assignees: '' + +--- + +### Grammar or Syntax Description +- Brief description of the failing SQL feature and the EBNF +- Example: `WITH ROLLUP` clause is not supported yet + +### SQL Example +- Simplified Query Example, focusing on the failing feature + ```sql + -- Replace with your ACTUAL example + select 1 + from dual + ``` +- Please don't send screen shots + +### Additional context +The used JSQLParser Version (please test the latest SNAPSHOT version before submitting). +State the applicable RDBMS and version +Links to the reference documentation + +### Tips: + diff --git a/.github/ISSUE_TEMPLATE/sql-parser-error.md b/.github/ISSUE_TEMPLATE/sql-parser-error.md new file mode 100644 index 000000000..2a5eaf28f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/sql-parser-error.md @@ -0,0 +1,31 @@ +--- +name: SQL Parser Error +about: Report a Parser Error +title: "[BUG] JSQLParser Version : RDBMS : failing feature description" +labels: '' +assignees: '' + +--- + +Always check against the **Latest SNAPSHOT of JSQLParser** and the [Syntax Diagram](https://jsqlparser.github.io/JSqlParser/syntax_snapshot.html) + +### Failing SQL Feature: +- Brief description of the failing SQL feature +- Example: `WITH ROLLUP` can't be parsed + +### SQL Example: +- Simplified Query Example, focusing on the failing feature + ```sql + -- Replace with your ACTUAL example + select 1 + from dual + ``` + +### Software Information: +- JSqlParser version +- Database (e. g. Oracle, MS SQL Server, H2, PostgreSQL, IBM DB2 ) + +### Tips: +Please write in English and avoid Screenshots (as we can't copy and paste content from it). +[Try your example online with the latest JSQLParser](http://jsqlformatter.manticore-projects.com) and share the link in the error report. +Do provide Links or References to the specific Grammar and Syntax you are trying to use. diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 000000000..b9134ea9a --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,8 @@ +changelog: + categories: + - title: Bugs solved + labels: + - "bug" + - title: Changes and new Features + labels: + - "*" \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..a3108f35b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,104 @@ +name: CI Pipeline + +on: + push: + branches: [ "**" ] # Run on every commit to any branch + pull_request: + branches: [ "**" ] # Run for PRs from any branch + workflow_dispatch: + +permissions: write-all + +jobs: + gradle_check: + name: Gradle Check + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest, macos-latest ] + steps: + - uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@main + with: + java-version: '17' + distribution: 'temurin' + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@main + + - name: Run Gradle Check + run: ./gradlew check + + maven_verify: + name: Maven Verify + needs: gradle_check # ✅ Run only after Gradle check succeeds + runs-on: ${{ matrix.os }} + strategy: + matrix: +# os: [ ubuntu-latest, windows-latest, macos-latest ] + os: [ ubuntu-latest, macos-latest ] + steps: + - uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@main + with: + java-version: '17' + distribution: 'temurin' + + - name: Run Maven Verify + run: mvn --batch-mode verify + + gradle_publish: + name: Gradle Publish + needs: [ gradle_check, maven_verify ] # ✅ Run only after both succeed + if: github.ref == 'refs/heads/master' && github.repository == 'JSQLParser/JSqlParser' # ✅ Only for master branch of main repo + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@main + with: + java-version: '17' + distribution: 'temurin' + + - name: Build with Gradle + uses: gradle/actions/setup-gradle@main + + - name: Publish with Gradle + run: ./gradlew publish + env: + ossrhUsername: ${{ secrets.OSSRHUSERNAME }} + ossrhPassword: ${{ secrets.OSSRHPASSWORD }} + + - uses: actions/setup-python@main + + - name: Install XSLT Processor + run: sudo apt-get install -y xsltproc sphinx-common + + - name: Install Python dependencies + run: pip install manticore_sphinx_theme sphinx_javadoc_xml myst_parser sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments + + - name: Build Sphinx documentation with Gradle + run: FLOATING_TOC=false ./gradlew -DFLOATING_TOC=false gitChangelogTask renderRR xslt xmldoc sphinx + + - name: Configure GitHub Pages + uses: actions/configure-pages@main + + - name: Upload artifact + uses: actions/upload-pages-artifact@main + with: + path: 'build/sphinx' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@main diff --git a/.gitignore b/.gitignore index 82e76e091..955e7bf2d 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,17 @@ # Generated by maven /target +/build +/out + +# Sphinx Theme related stuff, which shall be downloaded separately +/src/site/sphinx/_themes + +# Exclude the Auto-generated Changelog +/src/site/sphinx/changelog.rst +/src/site/sphinx/syntax_stable.rst +/src/site/sphinx/syntax_snapshot.rst +/src/site/sphinx/javadoc_stable.xml +/src/site/sphinx/javadoc_snapshot.xml # Generated by javacc-maven-plugin /bin @@ -17,4 +29,9 @@ *.jj~ *.java~ *.yml~ -/nbproject/ \ No newline at end of file +/nbproject/ + +/.gradle + +# Mac +.DS_Store diff --git a/.travis.yml b/.travis.yml index cd8afcc1b..581903065 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,13 @@ language: java jdk: - - openjdk7 - - oraclejdk8 + - openjdk8 + - openjdk11 after_success: - - mvn clean cobertura:cobertura coveralls:report \ No newline at end of file + - mvn clean cobertura:cobertura coveralls:report + +cache: + directories: + - $HOME/.m2 + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ \ No newline at end of file diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 868916df8..000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,15 +0,0 @@ -### Actual Behavior - -### Expected Behavior - -### Steps to Reproduce the Problem - - 1. - 1. - 1. - -### Specifications - - - Version: - - Platform: - - Subsystem: diff --git a/README.md b/README.md index 679993759..42122c891 100644 --- a/README.md +++ b/README.md @@ -1,132 +1,122 @@ -# JSqlParser +# [JSqlParser 5.3 Website](https://jsqlparser.github.io/JSqlParser) drawing -[![Build Status](https://travis-ci.org/JSQLParser/JSqlParser.svg?branch=master)](https://travis-ci.org/JSQLParser/JSqlParser) [![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/00b2d91995764ae4805b55627aca8d39)](https://www.codacy.com/app/wumpz/JSqlParser?utm_source=github.com&utm_medium=referral&utm_content=JSQLParser/JSqlParser&utm_campaign=Badge_Grade) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser/badge.svg)](http://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser) -[![Javadocs](https://www.javadoc.io/badge/com.github.jsqlparser/jsqlparser.svg)](https://www.javadoc.io/doc/com.github.jsqlparser/jsqlparser) +[![CI](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml) +[![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/6f9a2d7eb98f45969749e101322634a1)](https://www.codacy.com/gh/JSQLParser/JSqlParser/dashboard?utm_source=github.com&utm_medium=referral&utm_content=JSQLParser/JSqlParser&utm_campaign=Badge_Grade) +[![Maven Central](https://img.shields.io/maven-central/v/com.github.jsqlparser/jsqlparser.svg?label=maven-central)](https://central.sonatype.com/artifact/com.github.jsqlparser/jsqlparser) [![Javadocs](https://www.javadoc.io/badge/com.github.jsqlparser/jsqlparser.svg)](https://www.javadoc.io/doc/com.github.jsqlparser/jsqlparser) +[![Gitter](https://badges.gitter.im/JSQLParser/JSqlParser.svg)](https://gitter.im/JSQLParser/JSqlParser?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) -[![PayPal donate button](http://img.shields.io/paypal/donate.png?color=blue)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=64CCN9JJANZXA "Help this JSqlParser version using Paypal") +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! -[![Gitter](https://badges.gitter.im/JSQLParser/JSqlParser.svg)](https://gitter.im/JSQLParser/JSqlParser?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +## Summary -Look here for more information and examples: https://github.com/JSQLParser/JSqlParser/wiki. +Please visit our [WebSite](https://jsqlparser.github.io/JSqlParser) for detailed information. **JSqlParser** is a RDBMS agnostic SQL statement parser. It translates SQL statements into a traversable hierarchy of Java classes (see [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#parse-a-sql-statements)): -## License +```sql +SELECT 1 FROM dual WHERE a = b -JSqlParser is dual licensed under **LGPL V2.1** and **Apache Software License, Version 2.0**. +/* produces the following AST +SQL Text + └─Statements: statement.select.PlainSelect + ├─selectItems: statement.select.SelectItem + │ └─LongValue: 1 + ├─Table: dual + └─where: expression.operators.relational.EqualsTo + ├─Column: a + └─Column: b +*/ +``` -## News -* Changed behaviour of dotted multipart names for user variables, tables and columns to accept e.g. ORM class names. To achieve this some behaviour of name parsing had to be changed. Before this the parser would fail missing databasenames for SqlServer queries (server..schema.table). But this is allowed for the schema (server.database..table). Now the parser accepts missing inner names per se to avoid some very complicated parsing rules. -* Released version **1.2** of JSqlParser -* breaking **API** change: merge of *within group* and *over* (window expressions) -* Released version **1.1** of JSqlParser. -* JSqlParser has now a build in checkstyle configuration to introduce source code conventions. -* Released first major version **1.0** of JSqlParser. +```java +String sqlStr = "select 1 from dual where a=b"; + +PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); -More news can be found here: https://github.com/JSQLParser/JSqlParser/wiki/News. +SelectItem selectItem = + select.getSelectItems().get(0); +Assertions.assertEquals( + new LongValue(1) + , selectItem.getExpression()); -## JSqlParser +Table table = (Table) select.getFromItem(); +Assertions.assertEquals("dual", table.getName()); -JSqlParser is a SQL statement parser. It translates SQLs in a traversable hierarchy of Java classes. JSqlParser is not limited to one database but provides support for a lot of specials of Oracle, SqlServer, MySQL, PostgreSQL ... To name some, it has support for Oracles join syntax using (+), PostgreSQLs cast syntax using ::, relational operators like != and so on. +EqualsTo equalsTo = (EqualsTo) select.getWhere(); +Column a = (Column) equalsTo.getLeftExpression(); +Column b = (Column) equalsTo.getRightExpression(); +Assertions.assertEquals("a", a.getColumnName()); +Assertions.assertEquals("b", b.getColumnName()); +``` +## Support for `Piped SQL` + +Work is progressing for parsing `Piped SQL`, a much saner and more logical way to write queries in its semantic order. +```sql +FROM Produce +|> WHERE + item != 'bananas' + AND category IN ('fruit', 'nut') +|> AGGREGATE COUNT(*) AS num_items, SUM(sales) AS total_sales + GROUP BY item +|> ORDER BY item DESC; +``` -## Support -If you need help using JSqlParser feel free to file an issue or contact me. +For details, please see https://storage.googleapis.com/gweb-research2023-media/pubtools/1004848.pdf, https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax and https://duckdb.org/docs/sql/query_syntax/from.html#from-first-syntax -## Contributions -To help JSqlParsers development you are encouraged to provide -* feedback -* bugreports -* pull requests for new features -* improvement requests -* fund new features -* a little donation +## Java Version -**Please write in english, since it's the language most of the dev team knows.** +JSQLParser-4.9 was the last JDK8 compatible version. JSQLParser-5.0 and later depend on JDK11 and introduce API breaking changes to the AST Visitors. Please see the Migration Guide for the details. -Also I would like to know about needed examples or documentation stuff. +Building JSQLParser-5.1 and newer with Gradle will depend on a JDK17 toolchain due to the used plugins. -## Extensions in the latest SNAPSHOT version 1.3 +JSQLParser-5.4 Snapshot and later use JavaCC-8 Snapshots for generating the parser. -* support for additional raw string and byte prefixes (issue #659) -* support for special oracle type syntax **varchar2(255 BYTE)** (issue #273) -* introduced dotted multipart names for uservariables (issue #608) -* changed behaviour of dotted multipart names for tables and columns to accept ORM class names (issue #163) -** the parser allows now empty inner names, to still accept missing schema names for SQLServer (db..col) -** methods like **getDatabase** will still work but have no sense using it for classnames -* named parameter for **OFFSET** (issue #612) -* corrected ISNULL regression (issue #610) -* refactored statement test classes to the class corresponding packages -* allowed nested postgresql casts (e.g. col::bigint::int) +## 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. -## Extensions of JSqlParser releases +As per March-2026, the productions `Condition()`, `RegularCondition()` and `AndExpression()` have been refactored successfully. Furthermore, we have overhauled Token definition and handling of Reserved Keywords. This resulted in a massive performance boost and seem to have solved most of the performance issues. -* [Release Notes](https://github.com/JSQLParser/JSqlParser/releases) -* Modifications before GitHubs release tagging are listed in the [Older Releases](https://github.com/JSQLParser/JSqlParser/wiki/Older-Releases) page. +```text +Benchmark (version) Mode Cnt Score Error Units +JSQLParserBenchmark.parseSQLStatements latest avgt 15 7.602 ± 0.135 ms/op <-- March/26 +JSQLParserBenchmark.parseSQLStatements 5.3 avgt 15 84.687 ± 3.321 ms/op +JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 86.592 ± 5.781 ms/op +``` +## [Supported Grammar and Syntax](https://jsqlparser.github.io/JSqlParser/syntax.html) -## Building from the sources +**JSqlParser** aims to support the SQL standard as well as all major RDBMS. Any missing syntax or features can be added on demand. -As the project is a Maven project, building is rather simple by running: +| RDBMS | Statements | +|-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| +| BigQuery
Snowflake
DuckDB
Redshift
Oracle
MS SQL Server and Sybase
Postgres
MySQL and MariaDB
DB2
H2 and HSQLDB and Derby
SQLite | `SELECT`
`INSERT`, `UPDATE`, `UPSERT`, `MERGE`
`DELETE`, `TRUNCATE TABLE`
`CREATE ...`, `ALTER ....`, `DROP ...`
`WITH ...` | +| PostgreSQL Row Level Security | `CREATE POLICY`
`ALTER TABLE ... ENABLE/DISABLE/FORCE/NO FORCE ROW LEVEL SECURITY` | +| Salesforce SOQL | `INCLUDES`, `EXCLUDES` | +| Piped SQL (also known as FROM SQL) | | - mvn package - -The project requires the following to build: -- Maven -- JDK 1.7 or later. The jar will target JDK 1.6, but the version of the maven-compiler-plugin that JsqlParser uses requires JDK 1.7+ +**JSqlParser** can also be used to create SQL Statements from Java Code with a fluent API (see [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#build-a-sql-statements)). -This will produce the jsqlparser-VERSION.jar file in the target/ directory. +## Sister Projects -**To build this project without using Maven, one has to build the parser by JavaCC using the CLI options it provids.** +If you like JSqlParser then please check out its related projects: -## Debugging through problems +* [JSQLFormatter](https://manticore-projects.com/JSQLFormatter/index.html) for pretty printing and formatting SQL Text -Refer to the [Visualize Parsing](https://github.com/JSQLParser/JSqlParser/wiki/Examples-of-SQL-parsing#visualize-parsing) section to learn how to run the parser in debug mode. +* [JSQLTranspiler](https://manticore-projects.com/JSQLTranspiler/index.html) for dialect specific rewriting, SQL Column resolution and Lineage, provided by [Starlake.ai](https://starlake.ai/) -## Source Code conventions +## Alternatives to JSqlParser? -Recently a checkstyle process was integrated into the build process. JSqlParser follows the sun java format convention. There are no TABs allowed. Use spaces. +Alternatively the dual-licensed [JOOQ](https://www.jooq.org/doc/latest/manual/sql-building/sql-parser/) provides a handwritten Parser supporting a lot of RDBMS, translation between dialects, SQL transformation, can be used as a JDBC proxy for translation and transformation purposes. -```java -public void setUsingSelect(SubSelect usingSelect) { - this.usingSelect = usingSelect; - if (this.usingSelect != null) { - this.usingSelect.setUseBrackets(false); - } -} -``` +## [Documentation](https://jsqlparser.github.io/JSqlParser) + 1. [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#parse-a-sql-statements) + 2. [Build Instructions](https://jsqlparser.github.io/JSqlParser/usage.html) and [Maven Artifact](https://jsqlparser.github.io/JSqlParser/usage.html#build-dependencies) + 3. [Contribution](https://jsqlparser.github.io/JSqlParser/contribution.html) + 4. [Change Log](https://jsqlparser.github.io/JSqlParser/changelog.html#latest-changes-since-jsqlparser-version) + 5. [Issues](https://github.com/JSQLParser/JSqlParser/issues) -This is a valid piece of source code: -* blocks without braces are not allowed -* after control statements (if, while, for) a whitespace is expected -* the opening brace should be in the same line as the control statement - -## Maven Repository - -JSQLParser is deployed at sonatypes open source maven repository. -Starting from now I will deploy there. The first snapshot version there will be 0.8.5-SNAPSHOT. -To use it this is the repository configuration: - -```xml - - - jsqlparser-snapshots - - true - - https://oss.sonatype.org/content/groups/public/ - - -``` -This repositories releases will be synched to maven central. Snapshots remain at sonatype. - -And this is the dependency declaration in your pom: -```xml - - com.github.jsqlparser - jsqlparser - 1.2 - -``` +## License +**JSqlParser** is dual licensed under **LGPL V2.1** or **Apache Software License, Version 2.0**. diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..a690cef6b --- /dev/null +++ b/build.gradle @@ -0,0 +1,809 @@ +import se.bjurr.gitchangelog.plugin.gradle.GitChangelogTask +import com.nwalsh.gradle.saxon.SaxonXsltTask + +import java.time.Instant + +buildscript { + dependencies { + classpath group: 'net.sf.saxon', name: 'Saxon-HE', version: 'latest.release' + } +} + +plugins { + id 'java' + id 'maven-publish' + id 'signing' + + id "org.javacc.javacc" version "latest.release" + id 'jacoco' + id 'com.github.kt3k.coveralls' version "latest.release" + id "com.github.spotbugs" version "latest.release" + id "com.diffplug.spotless" version "latest.release" + id 'pmd' + id 'checkstyle' + id 'eclipse' + + // download the RR tools which have no Maven Repository + id "de.undercouch.download" version "latest.release" + id 'org.hidetake.ssh' version "latest.release" + + id "se.bjurr.gitchangelog.git-changelog-gradle-plugin" version "latest.release" + id "me.champeau.jmh" version "latest.release" + id "com.nwalsh.gradle.saxon.saxon-gradle" version "latest.release" + id 'biz.aQute.bnd.builder' version "latest.release" +} + +def getVersion = { boolean considerSnapshot -> + Integer major = 0 + Integer minor = 0 + Integer patch = null + Integer build = null + String commit = null + String snapshot = "" + + def versionStr = providers.exec { + commandLine "git", "--no-pager", "-C", project.projectDir, "describe", "--tags", "--always", "--dirty=-SNAPSHOT" + }.standardOutput.asText.get().trim() + + def pattern = /jsqlparser-(?\d*)\.(?\d*)(\.(?\d*))?(-(?\d*)-(?[a-zA-Z\d]*))?/ + def matcher = versionStr =~ pattern + + if (matcher.find()) { + major = matcher.group('major') as Integer ?: 0 + minor = matcher.group('minor') as Integer ?: 0 + patch = matcher.group('patch') as Integer ?: null + build = matcher.group('build') as Integer ?: null + commit = matcher.group('commit') ?: null + } + + if (considerSnapshot && (versionStr.endsWith('SNAPSHOT') || build != null)) { + minor++ + if (patch != null) patch = 0 + snapshot = "-SNAPSHOT" + } + + return patch != null + ? "${major}.${minor}.${patch}${snapshot}" + : "${major}.${minor}${snapshot}" +} + + +// for publishing a release, call Gradle with Environment Variable RELEASE: +// RELEASE=true gradle JSQLParser:publish +version = getVersion( !System.getenv("RELEASE") ) +group = 'com.github.jsqlparser' +description = 'JSQLParser library' + +tasks.register('generateBuildInfo') { + outputs.dir layout.buildDirectory.file("resources/main") + doLast { + def outputDir = new File( layout.buildDirectory.file("generated/sources/buildinfo/java/main").get().asFile, "net/sf/jsqlparser") + outputDir.mkdirs() + + def gitVersionStr = providers.exec { + commandLine "git", "--no-pager", "-C", project.projectDir, "describe", "--tags", "--always", "--dirty=-SNAPSHOT" + }.standardOutput.asText.get().trim() + + def gitCommitStr = providers.exec { + commandLine "git", "--no-pager", "-C", project.projectDir, "rev-parse", "--short", "HEAD" + }.standardOutput.asText.get().trim() + + def buildTime = Instant.now().toString() + + def content = """\ + |package net.sf.jsqlparser; + | + |public final class BuildInfo { + | public static final String NAME = "${project.name}"; + | public static final String VERSION = "${gitVersionStr}"; + | public static final String GIT_COMMIT = "${gitCommitStr ?: 'unknown'}"; + | public static final String BUILD_TIME = "${buildTime}"; + |} + """.stripMargin() + + new File(outputDir, "BuildInfo.java").text = content + } +} + +// Make sure the file is included in the compiled sources +sourceSets { + main { + java { + srcDir layout.buildDirectory.file("generated/sources/buildinfo/java/main").get().asFile + } + } +} + +tasks.withType(JavaCompile).configureEach { + mustRunAfter("generateBuildInfo") +} + +tasks.withType(Pmd).configureEach { + mustRunAfter("generateBuildInfo") +} + +tasks.withType(Checkstyle).configureEach { + exclude '**/module-info.java', '**/package-info.java' + + mustRunAfter("generateBuildInfo") +} + +repositories { + gradlePluginPortal() + mavenCentral() + + // JavaCC 8 Snapshots + maven { + url = uri('https://central.sonatype.com/repository/maven-snapshots/') + } + + maven { url "https://dev.saxonica.com/maven" } +} + +configurations { + xmlDoclet +} + +dependencies { + testImplementation 'commons-io:commons-io:2.+' + testImplementation 'org.apache.commons:commons-text:+' + testImplementation 'org.mockito:mockito-core:+' + testImplementation 'org.assertj:assertj-core:+' + testImplementation 'org.hamcrest:hamcrest-core:+' + testImplementation 'org.apache.commons:commons-lang3:+' + testImplementation 'com.h2database:h2:+' + + // for JaCoCo Reports + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.11.4' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.4' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.4' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.4' + + // https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter + testImplementation 'org.mockito:mockito-junit-jupiter: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:+'){ changing = true } + + // enforce latest version of 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', + // Comment this in to build the parser with tracing. + DEBUG_PARSER: 'false', + DEBUG_LOOKAHEAD: 'false' + ] +} + +// Post-process the generated CCJSqlParserTokenManager.java to split large static +// array initializers into separate methods, preventing the method from +// exceeding the JVM's 64KB bytecode limit (which breaks ASM-based tools like sbt-assembly). +tasks.register('splitTokenManagerStaticInit') { + dependsOn(compileJavacc) + + def tokenManagerFile = layout.buildDirectory.file( + "generated/javacc/net/sf/jsqlparser/parser/CCJSqlParserTokenManager.java" + ) + + inputs.file(tokenManagerFile) + outputs.file(tokenManagerFile) + + doLast { + def file = tokenManagerFile.get().asFile + if (!file.exists()) { + throw new GradleException("CCJSqlParserTokenManager.java not found at ${file}") + } + def content = file.text + + // Pattern matches static final array field declarations with inline initialization. + // We extract large ones and move their initialization into separate methods. + def fieldsToExtract = [ + // [regex-safe field name, array type for method return] + ['stringLiterals', 'int[]'], + ['jjstrLiteralImages', 'String[]'], + ['jjmatchKinds', 'int[]'], + ['jjnewLexState', 'int[]'], + ] + + fieldsToExtract.each { entry -> + def fieldName = entry[0] + def arrayType = entry[1] + + // Match: = { ... }; + // The field declaration may use 'public' or 'private' and 'static final' + def pattern = ~"(?s)((?:public|private)\\s+static\\s+final\\s+${java.util.regex.Pattern.quote(arrayType)}\\s+${fieldName}\\s*=\\s*)\\{(.*?)\\};" + def matcher = pattern.matcher(content) + if (matcher.find()) { + def prefix = matcher.group(1) + def body = matcher.group(2) + def methodName = "_init_${fieldName}" + def replacement = "${prefix}${methodName}();\n" + + " private static ${arrayType} ${methodName}() { return new ${arrayType} {${body}}; }" + content = matcher.replaceFirst(java.util.regex.Matcher.quoteReplacement(replacement)) + logger.lifecycle("splitTokenManagerStaticInit: extracted ${fieldName} initialization into ${methodName}()") + } + } + + // Handle int[][] arrays separately (jjcompositeState, jjnextStateSet) + def arrayArrayFields = ['jjcompositeState', 'jjnextStateSet'] + arrayArrayFields.each { fieldName -> + def pattern = ~"(?s)(private\\s+static\\s+final\\s+int\\[\\]\\[\\]\\s+${fieldName}\\s*=\\s*)\\{(.*?)\\};" + def matcher = pattern.matcher(content) + if (matcher.find()) { + def prefix = matcher.group(1) + def body = matcher.group(2) + def methodName = "_init_${fieldName}" + def replacement = "${prefix}${methodName}();\n" + + " private static int[][] ${methodName}() { return new int[][] {${body}}; }" + content = matcher.replaceFirst(java.util.regex.Matcher.quoteReplacement(replacement)) + logger.lifecycle("splitTokenManagerStaticInit: extracted ${fieldName} initialization into ${methodName}()") + } + } + + file.text = content + } +} + +tasks.withType(JavaCompile).configureEach { + dependsOn('splitTokenManagerStaticInit') +} + +java { + withSourcesJar() + withJavadocJar() + + sourceCompatibility = '11' + targetCompatibility = '11' + + // needed for XML-Doclet to work (since Doclet changed again with Java 13) + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +javadoc { + include("build/generated/javacc/net/sf/jsqlparser/parser/*.java" ) + if(JavaVersion.current().isJava9Compatible()) { + options.addBooleanOption('html5', true) + } + options.addBooleanOption("Xdoclint:none", true) +} + +jar { + manifest { + attributes ( + "Automatic-Module-Name": "net.sf.jsqlparser" + ) + } + + bundle { + properties.empty() + bnd( + "Created-By": System.properties.get('user.name'), + "Bundle-SymbolicName": "net.sf.jsqlparser", + "Import-Package": "*", + "Export-Package": "net.sf.jsqlparser.*", + "Automatic-Module-Name": "net.sf.jsqlparser" + ) + } + + dependsOn(generateBuildInfo) +} + +tasks.register('xmldoc', Javadoc) { + dependsOn(compileJavacc) + + def outFile = reporting.file( + version.endsWith("-SNAPSHOT") + ? "xmlDoclet/javadoc_snapshot.xml" + : "xmlDoclet/javadoc_stable.xml" + ) + + source = sourceSets.main.allJava + // 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.addStringOption("basePackage", "net.sf.jsqlparser") + options.addStringOption("filename", outFile.getName()) + + doLast { + copy { + from outFile + into layout.projectDirectory.dir("src/site/sphinx/").asFile + } + } +} + +test { + environment = [ 'EXPORT_TEST_TO_FILE': 'False' ] + useJUnitPlatform() + + // set heap size for the test JVM(s) + minHeapSize = "1G" + maxHeapSize = "4G" + + // set JVM stack size + jvmArgs = ['-Xss2m', '--add-opens=java.base/java.lang=ALL-UNNAMED'] + + jacoco { + excludes = ['net/sf/jsqlparser/parser/CCJSqlParserTokenManager'] + } +} + +coveralls { + jacocoReportPath 'build/reports/jacoco/test/jacocoTestReport.xml' +} + +jacocoTestReport { + dependsOn test // tests are required to run before generating the report + reports { + xml.required = false + csv.required = false + html.outputLocation = layout.buildDirectory.dir('reports/jacoco') + } +} +jacocoTestCoverageVerification { + // Jacoco can't handle the TokenManager class + afterEvaluate { + classDirectories.setFrom(files(classDirectories.files.collect { + fileTree(dir: it, exclude: [ + "**CCJSqlParserTokenManager**" + ]) + })) + } + violationRules { + rule { + //element = 'CLASS' + limit { + //@todo: temporarily reduced it 80%, we need to bring that back to 84% accepting the Keywords PR + minimum = 0.50 + } + excludes = [ + 'net.sf.jsqlparser.util.validation.*', + 'net.sf.jsqlparser.**.*Adapter', + 'net.sf.jsqlparser.parser.**' + ] + } + rule { + //element = 'CLASS' + limit { + counter = 'LINE' + value = 'MISSEDCOUNT' + + //@todo: temporarily increased to 7000, we need to bring that down to 5500 after accepting the Keywords PR + maximum = 20000 + } + excludes = [ + 'net.sf.jsqlparser.util.validation.*', + 'net.sf.jsqlparser.**.*Adapter', + 'net.sf.jsqlparser.parser.**' + ] + } +// rule { +// element = 'CLASS' +// limit { +// counter = 'LINE' +// value = 'MISSEDRATIO' +// maximum = 0.3 +// } +// excludes = [ +// 'net.sf.jsqlparser.util.validation.*', +// 'net.sf.jsqlparser.**.*Adapter', +// 'net.sf.jsqlparser.parser.**' +// ] +// } + } +} + +spotbugsMain { + reports { + html.required.set(true) + html.outputLocation.set( layout.buildDirectory.file("reports/spotbugs/main/spotbugs.html").get().asFile ) + html.stylesheet="fancy-hist.xsl" + } +} + + +spotbugs { + // fail only on P1 and without the net.sf.jsqlparser.parser.* + excludeFilter = file("config/spotbugs/spotBugsExcludeFilter.xml") +} + +// do not run over the test, although we should do that eventually +tasks.named('spotbugsTest').configure { + enabled = false +} + +pmd { + // later versions throw NPE + toolVersion = '7.17.0' + + consoleOutput = true + sourceSets = [sourceSets.main] + + // clear the ruleset in order to use configured rules only + ruleSets = [] + rulesMinimumPriority = 2 + ruleSetFiles = files("config/pmd/ruleset.xml") +} + +tasks.named('pmdMain').configure { + excludes = [ + "build/generated/*" + , "**/net/sf/jsqlparser/parser/SimpleCharStream.java" + ] +} + +checkstyle { + sourceSets = [sourceSets.main, sourceSets.test] + 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' + + format 'misc', { + // define the files to apply `misc` to + target '*.rst', '*.md', '.gitignore' + + // define the steps to apply to those files + trimTrailingWhitespace() + leadingTabsToSpaces(4) + endWithNewline() + } + java { + leadingTabsToSpaces(4) + eclipse().configFile('config/formatter/eclipse-java-google-style.xml') + } +} + + +tasks.register('renderRR') { + dependsOn(compileJavacc) + + doLast { + def rrDir = layout.buildDirectory.dir("rr").get().asFile + + // Download convert.war + download.run { + src 'http://manticore-projects.com/download/convert.war' + dest new File(rrDir, "convert.war") + overwrite false + onlyIfModified true + } + + // Download rr.war + download.run { + src 'http://manticore-projects.com/download/rr.war' + dest new File(rrDir, "rr.war") + overwrite false + onlyIfModified true + tempAndMove true + } + + // Convert JJ file to EBNF + def ebnfFile = new File(rrDir, "JSqlParserCC.ebnf") + def jjFile = layout.buildDirectory.dir("generated/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jj").get().asFile.absolutePath + + def convertProc = new ProcessBuilder('java', '-jar', + new File(rrDir, "convert.war").absolutePath, + jjFile) + .redirectOutput(ebnfFile) + .redirectErrorStream(true) + .start() + if (convertProc.waitFor() != 0) { + throw new GradleException("Failed to convert JJ to EBNF") + } + + // Generate RR diagrams + def rrProc = new ProcessBuilder('java', '-jar', + new File(rrDir, "rr.war").absolutePath, + "-noepsilon", + "-color:#4D88FF", + "-offset:0", + "-width:800", + "-out:${new File(rrDir, "JSqlParserCC.xhtml")}", + new File(rrDir, "JSqlParserCC.ebnf").absolutePath) + .redirectErrorStream(true) + .start() + rrProc.inputStream.eachLine { logger.info(it) } + if (rrProc.waitFor() != 0) { + throw new GradleException("Failed to generate RR diagrams") + } + } +} + + +tasks.register('gitChangelogTask', GitChangelogTask) { + fromRepo.set( file("$projectDir").toString() ) + file.set( new File("${projectDir}/src/site/sphinx/changelog.rst") ) + fromRevision.set( "4.0") + //toRef = "1.1"; + + // switch off the formatter since the indentation matters for Mark-down + // @formatter:off + templateContent.set (""" +************************ +Changelog +************************ + + +{{#tags}} +{{#ifMatches name "^Unreleased.*"}} +Latest Changes since |JSQLPARSER_VERSION| +{{/ifMatches}} +{{#ifMatches name "^(?!Unreleased).*"}} +Version {{name}} +{{/ifMatches}} +============================================================= + + {{#issues}} + + {{#commits}} + {{#ifMatches messageTitle "^(?!Merge).*"}} + * **{{{messageTitle}}}** + + {{authorName}}, {{commitDate}} + {{/ifMatches}} + {{/commits}} + + {{/issues}} +{{/tags}} +""") + // @formatter:on +} + +tasks.register('updateKeywords', JavaExec) { + group = "Execution" + description = "Generate the Reserved Keywords documentation" + classpath = sourceSets.main.runtimeClasspath + args = [ + file('src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt').absolutePath + , file('src/site/sphinx/keywords.rst').absolutePath + ] + mainClass.set("net.sf.jsqlparser.parser.ParserKeywordsUtils") + + dependsOn(compileJava) +} + +tasks.register('xslt', SaxonXsltTask) { + def outFile = version.endsWith("-SNAPSHOT") + ? 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.getProperty("FLOATING_TOC", "false"), + "isSnapshot": Boolean.toString(version.endsWith("-SNAPSHOT")) + ) + + // Transform every .xml file in the "input" directory. + input layout.buildDirectory.file("rr/JSqlParserCC.xhtml").get() + output outFile +} + +tasks.register('sphinx', Exec) { + dependsOn(gitChangelogTask, renderRR, xslt, xmldoc) + + String PROLOG = """ +.. |_| unicode:: U+00A0 + :trim: + +.. |JSQLPARSER_EMAIL| replace:: support@manticore-projects.com +.. |JSQLPARSER_VERSION| replace:: ${getVersion(false)} +.. |JSQLPARSER_SNAPSHOT_VERSION| replace:: ${getVersion(true)} +.. |JSQLPARSER_STABLE_VERSION_LINK| raw:: html + + ${project.name}-${getVersion(false)}.jar + +.. |JSQLPARSER_SNAPSHOT_VERSION_LINK| raw:: html + + ${project.name}-${getVersion(true)}.jar + +""" + + args = [ + "-Dproject=JSQLParser" + , "-Dcopyright=Tobias Warneke, 2022" + , "-Dauthor=Tobias Warneke" + , "-Drelease=${getVersion(false)}" + , "-Drst_prolog=$PROLOG" + , "${projectDir}/src/site/sphinx" + , layout.buildDirectory.file("sphinx").get().asFile + ] + + executable "sphinx-build" + + //store the output instead of printing to the console: + standardOutput = new ByteArrayOutputStream() + + //extension method stopTomcat.output() can be used to obtain the output: + ext.output = { + return standardOutput.toString() + } +} + +publish { + dependsOn(check, gitChangelogTask, renderRR, xslt, xmldoc) +} + +publishing { + publications { + mavenJava(MavenPublication) { + artifactId = 'jsqlparser' + + from components.java + + versionMapping { + usage('java-api') { + fromResolutionOf('runtimeClasspath') + } + usage('java-runtime') { + fromResolutionResult() + } + } + + pom { + name.set('JSQLParser library') + description.set('Parse SQL Statements into Abstract Syntax Trees (AST)') + url.set('https://github.com/JSQLParser/JSqlParser') + + licenses { + license { + name.set('GNU Library or Lesser General Public License (LGPL) V2.1') + url.set('http://www.gnu.org/licenses/lgpl-2.1.html') + } + license { + name.set('The Apache Software License, Version 2.0') + url.set('http://www.apache.org/licenses/LICENSE-2.0.txt') + } + } + + developers { + developer { + id.set('twa') + name.set('Tobias Warneke') + email.set('t.warneke@gmx.net') + } + developer { + id.set('are') + name.set('Andreas Reichel') + email.set('andreas@manticore-projects.com') + } + } + + scm { + connection.set('scm:git:https://github.com/JSQLParser/JSqlParser.git') + developerConnection.set('scm:git:ssh://git@github.com:JSQLParser/JSqlParser.git') + url.set('https://github.com/JSQLParser/JSqlParser.git') + } + } + } + } + + repositories { + maven { + name = "ossrh" + def releasesRepoUrl = "https://central.sonatype.com/repository/maven-releases" + def snapshotsRepoUrl = "https://central.sonatype.com/repository/maven-snapshots/" + url(version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl) + + credentials { + username = providers.environmentVariable("ossrhUsername").orNull + password = providers.environmentVariable("ossrhPassword").orNull + } + } + } +} + + +signing { + //def signingKey = findProperty("signingKey") + //def signingPassword = findProperty("signingPassword") + //useInMemoryPgpKeys(signingKey, signingPassword) + + // don't sign SNAPSHOTS + if (!version.endsWith('SNAPSHOT')) { + sign publishing.publications.mavenJava + } +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +remotes { + webServer { + host = findProperty("${project.name}.host") ?: "defaultHost" // Provide default if not found + user = findProperty("${project.name}.username") ?: "defaultUsername" // Provide default if not found + identity = file("${System.getProperty('user.home')}/.ssh/id_rsa") + } +} + + +tasks.register('upload') { + doFirst { + if (findProperty("${project.name}.host") == null) { + println( + """ + Property \"${project.name}.host\' not found. + Please define \"${project.name}.host\" in the Gradle configuration (e. g. \$HOME/.gradle/gradle.properties. + """ + ) + } + } + doLast { + ssh.run { + session(remotes.webServer) { + def versionStable = getVersion(false) + execute "mkdir -p download/${project.name}-${versionStable}" + for (File file: fileTree(include:['*.jar'], dir: layout.buildDirectory.dir("libs").get()).collect()) { + put from: file, into: "download/${project.name}-${versionStable}" + } + } + } + } + + dependsOn(check, assemble, gitChangelogTask, renderRR, xslt, xmldoc) +} + +check { + dependsOn jacocoTestCoverageVerification +} + +jmh { + includes = ['.*JSQLParserBenchmark.*'] + warmupIterations = 2 + fork = 3 + iterations = 5 + timeOnIteration = '1s' +} \ No newline at end of file diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..c49a70502 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/checkstyle_checks.xml b/config/checkstyle/checkstyle_checks.xml new file mode 100644 index 000000000..708f38789 --- /dev/null +++ b/config/checkstyle/checkstyle_checks.xml @@ -0,0 +1,879 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/google_checks.xml b/config/checkstyle/google_checks.xml new file mode 100644 index 000000000..153a045d6 --- /dev/null +++ b/config/checkstyle/google_checks.xml @@ -0,0 +1,358 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/sun_checks.xml b/config/checkstyle/sun_checks.xml new file mode 100644 index 000000000..e5f5367da --- /dev/null +++ b/config/checkstyle/sun_checks.xml @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..b5ddce587 --- /dev/null +++ b/config/checkstyle/suppressions.xml @@ -0,0 +1,659 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/formatter/eclipse-java-google-style.xml b/config/formatter/eclipse-java-google-style.xml new file mode 100644 index 000000000..5f9965da0 --- /dev/null +++ b/config/formatter/eclipse-java-google-style.xml @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/pmd/ruleset.xml b/config/pmd/ruleset.xml new file mode 100644 index 000000000..45804d4c0 --- /dev/null +++ b/config/pmd/ruleset.xml @@ -0,0 +1,114 @@ + + + + + + Custom PMD ruleset, compatible with PMD 7.x. + + Based on the old (pre PMD 6.0.0) rulesets java-basic, java-empty, java-imports, + java-unnecessary, java-unusedcode, migrated for PMD 7. + + This ruleset might be used as a starting point for an own customized ruleset [0]. + + [0] https://pmd.github.io/latest/pmd_userdocs_making_rulesets.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/spotbugs/spotBugsExcludeFilter.xml b/config/spotbugs/spotBugsExcludeFilter.xml new file mode 100644 index 000000000..14af0c11a --- /dev/null +++ b/config/spotbugs/spotBugsExcludeFilter.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 000000000..8b590d14c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,17 @@ +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx8G -Xss8m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError + +org.gradle.caching=true + +# Modularise your project and enable parallel build +org.gradle.parallel=true + +# Enable configure on demand. +org.gradle.configureondemand=true + +# see https://docs.gradle.org/current/userguide/upgrading_version_8.html#xml_parsing_now_requires_recent_parsers +systemProp.javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl +systemProp.javax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl +systemProp.javax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..d997cfc60 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..dbc3ce4a0 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..f640dbced --- /dev/null +++ b/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob//platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..c4bdd3ab8 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/nb-configuration.xml b/nb-configuration.xml index c60897d90..2c751cae4 100644 --- a/nb-configuration.xml +++ b/nb-configuration.xml @@ -13,12 +13,20 @@ That way multiple projects can share the same settings (useful for formatting rules for example). Any value defined here will override the pom.xml file value but is only applicable to the current project. --> - all + none false true LF false true - JDK_1.8 + JDK_11 + false + none + 4 + 4 + 4 + 120 + true + project diff --git a/pom.xml b/pom.xml index 91192221b..5ac0c4666 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.github.jsqlparser jsqlparser - 1.3-SNAPSHOT + 5.4-SNAPSHOT JSQLParser library 2004 @@ -24,31 +24,121 @@ + + + javacc8-snapshots + + true + + false + https://central.sonatype.com/repository/maven-snapshots/ + + + ossrh-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + true + false + + + + + javacc8-snapshots + + true + + false + https://central.sonatype.com/repository/maven-snapshots/ + + + ossrh-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + true + false + + + + + + org.javacc + core + 8.1.0-SNAPSHOT + pom + test + + + org.javacc.generator + java + 8.1.0-SNAPSHOT + test + commons-io commons-io - 2.4 + 2.18.0 test - junit - junit - 4.12 + org.junit.jupiter + junit-jupiter + 5.11.4 test - org.hamcrest - hamcrest-library - 1.3 + org.mockito + mockito-core + 5.15.2 test org.mockito - mockito-core - 2.16.0 + mockito-junit-jupiter + 5.15.2 test + + org.assertj + assertj-core + (3.27.7,) + test + + + org.apache.commons + commons-lang3 + [3.18.0,) + test + + + com.h2database + h2 + [2.3.232,) + test + + + + + org.hamcrest + hamcrest + 2.2 + test + + + + + org.openjdk.jmh + jmh-core + 1.37 + test + + + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + provided + + @@ -61,11 +151,13 @@ sonatype-nexus-staging - https://oss.sonatype.org/service/local/staging/deploy/maven2 + https://central.sonatype.com/repository/maven-releases sonatype-nexus-snapshots - https://oss.sonatype.org/content/repositories/snapshots + https://central.sonatype.com/repository/maven-snapshots/ + false + true @@ -83,20 +175,109 @@ + + + org.codehaus.mojo + exec-maven-plugin + 3.5.0 + + net.sf.jsqlparser.parser.ParserKeywordsUtils + + src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt + src/site/sphinx/keywords.rst + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.26.0 + + 2 + + + ${project.basedir}/config/pmd/ruleset.xml + + + **/*Bean.java + **/generated/*.java + **/net/sf/jsqlparser/parser/SimpleCharStream.java + + + target/generated-sources + target/generated-test-sources + + true + + + + pmd + + check + + process-sources + + + + + net.sourceforge.pmd + pmd-core + ${pmdVersion} + + + net.sourceforge.pmd + pmd-java + ${pmdVersion} + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.6.0 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/javacc/ + ${project.build.directory}/generated-sources/jjtree/ + + + + + maven-compiler-plugin - 3.7.0 + 3.14.0 - 1.7 - 1.7 + 11 + 11 true ${project.build.sourceEncoding} + true + 2000m + + -J-Xss4M + + true + + + org.openjdk.jmh + jmh-generator-annprocess + 1.37 + + - org.codehaus.mojo + org.javacc.plugin javacc-maven-plugin - 2.6 + 3.8.0 javacc @@ -104,30 +285,35 @@ jjtree-javacc + + + -CODE_GENERATOR="Java" + -GRAMMAR_ENCODING="UTF-8" + + + -GRAMMAR_ENCODING="UTF-8" + -CODE_GENERATOR="Java" + + - net.java.dev.javacc - javacc - 7.0.3 + org.javacc.generator + java + 8.1.0-SNAPSHOT + + + org.javacc + core + 8.1.0-SNAPSHOT - - org.apache.maven.plugins - maven-eclipse-plugin - 2.9 - - - /target/generated-sources/javacc - - - org.apache.maven.plugins maven-resources-plugin - 2.6 + 3.3.0 ${project.build.sourceEncoding} @@ -135,11 +321,16 @@ org.codehaus.mojo license-maven-plugin - 1.6 + 2.0.0 false false false + dual_lgpl_ap2 + ${project.baseUri}/src/license + + site/sphinx/** + @@ -148,36 +339,29 @@ update-file-header process-sources - - lgpl_v2_1 - - src/main/java - - org.apache.maven.plugins maven-release-plugin - 2.5.3 + + 3.1.1 true false forked-path + sign-release-artifacts - - - org.apache.maven.scm - maven-scm-provider-gitexe - 1.9.5 - - org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.3.1 attach-sources @@ -190,12 +374,18 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.11.2 attach-javadocs - ${javadoc.opts} + ${javadoc.opts} + net.sf.jsqlparser.parser + none + true + 2g + 800m + -J-Xss4m jar @@ -204,111 +394,159 @@ - maven-site-plugin - 3.3 + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + + net.sf.jsqlparser + + + + + + org.apache.felix + maven-bundle-plugin + 5.1.8 + true + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.2 + + false + + false + + --add-opens=java.base/java.lang=ALL-UNNAMED + --add-opens=java.base/java.util=ALL-UNNAMED + -Xmx2G -Xms800m -Xss4m + + + + + org.jacoco + jacoco-maven-plugin + 0.8.13 - attach-descriptor - attach-descriptor + prepare-agent + + + + report + prepare-package + + report - - en - - org.eluder.coveralls - coveralls-maven-plugin - 3.1.0 - - - org.codehaus.mojo - cobertura-maven-plugin - 2.7 + com.diffplug.spotless + spotless-maven-plugin + 2.44.4 - xml - 256m - - - net/sf/jsqlparser/parser/*.class - net/sf/jsqlparser/JSQLParserException.class - - + + origin/master + + + + + + *.md + .gitignore + + + + + + true + 4 + + + + + + + + src/main/java/**/*.java + src/test/java/**/*.java + + + + + + + + config/formatter/eclipse-java-google-style.xml + + + + - org.apache.felix - maven-bundle-plugin - 3.0.1 + org.sonatype.central + central-publishing-maven-plugin + 0.10.0 true - - - org.apache.maven.plugins - maven-surefire-plugin - 2.15 + + sonatype-nexus + - + org.apache.maven.plugins maven-surefire-report-plugin - 2.16 + 3.5.2 ${project.reporting.outputDirectory}/testresults + -Xmx2G -Xms800m -Xss4m org.apache.maven.plugins maven-javadoc-plugin - 2.10.3 + 3.11.2 - true + true + none + 2g + 800m + -J-Xss2m + + - - - html - - javadoc - - - org.apache.maven.plugins maven-project-info-reports-plugin - 2.7 + 3.9.0 org.apache.maven.plugins maven-jxr-plugin - 2.3 - - true - - - - org.codehaus.mojo - cobertura-maven-plugin - 2.6 - - true - %{project.reporting.outputDirectory}/cobertura - - - - org.codehaus.mojo - findbugs-maven-plugin - 2.5.3 + 3.6.0 + - org.codehaus.mojo - javacc-maven-plugin - 2.6 + com.github.spotbugs + spotbugs-maven-plugin + 4.9.3.0 @@ -327,7 +565,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.4 + 3.2.7 sign-artifacts @@ -344,28 +582,21 @@ - - doclint-java8-disable - - [1.8,) - - - -Xdoclint:none - - + check.sources !skipCheckSources + [11,) org.apache.maven.plugins maven-checkstyle-plugin - 2.17 + 3.6.0 verify-style @@ -378,7 +609,8 @@ true true - ${project.build.sourceDirectory} + ${project.build.sourceDirectory} + **/module-info.java,**/net/sf/jsqlparser/parser/SimpleCharStream.java @@ -400,14 +632,14 @@ - - - + + + - + @@ -417,19 +649,35 @@ com.puppycrawl.tools checkstyle - 6.19 + ${checkStyleVersion} + + + skip.all + + false + + + true + true + true + true + + UTF-8 + UTF-8 + 7.17.0 + 10.23.1 JSqlParser parses an SQL statement and translate it into a hierarchy of Java classes. The generated hierarchy can be navigated using the Visitor Pattern. - + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..d0322b0de --- /dev/null +++ b/settings.gradle @@ -0,0 +1,5 @@ +/* + * This file was generated by the Gradle 'init' task. + */ + +rootProject.name = 'JSQLParser' diff --git a/src/license/dual_lgpl_ap2/header.txt b/src/license/dual_lgpl_ap2/header.txt new file mode 100644 index 000000000..0dab25924 --- /dev/null +++ b/src/license/dual_lgpl_ap2/header.txt @@ -0,0 +1 @@ +Dual licensed under GNU LGPL 2.1 or Apache License 2.0 \ No newline at end of file diff --git a/src/license/dual_lgpl_ap2/license.txt b/src/license/dual_lgpl_ap2/license.txt new file mode 100644 index 000000000..8a2d35be0 --- /dev/null +++ b/src/license/dual_lgpl_ap2/license.txt @@ -0,0 +1,710 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +(This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.) + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random + Hacker. + + {signature of Ty Coon}, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + +********************************************************************************************* + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/license/licenses.properties b/src/license/licenses.properties new file mode 100644 index 000000000..dfdce951d --- /dev/null +++ b/src/license/licenses.properties @@ -0,0 +1,10 @@ +### +# #%L +# JSQLParser library +# %% +# Copyright (C) 2004 - 2019 JSQLParser +# %% +# Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +# #L% +### +dual_lgpl_ap2=Dual License GNU LGPL 2.1 or Apache License 2.0 diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 000000000..ada4bfdf4 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,61 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +module net.sf.jsqlparser { + requires java.sql; + requires java.logging; + requires java.desktop; + + exports net.sf.jsqlparser; + exports net.sf.jsqlparser.expression; + exports net.sf.jsqlparser.expression.operators.arithmetic; + exports net.sf.jsqlparser.expression.operators.conditional; + exports net.sf.jsqlparser.expression.operators.relational; + exports net.sf.jsqlparser.parser; + exports net.sf.jsqlparser.parser.feature; + exports net.sf.jsqlparser.schema; + exports net.sf.jsqlparser.statement; + exports net.sf.jsqlparser.statement.alter; + exports net.sf.jsqlparser.statement.alter.sequence; + exports net.sf.jsqlparser.statement.analyze; + 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; + exports net.sf.jsqlparser.statement.create.synonym; + exports net.sf.jsqlparser.statement.create.table; + exports net.sf.jsqlparser.statement.create.view; + 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; + exports net.sf.jsqlparser.statement.select; + exports net.sf.jsqlparser.statement.show; + exports net.sf.jsqlparser.statement.truncate; + exports net.sf.jsqlparser.statement.update; + exports net.sf.jsqlparser.statement.upsert; + exports net.sf.jsqlparser.util; + exports net.sf.jsqlparser.util.cnfexpression; + exports net.sf.jsqlparser.util.deparser; + exports net.sf.jsqlparser.util.validation; + exports net.sf.jsqlparser.util.validation.allowedtypes; + exports net.sf.jsqlparser.util.validation.feature; + exports net.sf.jsqlparser.util.validation.metadata; + exports net.sf.jsqlparser.util.validation.validator; +} diff --git a/src/main/java/net/sf/jsqlparser/JSQLParserException.java b/src/main/java/net/sf/jsqlparser/JSQLParserException.java index 234943553..d5ac69427 100644 --- a/src/main/java/net/sf/jsqlparser/JSQLParserException.java +++ b/src/main/java/net/sf/jsqlparser/JSQLParserException.java @@ -1,77 +1,32 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser; -/** - * An exception class with stack trace informations - */ public class JSQLParserException extends Exception { - /* The serial class version */ - private static final long serialVersionUID = -1099039459759769980L; - private Throwable cause = null; + private static final long serialVersionUID = -4200894355696788796L; public JSQLParserException() { super(); } - public JSQLParserException(String arg0) { - super(arg0); - } - - public JSQLParserException(Throwable arg0) { - this.cause = arg0; - } - - public JSQLParserException(String arg0, Throwable arg1) { - super(arg0); - this.cause = arg1; - } - - @Override - public Throwable getCause() { - return cause; + public JSQLParserException(String message, Throwable cause) { + super(message, cause); } - @Override - public void printStackTrace() { - printStackTrace(System.err); + public JSQLParserException(String message) { + super(message); } - @Override - public void printStackTrace(java.io.PrintWriter pw) { - super.printStackTrace(pw); - if (cause != null) { - pw.println("Caused by:"); - cause.printStackTrace(pw); - } + public JSQLParserException(Throwable cause) { + super(cause == null ? null : cause.getMessage(), cause); } - @Override - public void printStackTrace(java.io.PrintStream ps) { - super.printStackTrace(ps); - if (cause != null) { - ps.println("Caused by:"); - cause.printStackTrace(ps); - } - } } diff --git a/src/main/java/net/sf/jsqlparser/Model.java b/src/main/java/net/sf/jsqlparser/Model.java new file mode 100644 index 000000000..4ad52f429 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/Model.java @@ -0,0 +1,24 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser; + +import java.io.Serializable; + +/** + *

+ * A marker interface for jsqlparser-model-classes. + *

+ *

+ * The datastructure where the sql syntax is represented by a tree consists of {@link Model}'s + *

+ */ +public interface Model extends Serializable { + +} diff --git a/src/main/java/net/sf/jsqlparser/expression/Alias.java b/src/main/java/net/sf/jsqlparser/expression/Alias.java index 6de501342..ffc599680 100644 --- a/src/main/java/net/sf/jsqlparser/expression/Alias.java +++ b/src/main/java/net/sf/jsqlparser/expression/Alias.java @@ -1,34 +1,39 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2014 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import net.sf.jsqlparser.schema.MultiPartName; +import net.sf.jsqlparser.statement.create.table.ColDataType; + /** + * The type Alias for Tables, Columns or Views. * - * @author toben + * We support three different types: + * 1) Simple String: `SELECT 1 AS "ALIAS"` when NAME is set and aliasColumns has no elements + * 2) UDF Aliases: `SELECT udf(1,2,3) AS "Alias(a,b,c)"` " when NAME!=null and aliasColumns has elements + * 3) Column lists for LATERAL VIEW: `SELECT * from a LATERAL VIEW EXPLODE ... AS a, b, c`, when NAME is NULL and aliasColumns has elements + * @see Spark LATERAL VIEW */ -public class Alias { +public class Alias implements Serializable { private String name; private boolean useAs = true; + private List aliasColumns; public Alias(String name) { this.name = name; @@ -43,6 +48,10 @@ public String getName() { return name; } + public String getUnquotedName() { + return MultiPartName.unquote(name); + } + public void setName(String name) { this.name = name; } @@ -55,8 +64,87 @@ public void setUseAs(boolean useAs) { this.useAs = useAs; } + public List getAliasColumns() { + return aliasColumns; + } + + public void setAliasColumns(List aliasColumns) { + this.aliasColumns = aliasColumns; + } + @Override public String toString() { - return (useAs ? " AS " : " ") + name; + String alias = (useAs ? " AS " : " ") + (name != null ? name : ""); + + if (aliasColumns != null && !aliasColumns.isEmpty()) { + StringBuilder ac = new StringBuilder(); + for (AliasColumn col : aliasColumns) { + if (ac.length() > 0) { + ac.append(", "); + } + ac.append(col.name); + if (col.colDataType != null) { + ac.append(" ").append(col.colDataType); + } + } + alias += name != null ? "(" + ac + ")" : ac; + } + + return alias; + } + + public Alias withName(String name) { + this.setName(name); + return this; + } + + public Alias withUseAs(boolean useAs) { + this.setUseAs(useAs); + return this; + } + + public Alias withAliasColumns(List aliasColumns) { + this.setAliasColumns(aliasColumns); + return this; + } + + + public Alias addAliasColumns(String... columnNames) { + List collection = + Optional.ofNullable(getAliasColumns()).orElseGet(ArrayList::new); + for (String columnName : columnNames) { + collection.add(new AliasColumn(columnName)); + } + return this.withAliasColumns(collection); + } + + public Alias addAliasColumns(AliasColumn... aliasColumns) { + List collection = + Optional.ofNullable(getAliasColumns()).orElseGet(ArrayList::new); + Collections.addAll(collection, aliasColumns); + return this.withAliasColumns(collection); + } + + public Alias addAliasColumns(Collection aliasColumns) { + List collection = + Optional.ofNullable(getAliasColumns()).orElseGet(ArrayList::new); + collection.addAll(aliasColumns); + return this.withAliasColumns(collection); + } + + public static class AliasColumn implements Serializable { + + public final String name; + public final ColDataType colDataType; + + public AliasColumn(String name, ColDataType colDataType) { + Objects.requireNonNull(name); + this.name = name; + this.colDataType = colDataType; + } + + public AliasColumn(String name) { + this(name, null); + } } } diff --git a/src/main/java/net/sf/jsqlparser/expression/AllComparisonExpression.java b/src/main/java/net/sf/jsqlparser/expression/AllComparisonExpression.java deleted file mode 100644 index 3c596cc1d..000000000 --- a/src/main/java/net/sf/jsqlparser/expression/AllComparisonExpression.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2013 JSQLParser - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -package net.sf.jsqlparser.expression; - -import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -import net.sf.jsqlparser.statement.select.SubSelect; - -public class AllComparisonExpression extends ASTNodeAccessImpl implements Expression { - - private final SubSelect subSelect; - - public AllComparisonExpression(SubSelect subSelect) { - this.subSelect = subSelect; - } - - public SubSelect getSubSelect() { - return subSelect; - } - - @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); - } - - @Override - public String toString() { - return "ALL " + subSelect.toString(); - } -} diff --git a/src/main/java/net/sf/jsqlparser/expression/AllValue.java b/src/main/java/net/sf/jsqlparser/expression/AllValue.java new file mode 100644 index 000000000..14f924ab8 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/AllValue.java @@ -0,0 +1,25 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class AllValue extends ASTNodeAccessImpl implements Expression { + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return "ALL"; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java b/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java index 2e191a81e..1f59ebecc 100644 --- a/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/AnalyticExpression.java @@ -1,44 +1,33 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.select.Limit; import net.sf.jsqlparser.statement.select.OrderByElement; import java.util.List; -import net.sf.jsqlparser.expression.operators.relational.ExpressionList; + +import static java.util.stream.Collectors.joining; /** * Analytic function. The name of the function is variable but the parameters following the special - * analytic function path. e.g. row_number() over (order by test). Additional there can be an - * expression for an analytical aggregate like sum(col) or the "all collumns" wildcard like - * count(*). + * analytic function path. e.g. row_number() over (order by test). Additionally, there can be an + * expression for an analytical aggregate like sum(col) or the "all columns" wildcard like count(*). * * @author tw */ public class AnalyticExpression extends ASTNodeAccessImpl implements Expression { - private final OrderByClause orderBy = new OrderByClause(); - private final PartitionByClause partitionBy = new PartitionByClause(); + private String name; private Expression expression; private Expression offset; @@ -47,18 +36,78 @@ public class AnalyticExpression extends ASTNodeAccessImpl implements Expression private KeepExpression keep = null; private AnalyticType type = AnalyticType.OVER; private boolean distinct = false; + private boolean unique = false; + private boolean ignoreNullsOutside = false; // IGNORE NULLS outside function parameters + private Expression filterExpression = null; + private List funcOrderBy = null; + private String onOverflowTruncate = null; + + private String windowName = null; // refers to an external window definition (paritionBy, + // orderBy, windowElement) + private WindowDefinition windowDef = new WindowDefinition(); + + private Function.HavingClause havingClause; + + private Function.NullHandling nullHandling = null; + + private Limit limit = null; + + private List keywordArguments = null; + + public AnalyticExpression() {} + + public AnalyticExpression(Function function) { + this.name = String.join(" ", function.getMultipartName()); + this.allColumns = function.isAllColumns(); + this.distinct = function.isDistinct(); + this.unique = function.isUnique(); + + ExpressionList list = function.getParameters(); + if (list != null) { + if (list.size() > 3) { + throw new IllegalArgumentException( + "function object not valid to initialize analytic expression"); + } + + expression = list.get(0); + if (list.size() > 1) { + offset = list.get(1); + } + if (list.size() > 2) { + defaultValue = list.get(2); + } + } + this.havingClause = function.getHavingClause(); + this.ignoreNullsOutside = function.isIgnoreNullsOutside(); + this.nullHandling = function.getNullHandling(); + this.funcOrderBy = function.getOrderByElements(); + this.onOverflowTruncate = function.getOnOverflowTruncate(); + this.limit = function.getLimit(); + this.keep = function.getKeep(); + this.keywordArguments = function.getKeywordArguments(); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public List getOrderByElements() { - return orderBy.getOrderByElements(); + return windowDef.orderBy.getOrderByElements(); } public void setOrderByElements(List orderByElements) { - orderBy.setOrderByElements(orderByElements); + windowDef.orderBy.setOrderByElements(orderByElements); + } + + public String getOnOverflowTruncate() { + return onOverflowTruncate; + } + + public AnalyticExpression setOnOverflowTruncate(String onOverflowTruncate) { + this.onOverflowTruncate = onOverflowTruncate; + return this; } public KeepExpression getKeep() { @@ -69,12 +118,21 @@ public void setKeep(KeepExpression keep) { this.keep = keep; } - public ExpressionList getPartitionExpressionList() { - return partitionBy.getPartitionExpressionList(); + public ExpressionList getPartitionExpressionList() { + return windowDef.partitionBy; + } + + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + setPartitionExpressionList(partitionExpressionList, false); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { - partitionBy.setPartitionExpressionList(partitionExpressionList); + public void setPartitionExpressionList(ExpressionList partitionExpressionList, + boolean brackets) { + windowDef.partitionBy.setExpressions(partitionExpressionList, brackets); + } + + public boolean isPartitionByBrackets() { + return windowDef.partitionBy.isBrackets(); } public String getName() { @@ -110,11 +168,11 @@ public void setDefaultValue(Expression defaultValue) { } public WindowElement getWindowElement() { - return orderBy.getWindowElement(); + return windowDef.windowElement; } public void setWindowElement(WindowElement windowElement) { - orderBy.setWindowElement(windowElement); + windowDef.windowElement = windowElement; } public AnalyticType getType() { @@ -133,7 +191,92 @@ public void setDistinct(boolean distinct) { this.distinct = distinct; } + public boolean isUnique() { + return unique; + } + + public void setUnique(boolean unique) { + this.unique = unique; + } + + public boolean isIgnoreNulls() { + return this.nullHandling == Function.NullHandling.IGNORE_NULLS; + } + + public void setIgnoreNulls(boolean ignoreNulls) { + this.nullHandling = ignoreNulls ? Function.NullHandling.IGNORE_NULLS : null; + } + + public boolean isIgnoreNullsOutside() { + return ignoreNullsOutside; + } + + public void setIgnoreNullsOutside(boolean ignoreNullsOutside) { + this.ignoreNullsOutside = ignoreNullsOutside; + } + + public String getWindowName() { + return windowName; + } + + public void setWindowName(String windowName) { + this.windowName = windowName; + } + + public WindowDefinition getWindowDefinition() { + return windowDef; + } + + public void setWindowDefinition(WindowDefinition windowDef) { + this.windowDef = windowDef; + } + + + public Function.HavingClause getHavingClause() { + return havingClause; + } + + public AnalyticExpression setHavingClause(Function.HavingClause havingClause) { + this.havingClause = havingClause; + return this; + } + + public AnalyticExpression setHavingClause(String havingType, Expression expression) { + this.havingClause = new Function.HavingClause( + Function.HavingClause.HavingType.valueOf(havingType.trim().toUpperCase()), + expression); + return this; + } + + public Function.NullHandling getNullHandling() { + return nullHandling; + } + + public AnalyticExpression setNullHandling(Function.NullHandling nullHandling) { + this.nullHandling = nullHandling; + return this; + } + + public Limit getLimit() { + return limit; + } + + public AnalyticExpression setLimit(Limit limit) { + this.limit = limit; + return this; + } + + public List getKeywordArguments() { + return keywordArguments; + } + + public void setKeywordArguments(List keywordArguments) { + this.keywordArguments = keywordArguments; + } + @Override + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", + "PMD.MissingBreakInSwitch"}) public String toString() { StringBuilder b = new StringBuilder(); @@ -142,34 +285,100 @@ public String toString() { b.append("DISTINCT "); } if (expression != null) { - b.append(expression.toString()); + b.append(expression); if (offset != null) { - b.append(", ").append(offset.toString()); + b.append(", ").append(offset); if (defaultValue != null) { - b.append(", ").append(defaultValue.toString()); + b.append(", ").append(defaultValue); } } } else if (isAllColumns()) { b.append("*"); } + + if (havingClause != null) { + havingClause.appendTo(b); + } + + if (nullHandling != null && !ignoreNullsOutside) { + switch (nullHandling) { + case IGNORE_NULLS: + b.append(" IGNORE NULLS"); + break; + case RESPECT_NULLS: + b.append(" RESPECT NULLS"); + break; + } + } + + if (funcOrderBy != null) { + b.append(" ORDER BY "); + b.append(funcOrderBy.stream().map(OrderByElement::toString).collect(joining(", "))); + } + + if (onOverflowTruncate != null) { + b.append(" ON OVERFLOW ").append(onOverflowTruncate); + } + + if (limit != null) { + b.append(limit); + } + + // Generic keyword arguments (e.g. SEPARATOR ',') + if (keywordArguments != null) { + for (Function.KeywordArgument ka : keywordArguments) { + ka.appendTo(b); + } + } + b.append(") "); if (keep != null) { - b.append(keep.toString()).append(" "); + b.append(keep).append(" "); + } + + if (filterExpression != null) { + b.append("FILTER (WHERE "); + b.append(filterExpression); + b.append(")"); + if (type != AnalyticType.FILTER_ONLY) { + b.append(" "); + } + } + + if (nullHandling != null && ignoreNullsOutside) { + switch (nullHandling) { + case IGNORE_NULLS: + b.append(" IGNORE NULLS "); + break; + case RESPECT_NULLS: + b.append(" RESPECT NULLS "); + break; + } } switch (type) { + case FILTER_ONLY: + return b.toString(); case WITHIN_GROUP: b.append("WITHIN GROUP"); break; + case WITHIN_GROUP_OVER: + b.append("WITHIN GROUP ("); + windowDef.orderBy.toStringOrderByElements(b); + b.append(") OVER ("); + windowDef.partitionBy.toStringPartitionBy(b); + b.append(")"); + break; default: b.append("OVER"); } - b.append(" ("); - - partitionBy.toStringPartitionBy(b); - orderBy.toStringOrderByElements(b); - b.append(")"); + if (windowName != null) { + b.append(" ").append(windowName); + } else if (type != AnalyticType.WITHIN_GROUP_OVER) { + b.append(" "); + b.append(windowDef.toString()); + } return b.toString(); } @@ -182,4 +391,95 @@ public void setAllColumns(boolean allColumns) { this.allColumns = allColumns; } + public Expression getFilterExpression() { + return filterExpression; + } + + public void setFilterExpression(Expression filterExpression) { + this.filterExpression = filterExpression; + } + + public AnalyticExpression withName(String name) { + this.setName(name); + return this; + } + + public AnalyticExpression withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public AnalyticExpression withOffset(Expression offset) { + this.setOffset(offset); + return this; + } + + public AnalyticExpression withDefaultValue(Expression defaultValue) { + this.setDefaultValue(defaultValue); + return this; + } + + public AnalyticExpression withAllColumns(boolean allColumns) { + this.setAllColumns(allColumns); + return this; + } + + public AnalyticExpression withKeep(KeepExpression keep) { + this.setKeep(keep); + return this; + } + + public AnalyticExpression withType(AnalyticType type) { + this.setType(type); + return this; + } + + public AnalyticExpression withDistinct(boolean distinct) { + this.setDistinct(distinct); + return this; + } + + public AnalyticExpression withUnique(boolean unique) { + this.setUnique(unique); + return this; + } + + public AnalyticExpression withIgnoreNulls(boolean ignoreNulls) { + this.setIgnoreNulls(ignoreNulls); + return this; + } + + public AnalyticExpression withFilterExpression(Expression filterExpression) { + this.setFilterExpression(filterExpression); + return this; + } + + public AnalyticExpression withWindowElement(WindowElement windowElement) { + this.setWindowElement(windowElement); + return this; + } + + public E getExpression(Class type) { + return type.cast(getExpression()); + } + + public E getOffset(Class type) { + return type.cast(getOffset()); + } + + public E getDefaultValue(Class type) { + return type.cast(getDefaultValue()); + } + + public E getFilterExpression(Class type) { + return type.cast(getFilterExpression()); + } + + public List getFuncOrderBy() { + return funcOrderBy; + } + + public void setFuncOrderBy(List funcOrderBy) { + this.funcOrderBy = funcOrderBy; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/AnalyticType.java b/src/main/java/net/sf/jsqlparser/expression/AnalyticType.java index d9df6f655..2738849c6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/AnalyticType.java +++ b/src/main/java/net/sf/jsqlparser/expression/AnalyticType.java @@ -1,49 +1,18 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2017 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ -/* - * Copyright (C) 2017 JSQLParser. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ package net.sf.jsqlparser.expression; -/** - * - * @author Tobias Warneke (t.warneke@gmx.net) - */ public enum AnalyticType { - OVER, - WITHIN_GROUP + OVER, WITHIN_GROUP, WITHIN_GROUP_OVER, FILTER_ONLY; + + public static AnalyticType from(String type) { + return Enum.valueOf(AnalyticType.class, type.toUpperCase()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/AnyComparisonExpression.java b/src/main/java/net/sf/jsqlparser/expression/AnyComparisonExpression.java index 9bc270d03..cf3ba46d5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/AnyComparisonExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/AnyComparisonExpression.java @@ -1,28 +1,16 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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 net.sf.jsqlparser.statement.select.SubSelect; +import net.sf.jsqlparser.statement.select.Select; /** * Combines ANY and SOME expressions. @@ -30,22 +18,22 @@ * @author toben */ public class AnyComparisonExpression extends ASTNodeAccessImpl implements Expression { - - private final SubSelect subSelect; + private final Select select; private final AnyType anyType; - public AnyComparisonExpression(AnyType anyType, SubSelect subSelect) { + public AnyComparisonExpression(AnyType anyType, Select select) { this.anyType = anyType; - this.subSelect = subSelect; + this.select = select; } - public SubSelect getSubSelect() { - return subSelect; + public Select getSelect() { + return select; } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public AnyType getAnyType() { @@ -54,6 +42,7 @@ public AnyType getAnyType() { @Override public String toString() { - return anyType.name() + " " + subSelect.toString(); + String s = anyType.name() + select; + return s; } } diff --git a/src/main/java/net/sf/jsqlparser/expression/AnyType.java b/src/main/java/net/sf/jsqlparser/expression/AnyType.java index 1e5c24519..fec6fb09d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/AnyType.java +++ b/src/main/java/net/sf/jsqlparser/expression/AnyType.java @@ -1,50 +1,18 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2015 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ - /* - * Copyright (C) 2015 JSQLParser. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ package net.sf.jsqlparser.expression; -/** - * - * @author toben - */ public enum AnyType { + ANY, SOME, ALL; - ANY, - SOME + public static AnyType from(String type) { + return Enum.valueOf(AnyType.class, type.toUpperCase()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/ArrayConstructor.java b/src/main/java/net/sf/jsqlparser/expression/ArrayConstructor.java new file mode 100644 index 000000000..5e1c8d0e6 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/ArrayConstructor.java @@ -0,0 +1,75 @@ +/*- + * #%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.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.create.table.ColDataType; + +public class ArrayConstructor extends ASTNodeAccessImpl implements Expression { + private ExpressionList expressions; + private boolean arrayKeyword; + private ColDataType dataType; + + public ArrayConstructor(ExpressionList expressions, boolean arrayKeyword) { + this.expressions = expressions; + this.arrayKeyword = arrayKeyword; + } + + public ArrayConstructor(Expression... expressions) { + this(new ExpressionList(expressions), false); + } + + public ExpressionList getExpressions() { + return expressions; + } + + public void setExpressions(ExpressionList expressions) { + this.expressions = expressions; + } + + public boolean isArrayKeyword() { + return arrayKeyword; + } + + public void setArrayKeyword(boolean arrayKeyword) { + this.arrayKeyword = arrayKeyword; + } + + public ColDataType getDataType() { + return dataType; + } + + public ArrayConstructor setDataType(ColDataType dataType) { + this.dataType = dataType; + return this; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (arrayKeyword) { + sb.append("ARRAY"); + + if (dataType != null) { + sb.append("<").append(dataType).append(">"); + } + } + sb.append("["); + sb.append(expressions.toString()); + sb.append("]"); + return sb.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/ArrayExpression.java b/src/main/java/net/sf/jsqlparser/expression/ArrayExpression.java new file mode 100644 index 000000000..e86f34cad --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/ArrayExpression.java @@ -0,0 +1,117 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class ArrayExpression extends ASTNodeAccessImpl implements Expression { + + private Expression objExpression; + private Expression indexExpression; + private Expression startIndexExpression; + private Expression stopIndexExpression; + + + public ArrayExpression() { + // empty constructor + } + + public ArrayExpression(Expression objExpression, Expression indexExpression, + Expression startIndexExpression, Expression stopIndexExpression) { + this.objExpression = objExpression; + this.indexExpression = indexExpression; + this.startIndexExpression = startIndexExpression; + this.stopIndexExpression = stopIndexExpression; + } + + public ArrayExpression(Expression objExpression, Expression indexExpression) { + this(objExpression, indexExpression, null, null); + } + + public ArrayExpression(Expression objExpression, Expression startIndexExpression, + Expression stopIndexExpression) { + this(objExpression, null, startIndexExpression, stopIndexExpression); + } + + public Expression getObjExpression() { + return objExpression; + } + + public void setObjExpression(Expression objExpression) { + this.objExpression = objExpression; + } + + public Expression getIndexExpression() { + return indexExpression; + } + + public void setIndexExpression(Expression indexExpression) { + this.indexExpression = indexExpression; + } + + public Expression getStartIndexExpression() { + return startIndexExpression; + } + + public void setStartIndexExpression(Expression startIndexExpression) { + this.startIndexExpression = startIndexExpression; + } + + public Expression getStopIndexExpression() { + return stopIndexExpression; + } + + public void setStopIndexExpression(Expression stopIndexExpression) { + this.stopIndexExpression = stopIndexExpression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + if (indexExpression != null) { + return objExpression.toString() + "[" + indexExpression.toString() + "]"; + } else { + return objExpression.toString() + "[" + + (startIndexExpression == null ? "" : startIndexExpression.toString()) + + ":" + + (stopIndexExpression == null ? "" : stopIndexExpression.toString()) + + "]"; + } + } + + public ArrayExpression withObjExpression(Expression objExpression) { + this.setObjExpression(objExpression); + return this; + } + + public ArrayExpression withIndexExpression(Expression indexExpression) { + this.setIndexExpression(indexExpression); + return this; + } + + public ArrayExpression withRangeExpression(Expression startIndexExpression, + Expression stopIndexExpression) { + this.setStartIndexExpression(startIndexExpression); + this.setStopIndexExpression(stopIndexExpression); + return this; + } + + public E getObjExpression(Class type) { + return type.cast(getObjExpression()); + } + + public E getIndexExpression(Class type) { + return type.cast(getIndexExpression()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/BinaryExpression.java b/src/main/java/net/sf/jsqlparser/expression/BinaryExpression.java index e0d80983d..ffd9c2d84 100644 --- a/src/main/java/net/sf/jsqlparser/expression/BinaryExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/BinaryExpression.java @@ -1,28 +1,35 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package 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; +import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr; +import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseRightShift; +import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor; +import net.sf.jsqlparser.expression.operators.arithmetic.Concat; +import net.sf.jsqlparser.expression.operators.arithmetic.Division; +import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision; +import net.sf.jsqlparser.expression.operators.arithmetic.Modulo; +import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication; +import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.conditional.XorExpression; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Iterator; + /** * A basic class for binary expressions, that is expressions having a left member and a right member * which are in turn expressions. @@ -31,46 +38,229 @@ public abstract class BinaryExpression extends ASTNodeAccessImpl implements Expr private Expression leftExpression; private Expression rightExpression; - private boolean not = false; - - - - public BinaryExpression() { + + public BinaryExpression() {} + + public BinaryExpression(Expression leftExpression, Expression rightExpression) { + this.leftExpression = leftExpression; + this.rightExpression = rightExpression; } - public Expression getLeftExpression() { - return leftExpression; + public static Expression build(Class clz, Expression... expressions) + throws NoSuchMethodException, InvocationTargetException, InstantiationException, + IllegalAccessException { + switch (expressions.length) { + case 0: + return new NullValue(); + case 1: + return expressions[0]; + default: + Iterator it = Arrays.stream(expressions).iterator(); + + Expression leftExpression = it.next(); + Expression rightExpression = it.next(); + BinaryExpression binaryExpression = + clz.getConstructor(Expression.class, Expression.class) + .newInstance(leftExpression, rightExpression); + + while (it.hasNext()) { + rightExpression = it.next(); + binaryExpression = clz.getConstructor(Expression.class, Expression.class) + .newInstance(binaryExpression, rightExpression); + } + return binaryExpression; + } } - public Expression getRightExpression() { - return rightExpression; + public static Expression add(Expression... expressions) { + try { + return build(Addition.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression bitAnd(Expression... expressions) { + try { + return build(BitwiseAnd.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression bitShiftLeft(Expression... expressions) { + try { + return build(BitwiseLeftShift.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression multiply(Expression... expressions) { + try { + return build(Multiplication.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression bitOr(Expression... expressions) { + try { + return build(BitwiseOr.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression bitShiftRight(Expression... expressions) { + try { + return build(BitwiseRightShift.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression bitXor(Expression... expressions) { + try { + return build(BitwiseXor.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression concat(Expression... expressions) { + try { + return build(Concat.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression divide(Expression... expressions) { + try { + return build(Division.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression divideInt(Expression... expressions) { + try { + return build(IntegerDivision.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression modulo(Expression... expressions) { + try { + return build(Modulo.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression subtract(Expression... expressions) { + try { + return build(Subtraction.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression or(Expression... expressions) { + try { + return build(OrExpression.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression xor(Expression... expressions) { + try { + return build(XorExpression.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public static Expression and(Expression... expressions) { + try { + return build(AndExpression.class, expressions); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException + | IllegalAccessException e) { + // this should never happen, at least I don't see how + throw new RuntimeException(e); + } + } + + public Expression getLeftExpression() { + return leftExpression; } public void setLeftExpression(Expression expression) { leftExpression = expression; } + public Expression getRightExpression() { + return rightExpression; + } + public void setRightExpression(Expression expression) { rightExpression = expression; } - public void setNot() { - not = true; + public BinaryExpression withLeftExpression(Expression expression) { + setLeftExpression(expression); + return this; } - - public void removeNot() { - not = false; - } - - public boolean isNot() { - return not; + + public BinaryExpression withRightExpression(Expression expression) { + setRightExpression(expression); + return this; } @Override public String toString() { - return (not ? "NOT " : "") + getLeftExpression() + " " + getStringExpression() + " " + getRightExpression(); + return // (not ? "NOT " : "") + + getLeftExpression() + " " + getStringExpression() + " " + getRightExpression(); } public abstract String getStringExpression(); - + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } + + public E getRightExpression(Class type) { + return type.cast(getRightExpression()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/BooleanValue.java b/src/main/java/net/sf/jsqlparser/expression/BooleanValue.java new file mode 100644 index 000000000..258a89e16 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/BooleanValue.java @@ -0,0 +1,74 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.Objects; + +/** + * A boolean value true/false + */ +public final class BooleanValue extends ASTNodeAccessImpl implements Expression { + + private boolean value = false; + + public BooleanValue() { + // empty constructor + } + + public BooleanValue(String value) { + this(Boolean.parseBoolean(value)); + } + + public BooleanValue(boolean bool) { + value = bool; + } + + public boolean getValue() { + return value; + } + + public void setValue(boolean bool) { + value = bool; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return Boolean.toString(value); + } + + public BooleanValue withValue(boolean bool) { + this.setValue(bool); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + BooleanValue that = (BooleanValue) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/CaseExpression.java b/src/main/java/net/sf/jsqlparser/expression/CaseExpression.java index eae3f63a1..10fd7d56d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/CaseExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/CaseExpression.java @@ -1,83 +1,81 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Optional; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import net.sf.jsqlparser.statement.select.PlainSelect; /** * CASE/WHEN expression. + *

+ * Syntax: * - * Syntax:

+ * 
+ * 
  * CASE
  * WHEN condition THEN expression
  * [WHEN condition THEN expression]...
  * [ELSE expression]
  * END
- * 
+ *
+ *
* - *
- * or
- *
+ *
+ * or
+ *
* - *
+ * 
+ * 
  * CASE expression
  * WHEN condition THEN expression
  * [WHEN condition THEN expression]...
  * [ELSE expression]
  * END
- * 
- * - * See also: https://aurora.vcu.edu/db2help/db2s0/frame3.htm#casexp - * http://sybooks.sybase.com/onlinebooks/group-as/asg1251e /commands/ - * - * @ebt-link;pt=5954?target=%25N%15_52628_START_RESTART_N%25 - * - * - * @author Havard Rast Blok + *
+ *
*/ public class CaseExpression extends ASTNodeAccessImpl implements Expression { + private boolean usingBrackets = false; private Expression switchExpression; private List whenClauses; private Expression elseExpression; + public CaseExpression() {} + + public CaseExpression(WhenClause... whenClauses) { + this.whenClauses = Arrays.asList(whenClauses); + } + + public CaseExpression(Expression elseExpression, WhenClause... whenClauses) { + this.elseExpression = elseExpression; + this.whenClauses = Arrays.asList(whenClauses); + } + + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } - /** - * @return Returns the switchExpression. - */ public Expression getSwitchExpression() { return switchExpression; } - /** - * @param switchExpression The switchExpression to set. - */ public void setSwitchExpression(Expression switchExpression) { this.switchExpression = switchExpression; } @@ -112,8 +110,73 @@ public void setWhenClauses(List whenClauses) { @Override public String toString() { - return "CASE " + ((switchExpression != null) ? switchExpression + " " : "") + return (usingBrackets ? "(" : "") + "CASE " + + ((switchExpression != null) ? switchExpression + " " : "") + PlainSelect.getStringList(whenClauses, false, false) + " " - + ((elseExpression != null) ? "ELSE " + elseExpression + " " : "") + "END"; + + ((elseExpression != null) ? "ELSE " + elseExpression + " " : "") + "END" + + (usingBrackets ? ")" : ""); + } + + public CaseExpression withSwitchExpression(Expression switchExpression) { + this.setSwitchExpression(switchExpression); + return this; + } + + public CaseExpression withWhenClauses(WhenClause... whenClauses) { + return this.withWhenClauses(Arrays.asList(whenClauses)); + } + + public CaseExpression withWhenClauses(List whenClauses) { + this.setWhenClauses(whenClauses); + return this; + } + + public CaseExpression withElseExpression(Expression elseExpression) { + this.setElseExpression(elseExpression); + return this; + } + + public CaseExpression addWhenClauses(WhenClause... whenClauses) { + List collection = + Optional.ofNullable(getWhenClauses()).orElseGet(ArrayList::new); + Collections.addAll(collection, whenClauses); + return this.withWhenClauses(collection); + } + + public CaseExpression addWhenClauses(Collection whenClauses) { + List collection = + Optional.ofNullable(getWhenClauses()).orElseGet(ArrayList::new); + collection.addAll(whenClauses); + return this.withWhenClauses(collection); + } + + public E getSwitchExpression(Class type) { + return type.cast(getSwitchExpression()); + } + + public E getElseExpression(Class type) { + return type.cast(getElseExpression()); + } + + /** + * @return the usingBrackets + */ + public boolean isUsingBrackets() { + return usingBrackets; + } + + /** + * @param usingBrackets the usingBrackets to set + */ + public void setUsingBrackets(boolean usingBrackets) { + this.usingBrackets = usingBrackets; + } + + /** + * @param usingBrackets the usingBrackets to set + */ + public CaseExpression withUsingBrackets(boolean usingBrackets) { + this.usingBrackets = usingBrackets; + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/expression/CastExpression.java b/src/main/java/net/sf/jsqlparser/expression/CastExpression.java index 89cb4c91b..f06682068 100644 --- a/src/main/java/net/sf/jsqlparser/expression/CastExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/CastExpression.java @@ -1,45 +1,151 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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 net.sf.jsqlparser.statement.create.table.ColDataType; +import net.sf.jsqlparser.statement.create.table.ColumnDefinition; +import net.sf.jsqlparser.statement.select.Select; + +import java.util.ArrayList; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -/** - * - * @author tw - */ public class CastExpression extends ASTNodeAccessImpl implements Expression { + private final static Pattern PATTERN = + Pattern.compile("(^[a-z0-9_]*){1}", Pattern.CASE_INSENSITIVE); + public String keyword; private Expression leftExpression; - private ColDataType type; - private boolean useCastKeyword = true; + private ColDataType colDataType = null; + private ArrayList columnDefinitions = new ArrayList<>(); + + private boolean isImplicitCast = false; + + // BigQuery specific FORMAT clause: + // https://cloud.google.com/bigquery/docs/reference/standard-sql/conversion_functions#cast_as_date + private String format = null; + + public CastExpression(String keyword, Expression leftExpression, String dataType) { + this.keyword = keyword; + this.leftExpression = leftExpression; + this.colDataType = new ColDataType(dataType); + } + + // Implicit Cast + public CastExpression(String dataType, String value) { + this.keyword = null; + this.isImplicitCast = true; + this.colDataType = new ColDataType(dataType); + this.leftExpression = new StringValue(value); + } + + public CastExpression(ColDataType colDataType, String value) { + this.keyword = null; + this.isImplicitCast = true; + this.colDataType = colDataType; + this.leftExpression = new StringValue(value); + } + + public CastExpression(ColDataType colDataType, Long value) { + this.keyword = null; + this.isImplicitCast = true; + this.colDataType = colDataType; + this.leftExpression = new LongValue(value); + } + + public CastExpression(ColDataType colDataType, Double value) { + this.keyword = null; + this.isImplicitCast = true; + this.colDataType = colDataType; + this.leftExpression = new DoubleValue(value); + } + + public CastExpression(Expression leftExpression, String dataType) { + this.keyword = null; + this.leftExpression = leftExpression; + this.colDataType = new ColDataType(dataType); + } + + + public CastExpression(String keyword) { + this.keyword = keyword; + } + + public CastExpression() { + this("CAST"); + } + + public static boolean isOf(ColDataType colDataType, DataType... types) { + return Set.of(types).contains(DataType.from(colDataType.getDataType())); + } + + public static boolean isTime(ColDataType colDataType) { + return isOf(colDataType, DataType.TIME, DataType.TIME_WITH_TIME_ZONE, + DataType.TIME_WITHOUT_TIME_ZONE); + } + + public static boolean isTimeStamp(ColDataType colDataType) { + return isOf(colDataType, DataType.TIMESTAMP_NS, DataType.TIMESTAMP, + DataType.TIMESTAMP_WITHOUT_TIME_ZONE, + DataType.DATETIME, DataType.TIMESTAMP_MS, DataType.TIMESTAMP_S, + DataType.TIMESTAMPTZ, DataType.TIMESTAMP_WITH_TIME_ZONE); + } + + public static boolean isDate(ColDataType colDataType) { + return isOf(colDataType, DataType.DATE); + } + + public static boolean isBLOB(ColDataType colDataType) { + return isOf(colDataType, DataType.BLOB, DataType.BYTEA, DataType.BINARY, DataType.VARBINARY, + DataType.BYTES, DataType.VARBYTE); + } + + public static boolean isFloat(ColDataType colDataType) { + return isOf(colDataType, DataType.REAL, DataType.FLOAT4, DataType.FLOAT, DataType.DOUBLE, + DataType.DOUBLE_PRECISION, DataType.FLOAT8); + } - public ColDataType getType() { - return type; + public static boolean isInteger(ColDataType colDataType) { + return isOf(colDataType, DataType.TINYINT, DataType.INT1, DataType.SMALLINT, DataType.INT2, + DataType.SHORT, DataType.INTEGER, DataType.INT4, DataType.INT, DataType.SIGNED, + DataType.BIGINT, DataType.INT8, DataType.LONG, DataType.HUGEINT, DataType.UTINYINT, + DataType.USMALLINT, DataType.UINTEGER, DataType.UBIGINT, DataType.UHUGEINT); } - public void setType(ColDataType type) { - this.type = type; + public static boolean isDecimal(ColDataType colDataType) { + return isOf(colDataType, DataType.DECIMAL, DataType.NUMBER, DataType.NUMERIC); + } + + public static boolean isText(ColDataType colDataType) { + return isOf(colDataType, DataType.VARCHAR, DataType.NVARCHAR, DataType.CHAR, DataType.NCHAR, + DataType.BPCHAR, DataType.STRING, DataType.TEXT, DataType.CLOB); + } + + public ColDataType getColDataType() { + return colDataType; + } + + public void setColDataType(ColDataType colDataType) { + this.colDataType = colDataType; + } + + public ArrayList getColumnDefinitions() { + return columnDefinitions; + } + + public void addColumnDefinition(ColumnDefinition columnDefinition) { + this.columnDefinitions.add(columnDefinition); } public Expression getLeftExpression() { @@ -50,25 +156,140 @@ public void setLeftExpression(Expression expression) { leftExpression = expression; } + public boolean isImplicitCast() { + return isImplicitCast; + } + + public CastExpression setImplicitCast(boolean implicitCast) { + isImplicitCast = implicitCast; + return this; + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } + @Deprecated public boolean isUseCastKeyword() { - return useCastKeyword; + return keyword != null && !keyword.isEmpty(); } + @Deprecated public void setUseCastKeyword(boolean useCastKeyword) { - this.useCastKeyword = useCastKeyword; + if (useCastKeyword) { + if (keyword == null || keyword.isEmpty()) { + keyword = "CAST"; + } + } else { + keyword = null; + } + } + + public String getFormat() { + return format; + } + + public CastExpression setFormat(String format) { + this.format = format; + return this; } @Override public String toString() { - if (useCastKeyword) { - return "CAST(" + leftExpression + " AS " + type.toString() + ")"; + String formatStr = format != null && !format.isEmpty() + ? " FORMAT " + format + : ""; + if (isImplicitCast) { + return colDataType + " " + leftExpression; + } else if (keyword != null && !keyword.isEmpty()) { + return columnDefinitions.size() > 1 + ? keyword + "(" + leftExpression + " AS ROW(" + + Select.getStringList(columnDefinitions) + ")" + formatStr + ")" + : keyword + "(" + leftExpression + " AS " + colDataType.toString() + formatStr + + ")"; } else { - return leftExpression + "::" + type.toString(); + return leftExpression + "::" + colDataType.toString(); + } + } + + public CastExpression withType(ColDataType type) { + this.setColDataType(type); + return this; + } + + public CastExpression withUseCastKeyword(boolean useCastKeyword) { + this.setUseCastKeyword(useCastKeyword); + return this; + } + + public CastExpression withLeftExpression(Expression leftExpression) { + this.setLeftExpression(leftExpression); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } + + public boolean isOf(CastExpression anotherCast) { + return this.colDataType.equals(anotherCast.colDataType); + } + + public boolean isOf(DataType... types) { + return Set.of(types).contains(DataType.from(colDataType.getDataType())); + } + + public boolean isTime() { + return isTime(this.colDataType); + } + + public boolean isTimeStamp() { + return isTimeStamp(this.colDataType); + } + + public boolean isDate() { + return isDate(this.colDataType); + } + + public boolean isBLOB() { + return isBLOB(this.colDataType); + } + + public boolean isFloat() { + return isFloat(this.colDataType); + } + + public boolean isInteger() { + return isInteger(this.colDataType); + } + + public boolean isDecimal() { + return isDecimal(this.colDataType); + } + + public boolean isText() { + return isText(this.colDataType); + } + + public enum DataType { + ARRAY, BIT, BITSTRING, BLOB, BYTEA, BINARY, VARBINARY, BYTES, BOOLEAN, BOOL, ENUM, INTERVAL, LIST, MAP, STRUCT, TINYINT, INT1, SMALLINT, INT2, SHORT, INTEGER, INT4, INT, SIGNED, BIGINT, INT8, LONG, HUGEINT, UTINYINT, USMALLINT, UINTEGER, UBIGINT, UHUGEINT, DECIMAL, NUMBER, NUMERIC, REAL, FLOAT4, FLOAT, DOUBLE, DOUBLE_PRECISION, FLOAT8, FLOAT64, UUID, VARCHAR, NVARCHAR, CHAR, NCHAR, BPCHAR, STRING, TEXT, CLOB, DATE, TIME, TIME_WITHOUT_TIME_ZONE, TIMETZ, TIME_WITH_TIME_ZONE, TIMESTAMP_NS, TIMESTAMP, TIMESTAMP_WITHOUT_TIME_ZONE, DATETIME, TIMESTAMP_MS, TIMESTAMP_S, TIMESTAMPTZ, TIMESTAMP_WITH_TIME_ZONE, UNKNOWN, VARBYTE, JSON; + + public static DataType from(String typeStr) { + Matcher matcher = PATTERN.matcher(typeStr.trim().replaceAll("\\s+", "_").toUpperCase()); + if (matcher.find()) { + try { + return Enum.valueOf(DataType.class, matcher.group(0)); + } catch (Exception ex) { + Logger.getLogger(CastExpression.class.getName()).log(Level.FINE, + "Type " + typeStr + " unknown", ex); + return DataType.UNKNOWN; + } + } else { + Logger.getLogger(CastExpression.class.getName()).log(Level.FINE, + "Type " + typeStr + " unknown"); + return DataType.UNKNOWN; + } } } } diff --git a/src/main/java/net/sf/jsqlparser/expression/CollateExpression.java b/src/main/java/net/sf/jsqlparser/expression/CollateExpression.java new file mode 100644 index 000000000..8a419b241 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/CollateExpression.java @@ -0,0 +1,67 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class CollateExpression extends ASTNodeAccessImpl implements Expression { + + private Expression leftExpression; + private String collate; + + public CollateExpression() { + // empty constructor + } + + public CollateExpression(Expression leftExpression, String collate) { + this.leftExpression = leftExpression; + this.collate = collate; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public Expression getLeftExpression() { + return leftExpression; + } + + public void setLeftExpression(Expression leftExpression) { + this.leftExpression = leftExpression; + } + + public String getCollate() { + return collate; + } + + public void setCollate(String collate) { + this.collate = collate; + } + + @Override + public String toString() { + return leftExpression.toString() + " COLLATE " + collate; + } + + public CollateExpression withLeftExpression(Expression leftExpression) { + this.setLeftExpression(leftExpression); + return this; + } + + public CollateExpression withCollate(String collate) { + this.setCollate(collate); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java b/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java new file mode 100644 index 000000000..45c2fde6a --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/ConnectByPriorOperator.java @@ -0,0 +1,74 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2021 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +/* + * Copyright (C) 2021 JSQLParser. + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; + +import java.util.Objects; + +/** + * + * @author are + */ +public class ConnectByPriorOperator extends ASTNodeAccessImpl implements Expression { + private final Expression expression; + + @Deprecated + public ConnectByPriorOperator(Column column) { + this.expression = Objects.requireNonNull(column, + "The COLUMN of the ConnectByPrior Operator must not be null"); + } + + 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 + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("PRIOR ").append(expression); + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java b/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java new file mode 100644 index 000000000..776dc031e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/ConnectByRootOperator.java @@ -0,0 +1,74 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2021 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +/* + * Copyright (C) 2021 JSQLParser. + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +package net.sf.jsqlparser.expression; + +import java.util.Objects; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; + +/** + * @author are + */ +public class ConnectByRootOperator extends ASTNodeAccessImpl implements Expression { + private final Expression expression; + + @Deprecated + public ConnectByRootOperator(Column column) { + this.expression = Objects.requireNonNull(column, + "The COLUMN of the ConnectByRoot Operator must not be null"); + } + + 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 + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("CONNECT_BY_ROOT ").append(expression); + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + +} diff --git a/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java b/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java index 769d38bac..ccb15db4b 100644 --- a/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/DateTimeLiteralExpression.java @@ -1,50 +1,16 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2016 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ - /* - * Copyright (C) 2016 JSQLParser. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -/** - * - * @author toben - */ public class DateTimeLiteralExpression extends ASTNodeAccessImpl implements Expression { private String value; @@ -67,16 +33,30 @@ public void setType(DateTime type) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return type.name() + " " + value; + return type != null ? type.name() + " " + value : value; + } + + public DateTimeLiteralExpression withValue(String value) { + this.setValue(value); + return this; } - public static enum DateTime { - DATE, TIME, TIMESTAMP; + public DateTimeLiteralExpression withType(DateTime type) { + this.setType(type); + return this; + } + + public enum DateTime { + DATE, DATETIME, TIME, TIMESTAMP, TIMESTAMPTZ; + + public static DateTime from(String dateTimeStr) { + return Enum.valueOf(DateTime.class, dateTimeStr.toUpperCase()); + } } } 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/DateValue.java b/src/main/java/net/sf/jsqlparser/expression/DateValue.java index 72be75da1..d03a73c66 100644 --- a/src/main/java/net/sf/jsqlparser/expression/DateValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/DateValue.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -32,13 +20,26 @@ public class DateValue extends ASTNodeAccessImpl implements Expression { private Date value; + public DateValue() { + // empty constructor + } + + public DateValue(Date value) { + this.value = value; + } + + /** + * A Date in the form {d 'yyyy-mm-dd'} + * + * @param value The text presentation of the Date to be parsed. + */ public DateValue(String value) { - this.value = Date.valueOf(value.substring(1, value.length() - 1)); + this(Date.valueOf(value.substring(1, value.length() - 1))); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public Date getValue() { @@ -53,4 +54,9 @@ public void setValue(Date d) { public String toString() { return "{d '" + value.toString() + "'}"; } + + public DateValue withValue(Date value) { + this.setValue(value); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/DoubleValue.java b/src/main/java/net/sf/jsqlparser/expression/DoubleValue.java index 1d128e637..8d25aa61a 100644 --- a/src/main/java/net/sf/jsqlparser/expression/DoubleValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/DoubleValue.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -28,10 +16,17 @@ */ public class DoubleValue extends ASTNodeAccessImpl implements Expression { - private double value; + private Double value; private String stringValue; + public DoubleValue() { + // empty constructor + } + public DoubleValue(final String value) { + if (value == null || value.length() == 0) { + throw new IllegalArgumentException("value can neither be null nor empty."); + } String val = value; if (val.charAt(0) == '+') { val = val.substring(1); @@ -40,21 +35,32 @@ public DoubleValue(final String value) { this.stringValue = val; } + public DoubleValue(final double value) { + this.value = value; + this.stringValue = String.valueOf(value); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public double getValue() { return value; } - public void setValue(double d) { + public void setValue(Double d) { value = d; + stringValue = String.valueOf(value); } @Override public String toString() { return stringValue; } + + public DoubleValue withValue(Double value) { + this.setValue(value); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/Expression.java b/src/main/java/net/sf/jsqlparser/expression/Expression.java index 45ba5d533..1f733d564 100644 --- a/src/main/java/net/sf/jsqlparser/expression/Expression.java +++ b/src/main/java/net/sf/jsqlparser/expression/Expression.java @@ -1,29 +1,23 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; +import net.sf.jsqlparser.Model; import net.sf.jsqlparser.parser.ASTNodeAccess; -public interface Expression extends ASTNodeAccess { +public interface Expression extends ASTNodeAccess, Model { + + T accept(ExpressionVisitor expressionVisitor, S context); + + default void accept(ExpressionVisitor expressionVisitor) { + this.accept(expressionVisitor, null); + } - void accept(ExpressionVisitor expressionVisitor); } diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index b1e4e7463..998c60ef5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -1,26 +1,15 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; +import java.util.List; import net.sf.jsqlparser.expression.operators.arithmetic.Addition; import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd; import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift; @@ -29,155 +18,786 @@ import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor; import net.sf.jsqlparser.expression.operators.arithmetic.Concat; import net.sf.jsqlparser.expression.operators.arithmetic.Division; +import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision; import net.sf.jsqlparser.expression.operators.arithmetic.Modulo; import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication; import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.conditional.XorExpression; import net.sf.jsqlparser.expression.operators.relational.Between; +import net.sf.jsqlparser.expression.operators.relational.ContainedBy; +import net.sf.jsqlparser.expression.operators.relational.Contains; +import net.sf.jsqlparser.expression.operators.relational.CosineSimilarity; +import net.sf.jsqlparser.expression.operators.relational.DoubleAnd; import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.expression.operators.relational.ExcludesExpression; import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.FullTextSearch; +import net.sf.jsqlparser.expression.operators.relational.GeometryDistance; import net.sf.jsqlparser.expression.operators.relational.GreaterThan; import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals; import net.sf.jsqlparser.expression.operators.relational.InExpression; +import net.sf.jsqlparser.expression.operators.relational.IncludesExpression; +import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression; +import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression; import net.sf.jsqlparser.expression.operators.relational.IsNullExpression; +import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression; +import net.sf.jsqlparser.expression.operators.relational.JsonOperator; import net.sf.jsqlparser.expression.operators.relational.LikeExpression; import net.sf.jsqlparser.expression.operators.relational.Matches; +import net.sf.jsqlparser.expression.operators.relational.MemberOfExpression; import net.sf.jsqlparser.expression.operators.relational.MinorThan; import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals; import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo; +import net.sf.jsqlparser.expression.operators.relational.Plus; +import net.sf.jsqlparser.expression.operators.relational.PriorTo; import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator; -import net.sf.jsqlparser.expression.operators.relational.RegExpMySQLOperator; -import net.sf.jsqlparser.expression.operators.relational.JsonOperator; +import net.sf.jsqlparser.expression.operators.relational.SimilarToExpression; +import net.sf.jsqlparser.expression.operators.relational.TSQLLeftJoin; +import net.sf.jsqlparser.expression.operators.relational.TSQLRightJoin; import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.statement.select.SubSelect; +import net.sf.jsqlparser.statement.piped.FromQuery; +import net.sf.jsqlparser.statement.select.AllColumns; +import net.sf.jsqlparser.statement.select.AllTableColumns; +import net.sf.jsqlparser.statement.select.FunctionAllColumns; +import net.sf.jsqlparser.statement.select.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; + +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) { + this.visit(bitwiseRightShift, null); + } + + T visit(BitwiseLeftShift bitwiseLeftShift, S context); + + default void visit(BitwiseLeftShift bitwiseLeftShift) { + this.visit(bitwiseLeftShift, null); + } + + T visit(NullValue nullValue, S context); + + default void visit(NullValue nullValue) { + this.visit(nullValue, null); + } + + T visit(Function function, S context); + + default void visit(Function function) { + this.visit(function, null); + } + + T visit(SignedExpression signedExpression, S context); + + default void visit(SignedExpression signedExpression) { + this.visit(signedExpression, null); + } + + T visit(JdbcParameter jdbcParameter, S context); + + default void visit(JdbcParameter jdbcParameter) { + this.visit(jdbcParameter, null); + } + + T visit(JdbcNamedParameter jdbcNamedParameter, S context); + + default void visit(JdbcNamedParameter jdbcNamedParameter) { + this.visit(jdbcNamedParameter, null); + } + + T visit(DoubleValue doubleValue, S context); + + default void visit(DoubleValue doubleValue) { + this.visit(doubleValue, null); + } + + T visit(LongValue longValue, S context); + + default void visit(LongValue longValue) { + this.visit(longValue, null); + } + + T visit(HexValue hexValue, S context); + + default void visit(HexValue hexValue) { + this.visit(hexValue, null); + } + + T visit(DateValue dateValue, S context); + + default void visit(DateValue dateValue) { + this.visit(dateValue, null); + } + + T visit(TimeValue timeValue, S context); + + default void visit(TimeValue timeValue) { + this.visit(timeValue, null); + } + + T visit(TimestampValue timestampValue, S context); + + default void visit(TimestampValue timestampValue) { + this.visit(timestampValue, null); + } + + T visit(StringValue stringValue, S context); + + default void visit(StringValue stringValue) { + this.visit(stringValue, null); + } + + T visit(BooleanValue booleanValue, S context); + + default void visit(BooleanValue booleanValue) { + this.visit(booleanValue, null); + } + + T visit(Addition addition, S context); + + default void visit(Addition addition) { + this.visit(addition, null); + } + + T visit(Division division, S context); + + default void visit(Division division) { + this.visit(division, null); + } + + T visit(IntegerDivision integerDivision, S context); + + default void visit(IntegerDivision integerDivision) { + this.visit(integerDivision, null); + } + + T visit(Multiplication multiplication, S context); + + default void visit(Multiplication multiplication) { + this.visit(multiplication, null); + } + + T visit(Subtraction subtraction, S context); + + default void visit(Subtraction subtraction) { + this.visit(subtraction, null); + } + + T visit(AndExpression andExpression, S context); + + default void visit(AndExpression andExpression) { + this.visit(andExpression, null); + } + + T visit(OrExpression orExpression, S context); + + default void visit(OrExpression orExpression) { + this.visit(orExpression, null); + } + + T visit(XorExpression xorExpression, S context); + + default void visit(XorExpression xorExpression) { + this.visit(xorExpression, null); + } + + T visit(Between between, S context); + + default void visit(Between between) { + this.visit(between, null); + } + + T visit(OverlapsCondition overlapsCondition, S context); + + default void visit(OverlapsCondition overlapsCondition) { + this.visit(overlapsCondition, null); + } + + T visit(EqualsTo equalsTo, S context); + + default void visit(EqualsTo equalsTo) { + this.visit(equalsTo, null); + } + + T visit(GreaterThan greaterThan, S context); + + default void visit(GreaterThan greaterThan) { + this.visit(greaterThan, null); + } + + T visit(GreaterThanEquals greaterThanEquals, S context); + + default void visit(GreaterThanEquals greaterThanEquals) { + this.visit(greaterThanEquals, null); + } + + T visit(InExpression inExpression, S context); + + default void visit(InExpression inExpression) { + this.visit(inExpression, null); + } + + T visit(IncludesExpression includesExpression, S context); + + default void visit(IncludesExpression includesExpression) { + this.visit(includesExpression, null); + } + + T visit(ExcludesExpression excludesExpression, S context); + + default void visit(ExcludesExpression excludesExpression) { + this.visit(excludesExpression, null); + } + + T visit(FullTextSearch fullTextSearch, S context); + + default void visit(FullTextSearch fullTextSearch) { + this.visit(fullTextSearch, null); + } + + T visit(IsNullExpression isNullExpression, S context); + + default void visit(IsNullExpression isNullExpression) { + this.visit(isNullExpression, null); + } + + T visit(IsBooleanExpression isBooleanExpression, S context); + + default void visit(IsBooleanExpression isBooleanExpression) { + this.visit(isBooleanExpression, null); + } + + T visit(IsUnknownExpression isUnknownExpression, S context); + + default void visit(IsUnknownExpression isUnknownExpression) { + this.visit(isUnknownExpression, null); + } + + T visit(LikeExpression likeExpression, S context); + + default void visit(LikeExpression likeExpression) { + this.visit(likeExpression, null); + } + + T visit(MinorThan minorThan, S context); + + default void visit(MinorThan minorThan) { + this.visit(minorThan, null); + } + + T visit(MinorThanEquals minorThanEquals, S context); + + default void visit(MinorThanEquals minorThanEquals) { + this.visit(minorThanEquals, null); + } + + T visit(NotEqualsTo notEqualsTo, S context); + + default void visit(NotEqualsTo notEqualsTo) { + this.visit(notEqualsTo, null); + } + + T visit(DoubleAnd doubleAnd, S context); + + default void visit(DoubleAnd doubleAnd) { + this.visit(doubleAnd, null); + } + + T visit(Contains contains, S context); + + default void visit(Contains contains) { + this.visit(contains, null); + } + + T visit(ContainedBy containedBy, S context); + + default void visit(ContainedBy containedBy) { + this.visit(containedBy, null); + } + + T visit(ParenthesedSelect select, S context); + + T visit(Column column, S context); + + default void visit(Column column) { + this.visit(column, null); + } + + T visit(CaseExpression caseExpression, S context); + + default void visit(CaseExpression caseExpression) { + this.visit(caseExpression, null); + } + + T visit(WhenClause whenClause, S context); + + default void visit(WhenClause whenClause) { + this.visit(whenClause, null); + } + + T visit(ExistsExpression existsExpression, S context); + + default void visit(ExistsExpression existsExpression) { + this.visit(existsExpression, null); + } + + T visit(MemberOfExpression memberOfExpression, S context); + + default void visit(MemberOfExpression memberOfExpression) { + this.visit(memberOfExpression, null); + } + + T visit(AnyComparisonExpression anyComparisonExpression, S context); + + default void visit(AnyComparisonExpression anyComparisonExpression) { + this.visit(anyComparisonExpression, null); + } + + T visit(Concat concat, S context); + + default void visit(Concat concat) { + this.visit(concat, null); + } + + T visit(Matches matches, S context); + + default void visit(Matches matches) { + this.visit(matches, null); + } + + T visit(BitwiseAnd bitwiseAnd, S context); + + default void visit(BitwiseAnd bitwiseAnd) { + this.visit(bitwiseAnd, null); + } + + T visit(BitwiseOr bitwiseOr, S context); + + default void visit(BitwiseOr bitwiseOr) { + this.visit(bitwiseOr, null); + } + + T visit(BitwiseXor bitwiseXor, S context); + + default void visit(BitwiseXor bitwiseXor) { + this.visit(bitwiseXor, null); + } + + T visit(CastExpression castExpression, S context); + + default void visit(CastExpression castExpression) { + this.visit(castExpression, null); + } + + T visit(Modulo modulo, S context); + + default void visit(Modulo modulo) { + this.visit(modulo, null); + } + + T visit(AnalyticExpression analyticExpression, S context); + + default void visit(AnalyticExpression analyticExpression) { + this.visit(analyticExpression, null); + } + + T visit(ExtractExpression extractExpression, S context); + + default void visit(ExtractExpression extractExpression) { + this.visit(extractExpression, null); + } + + T visit(IntervalExpression intervalExpression, S context); + + default void visit(IntervalExpression intervalExpression) { + this.visit(intervalExpression, null); + } + + T visit(OracleHierarchicalExpression hierarchicalExpression, S context); + + default void visit(OracleHierarchicalExpression hierarchicalExpression) { + this.visit(hierarchicalExpression, null); + } + + T visit(RegExpMatchOperator regExpMatchOperator, S context); + + default void visit(RegExpMatchOperator regExpMatchOperator) { + this.visit(regExpMatchOperator, null); + } + + T visit(JsonExpression jsonExpression, S context); + + default void visit(JsonExpression jsonExpression) { + this.visit(jsonExpression, null); + } + + T visit(JsonOperator jsonOperator, S context); + + default void visit(JsonOperator jsonOperator) { + this.visit(jsonOperator, null); + } + + T visit(UserVariable userVariable, S context); + + default void visit(UserVariable userVariable) { + this.visit(userVariable, null); + } + + T visit(NumericBind numericBind, S context); + + default void visit(NumericBind numericBind) { + this.visit(numericBind, null); + } + + T visit(KeepExpression keepExpression, S context); + + default void visit(KeepExpression keepExpression) { + this.visit(keepExpression, null); + } + + T visit(MySQLGroupConcat groupConcat, S context); + + default void visit(MySQLGroupConcat groupConcat) { + this.visit(groupConcat, null); + } + + T visit(ExpressionList expressionList, S context); + + default void visit(ExpressionList expressionList) { + this.visit(expressionList, null); + } + + T visit(RowConstructor rowConstructor, S context); + + default void visit(RowConstructor rowConstructor) { + this.visit(rowConstructor, null); + } + + T visit(RowGetExpression rowGetExpression, S context); + + default void visit(RowGetExpression rowGetExpression) { + this.visit(rowGetExpression, null); + } + + T visit(OracleHint hint, S context); + + default void visit(OracleHint hint) { + this.visit(hint, null); + } + + T visit(TimeKeyExpression timeKeyExpression, S context); + + default void visit(TimeKeyExpression timeKeyExpression) { + this.visit(timeKeyExpression, null); + } + + T visit(DateTimeLiteralExpression dateTimeLiteralExpression, S context); + + default void visit(DateTimeLiteralExpression dateTimeLiteralExpression) { + this.visit(dateTimeLiteralExpression, null); + } + + T visit(NotExpression notExpression, S context); + + default void visit(NotExpression notExpression) { + this.visit(notExpression, null); + } + + T visit(NextValExpression nextValExpression, S context); + + default void visit(NextValExpression nextValExpression) { + this.visit(nextValExpression, null); + } + + T visit(CollateExpression collateExpression, S context); + + default void visit(CollateExpression collateExpression) { + this.visit(collateExpression, null); + } + + T visit(SimilarToExpression similarToExpression, S context); + + default void visit(SimilarToExpression similarToExpression) { + this.visit(similarToExpression, null); + } + + T visit(ArrayExpression arrayExpression, S context); -public interface ExpressionVisitor { + default void visit(ArrayExpression arrayExpression) { + this.visit(arrayExpression, null); + } - public void visit(BitwiseRightShift aThis); + T visit(ArrayConstructor arrayConstructor, S context); - public void visit(BitwiseLeftShift aThis); + default void visit(ArrayConstructor arrayConstructor) { + this.visit(arrayConstructor, null); + } - void visit(NullValue nullValue); + T visit(VariableAssignment variableAssignment, S context); - void visit(Function function); + default void visit(VariableAssignment variableAssignment) { + this.visit(variableAssignment, null); + } - void visit(SignedExpression signedExpression); + T visit(XMLSerializeExpr xmlSerializeExpr, S context); - void visit(JdbcParameter jdbcParameter); + default void visit(XMLSerializeExpr xmlSerializeExpr) { + this.visit(xmlSerializeExpr, null); + } - void visit(JdbcNamedParameter jdbcNamedParameter); + T visit(TimezoneExpression timezoneExpression, S context); - void visit(DoubleValue doubleValue); + default void visit(TimezoneExpression timezoneExpression) { + this.visit(timezoneExpression, null); + } - void visit(LongValue longValue); + T visit(JsonAggregateFunction jsonAggregateFunction, S context); - void visit(HexValue hexValue); + default void visit(JsonAggregateFunction jsonAggregateFunction) { + this.visit(jsonAggregateFunction, null); + } - void visit(DateValue dateValue); + T visit(JsonFunction jsonFunction, S context); - void visit(TimeValue timeValue); + default void visit(JsonFunction jsonFunction) { + this.visit(jsonFunction, null); + } - void visit(TimestampValue timestampValue); + default T visit(JsonTableFunction jsonTableFunction, S context) { + return visit((Function) jsonTableFunction, context); + } - void visit(Parenthesis parenthesis); + default void visit(JsonTableFunction jsonTableFunction) { + this.visit(jsonTableFunction, null); + } - void visit(StringValue stringValue); + T visit(ConnectByRootOperator connectByRootOperator, S context); - void visit(Addition addition); + default void visit(ConnectByRootOperator connectByRootOperator) { + this.visit(connectByRootOperator, null); + } - void visit(Division division); + T visit(ConnectByPriorOperator connectByPriorOperator, S context); - void visit(Multiplication multiplication); + default void visit(ConnectByPriorOperator connectByPriorOperator) { + this.visit(connectByPriorOperator, null); + } - void visit(Subtraction subtraction); + T visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context); - void visit(AndExpression andExpression); + default void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) { + this.visit(oracleNamedFunctionParameter, null); + } - void visit(OrExpression orExpression); + T visit(AllColumns allColumns, S context); - void visit(Between between); + T visit(FunctionAllColumns functionColumns, S context); - void visit(EqualsTo equalsTo); + default void visit(AllColumns allColumns) { + this.visit(allColumns, null); + } - void visit(GreaterThan greaterThan); + T visit(AllTableColumns allTableColumns, S context); - void visit(GreaterThanEquals greaterThanEquals); + default void visit(AllTableColumns allTableColumns) { + this.visit(allTableColumns, null); + } - void visit(InExpression inExpression); + T visit(AllValue allValue, S context); - void visit(IsNullExpression isNullExpression); + default void visit(AllValue allValue) { + this.visit(allValue, null); + } - void visit(LikeExpression likeExpression); + T visit(IsDistinctExpression isDistinctExpression, S context); - void visit(MinorThan minorThan); + default void visit(IsDistinctExpression isDistinctExpression) { + this.visit(isDistinctExpression, null); + } - void visit(MinorThanEquals minorThanEquals); + T visit(GeometryDistance geometryDistance, S context); - void visit(NotEqualsTo notEqualsTo); + default void visit(GeometryDistance geometryDistance) { + this.visit(geometryDistance, null); + } - void visit(Column tableColumn); + T visit(Select select, S context); - void visit(SubSelect subSelect); + T visit(TranscodingFunction transcodingFunction, S context); - void visit(CaseExpression caseExpression); + default void visit(TranscodingFunction transcodingFunction) { + this.visit(transcodingFunction, null); + } - void visit(WhenClause whenClause); + T visit(TrimFunction trimFunction, S context); - void visit(ExistsExpression existsExpression); + default void visit(TrimFunction trimFunction) { + this.visit(trimFunction, null); + } - void visit(AllComparisonExpression allComparisonExpression); + T visit(RangeExpression rangeExpression, S context); - void visit(AnyComparisonExpression anyComparisonExpression); + default void visit(RangeExpression rangeExpression) { + this.visit(rangeExpression, null); + } - void visit(Concat concat); + T visit(TSQLLeftJoin tsqlLeftJoin, S context); - void visit(Matches matches); + default void visit(TSQLLeftJoin tsqlLeftJoin) { + this.visit(tsqlLeftJoin, null); + } - void visit(BitwiseAnd bitwiseAnd); + T visit(TSQLRightJoin tsqlRightJoin, S context); - void visit(BitwiseOr bitwiseOr); + default void visit(TSQLRightJoin tsqlRightJoin) { + this.visit(tsqlRightJoin, null); + } - void visit(BitwiseXor bitwiseXor); + T visit(StructType structType, S context); - void visit(CastExpression cast); + default void visit(StructType structType) { + this.visit(structType, null); + } - void visit(Modulo modulo); + T visit(LambdaExpression lambdaExpression, S context); - void visit(AnalyticExpression aexpr); + default void visit(LambdaExpression lambdaExpression) { + this.visit(lambdaExpression, null); + } - void visit(ExtractExpression eexpr); + T visit(HighExpression highExpression, S context); - void visit(IntervalExpression iexpr); + default void visit(HighExpression highExpression) { + this.visit(highExpression, null); + } - void visit(OracleHierarchicalExpression oexpr); + T visit(LowExpression lowExpression, S context); - void visit(RegExpMatchOperator rexpr); + default void visit(LowExpression lowExpression) { + this.visit(lowExpression, null); + } - void visit(JsonExpression jsonExpr); + T visit(Plus plus, S context); - void visit(JsonOperator jsonExpr); + default void visit(Plus plus) { + this.visit(plus, null); + } - void visit(RegExpMySQLOperator regExpMySQLOperator); + T visit(PriorTo priorTo, S context); - void visit(UserVariable var); + default void visit(PriorTo priorTo) { + this.visit(priorTo, null); + } - void visit(NumericBind bind); + T visit(Inverse inverse, S context); - void visit(KeepExpression aexpr); + default void visit(Inverse inverse) { + this.visit(inverse, null); + } - void visit(MySQLGroupConcat groupConcat); - - void visit(ValueListExpression valueList); + T visit(CosineSimilarity cosineSimilarity, S context); - void visit(RowConstructor rowConstructor); + T visit(FromQuery fromQuery, S context); - void visit(OracleHint hint); + T visit(DateUnitExpression dateUnitExpression, S context); - void visit(TimeKeyExpression timeKeyExpression); + T visit(KeyExpression keyExpression, S context); - void visit(DateTimeLiteralExpression literal); + default void visit(KeyExpression keyExpression) { + this.visit(keyExpression, null); + } - public void visit(NotExpression aThis); + 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 995c22810..c546a4c2c 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -1,503 +1,888 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2015 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; -import net.sf.jsqlparser.expression.operators.arithmetic.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Optional; +import net.sf.jsqlparser.expression.operators.arithmetic.Addition; +import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd; +import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift; +import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr; +import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseRightShift; +import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor; +import net.sf.jsqlparser.expression.operators.arithmetic.Concat; +import net.sf.jsqlparser.expression.operators.arithmetic.Division; +import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision; +import net.sf.jsqlparser.expression.operators.arithmetic.Modulo; +import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication; +import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction; import net.sf.jsqlparser.expression.operators.conditional.AndExpression; import net.sf.jsqlparser.expression.operators.conditional.OrExpression; +import net.sf.jsqlparser.expression.operators.conditional.XorExpression; +import net.sf.jsqlparser.expression.operators.relational.Between; +import net.sf.jsqlparser.expression.operators.relational.ContainedBy; +import net.sf.jsqlparser.expression.operators.relational.Contains; +import net.sf.jsqlparser.expression.operators.relational.CosineSimilarity; +import net.sf.jsqlparser.expression.operators.relational.DoubleAnd; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.expression.operators.relational.ExcludesExpression; +import net.sf.jsqlparser.expression.operators.relational.ExistsExpression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.FullTextSearch; +import net.sf.jsqlparser.expression.operators.relational.GeometryDistance; +import net.sf.jsqlparser.expression.operators.relational.GreaterThan; +import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals; +import net.sf.jsqlparser.expression.operators.relational.InExpression; +import net.sf.jsqlparser.expression.operators.relational.IncludesExpression; +import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression; +import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression; +import net.sf.jsqlparser.expression.operators.relational.IsNullExpression; +import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression; import net.sf.jsqlparser.expression.operators.relational.JsonOperator; -import net.sf.jsqlparser.expression.operators.relational.*; +import net.sf.jsqlparser.expression.operators.relational.LikeExpression; +import net.sf.jsqlparser.expression.operators.relational.Matches; +import net.sf.jsqlparser.expression.operators.relational.MemberOfExpression; +import net.sf.jsqlparser.expression.operators.relational.MinorThan; +import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals; +import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo; +import net.sf.jsqlparser.expression.operators.relational.Plus; +import net.sf.jsqlparser.expression.operators.relational.PriorTo; +import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator; +import net.sf.jsqlparser.expression.operators.relational.SimilarToExpression; +import net.sf.jsqlparser.expression.operators.relational.TSQLLeftJoin; +import net.sf.jsqlparser.expression.operators.relational.TSQLRightJoin; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; -import net.sf.jsqlparser.statement.select.ExpressionListItem; -import net.sf.jsqlparser.statement.select.FunctionItem; +import net.sf.jsqlparser.statement.select.FunctionAllColumns; import net.sf.jsqlparser.statement.select.OrderByElement; +import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.Pivot; import net.sf.jsqlparser.statement.select.PivotVisitor; import net.sf.jsqlparser.statement.select.PivotXml; -import net.sf.jsqlparser.statement.select.SelectExpressionItem; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectItem; import net.sf.jsqlparser.statement.select.SelectItemVisitor; import net.sf.jsqlparser.statement.select.SelectVisitor; -import net.sf.jsqlparser.statement.select.SubSelect; +import net.sf.jsqlparser.statement.select.UnPivot; import net.sf.jsqlparser.statement.select.WithItem; -public class ExpressionVisitorAdapter implements ExpressionVisitor, ItemsListVisitor, PivotVisitor, SelectItemVisitor { +@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.UncommentedEmptyMethodBody"}) +public class ExpressionVisitorAdapter + implements ExpressionVisitor, PivotVisitor, SelectItemVisitor { - private SelectVisitor selectVisitor; + private SelectVisitor selectVisitor; - public SelectVisitor getSelectVisitor() { + 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 void visit(NullValue value) { - + public T visit(NullValue nullValue, S context) { + return applyExpression(nullValue, context); } @Override - public void visit(Function function) { + public T visit(Function function, S context) { + ArrayList subExpressions = new ArrayList<>(); if (function.getParameters() != null) { - function.getParameters().accept(this); + subExpressions.addAll(function.getParameters()); + } + if (function.getChainedParameters() != null) { + subExpressions.addAll(function.getChainedParameters()); } if (function.getKeep() != null) { - function.getKeep().accept(this); + subExpressions.add(function.getKeep()); + } + if (function.getOrderByElements() != null) { + for (OrderByElement orderByElement : function.getOrderByElements()) { + subExpressions.add(orderByElement.getExpression()); + } } + return visitExpressions(function, context, subExpressions); + } + + @Override + public T visit(SignedExpression signedExpression, S context) { + return signedExpression.getExpression().accept(this, context); } @Override - public void visit(SignedExpression expr) { - expr.getExpression().accept(this); + public T visit(JdbcParameter jdbcParameter, S context) { + return applyExpression(jdbcParameter, context); } @Override - public void visit(JdbcParameter parameter) { + public T visit(JdbcNamedParameter jdbcNamedParameter, S context) { + return applyExpression(jdbcNamedParameter, context); + } + + @Override + public T visit(DoubleValue doubleValue, S context) { + return applyExpression(doubleValue, context); + } + @Override + public T visit(LongValue longValue, S context) { + return applyExpression(longValue, context); } @Override - public void visit(JdbcNamedParameter parameter) { + public T visit(DateValue dateValue, S context) { + return applyExpression(dateValue, context); + } + @Override + public T visit(TimeValue timeValue, S context) { + return applyExpression(timeValue, context); } @Override - public void visit(DoubleValue value) { + public T visit(TimestampValue timestampValue, S context) { + return applyExpression(timestampValue, context); + } + @Override + public T visit(StringValue stringValue, S context) { + return applyExpression(stringValue, context); } @Override - public void visit(LongValue value) { + public T visit(BooleanValue booleanValue, S context) { + return applyExpression(booleanValue, context); + } + @Override + public T visit(Addition addition, S context) { + return visitBinaryExpression(addition, context); } @Override - public void visit(DateValue value) { + public T visit(Division division, S context) { + return visitBinaryExpression(division, context); + } + @Override + public T visit(IntegerDivision integerDivision, S context) { + return visitBinaryExpression(integerDivision, context); } @Override - public void visit(TimeValue value) { + public T visit(Multiplication multiplication, S context) { + return visitBinaryExpression(multiplication, context); + } + @Override + public T visit(Subtraction subtraction, S context) { + return visitBinaryExpression(subtraction, context); } @Override - public void visit(TimestampValue value) { + public T visit(AndExpression andExpression, S context) { + return visitBinaryExpression(andExpression, context); + } + @Override + public T visit(OrExpression orExpression, S context) { + return visitBinaryExpression(orExpression, context); } @Override - public void visit(Parenthesis parenthesis) { - parenthesis.getExpression().accept(this); + public T visit(XorExpression xorExpression, S context) { + return visitBinaryExpression(xorExpression, context); } @Override - public void visit(StringValue value) { + public T visit(Between between, S context) { + return visitExpressions(between, context, between.getLeftExpression(), + between.getBetweenExpressionStart(), between.getBetweenExpressionEnd()); + } + public T visit(OverlapsCondition overlapsCondition, S context) { + return visitExpressions(overlapsCondition, context, overlapsCondition.getLeft(), + overlapsCondition.getRight()); } + @Override - public void visit(Addition expr) { - visitBinaryExpression(expr); + public T visit(EqualsTo equalsTo, S context) { + return visitBinaryExpression(equalsTo, context); } @Override - public void visit(Division expr) { - visitBinaryExpression(expr); + public T visit(GreaterThan greaterThan, S context) { + return visitBinaryExpression(greaterThan, context); } @Override - public void visit(Multiplication expr) { - visitBinaryExpression(expr); + public T visit(GreaterThanEquals greaterThanEquals, S context) { + return visitBinaryExpression(greaterThanEquals, context); } @Override - public void visit(Subtraction expr) { - visitBinaryExpression(expr); + public T visit(InExpression inExpression, S context) { + return visitExpressions(inExpression, context, inExpression.getLeftExpression(), + inExpression.getRightExpression()); } @Override - public void visit(AndExpression expr) { - visitBinaryExpression(expr); + public T visit(IncludesExpression includesExpression, S context) { + return visitExpressions(includesExpression, context, includesExpression.getLeftExpression(), + includesExpression.getRightExpression()); } @Override - public void visit(OrExpression expr) { - visitBinaryExpression(expr); + public T visit(ExcludesExpression excludesExpression, S context) { + return visitExpressions(excludesExpression, context, excludesExpression.getLeftExpression(), + excludesExpression.getRightExpression()); } @Override - public void visit(Between expr) { - expr.getLeftExpression().accept(this); - expr.getBetweenExpressionStart().accept(this); - expr.getBetweenExpressionEnd().accept(this); + public T visit(IsNullExpression isNullExpression, S context) { + return isNullExpression.getLeftExpression().accept(this, context); } @Override - public void visit(EqualsTo expr) { - visitBinaryExpression(expr); + public T visit(FullTextSearch fullTextSearch, S context) { + ArrayList subExpressions = new ArrayList<>(fullTextSearch.getMatchColumns()); + subExpressions.add(fullTextSearch.getAgainstValue()); + return visitExpressions(fullTextSearch, context, subExpressions); } @Override - public void visit(GreaterThan expr) { - visitBinaryExpression(expr); + public T visit(IsBooleanExpression isBooleanExpression, S context) { + return isBooleanExpression.getLeftExpression().accept(this, context); } @Override - public void visit(GreaterThanEquals expr) { - visitBinaryExpression(expr); + public T visit(IsUnknownExpression isUnknownExpression, S context) { + return isUnknownExpression.getLeftExpression().accept(this, context); } @Override - public void visit(InExpression expr) { - if (expr.getLeftExpression() != null) { - expr.getLeftExpression().accept(this); - } else if (expr.getLeftItemsList() != null) { - expr.getLeftItemsList().accept(this); - } - expr.getRightItemsList().accept(this); + public T visit(LikeExpression likeExpression, S context) { + return visitBinaryExpression(likeExpression, context); } @Override - public void visit(IsNullExpression expr) { - expr.getLeftExpression().accept(this); + public T visit(MinorThan minorThan, S context) { + return visitBinaryExpression(minorThan, context); } @Override - public void visit(LikeExpression expr) { - visitBinaryExpression(expr); + public T visit(MinorThanEquals minorThanEquals, S context) { + return visitBinaryExpression(minorThanEquals, context); } @Override - public void visit(MinorThan expr) { - visitBinaryExpression(expr); + public T visit(NotEqualsTo notEqualsTo, S context) { + return visitBinaryExpression(notEqualsTo, context); } @Override - public void visit(MinorThanEquals expr) { - visitBinaryExpression(expr); + public T visit(DoubleAnd doubleAnd, S context) { + return visitBinaryExpression(doubleAnd, context); } @Override - public void visit(NotEqualsTo expr) { - visitBinaryExpression(expr); + public T visit(Contains contains, S context) { + return visitBinaryExpression(contains, context); } @Override - public void visit(Column column) { + public T visit(ContainedBy containedBy, S context) { + return visitBinaryExpression(containedBy, context); + } + @Override + public T visit(Column column, S context) { + return applyExpression(column, context); } @Override - public void visit(SubSelect subSelect) { - if (selectVisitor != null) { - if (subSelect.getWithItemsList() != null) { - for (WithItem item : subSelect.getWithItemsList()) { - item.accept(selectVisitor); - } - } - subSelect.getSelectBody().accept(selectVisitor); - } - if (subSelect.getPivot() != null) { - subSelect.getPivot().accept(this); + public T visit(ParenthesedSelect select, S context) { + visit((Select) select, context); + if (select.getPivot() != null) { + select.getPivot().accept(this, context); } + return null; } @Override - public void visit(CaseExpression expr) { - if (expr.getSwitchExpression() != null) { - expr.getSwitchExpression().accept(this); - } - for (Expression x : expr.getWhenClauses()) { - x.accept(this); + public T visit(CaseExpression caseExpression, S context) { + ArrayList subExpressions = new ArrayList<>(); + + if (caseExpression.getSwitchExpression() != null) { + subExpressions.add(caseExpression.getSwitchExpression()); } - if (expr.getElseExpression() != null) { - expr.getElseExpression().accept(this); + subExpressions.addAll(caseExpression.getWhenClauses()); + if (caseExpression.getElseExpression() != null) { + subExpressions.add(caseExpression.getElseExpression()); } + return visitExpressions(caseExpression, context, subExpressions); } @Override - public void visit(WhenClause expr) { - expr.getWhenExpression().accept(this); - expr.getThenExpression().accept(this); + public T visit(WhenClause whenClause, S context) { + return visitExpressions(whenClause, context, whenClause.getWhenExpression(), + whenClause.getThenExpression()); } @Override - public void visit(ExistsExpression expr) { - expr.getRightExpression().accept(this); + public T visit(ExistsExpression existsExpression, S context) { + return existsExpression.getRightExpression().accept(this, context); } @Override - public void visit(AllComparisonExpression expr) { - + public T visit(MemberOfExpression memberOfExpression, S context) { + return memberOfExpression.getRightExpression().accept(this, context); } @Override - public void visit(AnyComparisonExpression expr) { - + public T visit(AnyComparisonExpression anyComparisonExpression, S context) { + return applyExpression(anyComparisonExpression, context); } @Override - public void visit(Concat expr) { - visitBinaryExpression(expr); + public T visit(Concat concat, S context) { + return visitBinaryExpression(concat, context); } @Override - public void visit(Matches expr) { - visitBinaryExpression(expr); + public T visit(Matches matches, S context) { + return visitBinaryExpression(matches, context); } @Override - public void visit(BitwiseAnd expr) { - visitBinaryExpression(expr); + public T visit(BitwiseAnd bitwiseAnd, S context) { + return visitBinaryExpression(bitwiseAnd, context); } @Override - public void visit(BitwiseOr expr) { - visitBinaryExpression(expr); + public T visit(BitwiseOr bitwiseOr, S context) { + return visitBinaryExpression(bitwiseOr, context); } @Override - public void visit(BitwiseXor expr) { - visitBinaryExpression(expr); + public T visit(BitwiseXor bitwiseXor, S context) { + return visitBinaryExpression(bitwiseXor, context); } @Override - public void visit(CastExpression expr) { - expr.getLeftExpression().accept(this); + public T visit(CastExpression castExpression, S context) { + return castExpression.getLeftExpression().accept(this, context); } @Override - public void visit(Modulo expr) { - visitBinaryExpression(expr); + public T visit(Modulo modulo, S context) { + return visitBinaryExpression(modulo, context); } @Override - public void visit(AnalyticExpression expr) { - if (expr.getExpression() != null) { - expr.getExpression().accept(this); + public T visit(AnalyticExpression analyticExpression, S context) { + ArrayList subExpressions = new ArrayList<>(); + + if (analyticExpression.getExpression() != null) { + subExpressions.add(analyticExpression.getExpression()); } - if (expr.getDefaultValue() != null) { - expr.getDefaultValue().accept(this); + if (analyticExpression.getDefaultValue() != null) { + subExpressions.add(analyticExpression.getDefaultValue()); } - if (expr.getOffset() != null) { - expr.getOffset().accept(this); + if (analyticExpression.getOffset() != null) { + subExpressions.add(analyticExpression.getOffset()); } - if (expr.getKeep() != null) { - expr.getKeep().accept(this); + if (analyticExpression.getKeep() != null) { + subExpressions.add(analyticExpression.getKeep()); } - for (OrderByElement element : expr.getOrderByElements()) { - element.getExpression().accept(this); + if (analyticExpression.getFuncOrderBy() != null) { + for (OrderByElement element : analyticExpression.getOrderByElements()) { + subExpressions.add(element.getExpression()); + } } - - if (expr.getWindowElement() != null) { - expr.getWindowElement().getRange().getStart().getExpression().accept(this); - expr.getWindowElement().getRange().getEnd().getExpression().accept(this); - expr.getWindowElement().getOffset().getExpression().accept(this); + if (analyticExpression.getWindowElement() != null) { + /* + * Visit expressions from the range and offset of the window element. Do this using + * optional chains, because several things down the tree can be null e.g. the + * expression. So, null-safe versions of e.g.: + * analyticExpression.getWindowElement().getOffset().getExpression().accept(this, + * parameters); + */ + Optional.ofNullable(analyticExpression.getWindowElement().getRange()) + .map(WindowRange::getStart) + .map(WindowOffset::getExpression).ifPresent(subExpressions::add); + Optional.ofNullable(analyticExpression.getWindowElement().getRange()) + .map(WindowRange::getEnd) + .map(WindowOffset::getExpression).ifPresent(subExpressions::add); + Optional.ofNullable(analyticExpression.getWindowElement().getOffset()) + .map(WindowOffset::getExpression).ifPresent(subExpressions::add); } + return visitExpressions(analyticExpression, context, subExpressions); } @Override - public void visit(ExtractExpression expr) { - expr.getExpression().accept(this); + public T visit(ExtractExpression extractExpression, S context) { + return extractExpression.getExpression().accept(this, context); } @Override - public void visit(IntervalExpression expr) { + public T visit(IntervalExpression intervalExpression, S context) { + if (intervalExpression.getExpression() != null) { + intervalExpression.getExpression().accept(this, context); + } + return null; } @Override - public void visit(OracleHierarchicalExpression expr) { - expr.getConnectExpression().accept(this); - expr.getStartExpression().accept(this); + public T visit(OracleHierarchicalExpression hierarchicalExpression, S context) { + return visitExpressions(hierarchicalExpression, context, + hierarchicalExpression.getConnectExpression(), + hierarchicalExpression.getStartExpression()); } @Override - public void visit(RegExpMatchOperator expr) { - visitBinaryExpression(expr); + public T visit(RegExpMatchOperator regExpMatchOperator, S context) { + return visitBinaryExpression(regExpMatchOperator, context); } @Override - public void visit(ExpressionList expressionList) { - for (Expression expr : expressionList.getExpressions()) { - expr.accept(this); - } + public T visit(ExpressionList expressionList, S context) { + return visitExpressions(expressionList, context, (Collection) expressionList); } @Override - public void visit(MultiExpressionList multiExprList) { - for (ExpressionList list : multiExprList.getExprList()) { - visit(list); - } + public T visit(RowConstructor rowConstructor, S context) { + return visitExpressions(rowConstructor, context, (Collection) rowConstructor); } @Override - public void visit(NotExpression notExpr) { - notExpr.getExpression().accept(this); + public T visit(NotExpression notExpr, S context) { + return notExpr.getExpression().accept(this, context); } @Override - public void visit(BitwiseRightShift expr) { - visitBinaryExpression(expr); + public T visit(BitwiseRightShift bitwiseRightShift, S context) { + return visitBinaryExpression(bitwiseRightShift, context); } @Override - public void visit(BitwiseLeftShift expr) { - visitBinaryExpression(expr); + public T visit(BitwiseLeftShift bitwiseLeftShift, S context) { + return visitBinaryExpression(bitwiseLeftShift, context); } - protected void visitBinaryExpression(BinaryExpression expr) { - expr.getLeftExpression().accept(this); - expr.getRightExpression().accept(this); + protected T applyExpression(Expression expression, S context) { + return null; } - @Override - public void visit(JsonExpression jsonExpr) { - visit(jsonExpr.getColumn()); + protected T visitExpressions(Expression expression, S context, + ExpressionList subExpressions) { + return visitExpressions(expression, context, (Collection) subExpressions); } - @Override - public void visit(JsonOperator expr) { - visitBinaryExpression(expr); + protected T visitExpressions(Expression expression, S context, + Collection subExpressions) { + for (Expression e : subExpressions) { + if (e != null) { + e.accept(this, context); + } + } + return null; } - @Override - public void visit(RegExpMySQLOperator expr) { - visitBinaryExpression(expr); + protected T visitExpressions(Expression expression, S context, + Expression... subExpressions) { + return visitExpressions(expression, context, Arrays.asList(subExpressions)); + } + + protected T visitBinaryExpression(BinaryExpression binaryExpression, S context) { + return visitExpressions(binaryExpression, context, binaryExpression.getLeftExpression(), + binaryExpression.getRightExpression()); } @Override - public void visit(UserVariable var) { + public T visit(JsonExpression jsonExpr, S context) { + return jsonExpr.getExpression().accept(this, context); + } + @Override + public T visit(JsonOperator jsonOperator, S context) { + return visitBinaryExpression(jsonOperator, context); } @Override - public void visit(NumericBind bind) { + public T visit(UserVariable userVariable, S context) { + return applyExpression(userVariable, context); + } + @Override + public T visit(NumericBind numericBind, S context) { + return applyExpression(numericBind, context); } @Override - public void visit(KeepExpression expr) { - for (OrderByElement element : expr.getOrderByElements()) { - element.getExpression().accept(this); + public T visit(KeepExpression keepExpression, S context) { + ArrayList subExpressions = new ArrayList<>(); + for (OrderByElement element : keepExpression.getOrderByElements()) { + subExpressions.add(element.getExpression()); } + return visitExpressions(keepExpression, context, subExpressions); } @Override - public void visit(MySQLGroupConcat groupConcat) { - for (Expression expr : groupConcat.getExpressionList().getExpressions()) { - expr.accept(this); - } + public T visit(MySQLGroupConcat groupConcat, S context) { + ArrayList subExpressions = new ArrayList<>(groupConcat.getExpressionList()); if (groupConcat.getOrderByElements() != null) { for (OrderByElement element : groupConcat.getOrderByElements()) { - element.getExpression().accept(this); + subExpressions.add(element.getExpression()); } } - } - - @Override - public void visit(ValueListExpression valueListExpression) { - for (Expression expr : valueListExpression.getExpressionList().getExpressions()) { - expr.accept(this); - } + return visitExpressions(groupConcat, context, subExpressions); } @Override - public void visit(Pivot pivot) { - for (FunctionItem item : pivot.getFunctionItems()) { - item.getFunction().accept(this); + public T visit(Pivot pivot, S context) { + for (SelectItem item : pivot.getFunctionItems()) { + item.accept(this, context); } for (Column col : pivot.getForColumns()) { - col.accept(this); + col.accept(this, context); } if (pivot.getSingleInItems() != null) { - for (SelectExpressionItem item : pivot.getSingleInItems()) { - item.accept(this); + for (SelectItem item : pivot.getSingleInItems()) { + item.accept(this, context); } } - if (pivot.getMultiInItems() != null) { - for (ExpressionListItem item : pivot.getMultiInItems()) { - item.getExpressionList().accept(this); + for (SelectItem> item : pivot.getMultiInItems()) { + item.accept(this, context); } } + return null; } @Override - public void visit(PivotXml pivot) { - for (FunctionItem item : pivot.getFunctionItems()) { - item.getFunction().accept(this); + public T visit(PivotXml pivotXml, S context) { + for (SelectItem item : pivotXml.getFunctionItems()) { + item.accept(this, context); } - for (Column col : pivot.getForColumns()) { - col.accept(this); + for (Column col : pivotXml.getForColumns()) { + col.accept(this, context); } - if (pivot.getInSelect() != null && selectVisitor != null) { - pivot.getInSelect().accept(selectVisitor); + if (pivotXml.getInSelect() != null && selectVisitor != null) { + pivotXml.getInSelect().accept(selectVisitor, context); } + return null; + } + + @Override + public T visit(UnPivot unpivot, S context) { + return unpivot.accept(this, context); } @Override - public void visit(AllColumns allColumns) { + public T visit(AllColumns allColumns, S context) { + return applyExpression(allColumns, context); + } + @Override + public T visit(AllTableColumns allTableColumns, S context) { + return applyExpression(allTableColumns, context); } @Override - public void visit(AllTableColumns allTableColumns) { + public T visit(FunctionAllColumns functionAllColumns, S context) { + return applyExpression(functionAllColumns, context); + } + @Override + public T visit(AllValue allValue, S context) { + return applyExpression(allValue, context); } @Override - public void visit(SelectExpressionItem selectExpressionItem) { - selectExpressionItem.getExpression().accept(this); + public T visit(IsDistinctExpression isDistinctExpression, S context) { + return visitBinaryExpression(isDistinctExpression, context); } @Override - public void visit(RowConstructor rowConstructor) { - for (Expression expr : rowConstructor.getExprList().getExpressions()) { - expr.accept(this); + public T visit(SelectItem selectItem, S context) { + return selectItem.getExpression().accept(this, context); + } + + @Override + public T visit(RowGetExpression rowGetExpression, S context) { + return rowGetExpression.getExpression().accept(this, context); + } + + @Override + public T visit(HexValue hexValue, S context) { + return applyExpression(hexValue, context); + } + + @Override + public T visit(OracleHint hint, S context) { + return applyExpression(hint, context); + } + + @Override + public T visit(TimeKeyExpression timeKeyExpression, S context) { + return applyExpression(timeKeyExpression, context); + } + + @Override + public T visit(DateTimeLiteralExpression dateTimeLiteralExpression, S context) { + return applyExpression(dateTimeLiteralExpression, context); + } + + @Override + public T visit(NextValExpression nextValExpression, S context) { + return applyExpression(nextValExpression, context); + } + + @Override + public T visit(CollateExpression collateExpression, S context) { + return collateExpression.getLeftExpression().accept(this, context); + } + + @Override + public T visit(SimilarToExpression similarToExpression, S context) { + return visitBinaryExpression(similarToExpression, context); + } + + @Override + public T visit(ArrayExpression arrayExpression, S context) { + ArrayList subExpressions = new ArrayList<>(); + + subExpressions.add(arrayExpression.getObjExpression()); + if (arrayExpression.getIndexExpression() != null) { + subExpressions.add(arrayExpression.getIndexExpression()); + } + if (arrayExpression.getStartIndexExpression() != null) { + subExpressions.add(arrayExpression.getStartIndexExpression()); + } + if (arrayExpression.getStopIndexExpression() != null) { + subExpressions.add(arrayExpression.getStopIndexExpression()); + } + return visitExpressions(arrayExpression, context, subExpressions); + } + + @Override + public T visit(ArrayConstructor arrayConstructor, S context) { + return visitExpressions(arrayConstructor, context, arrayConstructor.getExpressions()); + } + + @Override + public T visit(VariableAssignment variableAssignment, S context) { + return visitExpressions(variableAssignment, context, variableAssignment.getVariable(), + variableAssignment.getExpression()); + } + + @Override + public T visit(XMLSerializeExpr xmlSerializeExpr, S context) { + ArrayList subExpressions = new ArrayList<>(); + + subExpressions.add(xmlSerializeExpr.getExpression()); + for (OrderByElement orderByElement : xmlSerializeExpr.getOrderByElements()) { + subExpressions.add(orderByElement.getExpression()); + } + return visitExpressions(xmlSerializeExpr, context, subExpressions); + } + + @Override + public T visit(TimezoneExpression timezoneExpression, S context) { + return timezoneExpression.getLeftExpression().accept(this, context); + } + + @Override + public T visit(JsonAggregateFunction jsonAggregateFunction, S context) { + return visitExpressions(jsonAggregateFunction, context, + jsonAggregateFunction.getExpression(), jsonAggregateFunction.getFilterExpression()); + } + + @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); + } + + @Override + public T visit(ConnectByPriorOperator connectByPriorOperator, S context) { + return connectByPriorOperator.getColumn().accept(this, context); + } + + @Override + public T visit(KeyExpression keyExpression, S context) { + return keyExpression.getExpression().accept(this, context); + } + + @Override + public T visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context) { + 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); + } + + @Override + public T visit(Select select, S context) { + if (selectVisitor != null) { + if (select.getWithItemsList() != null) { + for (WithItem item : select.getWithItemsList()) { + item.accept(selectVisitor, context); + } + } + select.accept(selectVisitor, context); } + return null; } @Override - public void visit(HexValue hexValue) { + public T visit(TranscodingFunction transcodingFunction, S context) { + return transcodingFunction.getExpression().accept(this, context); + } + @Override + public T visit(TrimFunction trimFunction, S context) { + return trimFunction.getExpression().accept(this, context); } @Override - public void visit(OracleHint hint) { + public T visit(RangeExpression rangeExpression, S context) { + return visitExpressions(rangeExpression, context, rangeExpression.getStartExpression(), + rangeExpression.getEndExpression()); + } + @Override + public T visit(TSQLLeftJoin tsqlLeftJoin, S context) { + return visitBinaryExpression(tsqlLeftJoin, context); } @Override - public void visit(TimeKeyExpression timeKeyExpression) { + public T visit(TSQLRightJoin tsqlRightJoin, S context) { + return visitBinaryExpression(tsqlRightJoin, context); + } + @Override + public T visit(StructType structType, S context) { + // @todo: visit the ColType also + if (structType.getArguments() != null) { + for (SelectItem selectItem : structType.getArguments()) { + selectItem.accept(this, context); + } + } + return null; } @Override - public void visit(DateTimeLiteralExpression literal) { + public T visit(LambdaExpression lambdaExpression, S context) { + return lambdaExpression.getExpression().accept(this, context); + } + + @Override + public T visit(HighExpression highExpression, S context) { + return highExpression.getExpression().accept(this, context); + } + + @Override + public T visit(LowExpression lowExpression, S context) { + return lowExpression.getExpression().accept(this, context); + } + + @Override + public T visit(Plus plus, S context) { + return visitBinaryExpression(plus, context); + } + @Override + public T visit(PriorTo priorTo, S context) { + return visitBinaryExpression(priorTo, context); + } + + @Override + public T visit(Inverse inverse, S context) { + return inverse.getExpression().accept(this, context); + } + + @Override + public T visit(CosineSimilarity cosineSimilarity, S context) { + cosineSimilarity.getLeftExpression().accept(this, context); + cosineSimilarity.getRightExpression().accept(this, context); + return null; + } + + @Override + 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/ExtractExpression.java b/src/main/java/net/sf/jsqlparser/expression/ExtractExpression.java index 013d4039f..dcbddfef8 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExtractExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExtractExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -35,8 +23,8 @@ public class ExtractExpression extends ASTNodeAccessImpl implements Expression { private Expression expression; @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public String getName() { @@ -59,4 +47,18 @@ public void setExpression(Expression expression) { public String toString() { return "EXTRACT(" + name + " FROM " + expression + ')'; } + + public ExtractExpression withName(String name) { + this.setName(name); + return this; + } + + public ExtractExpression withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public E getExpression(Class type) { + return type.cast(getExpression()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java b/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java new file mode 100644 index 000000000..a64d8eb27 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/FilterOverImpl.java @@ -0,0 +1,142 @@ +/*- + * #%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 java.util.List; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.select.OrderByElement; + +/** + * @author tw + */ +public class FilterOverImpl extends ASTNodeAccessImpl { + private final OrderByClause orderBy = new OrderByClause(); + private final PartitionByClause partitionBy = new PartitionByClause(); + private AnalyticType analyticType = AnalyticType.FILTER_ONLY; + private Expression filterExpression = null; + private WindowElement windowElement = null; + + public AnalyticType getAnalyticType() { + return analyticType; + } + + public void setAnalyticType(AnalyticType analyticType) { + this.analyticType = analyticType; + } + + public FilterOverImpl withAnalyticType(AnalyticType analyticType) { + this.setAnalyticType(analyticType); + return this; + } + + public List getOrderByElements() { + return orderBy.getOrderByElements(); + } + + public void setOrderByElements(List orderByElements) { + orderBy.setOrderByElements(orderByElements); + } + + public FilterOverImpl withOrderByElements(List orderByElements) { + this.setOrderByElements(orderByElements); + return this; + } + + public ExpressionList getPartitionExpressionList() { + return partitionBy; + } + + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + setPartitionExpressionList(partitionExpressionList, false); + } + + public void setPartitionExpressionList(ExpressionList partitionExpressionList, + boolean brackets) { + partitionBy.setExpressions(partitionExpressionList, brackets); + } + + public boolean isPartitionByBrackets() { + return partitionBy.isBrackets(); + } + + public Expression getFilterExpression() { + return filterExpression; + } + + public void setFilterExpression(Expression filterExpression) { + this.filterExpression = filterExpression; + } + + + public FilterOverImpl withFilterExpression(Expression filterExpression) { + this.setFilterExpression(filterExpression); + return this; + } + + public WindowElement getWindowElement() { + return windowElement; + } + + public void setWindowElement(WindowElement windowElement) { + this.windowElement = windowElement; + } + + public FilterOverImpl withWindowElement(WindowElement windowElement) { + this.setWindowElement(windowElement); + return this; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", + "PMD.MissingBreakInSwitch"}) + public StringBuilder append(StringBuilder builder) { + if (filterExpression != null) { + builder.append("FILTER (WHERE "); + builder.append(filterExpression.toString()); + builder.append(")"); + if (analyticType != AnalyticType.FILTER_ONLY) { + builder.append(" "); + } + } + + switch (analyticType) { + case FILTER_ONLY: + return builder; + case WITHIN_GROUP: + builder.append("WITHIN GROUP"); + break; + default: + builder.append("OVER"); + } + builder.append(" ("); + + partitionBy.toStringPartitionBy(builder); + orderBy.toStringOrderByElements(builder); + + if (windowElement != null) { + if (orderBy.getOrderByElements() != null) { + builder.append(' '); + } + builder.append(windowElement); + } + + builder.append(")"); + + return builder; + } + + @Override + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public String toString() { + StringBuilder builder = new StringBuilder(); + return append(builder).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/Function.java b/src/main/java/net/sf/jsqlparser/expression/Function.java index 53c1ca3d2..fcbf4531e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/Function.java +++ b/src/main/java/net/sf/jsqlparser/expression/Function.java @@ -1,65 +1,99 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.NamedExpressionList; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.select.Limit; +import net.sf.jsqlparser.statement.select.OrderByElement; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; /** * A function as MAX,COUNT... */ public class Function extends ASTNodeAccessImpl implements Expression { - - private String name; - private ExpressionList parameters; + private List nameparts; + private ExpressionList parameters; + private ExpressionList chainedParameters; + private NamedExpressionList namedParameters; private boolean allColumns = false; private boolean distinct = false; + private boolean unique = false; private boolean isEscaped = false; - private String attribute; + private Expression attributeExpression; + private HavingClause havingClause; + private Column attributeColumn = null; + private List orderByElements; + private NullHandling nullHandling = null; + private boolean ignoreNullsOutside = false; // IGNORE NULLS outside function parameters + private Limit limit = null; private KeepExpression keep = null; + private String onOverflowTruncate = null; + private String extraKeyword = null; + + /** + * Generic keyword arguments captured inside function parentheses, e.g. + * {@code GROUP_CONCAT(col ORDER BY col SEPARATOR ',')} where {@code SEPARATOR ','} is a keyword + * argument. This acts as a catch-all for dialect-specific {@code KEYWORD expr} pairs that don't + * have dedicated grammar branches. + */ + private List keywordArguments = null; + + public Function() {} + + public Function(String name, Expression... parameters) { + this.nameparts = Collections.singletonList(name); + this.parameters = new ExpressionList<>(parameters); + } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } - /** - * The name of he function, i.e. "MAX" - * - * @return the name of he function - */ public String getName() { - return name; + return nameparts == null ? null + : String.join(nameparts.get(0).equalsIgnoreCase("APPROXIMATE") ? " " : ".", + nameparts); } public void setName(String string) { - name = string; + nameparts = Arrays.asList(string); + } + + public void setName(List string) { + nameparts = string; + } + + public List getMultipartName() { + return nameparts; + } + + public Function withName(String name) { + this.setName(name); + return this; + } + + public Function withName(List nameparts) { + this.nameparts = nameparts; + return this; } - /** - * true if the parameter to the function is "*" - * - * @return true if the parameter to the function is "*" - */ public boolean isAllColumns() { return allColumns; } @@ -68,6 +102,60 @@ public void setAllColumns(boolean b) { allColumns = b; } + public NullHandling getNullHandling() { + return nullHandling; + } + + public Function setNullHandling(NullHandling nullHandling) { + this.nullHandling = nullHandling; + return this; + } + + public boolean isIgnoreNullsOutside() { + return ignoreNullsOutside; + } + + public Function setIgnoreNullsOutside(boolean ignoreNullsOutside) { + this.ignoreNullsOutside = ignoreNullsOutside; + return this; + } + + public Limit getLimit() { + return limit; + } + + public Function setLimit(Limit limit) { + this.limit = limit; + return this; + } + + public boolean isIgnoreNulls() { + return nullHandling != null && nullHandling == NullHandling.IGNORE_NULLS; + } + + /** + * This is at the moment only necessary for AnalyticExpression initialization and not for normal + * functions. Therefore there is no deparsing for it for normal functions. + */ + public void setIgnoreNulls(boolean ignoreNulls) { + this.nullHandling = ignoreNulls ? NullHandling.IGNORE_NULLS : null; + } + + public HavingClause getHavingClause() { + return havingClause; + } + + public Function setHavingClause(HavingClause havingClause) { + this.havingClause = havingClause; + return this; + } + + public Function setHavingClause(String havingType, Expression expression) { + this.havingClause = new HavingClause( + HavingClause.HavingType.valueOf(havingType.trim().toUpperCase()), expression); + return this; + } + /** * true if the function is "distinct" * @@ -81,20 +169,68 @@ public void setDistinct(boolean b) { distinct = b; } + /** + * true if the function is "unique" + * + * @return true if the function is "unique" + */ + public boolean isUnique() { + return unique; + } + + public void setUnique(boolean b) { + unique = b; + } + /** * The list of parameters of the function (if any, else null) If the parameter is "*", * allColumns is set to true * * @return the list of parameters of the function (if any, else null) */ - public ExpressionList getParameters() { + public ExpressionList getParameters() { return parameters; } - public void setParameters(ExpressionList list) { + public void setParameters(Expression... expressions) { + if (expressions.length == 1 && expressions[0] instanceof ExpressionList) { + parameters = (ExpressionList) expressions[0]; + } else { + parameters = new ExpressionList<>(expressions); + } + } + + public void setParameters(ExpressionList list) { parameters = list; } + /** + * Additional function-call parameters for dialects that support chained function calls, e.g. + * quantile(0.95)(cost) in ClickHouse. + * + * @return the chained parameters of the function (if any, else null) + */ + public ExpressionList getChainedParameters() { + return chainedParameters; + } + + public void setChainedParameters(ExpressionList chainedParameters) { + this.chainedParameters = chainedParameters; + } + + /** + * the parameters might be named parameters, e.g. substring('foobar' from 2 for 3) + * + * @return the list of named parameters of the function (if any, else null) + */ + public NamedExpressionList getNamedParameters() { + return namedParameters; + } + + public void setNamedParameters(NamedExpressionList list) { + namedParameters = list; + } + /** * Return true if it's in the form "{fn function_body() }" * @@ -108,12 +244,35 @@ public void setEscaped(boolean isEscaped) { this.isEscaped = isEscaped; } - public String getAttribute() { - return attribute; + public Object getAttribute() { + return attributeExpression != null ? attributeExpression : attributeColumn; + } + + public void setAttribute(Expression attributeExpression) { + this.attributeExpression = attributeExpression; + } + + public void setAttribute(Column attributeColumn) { + attributeExpression = null; + this.attributeColumn = attributeColumn; } - public void setAttribute(String attribute) { - this.attribute = attribute; + @Deprecated + public String getAttributeName() { + return attributeColumn.toString(); + } + + public void setAttributeName(String attributeName) { + this.attributeColumn = new Column().withColumnName(attributeName); + } + + public Column getAttributeColumn() { + return attributeColumn; + } + + public Function withAttribute(Column attributeColumn) { + setAttribute(attributeColumn); + return this; } public KeepExpression getKeep() { @@ -124,31 +283,161 @@ public void setKeep(KeepExpression keep) { this.keep = keep; } + public String getExtraKeyword() { + return extraKeyword; + } + + public Function setExtraKeyword(String extraKeyword) { + this.extraKeyword = extraKeyword; + return this; + } + + // ── Generic keyword argument support ─────────────────────────────── + + /** + * Returns the list of generic keyword arguments, e.g. {@code SEPARATOR ','}. + * + * @return keyword arguments or {@code null} + */ + public List getKeywordArguments() { + return keywordArguments; + } + + public void setKeywordArguments(List keywordArguments) { + this.keywordArguments = keywordArguments; + } + + /** + * Adds a single keyword argument (appends to the list, creating it if needed). + */ + public Function addKeywordArgument(String keyword, Expression expression) { + if (this.keywordArguments == null) { + this.keywordArguments = new ArrayList<>(); + } + this.keywordArguments.add(new KeywordArgument(keyword, expression)); + return this; + } + + public Function withKeywordArguments(List keywordArguments) { + this.keywordArguments = keywordArguments; + return this; + } + + /** + * Convenience lookup: returns the expression for the first keyword argument matching the given + * keyword (case-insensitive), or {@code null}. + */ + public Expression getKeywordArgumentValue(String keyword) { + if (keywordArguments == null) { + return null; + } + for (KeywordArgument ka : keywordArguments) { + if (ka.getKeyword().equalsIgnoreCase(keyword)) { + return ka.getExpression(); + } + } + return null; + } + @Override + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public String toString() { String params; - if (parameters != null) { - params = parameters.toString(); - if (isDistinct()) { - params = params.replaceFirst("\\(", "(DISTINCT "); - } else if (isAllColumns()) { - params = params.replaceFirst("\\(", "(ALL "); + if (parameters != null || namedParameters != null) { + if (parameters != null) { + StringBuilder b = new StringBuilder(); + b.append("("); + if (isDistinct()) { + b.append("DISTINCT "); + } else if (isUnique()) { + b.append("UNIQUE "); + } + if (isAllColumns()) { + b.append("ALL "); + } + + if (extraKeyword != null) { + b.append(extraKeyword).append(" "); + } + + b.append(parameters); + + if (havingClause != null) { + havingClause.appendTo(b); + } + + if (nullHandling != null && !isIgnoreNullsOutside()) { + switch (nullHandling) { + case IGNORE_NULLS: + b.append(" IGNORE NULLS"); + break; + case RESPECT_NULLS: + b.append(" RESPECT NULLS"); + break; + } + } + if (orderByElements != null) { + b.append(" ORDER BY "); + boolean comma = false; + for (OrderByElement orderByElement : orderByElements) { + if (comma) { + b.append(", "); + } else { + comma = true; + } + b.append(orderByElement); + } + } + if (limit != null) { + b.append(limit); + } + + if (onOverflowTruncate != null) { + b.append(" ON OVERFLOW ").append(onOverflowTruncate); + } + + // Generic keyword arguments (e.g. SEPARATOR ',') + if (keywordArguments != null) { + for (KeywordArgument ka : keywordArguments) { + ka.appendTo(b); + } + } + + b.append(")"); + params = b.toString(); + } else { + params = namedParameters.toString(); } - } else if (isAllColumns()) { - params = "(*)"; } else { params = "()"; } - String ans = name + "" + params + ""; + String ans = getName() + params; + + if (chainedParameters != null) { + ans += "(" + chainedParameters + ")"; + } + + if (nullHandling != null && isIgnoreNullsOutside()) { + switch (nullHandling) { + case IGNORE_NULLS: + ans += " IGNORE NULLS"; + break; + case RESPECT_NULLS: + ans += " RESPECT NULLS"; + break; + } + } - if (attribute != null) { - ans += "." + attribute; + if (attributeExpression != null) { + ans += "." + attributeExpression; + } else if (attributeColumn != null) { + ans += "." + attributeColumn; } if (keep != null) { - ans += " " + keep.toString(); + ans += " " + keep; } if (isEscaped) { @@ -157,4 +446,199 @@ public String toString() { return ans; } + + public Function withAttribute(Expression attribute) { + this.setAttribute(attribute); + return this; + } + + @Deprecated + public Function withAttributeName(String attributeName) { + this.setAttributeName(attributeName); + return this; + } + + public Function withKeep(KeepExpression keep) { + this.setKeep(keep); + return this; + } + + public Function withIgnoreNulls(boolean ignoreNulls) { + this.setIgnoreNulls(ignoreNulls); + return this; + } + + public Function withParameters(ExpressionList parameters) { + this.setParameters(parameters); + return this; + } + + public Function withParameters(Expression... parameters) { + return withParameters(new ExpressionList<>(parameters)); + } + + public Function withChainedParameters(ExpressionList chainedParameters) { + this.setChainedParameters(chainedParameters); + return this; + } + + public Function withNamedParameters(NamedExpressionList namedParameters) { + this.setNamedParameters(namedParameters); + return this; + } + + public Function withAllColumns(boolean allColumns) { + this.setAllColumns(allColumns); + return this; + } + + public Function withDistinct(boolean distinct) { + this.setDistinct(distinct); + return this; + } + + public Function withUnique(boolean unique) { + this.setUnique(unique); + return this; + } + + public List getOrderByElements() { + return orderByElements; + } + + public void setOrderByElements(List orderByElements) { + this.orderByElements = orderByElements; + } + + public String getOnOverflowTruncate() { + return onOverflowTruncate; + } + + public Function setOnOverflowTruncate(String onOverflowTruncate) { + this.onOverflowTruncate = onOverflowTruncate; + return this; + } + + public E getAttribute(Class type) { + return type.cast(getAttribute()); + } + + public enum NullHandling { + IGNORE_NULLS, RESPECT_NULLS; + } + + // ── KeywordArgument inner class ──────────────────────────────────── + + /** + * Represents a generic {@code KEYWORD expression} pair inside a function call. + *

+ * Examples: + *

    + *
  • {@code GROUP_CONCAT(col SEPARATOR ',')} → keyword="SEPARATOR", expression=','
  • + *
+ */ + public static class KeywordArgument implements Serializable { + private String keyword; + private Expression expression; + + public KeywordArgument() {} + + public KeywordArgument(String keyword, Expression expression) { + this.keyword = keyword; + this.expression = expression; + } + + public String getKeyword() { + return keyword; + } + + public KeywordArgument setKeyword(String keyword) { + this.keyword = keyword; + return this; + } + + public Expression getExpression() { + return expression; + } + + public KeywordArgument setExpression(Expression expression) { + this.expression = expression; + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append(" ").append(keyword).append(" ").append(expression); + return builder; + } + + @Override + public String toString() { + return keyword + " " + expression; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof KeywordArgument)) { + return false; + } + KeywordArgument that = (KeywordArgument) o; + return Objects.equals(keyword, that.keyword) + && Objects.equals(expression, that.expression); + } + + @Override + public int hashCode() { + return Objects.hash(keyword, expression); + } + } + + public static class HavingClause extends ASTNodeAccessImpl implements Expression { + HavingType havingType; + Expression expression; + + public HavingClause(HavingType havingType, Expression expression) { + this.havingType = havingType; + this.expression = expression; + } + + public HavingType getHavingType() { + return havingType; + } + + public HavingClause setHavingType(HavingType havingType) { + this.havingType = havingType; + return this; + } + + public Expression getExpression() { + return expression; + } + + public HavingClause setExpression(Expression expression) { + this.expression = expression; + return this; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expression.accept(expressionVisitor, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append(" HAVING ").append(havingType.name()).append(" ").append(expression); + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + + enum HavingType { + MAX, MIN; + } + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/HexValue.java b/src/main/java/net/sf/jsqlparser/expression/HexValue.java index 6401f5484..cba9a3ac1 100644 --- a/src/main/java/net/sf/jsqlparser/expression/HexValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/HexValue.java @@ -1,55 +1,93 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -/** - * Every number with a point or a exponential format is a DoubleValue - */ +import java.nio.charset.StandardCharsets; + public class HexValue extends ASTNodeAccessImpl implements Expression { - private String stringValue; + private String value; + + public HexValue() { + // empty constructor + } public HexValue(final String value) { String val = value; - this.stringValue = val; + this.value = val; + } + + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public String getValue() { - return stringValue; + return value; + } + + public void setValue(String value) { + this.value = value; } - public void setValue(String d) { - stringValue = d; + public HexValue withValue(String value) { + this.setValue(value); + return this; } @Override public String toString() { - return stringValue; + return value; + } + + public String getDigits() { + return value.toUpperCase().startsWith("0X") + ? value.substring(2) + : value.substring(2, value.length() - 1); + } + + public Long getLong() { + return Long.parseLong( + getDigits(), 16); + } + + public LongValue getLongValue() { + return new LongValue(getLong()); + } + + // `X'C3BC'` --> `'ü'` + public StringValue getStringValue() { + return new StringValue( + new String(hexStringToByteArray(getDigits()), StandardCharsets.UTF_8)); + } + + // `X'C3BC'` --> `\xC3\xBC` + public StringValue getBlob() { + StringBuilder builder = new StringBuilder(); + String digits = getDigits(); + int len = digits.length(); + for (int i = 0; i < len; i += 2) { + builder.append("\\x").append(digits.charAt(i)).append(digits.charAt(i + 1)); + } + return new StringValue(builder.toString()); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/HighExpression.java b/src/main/java/net/sf/jsqlparser/expression/HighExpression.java new file mode 100644 index 000000000..4d3a9cd63 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/HighExpression.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class HighExpression extends ASTNodeAccessImpl implements Expression { + private Expression expression; + + public HighExpression() { + // empty constructor + } + + public HighExpression(Expression expression) { + this.expression = expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return "HIGH " + expression.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/IntervalExpression.java b/src/main/java/net/sf/jsqlparser/expression/IntervalExpression.java index 7c0503380..9c028c769 100644 --- a/src/main/java/net/sf/jsqlparser/expression/IntervalExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/IntervalExpression.java @@ -1,36 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -/** - * - * @author wumpz - */ +import java.util.Objects; + public class IntervalExpression extends ASTNodeAccessImpl implements Expression { + private final boolean intervalKeyword; private String parameter = null; private String intervalType = null; + private Expression expression = null; + + public IntervalExpression() { + this(true); + } + + public IntervalExpression(boolean intervalKeyword) { + this.intervalKeyword = intervalKeyword; + } + + public IntervalExpression(int value, String type) { + this.parameter = null; + this.intervalKeyword = true; + this.expression = new LongValue(value); + this.intervalType = type; + } + + public boolean isUsingIntervalKeyword() { + return intervalKeyword; + } public String getParameter() { return parameter; @@ -48,13 +55,42 @@ public void setIntervalType(String intervalType) { this.intervalType = intervalType; } + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + @Override public String toString() { - return "INTERVAL " + parameter + (intervalType != null ? " " + intervalType : ""); + return (intervalKeyword ? "INTERVAL " : "") + + Objects.toString(expression, parameter) + + (intervalType != null ? " " + intervalType : ""); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public IntervalExpression withParameter(String parameter) { + this.setParameter(parameter); + return this; + } + + public IntervalExpression withIntervalType(String intervalType) { + this.setIntervalType(intervalType); + return this; + } + + public IntervalExpression withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public E getExpression(Class type) { + return type.cast(getExpression()); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/Inverse.java b/src/main/java/net/sf/jsqlparser/expression/Inverse.java new file mode 100644 index 000000000..b50d8be8f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/Inverse.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class Inverse extends ASTNodeAccessImpl implements Expression { + private Expression expression; + + public Inverse() { + // empty constructor + } + + public Inverse(Expression expression) { + this.expression = expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return "INVERSE (" + expression.toString() + ")"; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JdbcNamedParameter.java b/src/main/java/net/sf/jsqlparser/expression/JdbcNamedParameter.java index f45a8f73a..84aa0b34e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JdbcNamedParameter.java +++ b/src/main/java/net/sf/jsqlparser/expression/JdbcNamedParameter.java @@ -1,43 +1,35 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -/** - * - * @author aud - */ public class JdbcNamedParameter extends ASTNodeAccessImpl implements Expression { - + private String parameterCharacter = ":"; private String name; - public JdbcNamedParameter() { - } + public JdbcNamedParameter() {} public JdbcNamedParameter(String name) { this.name = name; } + public String getParameterCharacter() { + return parameterCharacter; + } + + public JdbcNamedParameter setParameterCharacter(String parameterCharacter) { + this.parameterCharacter = parameterCharacter; + return this; + } + public String getName() { return name; } @@ -47,12 +39,17 @@ public void setName(String name) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return ":" + name; + return parameterCharacter + name; + } + + public JdbcNamedParameter withName(String name) { + this.setName(name); + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java b/src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java index a0b7242b0..f512c47fc 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java +++ b/src/main/java/net/sf/jsqlparser/expression/JdbcParameter.java @@ -1,42 +1,53 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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.regex.Matcher; +import java.util.regex.Pattern; + /** - * A '?' in a statement or a ? e.g. ?4 + * A '?' in a statement or a ?<number> e.g. ?4 */ public class JdbcParameter extends ASTNodeAccessImpl implements Expression { + private String parameterCharacter = "?"; private Integer index; private boolean useFixedIndex = false; - public JdbcParameter() { - } + public JdbcParameter() {} - public JdbcParameter(Integer index, boolean useFixedIndex) { + public JdbcParameter(Integer index, boolean useFixedIndex, String parameterCharacter) { this.index = index; this.useFixedIndex = useFixedIndex; + this.parameterCharacter = parameterCharacter; + + // This is needed for Parameters starting with "$" like "$2" + // Those will contain the index in the parameterCharacter + final Pattern pattern = Pattern.compile("(\\$)(\\d*)"); + final Matcher matcher = pattern.matcher(parameterCharacter); + if (matcher.find() && matcher.groupCount() == 2) { + this.useFixedIndex = true; + this.parameterCharacter = matcher.group(1); + this.index = Integer.valueOf(matcher.group(2)); + } + } + + public String getParameterCharacter() { + return parameterCharacter; + } + + public JdbcParameter setParameterCharacter(String parameterCharacter) { + this.parameterCharacter = parameterCharacter; + return this; } public Integer getIndex() { @@ -56,12 +67,22 @@ public void setUseFixedIndex(boolean useFixedIndex) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return useFixedIndex ? "?" + index : "?"; + return useFixedIndex ? parameterCharacter + index : parameterCharacter; + } + + public JdbcParameter withIndex(Integer index) { + this.setIndex(index); + return this; + } + + public JdbcParameter withUseFixedIndex(boolean useFixedIndex) { + this.setUseFixedIndex(useFixedIndex); + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateFunction.java b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateFunction.java new file mode 100644 index 000000000..20bfa272e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateFunction.java @@ -0,0 +1,295 @@ +/*- + * #%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 java.util.List; +import java.util.Objects; + +import net.sf.jsqlparser.statement.select.OrderByElement; + +/** + * @author Andreas Reichel + */ + +public class JsonAggregateFunction extends FilterOverImpl implements Expression { + private final OrderByClause expressionOrderBy = new OrderByClause(); + private JsonFunctionType functionType; + private Expression expression = null; + private boolean usingKeyKeyword = false; + private Object key; + private boolean usingValueKeyword = false; + private Object value; + + private boolean usingFormatJson = false; + + private JsonAggregateOnNullType onNullType; + private JsonAggregateUniqueKeysType uniqueKeysType; + + + public JsonAggregateOnNullType getOnNullType() { + return onNullType; + } + + public void setOnNullType(JsonAggregateOnNullType onNullType) { + this.onNullType = onNullType; + } + + public JsonAggregateFunction withOnNullType(JsonAggregateOnNullType onNullType) { + this.setOnNullType(onNullType); + return this; + } + + public JsonAggregateUniqueKeysType getUniqueKeysType() { + return uniqueKeysType; + } + + public void setUniqueKeysType(JsonAggregateUniqueKeysType uniqueKeysType) { + this.uniqueKeysType = uniqueKeysType; + } + + public JsonAggregateFunction withUniqueKeysType(JsonAggregateUniqueKeysType uniqueKeysType) { + this.setUniqueKeysType(uniqueKeysType); + return this; + } + + public JsonFunctionType getType() { + return functionType; + } + + public void setType(JsonFunctionType type) { + this.functionType = Objects.requireNonNull(type, + "The Type of the JSON Aggregate Function must not be null"); + } + + public void setType(String typeName) { + this.functionType = JsonFunctionType + .valueOf(Objects + .requireNonNull(typeName, + "The Type of the JSON Aggregate Function must not be null") + .toUpperCase()); + } + + public JsonAggregateFunction withType(JsonFunctionType type) { + this.setType(type); + return this; + } + + public JsonAggregateFunction withType(String typeName) { + this.setType(typeName); + return this; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public JsonAggregateFunction withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public boolean isUsingKeyKeyword() { + return usingKeyKeyword; + } + + public void setUsingKeyKeyword(boolean usingKeyKeyword) { + this.usingKeyKeyword = usingKeyKeyword; + } + + public JsonAggregateFunction withUsingKeyKeyword(boolean usingKeyKeyword) { + this.setUsingKeyKeyword(usingKeyKeyword); + return this; + } + + public Object getKey() { + return key; + } + + public void setKey(Object key) { + this.key = key; + } + + public JsonAggregateFunction withKey(Object key) { + this.setKey(key); + return this; + } + + public boolean isUsingValueKeyword() { + return usingValueKeyword; + } + + public void setUsingValueKeyword(boolean usingValueKeyword) { + this.usingValueKeyword = usingValueKeyword; + } + + public JsonAggregateFunction withUsingValueKeyword(boolean usingValueKeyword) { + this.setUsingValueKeyword(usingValueKeyword); + return this; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public JsonAggregateFunction withValue(Object value) { + this.setValue(value); + return this; + } + + public boolean isUsingFormatJson() { + return usingFormatJson; + } + + public void setUsingFormatJson(boolean usingFormatJson) { + this.usingFormatJson = usingFormatJson; + } + + public JsonAggregateFunction withUsingFormatJson(boolean usingFormatJson) { + this.setUsingFormatJson(usingFormatJson); + return this; + } + + public List getExpressionOrderByElements() { + return expressionOrderBy.getOrderByElements(); + } + + public void setExpressionOrderByElements(List orderByElements) { + expressionOrderBy.setOrderByElements(orderByElements); + } + + public JsonAggregateFunction withExpressionOrderByElements( + List orderByElements) { + this.setExpressionOrderByElements(orderByElements); + return this; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + // avoid countless Builder --> String conversion + @Override + public StringBuilder append(StringBuilder builder) { + switch (functionType) { + case OBJECT: + case MYSQL_OBJECT: + appendObject(builder); + break; + case ARRAY: + appendArray(builder); + break; + default: + // this should never happen really + throw new UnsupportedOperationException("JSON Aggregate Function of the type " + + functionType.name() + " has not been implemented yet."); + } + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendObject(StringBuilder builder) { + builder.append("JSON_OBJECTAGG( "); + if (usingValueKeyword) { + if (usingKeyKeyword) { + builder.append("KEY "); + } + builder.append(key).append(" VALUE ").append(value); + } else if (functionType == JsonFunctionType.MYSQL_OBJECT) { + builder.append(key).append(", ").append(value); + } else { + builder.append(key).append(":").append(value); + } + + if (usingFormatJson) { + builder.append(" FORMAT JSON"); + } + + if (onNullType != null) { + switch (onNullType) { + case NULL: + builder.append(" NULL ON NULL"); + break; + case ABSENT: + builder.append(" ABSENT On NULL"); + break; + default: + // this should never happen + } + } + + if (uniqueKeysType != null) { + switch (uniqueKeysType) { + case WITH: + builder.append(" WITH UNIQUE KEYS"); + break; + case WITHOUT: + builder.append(" WITHOUT UNIQUE KEYS"); + break; + default: + // this should never happen + } + } + + builder.append(" ) "); + + + // FILTER( WHERE expression ) OVER windowNameOrSpecification + super.append(builder); + + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendArray(StringBuilder builder) { + builder.append("JSON_ARRAYAGG( "); + builder.append(expression).append(" "); + + if (usingFormatJson) { + builder.append("FORMAT JSON "); + } + + expressionOrderBy.toStringOrderByElements(builder); + + 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 ommitted + } + } + builder.append(") "); + + + // FILTER( WHERE expression ) OVER windowNameOrSpecification + super.append(builder); + + return builder; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + return append(builder).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateOnNullType.java b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateOnNullType.java new file mode 100644 index 000000000..898dad7c0 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateOnNullType.java @@ -0,0 +1,37 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2021 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +/* + * Copyright (C) 2021 JSQLParser. + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +package net.sf.jsqlparser.expression; + +/** + * @author Andreas Reichel + */ +public enum JsonAggregateOnNullType { + NULL, ABSENT; + + public static JsonAggregateOnNullType from(String type) { + return Enum.valueOf(JsonAggregateOnNullType.class, type.toUpperCase()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonAggregateUniqueKeysType.java b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateUniqueKeysType.java new file mode 100644 index 000000000..097aad552 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonAggregateUniqueKeysType.java @@ -0,0 +1,37 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2021 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +/* + * Copyright (C) 2021 JSQLParser. + * + * This library is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; either version + * 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +package net.sf.jsqlparser.expression; + +/** + * @author Andreas Reichel + */ +public enum JsonAggregateUniqueKeysType { + WITH, WITHOUT; + + public static JsonAggregateUniqueKeysType from(String type) { + return Enum.valueOf(JsonAggregateUniqueKeysType.class, type.toUpperCase()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonExpression.java b/src/main/java/net/sf/jsqlparser/expression/JsonExpression.java index 86cba6e17..f258e855c 100644 --- a/src/main/java/net/sf/jsqlparser/expression/JsonExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/JsonExpression.java @@ -1,83 +1,99 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2014 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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.AbstractMap; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Map; -import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -import net.sf.jsqlparser.schema.Column; - -/** - * - * @author toben - */ public class JsonExpression extends ASTNodeAccessImpl implements Expression { + private final List> idents = new ArrayList<>(); + private Expression expr; - private Column column; + public JsonExpression() { - private List idents = new ArrayList(); - private List operators = new ArrayList(); + } + + public JsonExpression(Expression expr) { + this.expr = expr; + } + + public JsonExpression(Expression expr, List> idents) { + this.expr = expr; + this.idents.addAll(idents); + } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } - public Column getColumn() { - return column; + public Expression getExpression() { + return expr; } - public void setColumn(Column column) { - this.column = column; + public void setExpression(Expression expr) { + this.expr = expr; } -// public List getIdents() { -// return idents; -// } -// -// public void setIdents(List idents) { -// this.idents = idents; -// operators = new ArrayList(); -// for (String ident : idents) { -// operators.add("->"); -// } -// } -// -// public void addIdent(String ident) { -// addIdent(ident, "->"); -// } - public void addIdent(String ident, String operator) { - idents.add(ident); - operators.add(operator); + public void addIdent(Expression ident, String operator) { + idents.add(new AbstractMap.SimpleEntry<>(ident, operator)); + } + + public void addAllIdents(Collection> idents) { + this.idents.addAll(idents); + } + + public List> getIdentList() { + return idents; + } + + public Map.Entry getIdent(int index) { + return idents.get(index); + } + + @Deprecated + public List getIdents() { + ArrayList l = new ArrayList<>(); + for (Map.Entry ident : idents) { + l.add(ident.getKey()); + } + + return l; + } + + @Deprecated + public List getOperators() { + ArrayList l = new ArrayList<>(); + for (Map.Entry ident : idents) { + l.add(ident.getValue()); + } + return l; } @Override public String toString() { StringBuilder b = new StringBuilder(); - b.append(column.toString()); - for (int i = 0; i < idents.size(); i++) { - b.append(operators.get(i)).append(idents.get(i)); + b.append(expr.toString()); + for (Map.Entry ident : idents) { + b.append(ident.getValue()).append(ident.getKey()); } return b.toString(); } + + public JsonExpression withExpression(Expression expr) { + this.setExpression(expr); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java new file mode 100644 index 000000000..3cc409873 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunction.java @@ -0,0 +1,608 @@ +/*- + * #%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 java.util.ArrayList; +import java.util.Objects; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.create.table.ColDataType; + +/** + * Represents a JSON-Function.
+ * Currently supported are the types in {@link JsonFunctionType}.
+ *
+ * For JSON_OBJECT the parameters are available from {@link #getKeyValuePairs()}
+ *
+ * For JSON_ARRAY the parameters are availble from {@link #getExpressions()}.
+ * + * @author Andreas Reichel + */ +public class JsonFunction extends ASTNodeAccessImpl implements Expression { + public enum JsonOnResponseBehaviorType { + ERROR, NULL, DEFAULT, EMPTY, EMPTY_ARRAY, EMPTY_OBJECT, TRUE, FALSE, UNKNOWN + } + + public enum JsonWrapperType { + WITHOUT, WITH + } + + public enum JsonWrapperMode { + CONDITIONAL, UNCONDITIONAL + } + + public enum JsonQuotesType { + KEEP, OMIT + } + + public enum ScalarsType { + ALLOW, DISALLOW + } + + public static class JsonOnResponseBehavior { + private JsonOnResponseBehaviorType type; + private Expression expression; + + public JsonOnResponseBehavior(JsonOnResponseBehaviorType type) { + this(type, null); + } + + public JsonOnResponseBehavior(JsonOnResponseBehaviorType type, Expression expression) { + this.type = type; + this.expression = expression; + } + + public JsonOnResponseBehaviorType getType() { + return type; + } + + public void setType(JsonOnResponseBehaviorType type) { + this.type = type; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public StringBuilder append(StringBuilder builder) { + switch (type) { + case ERROR: + builder.append("ERROR"); + break; + case NULL: + builder.append("NULL"); + break; + case DEFAULT: + builder.append("DEFAULT ").append(expression); + break; + case EMPTY: + builder.append("EMPTY "); + break; + case EMPTY_ARRAY: + builder.append("EMPTY ARRAY"); + break; + case EMPTY_OBJECT: + builder.append("EMPTY OBJECT"); + break; + case TRUE: + builder.append("TRUE"); + break; + case FALSE: + builder.append("FALSE"); + break; + case UNKNOWN: + builder.append("UNKNOWN"); + break; + default: + throw new IllegalStateException("Unhandled JsonOnResponseBehavior: " + type); + // this should never happen + } + return builder; + } + + @Override + public String toString() { + return append(new StringBuilder()).toString(); + } + } + + private final ArrayList keyValuePairs = new ArrayList<>(); + private final ArrayList expressions = new ArrayList<>(); + private final ArrayList passingExpressions = new ArrayList<>(); + private final ArrayList additionalQueryPathArguments = new ArrayList<>(); + private JsonFunctionType functionType; + private JsonAggregateOnNullType onNullType; + private JsonAggregateUniqueKeysType uniqueKeysType; + + private boolean isStrict = false; + private JsonFunctionExpression inputExpression; + private Expression jsonPathExpression; + private ColDataType returningType; + private boolean returningFormatJson; + private String returningEncoding; + private JsonOnResponseBehavior onEmptyBehavior; + private JsonOnResponseBehavior onErrorBehavior; + private JsonWrapperType wrapperType; + private JsonWrapperMode wrapperMode; + private boolean wrapperArray; + private JsonQuotesType quotesType; + private boolean quotesOnScalarString; + private ScalarsType scalarsType; + + public JsonFunction() {} + + public JsonFunction(JsonFunctionType functionType) { + this.functionType = functionType; + } + + /** + * Returns the Parameters of an JSON_OBJECT
+ * The KeyValuePairs may not have both key and value set, in some cases only the Key is set. + * + * @see net.sf.jsqlparser.parser.feature.Feature#allowCommaAsKeyValueSeparator + * + * @return A List of KeyValuePairs, never NULL + */ + public ArrayList getKeyValuePairs() { + return keyValuePairs; + } + + /** + * Returns the parameters of JSON_ARRAY
+ * + * @return A List of {@link JsonFunctionExpression}s, never NULL + */ + public ArrayList getExpressions() { + return expressions; + } + + public JsonKeyValuePair getKeyValuePair(int i) { + return keyValuePairs.get(i); + } + + public JsonFunctionExpression getExpression(int i) { + return expressions.get(i); + } + + public boolean add(JsonKeyValuePair keyValuePair) { + return keyValuePairs.add(keyValuePair); + } + + public void add(int i, JsonKeyValuePair keyValuePair) { + keyValuePairs.add(i, keyValuePair); + } + + public boolean add(JsonFunctionExpression expression) { + return expressions.add(expression); + } + + public void add(int i, JsonFunctionExpression expression) { + expressions.add(i, expression); + } + + public ArrayList getPassingExpressions() { + return passingExpressions; + } + + public boolean addPassingExpression(Expression expression) { + return passingExpressions.add(expression); + } + + public ArrayList getAdditionalQueryPathArguments() { + return additionalQueryPathArguments; + } + + public boolean addAdditionalQueryPathArgument(String argument) { + return additionalQueryPathArguments.add(argument); + } + + public JsonFunctionExpression getInputExpression() { + return inputExpression; + } + + public void setInputExpression(JsonFunctionExpression inputExpression) { + this.inputExpression = inputExpression; + } + + public Expression getJsonPathExpression() { + return jsonPathExpression; + } + + public void setJsonPathExpression(Expression jsonPathExpression) { + this.jsonPathExpression = jsonPathExpression; + } + + public ColDataType getReturningType() { + return returningType; + } + + public void setReturningType(ColDataType returningType) { + this.returningType = returningType; + } + + public boolean isReturningFormatJson() { + return returningFormatJson; + } + + public void setReturningFormatJson(boolean returningFormatJson) { + this.returningFormatJson = returningFormatJson; + } + + public String getReturningEncoding() { + return returningEncoding; + } + + public void setReturningEncoding(String returningEncoding) { + this.returningEncoding = returningEncoding; + } + + public JsonOnResponseBehavior getOnEmptyBehavior() { + return onEmptyBehavior; + } + + public void setOnEmptyBehavior(JsonOnResponseBehavior onEmptyBehavior) { + this.onEmptyBehavior = onEmptyBehavior; + } + + public JsonOnResponseBehavior getOnErrorBehavior() { + return onErrorBehavior; + } + + public void setOnErrorBehavior(JsonOnResponseBehavior onErrorBehavior) { + this.onErrorBehavior = onErrorBehavior; + } + + public JsonWrapperType getWrapperType() { + return wrapperType; + } + + public void setWrapperType(JsonWrapperType wrapperType) { + this.wrapperType = wrapperType; + } + + public JsonWrapperMode getWrapperMode() { + return wrapperMode; + } + + public void setWrapperMode(JsonWrapperMode wrapperMode) { + this.wrapperMode = wrapperMode; + } + + public boolean isWrapperArray() { + return wrapperArray; + } + + public void setWrapperArray(boolean wrapperArray) { + this.wrapperArray = wrapperArray; + } + + public JsonQuotesType getQuotesType() { + return quotesType; + } + + public void setQuotesType(JsonQuotesType quotesType) { + this.quotesType = quotesType; + } + + public boolean isQuotesOnScalarString() { + return quotesOnScalarString; + } + + public void setQuotesOnScalarString(boolean quotesOnScalarString) { + this.quotesOnScalarString = quotesOnScalarString; + } + + public ScalarsType getScalarsType() { + return scalarsType; + } + + public void setScalarsType(ScalarsType type) { + this.scalarsType = type; + } + + public boolean isEmpty() { + return keyValuePairs.isEmpty(); + } + + public JsonAggregateOnNullType getOnNullType() { + return onNullType; + } + + public void setOnNullType(JsonAggregateOnNullType onNullType) { + this.onNullType = onNullType; + } + + public JsonFunction withOnNullType(JsonAggregateOnNullType onNullType) { + this.setOnNullType(onNullType); + return this; + } + + public JsonAggregateUniqueKeysType getUniqueKeysType() { + return uniqueKeysType; + } + + public void setUniqueKeysType(JsonAggregateUniqueKeysType uniqueKeysType) { + this.uniqueKeysType = uniqueKeysType; + } + + public JsonFunction withUniqueKeysType(JsonAggregateUniqueKeysType uniqueKeysType) { + this.setUniqueKeysType(uniqueKeysType); + return this; + } + + public JsonFunctionType getType() { + return functionType; + } + + public void setType(JsonFunctionType type) { + this.functionType = + Objects.requireNonNull(type, + "The Type of the JSON Aggregate Function must not be null"); + } + + public void setType(String typeName) { + this.functionType = JsonFunctionType.valueOf( + Objects.requireNonNull(typeName, + "The Type of the JSON Aggregate Function must not be null") + .toUpperCase()); + } + + public JsonFunction withType(JsonFunctionType type) { + this.setType(type); + return this; + } + + public JsonFunction withType(String typeName) { + this.setType(typeName); + return this; + } + + public boolean isStrict() { + return isStrict; + } + + public void setStrict(boolean strict) { + isStrict = strict; + } + + public JsonFunction withStrict(boolean strict) { + this.setStrict(strict); + return this; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + // avoid countless Builder --> String conversion + public StringBuilder append(StringBuilder builder) { + switch (functionType) { + case OBJECT: + case POSTGRES_OBJECT: + case MYSQL_OBJECT: + appendObject(builder); + break; + case ARRAY: + appendArray(builder); + break; + case VALUE: + appendValue(builder); + break; + case QUERY: + appendQuery(builder); + break; + case EXISTS: + appendExists(builder); + break; + default: + // this should never happen really + } + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendObject(StringBuilder builder) { + builder.append("JSON_OBJECT( "); + int i = 0; + for (JsonKeyValuePair keyValuePair : keyValuePairs) { + if (i > 0) { + builder.append(", "); + } + keyValuePair.append(builder); + i++; + } + + appendOnNullType(builder); + if (isStrict) { + builder.append(" STRICT"); + } + appendUniqueKeys(builder); + appendReturningClause(builder, true); + + builder.append(" ) "); + + return builder; + } + + private void appendOnNullType(StringBuilder builder) { + if (onNullType != null) { + switch (onNullType) { + case NULL: + builder.append(" NULL ON NULL"); + break; + case ABSENT: + builder.append(" ABSENT ON NULL"); + break; + default: + // this should never happen + } + } + } + + private void appendUniqueKeys(StringBuilder builder) { + if (uniqueKeysType != null) { + switch (uniqueKeysType) { + case WITH: + builder.append(" WITH UNIQUE KEYS"); + break; + case WITHOUT: + builder.append(" WITHOUT UNIQUE KEYS"); + break; + default: + // this should never happen + } + } + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendArray(StringBuilder builder) { + builder.append("JSON_ARRAY( "); + int i = 0; + + for (JsonFunctionExpression expr : expressions) { + if (i > 0) { + builder.append(", "); + } + expr.append(builder); + i++; + } + + appendOnNullType(builder); + appendReturningClause(builder, true); + builder.append(") "); + + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendValue(StringBuilder builder) { + builder.append("JSON_VALUE("); + appendValueOrQueryPrefix(builder); + + if (returningType != null) { + builder.append(" RETURNING ").append(returningType); + } + + appendOnResponseClause(builder, onEmptyBehavior, "EMPTY"); + appendOnResponseClause(builder, onErrorBehavior, "ERROR"); + + builder.append(")"); + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendQuery(StringBuilder builder) { + builder.append("JSON_QUERY("); + appendValueOrQueryPrefix(builder); + + appendReturningClause(builder, true); + + appendWrapperClause(builder); + appendQuotesClause(builder); + appendOnResponseClause(builder, onEmptyBehavior, "EMPTY"); + appendOnResponseClause(builder, onErrorBehavior, "ERROR"); + + for (String additionalQueryPathArgument : additionalQueryPathArguments) { + builder.append(", ").append(additionalQueryPathArgument); + } + + builder.append(")"); + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) + public StringBuilder appendExists(StringBuilder builder) { + builder.append("JSON_EXISTS("); + appendValueOrQueryPrefix(builder); + appendOnResponseClause(builder, onErrorBehavior, "ERROR"); + builder.append(")"); + return builder; + } + + private void appendValueOrQueryPrefix(StringBuilder builder) { + if (inputExpression != null) { + inputExpression.append(builder); + } + + if (jsonPathExpression != null) { + if (inputExpression != null) { + builder.append(", "); + } + builder.append(jsonPathExpression); + } + + if (!passingExpressions.isEmpty()) { + builder.append(" PASSING "); + boolean comma = false; + for (Expression passingExpression : passingExpressions) { + if (comma) { + builder.append(", "); + } else { + comma = true; + } + builder.append(passingExpression); + } + } + } + + private void appendOnResponseClause(StringBuilder builder, JsonOnResponseBehavior behavior, + String clause) { + if (behavior != null) { + builder.append(" "); + behavior.append(builder); + builder.append(" ON ").append(clause); + } + } + + private void appendReturningClause(StringBuilder builder, boolean formatJsonAllowed) { + if (returningType != null) { + builder.append(" RETURNING ").append(returningType); + if (formatJsonAllowed && returningFormatJson) { + builder.append(" FORMAT JSON"); + if (returningEncoding != null) { + builder.append(" ENCODING ").append(returningEncoding); + } + } + } + } + + private void appendWrapperClause(StringBuilder builder) { + if (wrapperType != null) { + builder.append(" ").append(wrapperType); + if (wrapperMode != null) { + builder.append(" ").append(wrapperMode); + } + if (wrapperArray) { + builder.append(" ARRAY"); + } + builder.append(" WRAPPER"); + } + } + + private void appendQuotesClause(StringBuilder builder) { + if (quotesType != null) { + builder.append(" ").append(quotesType).append(" QUOTES"); + if (quotesOnScalarString) { + builder.append(" ON SCALAR STRING"); + } + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + return append(builder).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java new file mode 100644 index 000000000..738c09fc2 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionExpression.java @@ -0,0 +1,75 @@ +/*- + * #%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 java.io.Serializable; +import java.util.Objects; + +/** + * @author Andreas Reichel + */ + +public class JsonFunctionExpression implements Serializable { + private final Expression expression; + + private boolean usingFormatJson = false; + private String encoding; + + public JsonFunctionExpression(Expression expression) { + this.expression = Objects.requireNonNull(expression, "The EXPRESSION must not be null"); + } + + public Expression getExpression() { + return expression; + } + + public boolean isUsingFormatJson() { + return usingFormatJson; + } + + public void setUsingFormatJson(boolean usingFormatJson) { + this.usingFormatJson = usingFormatJson; + } + + public JsonFunctionExpression withUsingFormatJson(boolean usingFormatJson) { + this.setUsingFormatJson(usingFormatJson); + return this; + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public JsonFunctionExpression withEncoding(String encoding) { + this.setEncoding(encoding); + return this; + } + + public StringBuilder append(StringBuilder builder) { + builder.append(getExpression()); + if (isUsingFormatJson()) { + builder.append(" FORMAT JSON"); + if (encoding != null) { + builder.append(" ENCODING ").append(encoding); + } + } + return builder; + } + + @Override + public String toString() { + return append(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java new file mode 100644 index 000000000..ebd497e79 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonFunctionType.java @@ -0,0 +1,34 @@ +/*- + * #%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; + +/** + * @author Andreas Reichel + */ +public enum JsonFunctionType { + 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 new file mode 100644 index 000000000..18fb4752d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePair.java @@ -0,0 +1,181 @@ +/*- + * #%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 java.io.Serializable; +import java.util.Objects; + +/** + * @author Andreas Reichel + */ + +public class JsonKeyValuePair implements Serializable { + private final Object key; + private final Object value; + private boolean usingKeyKeyword; + private JsonKeyValuePairSeparator separator; + private boolean usingFormatJson = false; + private String encoding; + + /** + * Please use the Constructor with {@link JsonKeyValuePairSeparator} parameter. + */ + @Deprecated + public JsonKeyValuePair(Object key, Object value, boolean usingKeyKeyword, + boolean usingValueKeyword) { + this(key, value, usingKeyKeyword, usingValueKeyword ? JsonKeyValuePairSeparator.VALUE + : JsonKeyValuePairSeparator.COLON); + } + + public JsonKeyValuePair(Object key, Object value, boolean usingKeyKeyword, + JsonKeyValuePairSeparator separator) { + this.key = Objects.requireNonNull(key, "The KEY of the Pair must not be null"); + this.value = value; + this.usingKeyKeyword = usingKeyKeyword; + this.separator = + Objects.requireNonNull(separator, "The KeyValuePairSeparator must not be NULL"); + } + + public boolean isUsingKeyKeyword() { + return usingKeyKeyword; + } + + public void setUsingKeyKeyword(boolean usingKeyKeyword) { + this.usingKeyKeyword = usingKeyKeyword; + } + + public JsonKeyValuePair withUsingKeyKeyword(boolean usingKeyKeyword) { + this.setUsingKeyKeyword(usingKeyKeyword); + return this; + } + + /** + * Use {@link #getSeparator()} + */ + @Deprecated + public boolean isUsingValueKeyword() { + return separator == JsonKeyValuePairSeparator.VALUE; + } + + /** + * Use {@link #setSeparator(JsonKeyValuePairSeparator)} + */ + @Deprecated + public void setUsingValueKeyword(boolean usingValueKeyword) { + separator = usingValueKeyword ? JsonKeyValuePairSeparator.VALUE + : JsonKeyValuePairSeparator.COLON; + } + + /** + * Use {@link #withSeparator(JsonKeyValuePairSeparator)} + */ + @Deprecated + public JsonKeyValuePair withUsingValueKeyword(boolean usingValueKeyword) { + this.setUsingValueKeyword(usingValueKeyword); + return this; + } + + public JsonKeyValuePairSeparator getSeparator() { + return separator; + } + + public void setSeparator(JsonKeyValuePairSeparator separator) { + this.separator = separator; + } + + public JsonKeyValuePair withSeparator(JsonKeyValuePairSeparator separator) { + this.setSeparator(separator); + return this; + } + + public boolean isUsingFormatJson() { + return usingFormatJson; + } + + public void setUsingFormatJson(boolean usingFormatJson) { + this.usingFormatJson = usingFormatJson; + } + + public JsonKeyValuePair withUsingFormatJson(boolean usingFormatJson) { + this.setUsingFormatJson(usingFormatJson); + return this; + } + + public String getEncoding() { + return encoding; + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + public JsonKeyValuePair withEncoding(String encoding) { + this.setEncoding(encoding); + return this; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.key); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final JsonKeyValuePair other = (JsonKeyValuePair) obj; + return Objects.equals(this.key, other.key); + } + + public Object getKey() { + return key; + } + + public Object getValue() { + return value; + } + + public StringBuilder append(StringBuilder builder) { + if (isUsingKeyKeyword() && getSeparator() == JsonKeyValuePairSeparator.VALUE) { + builder.append("KEY "); + } + builder.append(getKey()); + + if (getValue() != null) { + builder.append(getSeparator().getSeparatorString()); + builder.append(getValue()); + } + + if (isUsingFormatJson()) { + builder.append(" FORMAT JSON"); + if (encoding != null) { + builder.append(" ENCODING ").append(encoding); + } + } + + return builder; + } + + @Override + public String toString() { + return append(new StringBuilder()).toString(); + } + +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java new file mode 100644 index 000000000..e4e998aa5 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonKeyValuePairSeparator.java @@ -0,0 +1,33 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +/** + * Describes the string used to separate the key from the value. + */ +public enum JsonKeyValuePairSeparator { + VALUE(" VALUE "), COLON(":"), + + // Used in MySQL dialect + COMMA(","), + + // Is used in case they KeyValuePair has only a key and no value + NOT_USED(""); + + private final String separator; + + JsonKeyValuePairSeparator(String separator) { + this.separator = separator; + } + + public String getSeparatorString() { + return separator; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/JsonTableFunction.java b/src/main/java/net/sf/jsqlparser/expression/JsonTableFunction.java new file mode 100644 index 000000000..5ee166e6f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/JsonTableFunction.java @@ -0,0 +1,864 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.create.table.ColDataType; + +public class JsonTableFunction extends Function { + + private Expression jsonInputExpression; + private Expression jsonPathExpression; + private String pathName; + private final List passingClauses = new ArrayList<>(); + private JsonTableColumnsClause columnsClause; + private JsonTablePlanClause planClause; + private JsonTableOnErrorClause onErrorClause; + private JsonTableParsingTypeClause parsingTypeClause; + private JsonTableOnEmptyClause onEmptyClause; + private boolean formatJson; + + public enum JsonTablePlanOperator { + COMMA(", "), INNER(" INNER "), OUTER(" OUTER "), CROSS(" CROSS "), UNION(" UNION "); + + private final String display; + + JsonTablePlanOperator(String display) { + this.display = display; + } + + public String getDisplay() { + return display; + } + } + + public enum JsonTableOnErrorType { + ERROR, NULL, EMPTY, TRUE, FALSE + } + + public enum JsonTableOnEmptyType { + ERROR, NULL, EMPTY, TRUE, FALSE + } + + public enum JsonTableParsingType { + STRICT, LAX + } + + public static class JsonTablePassingClause extends ASTNodeAccessImpl implements Serializable { + private Expression valueExpression; + private String parameterName; + + public JsonTablePassingClause() {} + + public JsonTablePassingClause(Expression valueExpression, String parameterName) { + this.valueExpression = valueExpression; + this.parameterName = parameterName; + } + + public Expression getValueExpression() { + return valueExpression; + } + + public JsonTablePassingClause setValueExpression(Expression valueExpression) { + this.valueExpression = valueExpression; + return this; + } + + public String getParameterName() { + return parameterName; + } + + public JsonTablePassingClause setParameterName(String parameterName) { + this.parameterName = parameterName; + return this; + } + + public void collectExpressions(List expressions) { + if (valueExpression != null) { + expressions.add(valueExpression); + } + } + + @Override + public String toString() { + return valueExpression + " AS " + parameterName; + } + } + + public static class JsonTableWrapperClause extends ASTNodeAccessImpl implements Serializable { + private boolean beforePathExpression; + private JsonFunction.JsonWrapperType wrapperType; + private JsonFunction.JsonWrapperMode wrapperMode; + private boolean array; + + /** + * Creates a wrapper clause. Depending on the dialect, this clause can come before or after + * the PATH expression. + *
    + *
  • Trino: after PATH
  • + *
  • Oracle: before PATH
  • + *
+ * + * @param beforePathExpression A flag to determine wether the clause is rendered before or + * after the PATH expression + */ + public JsonTableWrapperClause(boolean beforePathExpression) { + this.beforePathExpression = beforePathExpression; + } + + public boolean isBeforePathExpression() { + return beforePathExpression; + } + + public JsonFunction.JsonWrapperType getWrapperType() { + return wrapperType; + } + + public JsonTableWrapperClause setWrapperType(JsonFunction.JsonWrapperType wrapperType) { + this.wrapperType = wrapperType; + return this; + } + + public JsonFunction.JsonWrapperMode getWrapperMode() { + return wrapperMode; + } + + public JsonTableWrapperClause setWrapperMode(JsonFunction.JsonWrapperMode wrapperMode) { + this.wrapperMode = wrapperMode; + return this; + } + + public boolean isArray() { + return array; + } + + public JsonTableWrapperClause setArray(boolean array) { + this.array = array; + return this; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(wrapperType); + if (wrapperMode != null) { + builder.append(" ").append(wrapperMode); + } + if (array) { + builder.append(" ARRAY"); + } + builder.append(" WRAPPER"); + return builder.toString(); + } + } + + public static class JsonTableQuotesClause extends ASTNodeAccessImpl implements Serializable { + private JsonFunction.JsonQuotesType quotesType; + private boolean onScalarString; + + public JsonFunction.JsonQuotesType getQuotesType() { + return quotesType; + } + + public JsonTableQuotesClause setQuotesType(JsonFunction.JsonQuotesType quotesType) { + this.quotesType = quotesType; + return this; + } + + public boolean isOnScalarString() { + return onScalarString; + } + + public JsonTableQuotesClause setOnScalarString(boolean onScalarString) { + this.onScalarString = onScalarString; + return this; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(quotesType).append(" QUOTES"); + if (onScalarString) { + builder.append(" ON SCALAR STRING"); + } + return builder.toString(); + } + } + + public static class JsonTableOnErrorClause extends ASTNodeAccessImpl implements Serializable { + private JsonTableOnErrorType type; + private boolean beforeColumns = true; + + public JsonTableOnErrorClause(boolean beforeColumns) { + this.beforeColumns = beforeColumns; + } + + public boolean isBeforeColumns() { + return beforeColumns; + } + + public JsonTableOnErrorType getType() { + return type; + } + + public JsonTableOnErrorClause setType(JsonTableOnErrorType type) { + this.type = type; + return this; + } + + @Override + public String toString() { + return type + " ON ERROR"; + } + } + + public static class JsonTableOnEmptyClause extends ASTNodeAccessImpl implements Serializable { + private JsonTableOnEmptyType type; + + public JsonTableOnEmptyType getType() { + return type; + } + + public JsonTableOnEmptyClause setType(JsonTableOnEmptyType type) { + this.type = type; + return this; + } + + @Override + public String toString() { + return type + " ON EMPTY"; + } + } + + public static class JsonTableParsingTypeClause extends ASTNodeAccessImpl + implements Serializable { + private JsonTableParsingType type; + + public JsonTableParsingType getType() { + return type; + } + + public JsonTableParsingTypeClause setType(JsonTableParsingType type) { + this.type = type; + return this; + } + + @Override + public String toString() { + return "TYPE(" + type + ")"; + } + } + + public static class JsonTablePlanTerm extends ASTNodeAccessImpl implements Serializable { + private JsonTablePlanExpression nestedPlanExpression; + private String name; + private Expression expression; + + public JsonTablePlanExpression getNestedPlanExpression() { + return nestedPlanExpression; + } + + public JsonTablePlanTerm setNestedPlanExpression( + JsonTablePlanExpression nestedPlanExpression) { + this.nestedPlanExpression = nestedPlanExpression; + return this; + } + + public String getName() { + return name; + } + + public JsonTablePlanTerm setName(String name) { + this.name = name; + return this; + } + + public Expression getExpression() { + return expression; + } + + public JsonTablePlanTerm setExpression(Expression expression) { + this.expression = expression; + return this; + } + + public void collectExpressions(List expressions) { + if (expression != null) { + expressions.add(expression); + } + if (nestedPlanExpression != null) { + nestedPlanExpression.collectExpressions(expressions); + } + } + + @Override + public String toString() { + if (nestedPlanExpression != null) { + return "(" + nestedPlanExpression + ")"; + } + if (name != null) { + return name; + } + return expression != null ? expression.toString() : ""; + } + } + + public static class JsonTablePlanExpression extends ASTNodeAccessImpl implements Serializable { + private final List terms = new ArrayList<>(); + private final List operators = new ArrayList<>(); + + public List getTerms() { + return terms; + } + + public JsonTablePlanExpression addTerm(JsonTablePlanTerm term) { + terms.add(term); + return this; + } + + public List getOperators() { + return operators; + } + + public JsonTablePlanExpression addOperator(JsonTablePlanOperator operator) { + operators.add(operator); + return this; + } + + public void collectExpressions(List expressions) { + for (JsonTablePlanTerm term : terms) { + if (term != null) { + term.collectExpressions(expressions); + } + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (!terms.isEmpty()) { + builder.append(terms.get(0)); + } + for (int i = 0; i < operators.size() && i + 1 < terms.size(); i++) { + builder.append(operators.get(i).getDisplay()).append(terms.get(i + 1)); + } + return builder.toString(); + } + } + + public static class JsonTablePlanClause extends ASTNodeAccessImpl implements Serializable { + private boolean defaultPlan; + private JsonTablePlanExpression planExpression; + + public boolean isDefaultPlan() { + return defaultPlan; + } + + public JsonTablePlanClause setDefaultPlan(boolean defaultPlan) { + this.defaultPlan = defaultPlan; + return this; + } + + public JsonTablePlanExpression getPlanExpression() { + return planExpression; + } + + public JsonTablePlanClause setPlanExpression(JsonTablePlanExpression planExpression) { + this.planExpression = planExpression; + return this; + } + + public void collectExpressions(List expressions) { + if (planExpression != null) { + planExpression.collectExpressions(expressions); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("PLAN"); + if (defaultPlan) { + builder.append(" DEFAULT"); + } + builder.append(" (").append(planExpression).append(")"); + return builder.toString(); + } + } + + public abstract static class JsonTableColumnDefinition extends ASTNodeAccessImpl + implements Serializable { + public abstract void collectExpressions(List expressions); + } + + public static class JsonTableNestedColumnDefinition extends JsonTableColumnDefinition { + private boolean pathKeyword; + private Expression pathExpression; + private String pathName; + private JsonTableColumnsClause columnsClause; + + public boolean isPathKeyword() { + return pathKeyword; + } + + public JsonTableNestedColumnDefinition setPathKeyword(boolean pathKeyword) { + this.pathKeyword = pathKeyword; + return this; + } + + public Expression getPathExpression() { + return pathExpression; + } + + public JsonTableNestedColumnDefinition setPathExpression(Expression pathExpression) { + this.pathExpression = pathExpression; + return this; + } + + public String getPathName() { + return pathName; + } + + public JsonTableNestedColumnDefinition setPathName(String pathName) { + this.pathName = pathName; + return this; + } + + public JsonTableColumnsClause getColumnsClause() { + return columnsClause; + } + + public JsonTableNestedColumnDefinition setColumnsClause( + JsonTableColumnsClause columnsClause) { + this.columnsClause = columnsClause; + return this; + } + + @Override + public void collectExpressions(List expressions) { + if (pathExpression != null) { + expressions.add(pathExpression); + } + if (columnsClause != null) { + columnsClause.collectExpressions(expressions); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("NESTED"); + if (pathKeyword) { + builder.append(" PATH"); + } + builder.append(" ").append(pathExpression); + if (pathName != null) { + builder.append(" AS ").append(pathName); + } + builder.append(" ").append(columnsClause); + return builder.toString(); + } + } + + public static class JsonTableValueColumnDefinition extends JsonTableColumnDefinition { + private String columnName; + private boolean forOrdinality; + private ColDataType dataType; + private boolean formatJson; + private boolean exists; + private boolean onEmptyAfterOnError; + private String encoding; + private Expression pathExpression; + private JsonTableWrapperClause wrapperClause; + private JsonTableQuotesClause quotesClause; + private JsonFunction.JsonOnResponseBehavior onEmptyBehavior; + private JsonFunction.JsonOnResponseBehavior onErrorBehavior; + private JsonFunction.ScalarsType scalarsType; + + public String getColumnName() { + return columnName; + } + + public JsonTableValueColumnDefinition setColumnName(String columnName) { + this.columnName = columnName; + return this; + } + + public boolean isExists() { + return exists; + } + + public JsonTableValueColumnDefinition setExistsKeyword(boolean exists) { + this.exists = exists; + return this; + } + + public JsonTableValueColumnDefinition setOnEmptyAfterOnError(boolean b) { + this.onEmptyAfterOnError = b; + return this; + } + + public boolean isForOrdinality() { + return forOrdinality; + } + + public JsonTableValueColumnDefinition setForOrdinality(boolean forOrdinality) { + this.forOrdinality = forOrdinality; + return this; + } + + public ColDataType getDataType() { + return dataType; + } + + public JsonTableValueColumnDefinition setDataType(ColDataType dataType) { + this.dataType = dataType; + return this; + } + + public boolean isFormatJson() { + return formatJson; + } + + public JsonTableValueColumnDefinition setFormatJson(boolean formatJson) { + this.formatJson = formatJson; + return this; + } + + public String getEncoding() { + return encoding; + } + + public JsonTableValueColumnDefinition setEncoding(String encoding) { + this.encoding = encoding; + return this; + } + + public Expression getPathExpression() { + return pathExpression; + } + + public JsonTableValueColumnDefinition setPathExpression(Expression pathExpression) { + this.pathExpression = pathExpression; + return this; + } + + public JsonTableWrapperClause getWrapperClause() { + return wrapperClause; + } + + public JsonTableValueColumnDefinition setWrapperClause( + JsonTableWrapperClause wrapperClause) { + this.wrapperClause = wrapperClause; + return this; + } + + public JsonTableQuotesClause getQuotesClause() { + return quotesClause; + } + + public JsonTableValueColumnDefinition setQuotesClause(JsonTableQuotesClause quotesClause) { + this.quotesClause = quotesClause; + return this; + } + + public JsonFunction.JsonOnResponseBehavior getOnEmptyBehavior() { + return onEmptyBehavior; + } + + public JsonTableValueColumnDefinition setOnEmptyBehavior( + JsonFunction.JsonOnResponseBehavior onEmptyBehavior) { + this.onEmptyBehavior = onEmptyBehavior; + return this; + } + + public JsonFunction.JsonOnResponseBehavior getOnErrorBehavior() { + return onErrorBehavior; + } + + public JsonTableValueColumnDefinition setOnErrorBehavior( + JsonFunction.JsonOnResponseBehavior onErrorBehavior) { + this.onErrorBehavior = onErrorBehavior; + return this; + } + + public void setScalarsType(JsonFunction.ScalarsType scalarsType) { + this.scalarsType = scalarsType; + } + + public JsonFunction.ScalarsType getScalarsType() { + return scalarsType; + } + + @Override + public void collectExpressions(List expressions) { + if (pathExpression != null) { + expressions.add(pathExpression); + } + if (onEmptyBehavior != null && onEmptyBehavior.getExpression() != null) { + expressions.add(onEmptyBehavior.getExpression()); + } + if (onErrorBehavior != null && onErrorBehavior.getExpression() != null) { + expressions.add(onErrorBehavior.getExpression()); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(columnName); + if (forOrdinality) { + builder.append(" FOR ORDINALITY"); + return builder.toString(); + } + if (exists) { + builder.append(" EXISTS"); + } + if (dataType != null) { + builder.append(" ").append(dataType); + } + if (formatJson) { + builder.append(" FORMAT JSON"); + if (encoding != null) { + builder.append(" ENCODING ").append(encoding); + } + } + if (scalarsType != null) { + builder.append(" "); + builder.append(scalarsType); + builder.append(" SCALARS"); + } + if (wrapperClause != null && wrapperClause.isBeforePathExpression()) { + builder.append(" ").append(wrapperClause); + } + if (pathExpression != null) { + builder.append(" PATH ").append(pathExpression); + } + if (wrapperClause != null && !wrapperClause.isBeforePathExpression()) { + builder.append(" ").append(wrapperClause); + } + if (quotesClause != null) { + builder.append(" ").append(quotesClause); + } + if (onEmptyBehavior != null && !onEmptyAfterOnError) { + builder.append(" ").append(onEmptyBehavior).append(" ON EMPTY"); + } + if (onErrorBehavior != null) { + builder.append(" ").append(onErrorBehavior).append(" ON ERROR"); + } + if (onEmptyBehavior != null && onEmptyAfterOnError) { + builder.append(" ").append(onEmptyBehavior).append(" ON EMPTY"); + } + return builder.toString(); + } + } + + public static class JsonTableColumnsClause extends ASTNodeAccessImpl implements Serializable { + private final List columnDefinitions = new ArrayList<>(); + + public List getColumnDefinitions() { + return columnDefinitions; + } + + public JsonTableColumnsClause addColumnDefinition( + JsonTableColumnDefinition columnDefinition) { + columnDefinitions.add(columnDefinition); + return this; + } + + public void collectExpressions(List expressions) { + for (JsonTableColumnDefinition columnDefinition : columnDefinitions) { + if (columnDefinition != null) { + columnDefinition.collectExpressions(expressions); + } + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("COLUMNS ("); + boolean first = true; + for (JsonTableColumnDefinition columnDefinition : columnDefinitions) { + if (!first) { + builder.append(", "); + } + builder.append(columnDefinition); + first = false; + } + builder.append(")"); + return builder.toString(); + } + } + + public JsonTableFunction() { + setName("JSON_TABLE"); + } + + public boolean getFormatJson() { + return formatJson; + } + + public JsonTableFunction setFormatJson(boolean formatJson) { + this.formatJson = formatJson; + return this; + } + + public Expression getJsonInputExpression() { + return jsonInputExpression; + } + + public JsonTableFunction setJsonInputExpression(Expression jsonInputExpression) { + this.jsonInputExpression = jsonInputExpression; + return this; + } + + public Expression getJsonPathExpression() { + return jsonPathExpression; + } + + public JsonTableFunction setJsonPathExpression(Expression jsonPathExpression) { + this.jsonPathExpression = jsonPathExpression; + return this; + } + + public String getPathName() { + return pathName; + } + + public JsonTableFunction setPathName(String pathName) { + this.pathName = pathName; + return this; + } + + public List getPassingClauses() { + return passingClauses; + } + + public JsonTableFunction addPassingClause(JsonTablePassingClause passingClause) { + passingClauses.add(Objects.requireNonNull(passingClause, "passingClause")); + return this; + } + + public JsonTableColumnsClause getColumnsClause() { + return columnsClause; + } + + public JsonTableFunction setColumnsClause(JsonTableColumnsClause columnsClause) { + this.columnsClause = columnsClause; + return this; + } + + public JsonTablePlanClause getPlanClause() { + return planClause; + } + + public JsonTableFunction setPlanClause(JsonTablePlanClause planClause) { + this.planClause = planClause; + return this; + } + + public JsonTableOnErrorClause getOnErrorClause() { + return onErrorClause; + } + + public JsonTableFunction setOnErrorClause(JsonTableOnErrorClause onErrorClause) { + this.onErrorClause = onErrorClause; + return this; + } + + public JsonTableParsingTypeClause getParsingTypeClause() { + return parsingTypeClause; + } + + public JsonTableFunction setParsingTypeClause(JsonTableParsingTypeClause parsingTypeClause) { + this.parsingTypeClause = parsingTypeClause; + return this; + } + + public JsonTableOnEmptyClause getOnEmptyClause() { + return onEmptyClause; + } + + public JsonTableFunction setOnEmptyClause(JsonTableOnEmptyClause onEmptyClause) { + this.onEmptyClause = onEmptyClause; + return this; + } + + public List getAllExpressions() { + List expressions = new ArrayList<>(); + if (jsonInputExpression != null) { + expressions.add(jsonInputExpression); + } + if (jsonPathExpression != null) { + expressions.add(jsonPathExpression); + } + for (JsonTablePassingClause passingClause : passingClauses) { + passingClause.collectExpressions(expressions); + } + if (columnsClause != null) { + columnsClause.collectExpressions(expressions); + } + if (planClause != null) { + planClause.collectExpressions(expressions); + } + return expressions; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("JSON_TABLE("); + builder.append(jsonInputExpression); + if (formatJson) { + builder.append(" FORMAT JSON"); + } + if (jsonPathExpression != null) { + builder.append(", ").append(jsonPathExpression); + } + if (pathName != null) { + builder.append(" AS ").append(pathName); + } + if (!passingClauses.isEmpty()) { + builder.append(" PASSING "); + boolean first = true; + for (JsonTablePassingClause passingClause : passingClauses) { + if (!first) { + builder.append(", "); + } + builder.append(passingClause); + first = false; + } + } + if (onErrorClause != null && onErrorClause.isBeforeColumns()) { + builder.append(" ").append(onErrorClause); + } + if (parsingTypeClause != null) { + builder.append(" ").append(parsingTypeClause); + } + if (onEmptyClause != null) { + builder.append(" ").append(onEmptyClause); + } + builder.append(" ").append(columnsClause); + if (planClause != null) { + builder.append(" ").append(planClause); + } + if (onErrorClause != null && !onErrorClause.isBeforeColumns()) { + builder.append(" ").append(onErrorClause); + } + builder.append(")"); + return builder.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/KeepExpression.java b/src/main/java/net/sf/jsqlparser/expression/KeepExpression.java index 2ee6a8e39..b8e493244 100644 --- a/src/main/java/net/sf/jsqlparser/expression/KeepExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/KeepExpression.java @@ -1,39 +1,23 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import net.sf.jsqlparser.statement.select.OrderByElement; -import java.util.List; - -/** - * Analytic function. The name of the function is variable but the parameters following the special - * analytic function path. e.g. row_number() over (order by test). Additional there can be an - * expression for an analytical aggregate like sum(col) or the "all collumns" wildcard like - * count(*). - * - * @author tw - */ public class KeepExpression extends ASTNodeAccessImpl implements Expression { private String name; @@ -41,8 +25,8 @@ public class KeepExpression extends ASTNodeAccessImpl implements Expression { private boolean first = false; @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public List getOrderByElements() { @@ -94,4 +78,33 @@ private void toStringOrderByElements(StringBuilder b) { } } } + + public KeepExpression withName(String name) { + this.setName(name); + return this; + } + + public KeepExpression withOrderByElements(List orderByElements) { + this.setOrderByElements(orderByElements); + return this; + } + + public KeepExpression withFirst(boolean first) { + this.setFirst(first); + return this; + } + + public KeepExpression addOrderByElements(OrderByElement... orderByElements) { + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + Collections.addAll(collection, orderByElements); + return this.withOrderByElements(collection); + } + + public KeepExpression addOrderByElements(Collection orderByElements) { + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + collection.addAll(orderByElements); + return this.withOrderByElements(collection); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/KeyExpression.java b/src/main/java/net/sf/jsqlparser/expression/KeyExpression.java new file mode 100644 index 000000000..2bb063875 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/KeyExpression.java @@ -0,0 +1,44 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import java.util.Objects; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +/** + * Dialect specific expression for constructs such as {@code KEY chain.entity}. + */ +public class KeyExpression extends ASTNodeAccessImpl implements Expression { + private final Expression expression; + + public KeyExpression(Expression expression) { + this.expression = Objects.requireNonNull(expression, + "The EXPRESSION of the KEY expression must not be null"); + } + + public Expression getExpression() { + return expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("KEY ").append(expression); + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/LambdaExpression.java b/src/main/java/net/sf/jsqlparser/expression/LambdaExpression.java new file mode 100644 index 000000000..e2819060f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/LambdaExpression.java @@ -0,0 +1,83 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class LambdaExpression extends ASTNodeAccessImpl implements Expression { + private List identifiers; + private Expression expression; + + public LambdaExpression(String identifier, Expression expression) { + this.identifiers = Collections.singletonList(identifier); + this.expression = expression; + } + + public LambdaExpression(List identifiers, Expression expression) { + this.identifiers = identifiers; + this.expression = expression; + } + + public static LambdaExpression from(ExpressionList expressionList, + Expression expression) { + List identifiers = new ArrayList<>(expressionList.size()); + for (Expression variable : expressionList) { + identifiers.add(variable.toString()); + } + return new LambdaExpression(identifiers, expression); + } + + public List getIdentifiers() { + return identifiers; + } + + public LambdaExpression setIdentifiers(List identifiers) { + this.identifiers = identifiers; + return this; + } + + public Expression getExpression() { + return expression; + } + + public LambdaExpression setExpression(Expression expression) { + this.expression = expression; + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + if (identifiers.size() == 1) { + builder.append(identifiers.get(0)); + } else { + int i = 0; + builder.append("( "); + for (String s : identifiers) { + builder.append(i++ > 0 ? ", " : "").append(s); + } + builder.append(" )"); + } + return builder.append(" -> ").append(expression); + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/LongValue.java b/src/main/java/net/sf/jsqlparser/expression/LongValue.java index 14b9ed3c3..eeba186cc 100644 --- a/src/main/java/net/sf/jsqlparser/expression/LongValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/LongValue.java @@ -1,29 +1,18 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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.math.BigInteger; +import java.util.Objects; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; /** * Every number without a point or an exponential format is a LongValue. @@ -32,7 +21,14 @@ public class LongValue extends ASTNodeAccessImpl implements Expression { private String stringValue; + public LongValue() { + // empty constructor + } + public LongValue(final String value) { + if (value == null || value.length() == 0) { + throw new IllegalArgumentException("value can neither be null nor empty."); + } String val = value; if (val.charAt(0) == '+') { val = val.substring(1); @@ -45,20 +41,25 @@ public LongValue(long value) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public long getValue() { - return Long.valueOf(stringValue); + return Long.parseLong(stringValue); + } + + public void setValue(long d) { + stringValue = String.valueOf(d); } public BigInteger getBigIntegerValue() { return new BigInteger(stringValue); } - public void setValue(long d) { - stringValue = String.valueOf(d); + public LongValue withValue(long d) { + setValue(d); + return this; } public String getStringValue() { @@ -73,4 +74,26 @@ public void setStringValue(String string) { public String toString() { return getStringValue(); } + + public LongValue withStringValue(String stringValue) { + this.setStringValue(stringValue); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LongValue longValue = (LongValue) o; + return stringValue.equals(longValue.stringValue); + } + + @Override + public int hashCode() { + return Objects.hash(stringValue); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/LowExpression.java b/src/main/java/net/sf/jsqlparser/expression/LowExpression.java new file mode 100644 index 000000000..2d2882a53 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/LowExpression.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class LowExpression extends ASTNodeAccessImpl implements Expression { + private Expression expression; + + public LowExpression() { + // empty constructor + } + + public LowExpression(Expression expression) { + this.expression = expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return "LOW " + expression.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/MySQLGroupConcat.java b/src/main/java/net/sf/jsqlparser/expression/MySQLGroupConcat.java index 3f3880b2d..aa4a53357 100644 --- a/src/main/java/net/sf/jsqlparser/expression/MySQLGroupConcat.java +++ b/src/main/java/net/sf/jsqlparser/expression/MySQLGroupConcat.java @@ -1,54 +1,24 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2015 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ - /* - * Copyright (C) 2015 JSQLParser. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ package net.sf.jsqlparser.expression; -import java.util.List; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import net.sf.jsqlparser.statement.select.OrderByElement; -import net.sf.jsqlparser.statement.select.PlainSelect; -/** - * - * @author toben - */ +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + public class MySQLGroupConcat extends ASTNodeAccessImpl implements Expression { private ExpressionList expressionList; @@ -56,7 +26,7 @@ public class MySQLGroupConcat extends ASTNodeAccessImpl implements Expression { private List orderByElements; private String separator; - public ExpressionList getExpressionList() { + public ExpressionList getExpressionList() { return expressionList; } @@ -89,8 +59,8 @@ public void setSeparator(String separator) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override @@ -100,7 +70,7 @@ public String toString() { if (isDistinct()) { b.append("DISTINCT "); } - b.append(PlainSelect.getStringList(expressionList.getExpressions(), true, false)); + b.append(expressionList); if (orderByElements != null && !orderByElements.isEmpty()) { b.append(" ORDER BY "); for (int i = 0; i < orderByElements.size(); i++) { @@ -116,4 +86,39 @@ public String toString() { b.append(")"); return b.toString(); } + + public MySQLGroupConcat withExpressionList(ExpressionList expressionList) { + this.setExpressionList(expressionList); + return this; + } + + public MySQLGroupConcat withDistinct(boolean distinct) { + this.setDistinct(distinct); + return this; + } + + public MySQLGroupConcat withOrderByElements(List orderByElements) { + this.setOrderByElements(orderByElements); + return this; + } + + public MySQLGroupConcat withSeparator(String separator) { + this.setSeparator(separator); + return this; + } + + public MySQLGroupConcat addOrderByElements(OrderByElement... orderByElements) { + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + Collections.addAll(collection, orderByElements); + return this.withOrderByElements(collection); + } + + public MySQLGroupConcat addOrderByElements( + Collection orderByElements) { + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + collection.addAll(orderByElements); + return this.withOrderByElements(collection); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/MySQLIndexHint.java b/src/main/java/net/sf/jsqlparser/expression/MySQLIndexHint.java index ca3bb7580..7360a4b2e 100644 --- a/src/main/java/net/sf/jsqlparser/expression/MySQLIndexHint.java +++ b/src/main/java/net/sf/jsqlparser/expression/MySQLIndexHint.java @@ -1,29 +1,18 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2017 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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.List; -public class MySQLIndexHint { +public class MySQLIndexHint implements Serializable { private final String action; private final String indexQualifier; @@ -35,6 +24,18 @@ public MySQLIndexHint(String action, String indexQualifier, List indexNa this.indexNames = indexNames; } + public String getAction() { + return action; + } + + public String getIndexQualifier() { + return indexQualifier; + } + + public List getIndexNames() { + return indexNames; + } + @Override public String toString() { // use|ignore|force key|index (index1,...,indexN) diff --git a/src/main/java/net/sf/jsqlparser/expression/NextValExpression.java b/src/main/java/net/sf/jsqlparser/expression/NextValExpression.java new file mode 100644 index 000000000..a56723851 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/NextValExpression.java @@ -0,0 +1,71 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import java.util.List; +import java.util.regex.Pattern; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class NextValExpression extends ASTNodeAccessImpl implements Expression { + + public static final Pattern NEXT_VALUE_PATTERN = + Pattern.compile("NEXT\\s+VALUE\\s+FOR", Pattern.CASE_INSENSITIVE); + private final List nameList; + private boolean usingNextValueFor = false; + + public NextValExpression(List nameList, String image) { + this.nameList = nameList; + // Test if we shall use NEXT VALUE FOR instead of NEXTVAL FOR + if (NEXT_VALUE_PATTERN.matcher(image).matches()) { + usingNextValueFor = true; + } + } + + public boolean isUsingNextValueFor() { + return usingNextValueFor; + } + + public void setUsingNextValueFor(boolean usingNextValueFor) { + this.usingNextValueFor = usingNextValueFor; + } + + public NextValExpression withNextValueFor(boolean usingNextValueFor) { + setUsingNextValueFor(usingNextValueFor); + return this; + } + + public List getNameList() { + return nameList; + } + + public String getName() { + StringBuilder b = new StringBuilder(); + for (String name : nameList) { + if (b.length() > 0) { + b.append("."); + } + b.append(name); + } + return b.toString(); + } + + @Override + public String toString() { + return (usingNextValueFor + ? "NEXT VALUE FOR " + : "NEXTVAL FOR ") + getName(); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/NotExpression.java b/src/main/java/net/sf/jsqlparser/expression/NotExpression.java index 39f8c058f..bb2769fdd 100644 --- a/src/main/java/net/sf/jsqlparser/expression/NotExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/NotExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2017 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -24,14 +12,25 @@ import net.sf.jsqlparser.parser.ASTNodeAccessImpl; /** - * It represents a "-" or "+" before an expression + * It represents a "not " or "!" before an expression. */ public class NotExpression extends ASTNodeAccessImpl implements Expression { private Expression expression; + private boolean exclamationMark = false; + + public NotExpression() { + // empty constructor + } + public NotExpression(Expression expression) { + this(expression, false); + } + + public NotExpression(Expression expression, boolean useExclamationMark) { setExpression(expression); + this.exclamationMark = useExclamationMark; } public Expression getExpression() { @@ -43,12 +42,34 @@ public final void setExpression(Expression expression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return "NOT " + expression.toString(); + return (exclamationMark ? "! " : "NOT ") + expression.toString(); + } + + public boolean isExclamationMark() { + return exclamationMark; + } + + public void setExclamationMark(boolean exclamationMark) { + this.exclamationMark = exclamationMark; + } + + public NotExpression withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public NotExpression withExclamationMark(boolean exclamationMark) { + this.setExclamationMark(exclamationMark); + return this; + } + + public E getExpression(Class type) { + return type.cast(getExpression()); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/NullValue.java b/src/main/java/net/sf/jsqlparser/expression/NullValue.java index 211cf7295..fb096eff6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/NullValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/NullValue.java @@ -1,36 +1,21 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -/** - * A "NULL" in a sql statement - */ public class NullValue extends ASTNodeAccessImpl implements Expression { @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override diff --git a/src/main/java/net/sf/jsqlparser/expression/NumericBind.java b/src/main/java/net/sf/jsqlparser/expression/NumericBind.java index 6e535bea3..f38ff15d4 100644 --- a/src/main/java/net/sf/jsqlparser/expression/NumericBind.java +++ b/src/main/java/net/sf/jsqlparser/expression/NumericBind.java @@ -1,32 +1,16 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2015 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -/** - * - * @author aud - */ public class NumericBind extends ASTNodeAccessImpl implements Expression { private int bindId; @@ -40,12 +24,17 @@ public void setBindId(int bindId) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { return ":" + bindId; } + + public NumericBind withBindId(int bindId) { + this.setBindId(bindId); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/OracleHierarchicalExpression.java b/src/main/java/net/sf/jsqlparser/expression/OracleHierarchicalExpression.java index b1f701b8b..693128d03 100644 --- a/src/main/java/net/sf/jsqlparser/expression/OracleHierarchicalExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/OracleHierarchicalExpression.java @@ -1,38 +1,22 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -/** - * - * @author toben - */ public class OracleHierarchicalExpression extends ASTNodeAccessImpl implements Expression { + boolean connectFirst = false; private Expression startExpression; private Expression connectExpression; private boolean noCycle = false; - boolean connectFirst = false; public Expression getStartExpression() { return startExpression; @@ -67,8 +51,8 @@ public void setConnectFirst(boolean connectFirst) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override @@ -81,11 +65,11 @@ public String toString() { } b.append(connectExpression.toString()); if (startExpression != null) { - b.append(" START WITH ").append(startExpression.toString()); + b.append(" START WITH ").append(startExpression); } } else { if (startExpression != null) { - b.append(" START WITH ").append(startExpression.toString()); + b.append(" START WITH ").append(startExpression); } b.append(" CONNECT BY "); if (isNoCycle()) { @@ -95,4 +79,32 @@ public String toString() { } return b.toString(); } + + public OracleHierarchicalExpression withStartExpression(Expression startExpression) { + this.setStartExpression(startExpression); + return this; + } + + public OracleHierarchicalExpression withConnectExpression(Expression connectExpression) { + this.setConnectExpression(connectExpression); + return this; + } + + public OracleHierarchicalExpression withNoCycle(boolean noCycle) { + this.setNoCycle(noCycle); + return this; + } + + public OracleHierarchicalExpression withConnectFirst(boolean connectFirst) { + this.setConnectFirst(connectFirst); + return this; + } + + public E getStartExpression(Class type) { + return type.cast(getStartExpression()); + } + + public E getConnectExpression(Class type) { + return type.cast(getConnectExpression()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/OracleHint.java b/src/main/java/net/sf/jsqlparser/expression/OracleHint.java index 58e04532c..4ab164f98 100644 --- a/src/main/java/net/sf/jsqlparser/expression/OracleHint.java +++ b/src/main/java/net/sf/jsqlparser/expression/OracleHint.java @@ -1,48 +1,47 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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 net.sf.jsqlparser.statement.select.ParenthesedSelect; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Oracle Hint Expression - * - * @author valdo */ public class OracleHint extends ASTNodeAccessImpl implements Expression { private static final Pattern SINGLE_LINE = Pattern.compile("--\\+ *([^ ].*[^ ])"); - private static final Pattern MULTI_LINE = Pattern. - compile("\\/\\*\\+ *([^ ].*[^ ]) *\\*+\\/", Pattern.MULTILINE | Pattern.DOTALL); + private static final Pattern MULTI_LINE = + Pattern.compile("/\\*\\+ *([^ ].*[^ ]) *\\*+/", Pattern.MULTILINE | Pattern.DOTALL); private String value; private boolean singleLine = false; public static boolean isHintMatch(String comment) { - return SINGLE_LINE.matcher(comment).find() - || MULTI_LINE.matcher(comment).find(); + return SINGLE_LINE.matcher(comment).find() || MULTI_LINE.matcher(comment).find(); + } + + public static OracleHint getHintFromSelectBody(Select selectBody) { + + if (selectBody instanceof PlainSelect) { + return ((PlainSelect) selectBody).getOracleHint(); + } else if (selectBody instanceof ParenthesedSelect) { + return getHintFromSelectBody(((ParenthesedSelect) selectBody).getSelect()); + } else { + return null; + } } public final void setComment(String comment) { @@ -77,8 +76,8 @@ public void setSingleLine(boolean singleLine) { } @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override @@ -90,4 +89,13 @@ public String toString() { } } + public OracleHint withValue(String value) { + this.setValue(value); + return this; + } + + public OracleHint withSingleLine(boolean singleLine) { + this.setSingleLine(singleLine); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameter.java b/src/main/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameter.java new file mode 100644 index 000000000..0dd76b5f6 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/OracleNamedFunctionParameter.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 java.util.Objects; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +/** + * @author Andreas Reichel + */ +public class OracleNamedFunctionParameter extends ASTNodeAccessImpl implements Expression { + private final String name; + private final Expression expression; + + public OracleNamedFunctionParameter(String name, Expression expression) { + this.name = Objects.requireNonNull(name, + "The NAME of the OracleNamedFunctionParameter must not be null."); + this.expression = Objects.requireNonNull(expression, + "The EXPRESSION of the OracleNamedFunctionParameter must not be null."); + } + + 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/OrderByClause.java b/src/main/java/net/sf/jsqlparser/expression/OrderByClause.java index 2bfad00a8..fbf21de87 100644 --- a/src/main/java/net/sf/jsqlparser/expression/OrderByClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/OrderByClause.java @@ -1,33 +1,25 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2018 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; -import net.sf.jsqlparser.statement.select.OrderByElement; - +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Optional; + +import net.sf.jsqlparser.statement.select.OrderByElement; -public class OrderByClause { +public class OrderByClause implements Serializable { private List orderByElements; - private WindowElement windowElement; public List getOrderByElements() { return orderByElements; @@ -37,15 +29,7 @@ public void setOrderByElements(List orderByElements) { this.orderByElements = orderByElements; } - public WindowElement getWindowElement() { - return windowElement; - } - - public void setWindowElement(WindowElement windowElement) { - this.windowElement = windowElement; - } - - void toStringOrderByElements(StringBuilder b) { + public void toStringOrderByElements(StringBuilder b) { if (orderByElements != null && !orderByElements.isEmpty()) { b.append("ORDER BY "); for (int i = 0; i < orderByElements.size(); i++) { @@ -54,11 +38,25 @@ void toStringOrderByElements(StringBuilder b) { } b.append(orderByElements.get(i).toString()); } - - if (windowElement != null) { - b.append(' '); - b.append(windowElement); - } } } -} \ No newline at end of file + + public OrderByClause withOrderByElements(List orderByElements) { + this.setOrderByElements(orderByElements); + return this; + } + + public OrderByClause addOrderByElements(OrderByElement... orderByElements) { + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + Collections.addAll(collection, orderByElements); + return this.withOrderByElements(collection); + } + + public OrderByClause addOrderByElements(Collection orderByElements) { + List collection = + Optional.ofNullable(getOrderByElements()).orElseGet(ArrayList::new); + collection.addAll(orderByElements); + return this.withOrderByElements(collection); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java b/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java new file mode 100644 index 000000000..09ccd6183 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/OverlapsCondition.java @@ -0,0 +1,41 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class OverlapsCondition extends ASTNodeAccessImpl implements Expression { + private final ExpressionList left; + private final ExpressionList right; + + public OverlapsCondition(ExpressionList left, ExpressionList right) { + this.left = left; + this.right = right; + } + + public ExpressionList getLeft() { + return left; + } + + public ExpressionList getRight() { + return right; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return String.format("%s OVERLAPS %s", left.toString(), right.toString()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/Parenthesis.java b/src/main/java/net/sf/jsqlparser/expression/Parenthesis.java index 71178dd8a..c162cd1ef 100644 --- a/src/main/java/net/sf/jsqlparser/expression/Parenthesis.java +++ b/src/main/java/net/sf/jsqlparser/expression/Parenthesis.java @@ -1,67 +1,37 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * 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 net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; /** - * It represents an expression like "(" expression ")" + * @deprecated This class is deprecated since version 5.0. Use {@link ParenthesedExpressionList} + * instead. The reason for deprecation is the ambiguity and redundancy. */ -public class Parenthesis extends ASTNodeAccessImpl implements Expression { - - private Expression expression; - - private boolean not = false; - - public Parenthesis() { - } - - public Parenthesis(Expression expression) { - setExpression(expression); - } - +@Deprecated(since = "5.0", forRemoval = true) +public class Parenthesis extends ParenthesedExpressionList { public Expression getExpression() { - return expression; - } - - public final void setExpression(Expression expression) { - this.expression = expression; + return isEmpty() ? null : get(0); } - @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public Parenthesis setExpression(Expression expression) { + this.set(0, expression); + return this; } - public void setNot() { - not = true; + public Parenthesis withExpression(Expression expression) { + return this.setExpression(expression); } - public boolean isNot() { - return not; + public E getExpression(Class type) { + return type.cast(getExpression()); } - @Override - public String toString() { - return (not ? "NOT " : "") + "(" + expression + ")"; - } } diff --git a/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java b/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java index fb26c8e42..6ad41e994 100644 --- a/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/PartitionByClause.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2018 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -24,23 +12,54 @@ import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.statement.select.PlainSelect; -public class PartitionByClause { - ExpressionList partitionExpressionList; +import java.io.Serializable; - public ExpressionList getPartitionExpressionList() { - return partitionExpressionList; +public class PartitionByClause extends ExpressionList implements Serializable { + boolean brackets = false; + + @Deprecated + public ExpressionList getPartitionExpressionList() { + return this; + } + + @Deprecated + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + setPartitionExpressionList(partitionExpressionList, false); + } + + @Deprecated + public void setPartitionExpressionList(ExpressionList partitionExpressionList, + boolean brackets) { + setExpressions(partitionExpressionList, brackets); } - public void setPartitionExpressionList(ExpressionList partitionExpressionList) { - this.partitionExpressionList = partitionExpressionList; + public PartitionByClause setExpressions(ExpressionList partitionExpressionList, + boolean brackets) { + clear(); + if (partitionExpressionList != null) { + addAll(partitionExpressionList); + } + this.brackets = brackets; + return this; } - void toStringPartitionBy(StringBuilder b) { - if (partitionExpressionList != null && !partitionExpressionList.getExpressions().isEmpty()) { + public void toStringPartitionBy(StringBuilder b) { + if (!isEmpty()) { b.append("PARTITION BY "); - b.append(PlainSelect. - getStringList(partitionExpressionList.getExpressions(), true, false)); + b.append(PlainSelect.getStringList(this, true, + brackets)); b.append(" "); } } -} \ No newline at end of file + + public boolean isBrackets() { + return brackets; + } + + @Deprecated + public PartitionByClause withPartitionExpressionList( + ExpressionList partitionExpressionList) { + this.setPartitionExpressionList(partitionExpressionList); + return this; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameter.java b/src/main/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameter.java new file mode 100644 index 000000000..573ad60f2 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/PostgresNamedFunctionParameter.java @@ -0,0 +1,55 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2021 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.Objects; + +/** + * @author Andreas Reichel + */ +public class PostgresNamedFunctionParameter extends ASTNodeAccessImpl implements Expression { + private final String name; + private final Expression expression; + + public PostgresNamedFunctionParameter(String name, Expression expression) { + this.name = Objects.requireNonNull(name, + "The NAME of the PostgresNamedFunctionParameter must not be null."); + this.expression = Objects.requireNonNull(expression, + "The EXPRESSION of the PostgresNamedFunctionParameter must not be null."); + } + + public String getName() { + return name; + } + + public Expression getExpression() { + return expression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append(name) + .append(" := ") + .append(expression); + + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java b/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java new file mode 100644 index 000000000..2db468dbb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/PreferringClause.java @@ -0,0 +1,66 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; + +import java.io.Serializable; + +public class PreferringClause implements Serializable { + private Expression preferring; + private PartitionByClause partitionBy; + + public PreferringClause(Expression preferring) { + this.preferring = preferring; + } + + public void setPartitionExpressionList(ExpressionList expressionList, + boolean brackets) { + if (this.partitionBy == null) { + this.partitionBy = new PartitionByClause(); + } + partitionBy.setExpressions(expressionList, brackets); + } + + public void toStringPreferring(StringBuilder b) { + b.append("PREFERRING "); + b.append(preferring.toString()); + + if (partitionBy != null) { + b.append(" "); + partitionBy.toStringPartitionBy(b); + } + } + + public Expression getPreferring() { + return preferring; + } + + public PreferringClause setPreferring(Expression preferring) { + this.preferring = preferring; + return this; + } + + public PartitionByClause getPartitionBy() { + return partitionBy; + } + + public PreferringClause setPartitionBy(PartitionByClause partitionBy) { + this.partitionBy = partitionBy; + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + toStringPreferring(sb); + return sb.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/RangeExpression.java b/src/main/java/net/sf/jsqlparser/expression/RangeExpression.java new file mode 100644 index 000000000..dd05827d6 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/RangeExpression.java @@ -0,0 +1,50 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class RangeExpression extends ASTNodeAccessImpl implements Expression { + private Expression startExpression; + private Expression endExpression; + + public RangeExpression(Expression startExpression, Expression endExpression) { + this.startExpression = startExpression; + this.endExpression = endExpression; + } + + public Expression getStartExpression() { + return startExpression; + } + + public RangeExpression setStartExpression(Expression startExpression) { + this.startExpression = startExpression; + return this; + } + + public Expression getEndExpression() { + return endExpression; + } + + public RangeExpression setEndExpression(Expression endExpression) { + this.endExpression = endExpression; + return this; + } + + @Override + public String toString() { + return startExpression + ":" + endExpression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/RawFunction.java b/src/main/java/net/sf/jsqlparser/expression/RawFunction.java new file mode 100644 index 000000000..1c2d5b874 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/RawFunction.java @@ -0,0 +1,41 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2026 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +/** + * Function with a raw argument body preserved as-is for deparsing. + */ +public class RawFunction extends Function { + private String rawArguments; + + public RawFunction() {} + + public RawFunction(String name, String rawArguments) { + setName(name); + this.rawArguments = rawArguments; + } + + public String getRawArguments() { + return rawArguments; + } + + public void setRawArguments(String rawArguments) { + this.rawArguments = rawArguments; + } + + @Override + public String toString() { + String name = getName(); + if (rawArguments == null) { + return name + "()"; + } + return name + "(" + rawArguments + ")"; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/RowConstructor.java b/src/main/java/net/sf/jsqlparser/expression/RowConstructor.java index f0b65a09d..2f5844ea0 100644 --- a/src/main/java/net/sf/jsqlparser/expression/RowConstructor.java +++ b/src/main/java/net/sf/jsqlparser/expression/RowConstructor.java @@ -1,48 +1,26 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2015 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; -import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; -/** - * Rowconstructor. - * - * @author tw - */ -public class RowConstructor extends ASTNodeAccessImpl implements Expression { - - private ExpressionList exprList; +public class RowConstructor extends ParenthesedExpressionList + implements Expression { private String name = null; - public RowConstructor() { - } - - public ExpressionList getExprList() { - return exprList; - } + public RowConstructor() {} - public void setExprList(ExpressionList exprList) { - this.exprList = exprList; + public RowConstructor(String name, ExpressionList expressionList) { + this.name = name; + addAll(expressionList); } public String getName() { @@ -54,12 +32,17 @@ public void setName(String name) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public String toString() { + return (name != null ? name : "") + super.toString(); + } + + public RowConstructor withName(String name) { + this.setName(name); + return this; } @Override - public String toString() { - return (name != null ? name : "") + exprList.toString(); + public K accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/RowGetExpression.java b/src/main/java/net/sf/jsqlparser/expression/RowGetExpression.java new file mode 100644 index 000000000..0aaefa1aa --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/RowGetExpression.java @@ -0,0 +1,48 @@ +/*- + * #%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; + +public final class RowGetExpression extends ASTNodeAccessImpl implements Expression { + private Expression expression; + private String columnName; + + public RowGetExpression(Expression expression, String columnName) { + this.expression = expression; + this.columnName = columnName; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return expression + "." + columnName; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/SQLServerHints.java b/src/main/java/net/sf/jsqlparser/expression/SQLServerHints.java new file mode 100644 index 000000000..34d14964b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/SQLServerHints.java @@ -0,0 +1,67 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class SQLServerHints implements Serializable { + + private Boolean noLock; + private String indexName; + + public SQLServerHints() {} + + public SQLServerHints withNoLock() { + this.noLock = true; + return this; + } + + public Boolean getNoLock() { + return noLock; + } + + public void setNoLock(Boolean noLock) { + this.noLock = noLock; + } + + public String getIndexName() { + return indexName; + } + + public void setIndexName(String indexName) { + this.indexName = indexName; + } + + @Override + public String toString() { + List hints = new ArrayList<>(); + if (indexName != null) { + hints.add("INDEX (" + indexName + ")"); + } + if (Boolean.TRUE.equals(noLock)) { + hints.add("NOLOCK"); + } + return " WITH (" + + String.join(", ", hints) + + ")"; + } + + public SQLServerHints withNoLock(Boolean noLock) { + this.setNoLock(noLock); + return this; + } + + public SQLServerHints withIndexName(String indexName) { + this.setIndexName(indexName); + return this; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/SignedExpression.java b/src/main/java/net/sf/jsqlparser/expression/SignedExpression.java index 8d8569405..725d449e8 100644 --- a/src/main/java/net/sf/jsqlparser/expression/SignedExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/SignedExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -31,6 +19,10 @@ public class SignedExpression extends ASTNodeAccessImpl implements Expression { private char sign; private Expression expression; + public SignedExpression() { + // empty constructor + } + public SignedExpression(char sign, Expression expression) { setSign(sign); setExpression(expression); @@ -56,12 +48,26 @@ public final void setExpression(Expression expression) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { return getSign() + expression.toString(); } + + public SignedExpression withSign(char sign) { + this.setSign(sign); + return this; + } + + public SignedExpression withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public E getExpression(Class type) { + return type.cast(getExpression()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/SpannerInterleaveIn.java b/src/main/java/net/sf/jsqlparser/expression/SpannerInterleaveIn.java new file mode 100644 index 000000000..0bf49925d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/SpannerInterleaveIn.java @@ -0,0 +1,80 @@ +/*- + * #%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.schema.Table; + +import java.util.Collections; +import java.util.List; + +public class SpannerInterleaveIn { + + private Table table; + private OnDelete onDelete; + + public SpannerInterleaveIn() { + + } + + public SpannerInterleaveIn(Table table, OnDelete action) { + setTable(table); + setOnDelete(action); + } + + public SpannerInterleaveIn(List nameParts) { + this(new Table(nameParts), null); + } + + public SpannerInterleaveIn(String tableName) { + this(Collections.singletonList(tableName)); + } + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + public OnDelete getOnDelete() { + return onDelete; + } + + public void setOnDelete(OnDelete action) { + this.onDelete = action; + } + + @Override + public String toString() { + return "INTERLEAVE IN PARENT " + getTable().getName() + + (getOnDelete() == null ? "" + : " ON DELETE " + + (getOnDelete() == OnDelete.CASCADE ? "CASCADE" : "NO ACTION")); + } + + public SpannerInterleaveIn withTable(Table table) { + this.setTable(table); + return this; + } + + public SpannerInterleaveIn withOnDelete(OnDelete action) { + this.setOnDelete(action); + return this; + } + + public enum OnDelete { + CASCADE, NO_ACTION; + + public static OnDelete from(String action) { + return Enum.valueOf(OnDelete.class, action.toUpperCase()); + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/StringValue.java b/src/main/java/net/sf/jsqlparser/expression/StringValue.java index c5ef705af..a16536fab 100644 --- a/src/main/java/net/sf/jsqlparser/expression/StringValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/StringValue.java @@ -1,28 +1,18 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; import java.util.Arrays; import java.util.List; +import java.util.Objects; + import net.sf.jsqlparser.parser.ASTNodeAccessImpl; /** @@ -30,29 +20,34 @@ */ public final class StringValue extends ASTNodeAccessImpl implements Expression { + public static final List ALLOWED_PREFIXES = + Arrays.asList("N", "U", "E", "R", "B", "RB", "_utf8", "Q"); private String value = ""; private String prefix = null; + private String quoteStr = "'"; - /* - N - SQLServer Unicode encoding - U - Oracle Unicode encoding - E - Postgresql Unicode encoding - R - Cloud Spanner Raw string - B - Cloud Spanner Byte string - RB - Cloud Spanner Raw Byte string - */ - public static final List ALLOWED_PREFIXES = Arrays.asList("N", "U", "E", "R", "B", "RB"); + public StringValue() { + // empty constructor + } public StringValue(String escapedValue) { - // romoving "'" at the start and at the end - if (escapedValue.startsWith("'") && escapedValue.endsWith("'")) { + // removing "'" at the start and at the end + if (escapedValue.length() >= 2 && escapedValue.startsWith("'") + && 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) { - for(String p : ALLOWED_PREFIXES) { - if(escapedValue.length() > p.length() && escapedValue.substring(0, p.length()).equalsIgnoreCase(p) && escapedValue.charAt(p.length())=='\'') { + for (String p : ALLOWED_PREFIXES) { + if (escapedValue.length() > p.length() + && escapedValue.substring(0, p.length()).equalsIgnoreCase(p) + && escapedValue.charAt(p.length()) == '\'') { this.prefix = p; value = escapedValue.substring(p.length() + 1, escapedValue.length() - 1); return; @@ -67,10 +62,27 @@ public String getValue() { return value; } + public void setValue(String string) { + value = string; + } + public String getPrefix() { return prefix; } + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getQuoteStr() { + return quoteStr; + } + + public StringValue setQuoteStr(String quoteStr) { + this.quoteStr = quoteStr; + return this; + } + public String getNotExcapedValue() { StringBuilder buffer = new StringBuilder(value); int index = 0; @@ -83,21 +95,40 @@ public String getNotExcapedValue() { return buffer.toString(); } - public void setValue(String string) { - value = string; + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } - public void setPrefix(String prefix) { - this.prefix = prefix; + @Override + public String toString() { + return (prefix != null ? prefix : "") + quoteStr + value + quoteStr; + } + + public StringValue withPrefix(String prefix) { + this.setPrefix(prefix); + return this; + } + + public StringValue withValue(String value) { + this.setValue(value); + return this; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + StringValue that = (StringValue) o; + return Objects.equals(value, that.value) && Objects.equals(prefix, that.prefix); } @Override - public String toString() { - return (prefix != null ? prefix : "") + "'" + value + "'"; + public int hashCode() { + return Objects.hash(value, prefix); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/StructType.java b/src/main/java/net/sf/jsqlparser/expression/StructType.java new file mode 100644 index 000000000..4bd38a693 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/StructType.java @@ -0,0 +1,198 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.create.table.ColDataType; +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/* + * STRUCT + * + * Type Declaration Meaning STRUCT Simple struct with a single unnamed 64-bit integer field. + * STRUCT Simple struct with a single parameterized string field named x. STRUCT> A struct with a nested struct named x inside it. The struct x has two + * fields, y and z, both of which are 64-bit integers. STRUCT> A struct + * containing an array named inner_array that holds 64-bit integer elements. + * + * STRUCT( expr1 [AS field_name] [, ... ]) + * + * Syntax Output Type STRUCT(1,2,3) STRUCT STRUCT() STRUCT<> STRUCT('abc') + * STRUCT STRUCT(1, t.str_col) STRUCT STRUCT(1 AS a, 'abc' AS b) + * STRUCT STRUCT(str_col AS abc) STRUCT + * + * + * Struct Literals + * + * Example Output Type (1, 2, 3) STRUCT (1, 'abc') STRUCT + * STRUCT(1 AS foo, 'abc' AS bar) STRUCT STRUCT(1, 'abc') + * STRUCT STRUCT(1) STRUCT STRUCT(1) STRUCT + * + */ +public class StructType extends ASTNodeAccessImpl implements Expression { + private Dialect dialect = Dialect.BIG_QUERY;; + private String keyword; + private List> parameters; + private List> arguments; + + public StructType(Dialect dialect, String keyword, + List> parameters, + List> arguments) { + this.dialect = dialect; + this.keyword = keyword; + this.parameters = parameters; + this.arguments = arguments; + } + + public StructType(Dialect dialect, List> parameters, + List> arguments) { + this.dialect = dialect; + this.parameters = parameters; + this.arguments = arguments; + } + + public StructType(Dialect dialect, List> arguments) { + this.dialect = dialect; + this.arguments = arguments; + } + + public Dialect getDialect() { + return dialect; + } + + public StructType setDialect(Dialect dialect) { + this.dialect = dialect; + return this; + } + + public String getKeyword() { + return keyword; + } + + public StructType setKeyword(String keyword) { + this.keyword = keyword; + return this; + } + + public List> getParameters() { + return parameters; + } + + public StructType setParameters(List> parameters) { + this.parameters = parameters; + return this; + } + + public List> getArguments() { + return arguments; + } + + public StructType setArguments(List> arguments) { + this.arguments = arguments; + return this; + } + + public StructType add(Expression expression, String aliasName) { + if (arguments == null) { + arguments = new ArrayList<>(); + } + arguments.add(new SelectItem<>(expression, aliasName)); + + return this; + } + + public StringBuilder appendTo(StringBuilder builder) { + if (dialect != Dialect.DUCKDB && keyword != null) { + builder.append(keyword); + } + + if (dialect != Dialect.DUCKDB && parameters != null && !parameters.isEmpty()) { + builder.append("<"); + int i = 0; + + for (Map.Entry e : parameters) { + if (0 < i++) { + builder.append(","); + } + // optional name + if (e.getKey() != null && !e.getKey().isEmpty()) { + builder.append(e.getKey()).append(" "); + } + + // mandatory type + builder.append(e.getValue()); + } + + builder.append(">"); + } + + if (arguments != null && !arguments.isEmpty()) { + + if (dialect == Dialect.DUCKDB) { + builder.append("{ "); + int i = 0; + for (SelectItem e : arguments) { + if (0 < i++) { + builder.append(","); + } + builder.append(e.getAlias().getName()); + builder.append(":"); + builder.append(e.getExpression()); + } + builder.append(" }"); + } else { + builder.append("("); + int i = 0; + for (SelectItem e : arguments) { + if (0 < i++) { + builder.append(","); + } + e.appendTo(builder); + } + + builder.append(")"); + } + } + + if (dialect == Dialect.DUCKDB && parameters != null && !parameters.isEmpty()) { + builder.append("::STRUCT( "); + int i = 0; + + for (Map.Entry e : parameters) { + if (0 < i++) { + builder.append(","); + } + builder.append(e.getKey()).append(" "); + builder.append(e.getValue()); + } + builder.append(")"); + } + + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public enum Dialect { + BIG_QUERY, DUCKDB + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/TimeKeyExpression.java b/src/main/java/net/sf/jsqlparser/expression/TimeKeyExpression.java index 0e227e37b..759da0e7a 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TimeKeyExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/TimeKeyExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2016 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -27,13 +15,17 @@ public class TimeKeyExpression extends ASTNodeAccessImpl implements Expression { private String stringValue; + public TimeKeyExpression() { + // empty constructor + } + public TimeKeyExpression(final String value) { this.stringValue = value; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public String getStringValue() { @@ -48,4 +40,9 @@ public void setStringValue(String string) { public String toString() { return getStringValue(); } + + public TimeKeyExpression withStringValue(String stringValue) { + this.setStringValue(stringValue); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/TimeValue.java b/src/main/java/net/sf/jsqlparser/expression/TimeValue.java index b1e7fad41..2b3f74394 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TimeValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/TimeValue.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -32,13 +20,20 @@ public class TimeValue extends ASTNodeAccessImpl implements Expression { private Time value; + public TimeValue() { + // empty constructor + } + public TimeValue(String value) { + if (value == null || value.isEmpty()) { + throw new IllegalArgumentException("value can neither be null nor empty."); + } this.value = Time.valueOf(value.substring(1, value.length() - 1)); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public Time getValue() { @@ -53,4 +48,9 @@ public void setValue(Time d) { public String toString() { return "{t '" + value + "'}"; } + + public TimeValue withValue(Time value) { + this.setValue(value); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/TimestampValue.java b/src/main/java/net/sf/jsqlparser/expression/TimestampValue.java index dd72705d3..a06082304 100644 --- a/src/main/java/net/sf/jsqlparser/expression/TimestampValue.java +++ b/src/main/java/net/sf/jsqlparser/expression/TimestampValue.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -24,29 +12,33 @@ import net.sf.jsqlparser.parser.ASTNodeAccessImpl; import java.sql.Timestamp; +import java.util.Objects; /** * A Timestamp in the form {ts 'yyyy-mm-dd hh:mm:ss.f . . .'} */ -public class TimestampValue extends ASTNodeAccessImpl implements Expression { +public final class TimestampValue extends ASTNodeAccessImpl implements Expression { + private static final char QUOTATION = '\''; private Timestamp value; - private char quotation = '\''; + private String rawValue; + + public TimestampValue() { + // empty constructor + } + public TimestampValue(String value) { - if (value == null) { - throw new java.lang.IllegalArgumentException("null string"); - } else { - if (value.charAt(0) == quotation) { - this.value = Timestamp.valueOf(value.substring(1, value.length() - 1)); - } else { - this.value = Timestamp.valueOf(value.substring(0, value.length())); - } - } + // if (value == null) { + // throw new IllegalArgumentException("null string"); + // } else { + // setRawValue(value); + // } + setRawValue(Objects.requireNonNull(value, "The Timestamp string value must not be null.")); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public Timestamp getValue() { @@ -57,8 +49,26 @@ public void setValue(Timestamp d) { value = d; } + public String getRawValue() { + return rawValue; + } + + public void setRawValue(String rawValue) { + this.rawValue = rawValue; + if (rawValue.charAt(0) == QUOTATION) { + this.value = Timestamp.valueOf(rawValue.substring(1, rawValue.length() - 1)); + } else { + this.value = Timestamp.valueOf(rawValue.substring(0, rawValue.length())); + } + } + @Override public String toString() { return "{ts '" + value + "'}"; } + + public TimestampValue withValue(Timestamp value) { + this.setValue(value); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/TimezoneExpression.java b/src/main/java/net/sf/jsqlparser/expression/TimezoneExpression.java new file mode 100644 index 000000000..a67572ace --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/TimezoneExpression.java @@ -0,0 +1,63 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.Arrays; +import java.util.List; + +public class TimezoneExpression extends ASTNodeAccessImpl implements Expression { + + private final ExpressionList timezoneExpressions = new ExpressionList<>(); + private Expression leftExpression; + + public TimezoneExpression() { + leftExpression = null; + } + + public TimezoneExpression(Expression leftExpression, Expression... timezoneExpressions) { + this.leftExpression = leftExpression; + this.timezoneExpressions.addAll(Arrays.asList(timezoneExpressions)); + } + + public Expression getLeftExpression() { + return leftExpression; + } + + public TimezoneExpression setLeftExpression(Expression expression) { + this.leftExpression = expression; + return this; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public List getTimezoneExpressions() { + return timezoneExpressions; + } + + public void addTimezoneExpression(Expression... timezoneExpr) { + this.timezoneExpressions.addAll(Arrays.asList(timezoneExpr)); + } + + @Override + public String toString() { + StringBuilder returnValue = new StringBuilder(leftExpression.toString()); + for (Expression expr : timezoneExpressions) { + returnValue.append(" AT TIME ZONE ").append(expr.toString()); + } + + return returnValue.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java b/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java new file mode 100644 index 000000000..b68f1dfb7 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/TranscodingFunction.java @@ -0,0 +1,141 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +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; + this.expression = expression; + this.transcodingName = transcodingName; + this.isTranscodeStyle = false; + } + + 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; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public TranscodingFunction withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public String getTranscodingName() { + return transcodingName; + } + + public void setTranscodingName(String transcodingName) { + this.transcodingName = transcodingName; + } + + public TranscodingFunction withTranscodingName(String transcodingName) { + this.setTranscodingName(transcodingName); + return this; + + } + + public ColDataType getColDataType() { + return colDataType; + } + + public TranscodingFunction setColDataType(ColDataType colDataType) { + this.colDataType = colDataType; + return this; + } + + public boolean isTranscodeStyle() { + return isTranscodeStyle; + } + + public TranscodingFunction setTranscodeStyle(boolean transcodeStyle) { + isTranscodeStyle = transcodeStyle; + return this; + } + + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + if (isTranscodeStyle) { + return builder + .append(keyword) + .append("( ") + .append(expression) + .append(" USING ") + .append(transcodingName) + .append(" )"); + } else { + return builder + .append(keyword) + .append("( ") + .append(colDataType) + .append(", ") + .append(expression) + .append(transcodingName != null && !transcodingName.isEmpty() + ? ", " + transcodingName + : "") + .append(" )"); + } + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/TrimFunction.java b/src/main/java/net/sf/jsqlparser/expression/TrimFunction.java new file mode 100644 index 000000000..e8ea0305d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/TrimFunction.java @@ -0,0 +1,124 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class TrimFunction extends ASTNodeAccessImpl implements Expression { + private TrimSpecification trimSpecification; + private Expression expression; + private Expression fromExpression; + private boolean isUsingFromKeyword; + + public TrimFunction(TrimSpecification trimSpecification, + Expression expression, + Expression fromExpression, + boolean isUsingFromKeyword) { + + this.trimSpecification = trimSpecification; + this.expression = expression; + this.fromExpression = fromExpression; + this.isUsingFromKeyword = isUsingFromKeyword; + } + + public TrimFunction() { + this(null, null, null, false); + } + + public TrimSpecification getTrimSpecification() { + return trimSpecification; + } + + public void setTrimSpecification(TrimSpecification trimSpecification) { + this.trimSpecification = trimSpecification; + } + + public TrimFunction withTrimSpecification(TrimSpecification trimSpecification) { + this.setTrimSpecification(trimSpecification); + return this; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public TrimFunction withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public Expression getFromExpression() { + return fromExpression; + } + + public void setFromExpression(Expression fromExpression) { + if (fromExpression == null) { + setUsingFromKeyword(false); + } + this.fromExpression = fromExpression; + } + + public TrimFunction withFromExpression(Expression fromExpression) { + this.setFromExpression(fromExpression); + return this; + } + + public boolean isUsingFromKeyword() { + return isUsingFromKeyword; + } + + public void setUsingFromKeyword(boolean useFromKeyword) { + isUsingFromKeyword = useFromKeyword; + } + + public TrimFunction withUsingFromKeyword(boolean useFromKeyword) { + this.setUsingFromKeyword(useFromKeyword); + return this; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("Trim("); + + if (trimSpecification != null) { + builder.append(" ").append(trimSpecification.name()); + } + + if (expression != null) { + builder.append(" ").append(expression); + } + + if (fromExpression != null) { + builder + .append(isUsingFromKeyword ? " FROM " : ", ") + .append(fromExpression); + } + builder.append(" )"); + + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + + public enum TrimSpecification { + LEADING, TRAILING, BOTH + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/UserVariable.java b/src/main/java/net/sf/jsqlparser/expression/UserVariable.java index d751523eb..b0599a3c5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/UserVariable.java +++ b/src/main/java/net/sf/jsqlparser/expression/UserVariable.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2015 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -25,30 +13,39 @@ /** * Simple uservariables like @test. - * - * @author aud */ public class UserVariable extends ASTNodeAccessImpl implements Expression { private String name; private boolean doubleAdd = false; - /** - * The name of the parameter - * - * @return the name of the parameter - */ + public UserVariable() { + // empty constructor + } + + public UserVariable(String name) { + setName(name); + } + public String getName() { return name; } public void setName(String name) { - this.name = name; + if (name.startsWith("@@")) { + this.name = name.substring(2); + doubleAdd = true; + } else if (name.startsWith("@")) { + this.name = name.substring(1); + doubleAdd = false; + } else { + this.name = name; + } } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public boolean isDoubleAdd() { @@ -63,4 +60,14 @@ public void setDoubleAdd(boolean doubleAdd) { public String toString() { return "@" + (doubleAdd ? "@" : "") + name; } + + public UserVariable withName(String name) { + this.setName(name); + return this; + } + + public UserVariable withDoubleAdd(boolean doubleAdd) { + this.setDoubleAdd(doubleAdd); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/ValueListExpression.java b/src/main/java/net/sf/jsqlparser/expression/ValueListExpression.java deleted file mode 100644 index 175916282..000000000 --- a/src/main/java/net/sf/jsqlparser/expression/ValueListExpression.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2018 JSQLParser - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -/** - * - */ -package net.sf.jsqlparser.expression; - -import net.sf.jsqlparser.expression.operators.relational.ExpressionList; -import net.sf.jsqlparser.parser.ASTNodeAccessImpl; - -/** - * Models a list of expressions usable as condition.
- * This allows for instance the following expression : - * "[WHERE] (a, b) [OPERATOR] (c, d)" - * where "(a, b)" and "(c, d)" are instances of this class. - * - * @author adriil - */ -public class ValueListExpression extends ASTNodeAccessImpl implements Expression { - - private ExpressionList expressionList; - - public ExpressionList getExpressionList() { - return expressionList; - } - - public void setExpressionList(ExpressionList expressionList) { - this.expressionList = expressionList; - } - - @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); - } - - @Override - public String toString() { - return expressionList.toString(); - } - -} diff --git a/src/main/java/net/sf/jsqlparser/expression/VariableAssignment.java b/src/main/java/net/sf/jsqlparser/expression/VariableAssignment.java new file mode 100644 index 000000000..2ad773205 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/VariableAssignment.java @@ -0,0 +1,58 @@ +/*- + * #%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; + +/** + * Assignment to a user variable like in select @a = 5. + */ +public class VariableAssignment extends ASTNodeAccessImpl implements Expression { + + private UserVariable variable; + private String operation; + private Expression expression; + + public UserVariable getVariable() { + return variable; + } + + public void setVariable(UserVariable variable) { + this.variable = variable; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + @Override + public String toString() { + return variable.toString() + " " + operation + " " + expression.toString(); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + +} diff --git a/src/main/java/net/sf/jsqlparser/expression/WhenClause.java b/src/main/java/net/sf/jsqlparser/expression/WhenClause.java index c22ee2743..5ed58de11 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WhenClause.java +++ b/src/main/java/net/sf/jsqlparser/expression/WhenClause.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; @@ -25,29 +13,28 @@ /** * A clause of following syntax: WHEN condition THEN expression. Which is part of a CaseExpression. - * - * @author Havard Rast Blok */ public class WhenClause extends ASTNodeAccessImpl implements Expression { private Expression whenExpression; private Expression thenExpression; + public WhenClause() {} + + public WhenClause(Expression whenExpression, Expression thenExpression) { + this.whenExpression = whenExpression; + this.thenExpression = thenExpression; + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } - /** - * @return Returns the thenExpression. - */ public Expression getThenExpression() { return thenExpression; } - /** - * @param thenExpression The thenExpression to set. - */ public void setThenExpression(Expression thenExpression) { this.thenExpression = thenExpression; } @@ -70,4 +57,22 @@ public void setWhenExpression(Expression whenExpression) { public String toString() { return "WHEN " + whenExpression + " THEN " + thenExpression; } + + public WhenClause withWhenExpression(Expression whenExpression) { + this.setWhenExpression(whenExpression); + return this; + } + + public WhenClause withThenExpression(Expression thenExpression) { + this.setThenExpression(thenExpression); + return this; + } + + public E getThenExpression(Class type) { + return type.cast(getThenExpression()); + } + + public E getWhenExpression(Class type) { + return type.cast(getWhenExpression()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java b/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java new file mode 100644 index 000000000..60760baee --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/WindowDefinition.java @@ -0,0 +1,95 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import java.io.Serializable; +import java.util.List; + +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.statement.select.OrderByElement; + +public class WindowDefinition implements Serializable { + + + final OrderByClause orderBy = new OrderByClause(); + final PartitionByClause partitionBy = new PartitionByClause(); + WindowElement windowElement = null; + private String windowName; + + public OrderByClause getOrderBy() { + return orderBy; + } + + public PartitionByClause getPartitionBy() { + return partitionBy; + } + + public WindowElement getWindowElement() { + return windowElement; + } + + public void setWindowElement(WindowElement windowElement) { + this.windowElement = windowElement; + } + + public List getOrderByElements() { + return orderBy.getOrderByElements(); + } + + public void setOrderByElements(List orderByElements) { + orderBy.setOrderByElements(orderByElements); + } + + public ExpressionList getPartitionExpressionList() { + return partitionBy.getPartitionExpressionList(); + } + + public void setPartitionExpressionList(ExpressionList partitionExpressionList) { + setPartitionExpressionList(partitionExpressionList, false); + } + + public void setPartitionExpressionList(ExpressionList partitionExpressionList, + boolean brackets) { + partitionBy.setExpressions(partitionExpressionList, brackets); + } + + public String getWindowName() { + return windowName; + } + + public void setWindowName(String windowName) { + this.windowName = windowName; + } + + public WindowDefinition withWindowName(String windowName) { + setWindowName(windowName); + return this; + } + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + if (windowName != null) { + b.append(windowName).append(" AS "); + } + b.append("("); + partitionBy.toStringPartitionBy(b); + orderBy.toStringOrderByElements(b); + + if (windowElement != null) { + if (orderBy.getOrderByElements() != null) { + b.append(' '); + } + b.append(windowElement); + } + b.append(")"); + return b.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowElement.java b/src/main/java/net/sf/jsqlparser/expression/WindowElement.java index 7ad4f7a07..97260ce97 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowElement.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowElement.java @@ -1,33 +1,17 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2014 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; -public class WindowElement { +import java.io.Serializable; - public enum Type { - - ROWS, - RANGE - } +public class WindowElement implements Serializable { private Type type; private WindowOffset offset; @@ -69,4 +53,28 @@ public String toString() { return buffer.toString(); } + + public WindowElement withType(Type type) { + this.setType(type); + return this; + } + + public WindowElement withOffset(WindowOffset offset) { + this.setOffset(offset); + return this; + } + + public WindowElement withRange(WindowRange range) { + this.setRange(range); + return this; + } + + public enum Type { + ROWS, RANGE; + + public static Type from(String type) { + return Enum.valueOf(Type.class, type.toUpperCase()); + } + } + } diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowOffset.java b/src/main/java/net/sf/jsqlparser/expression/WindowOffset.java index e899becc9..0303b4f06 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowOffset.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowOffset.java @@ -1,35 +1,17 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2014 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; -public class WindowOffset { +import java.io.Serializable; - public enum Type { - - PRECEDING, - FOLLOWING, - CURRENT, - EXPR - } +public class WindowOffset implements Serializable { private Expression expression; private Type type; @@ -60,20 +42,45 @@ public String toString() { buffer.append(type); } } else { - switch (type) { - case PRECEDING: - buffer.append(" UNBOUNDED PRECEDING"); - break; - case FOLLOWING: - buffer.append(" UNBOUNDED FOLLOWING"); - break; - case CURRENT: - buffer.append(" CURRENT ROW"); - break; - default: - break; + if (type != null) { + switch (type) { + case PRECEDING: + buffer.append(" UNBOUNDED PRECEDING"); + break; + case FOLLOWING: + buffer.append(" UNBOUNDED FOLLOWING"); + break; + case CURRENT: + buffer.append(" CURRENT ROW"); + break; + default: + break; + } } } return buffer.toString(); } + + public WindowOffset withExpression(Expression expression) { + this.setExpression(expression); + return this; + } + + public WindowOffset withType(Type type) { + this.setType(type); + return this; + } + + public E getExpression(Class type) { + return type.cast(getExpression()); + } + + public enum Type { + PRECEDING, FOLLOWING, CURRENT, EXPR; + + public static Type from(String type) { + return Enum.valueOf(Type.class, type.toUpperCase()); + } + } + } diff --git a/src/main/java/net/sf/jsqlparser/expression/WindowRange.java b/src/main/java/net/sf/jsqlparser/expression/WindowRange.java index d90ace12c..fc5f0af36 100644 --- a/src/main/java/net/sf/jsqlparser/expression/WindowRange.java +++ b/src/main/java/net/sf/jsqlparser/expression/WindowRange.java @@ -1,27 +1,17 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2014 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression; -public class WindowRange { +import java.io.Serializable; + +public class WindowRange implements Serializable { private WindowOffset start; private WindowOffset end; @@ -44,11 +34,19 @@ public void setStart(WindowOffset start) { @Override public String toString() { - StringBuilder buffer = new StringBuilder(); - buffer.append(" BETWEEN"); - buffer.append(start); - buffer.append(" AND"); - buffer.append(end); - return buffer.toString(); + return " BETWEEN" + + start + + " AND" + + end; + } + + public WindowRange withStart(WindowOffset start) { + this.setStart(start); + return this; + } + + public WindowRange withEnd(WindowOffset end) { + this.setEnd(end); + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/expression/XMLSerializeExpr.java b/src/main/java/net/sf/jsqlparser/expression/XMLSerializeExpr.java new file mode 100644 index 000000000..d2534e62d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/XMLSerializeExpr.java @@ -0,0 +1,62 @@ +/*- + * #%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 java.util.List; + +import static java.util.stream.Collectors.joining; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.create.table.ColDataType; +import net.sf.jsqlparser.statement.select.OrderByElement; + +public class XMLSerializeExpr extends ASTNodeAccessImpl implements Expression { + + private Expression expression; + private List orderByElements; + private ColDataType dataType; + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public List getOrderByElements() { + return orderByElements; + } + + public void setOrderByElements(List orderByElements) { + this.orderByElements = orderByElements; + } + + public ColDataType getDataType() { + return dataType; + } + + public void setDataType(ColDataType dataType) { + this.dataType = dataType; + } + + @Override + public String toString() { + return "xmlserialize(xmlagg(xmltext(" + expression + ")" + + (orderByElements != null ? " ORDER BY " + orderByElements.stream() + .map(OrderByElement::toString).collect(joining(", ")) : "") + + ") AS " + dataType + ")"; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Addition.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Addition.java index e3c6af3d8..fca4fd08d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Addition.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Addition.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class Addition extends BinaryExpression { + public Addition() {} + + public Addition(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "+"; } + + @Override + public Addition withLeftExpression(Expression arg0) { + return (Addition) super.withLeftExpression(arg0); + } + + @Override + public Addition withRightExpression(Expression arg0) { + return (Addition) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseAnd.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseAnd.java index fe998947a..f5eac9390 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseAnd.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseAnd.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class BitwiseAnd extends BinaryExpression { + public BitwiseAnd() {} + + public BitwiseAnd(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "&"; } + + @Override + public BitwiseAnd withLeftExpression(Expression arg0) { + return (BitwiseAnd) super.withLeftExpression(arg0); + } + + @Override + public BitwiseAnd withRightExpression(Expression arg0) { + return (BitwiseAnd) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseLeftShift.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseLeftShift.java index 402961d34..0f2094ce9 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseLeftShift.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseLeftShift.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class BitwiseLeftShift extends BinaryExpression { + public BitwiseLeftShift() {} + + public BitwiseLeftShift(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "<<"; } + + @Override + public BitwiseLeftShift withLeftExpression(Expression arg0) { + return (BitwiseLeftShift) super.withLeftExpression(arg0); + } + + @Override + public BitwiseLeftShift withRightExpression(Expression arg0) { + return (BitwiseLeftShift) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseOr.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseOr.java index 1365e1a92..2d11d9e6f 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseOr.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseOr.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class BitwiseOr extends BinaryExpression { + public BitwiseOr() {} + + public BitwiseOr(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "|"; } + + @Override + public BitwiseOr withLeftExpression(Expression arg0) { + return (BitwiseOr) super.withLeftExpression(arg0); + } + + @Override + public BitwiseOr withRightExpression(Expression arg0) { + return (BitwiseOr) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseRightShift.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseRightShift.java index aa331de91..13b5dbdd3 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseRightShift.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseRightShift.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class BitwiseRightShift extends BinaryExpression { + public BitwiseRightShift() {} + + public BitwiseRightShift(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return ">>"; } + + @Override + public BitwiseRightShift withLeftExpression(Expression arg0) { + return (BitwiseRightShift) super.withLeftExpression(arg0); + } + + @Override + public BitwiseRightShift withRightExpression(Expression arg0) { + return (BitwiseRightShift) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseXor.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseXor.java index bcc49f15e..89cbcb64a 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseXor.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/BitwiseXor.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class BitwiseXor extends BinaryExpression { + public BitwiseXor() {} + + public BitwiseXor(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "^"; } + + @Override + public BitwiseXor withLeftExpression(Expression arg0) { + return (BitwiseXor) super.withLeftExpression(arg0); + } + + @Override + public BitwiseXor withRightExpression(Expression arg0) { + return (BitwiseXor) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Concat.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Concat.java index b9981d4e4..1ad8bb119 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Concat.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Concat.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class Concat extends BinaryExpression { + public Concat() {} + + public Concat(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "||"; } + + @Override + public Concat withLeftExpression(Expression arg0) { + return (Concat) super.withLeftExpression(arg0); + } + + @Override + public Concat withRightExpression(Expression arg0) { + return (Concat) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Division.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Division.java index 201d78ed5..a963d63f3 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Division.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Division.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class Division extends BinaryExpression { + public Division() {} + + public Division(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "/"; } + + @Override + public Division withLeftExpression(Expression arg0) { + return (Division) super.withLeftExpression(arg0); + } + + @Override + public Division withRightExpression(Expression arg0) { + return (Division) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/IntegerDivision.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/IntegerDivision.java new file mode 100644 index 000000000..73489eb8d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/IntegerDivision.java @@ -0,0 +1,43 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.arithmetic; + +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class IntegerDivision extends BinaryExpression { + + public IntegerDivision() {} + + public IntegerDivision(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String getStringExpression() { + return "DIV"; + } + + @Override + public IntegerDivision withLeftExpression(Expression arg0) { + return (IntegerDivision) super.withLeftExpression(arg0); + } + + @Override + public IntegerDivision withRightExpression(Expression arg0) { + return (IntegerDivision) super.withRightExpression(arg0); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Modulo.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Modulo.java index 9b88105a1..63482d2a2 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Modulo.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Modulo.java @@ -1,46 +1,46 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; /** * Modulo expression (a % b). - * - * @author toben */ public class Modulo extends BinaryExpression { - public Modulo() { + public Modulo() {} + + public Modulo(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "%"; } + + @Override + public Modulo withLeftExpression(Expression arg0) { + return (Modulo) super.withLeftExpression(arg0); + } + + @Override + public Modulo withRightExpression(Expression arg0) { + return (Modulo) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Multiplication.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Multiplication.java index 64d5fb55e..774db570b 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Multiplication.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Multiplication.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class Multiplication extends BinaryExpression { + public Multiplication() {} + + public Multiplication(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "*"; } + + @Override + public Multiplication withLeftExpression(Expression arg0) { + return (Multiplication) super.withLeftExpression(arg0); + } + + @Override + public Multiplication withRightExpression(Expression arg0) { + return (Multiplication) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Subtraction.java b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Subtraction.java index 630cf5908..dc2b74c7b 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Subtraction.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/arithmetic/Subtraction.java @@ -1,38 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.arithmetic; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class Subtraction extends BinaryExpression { + public Subtraction() {} + + public Subtraction(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "-"; } + + @Override + public Subtraction withLeftExpression(Expression arg0) { + return (Subtraction) super.withLeftExpression(arg0); + } + + @Override + public Subtraction withRightExpression(Expression arg0) { + return (Subtraction) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/AndExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/AndExpression.java index 4dc1367d1..0d9d36377 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/AndExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/AndExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.conditional; @@ -26,19 +14,47 @@ import net.sf.jsqlparser.expression.ExpressionVisitor; public class AndExpression extends BinaryExpression { + private boolean useOperator = false; + + public AndExpression() { + // nothing + } public AndExpression(Expression leftExpression, Expression rightExpression) { setLeftExpression(leftExpression); setRightExpression(rightExpression); } + public boolean isUseOperator() { + return useOperator; + } + + public void setUseOperator(boolean useOperator) { + this.useOperator = useOperator; + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { - return "AND"; + return useOperator ? "&&" : "AND"; + } + + public AndExpression withUseOperator(boolean useOperator) { + this.setUseOperator(useOperator); + return this; + } + + @Override + public AndExpression withLeftExpression(Expression arg0) { + return (AndExpression) super.withLeftExpression(arg0); + } + + @Override + public AndExpression withRightExpression(Expression arg0) { + return (AndExpression) super.withRightExpression(arg0); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/OrExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/OrExpression.java index 7a1fc5ddc..f08cc7de2 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/OrExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/OrExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.conditional; @@ -27,18 +15,33 @@ public class OrExpression extends BinaryExpression { + public OrExpression() { + // nothing + } + public OrExpression(Expression leftExpression, Expression rightExpression) { setLeftExpression(leftExpression); setRightExpression(rightExpression); } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public OrExpression withLeftExpression(Expression expression) { + return (OrExpression) super.withLeftExpression(expression); + } + + @Override + public OrExpression withRightExpression(Expression expression) { + return (OrExpression) super.withRightExpression(expression); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "OR"; } + } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/conditional/XorExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/XorExpression.java new file mode 100644 index 000000000..9bab8b53f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/conditional/XorExpression.java @@ -0,0 +1,47 @@ +/*- + * #%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.operators.conditional; + +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class XorExpression extends BinaryExpression { + + public XorExpression() { + // nothing + } + + public XorExpression(Expression leftExpression, Expression rightExpression) { + setLeftExpression(leftExpression); + setRightExpression(rightExpression); + } + + @Override + public XorExpression withLeftExpression(Expression expression) { + return (XorExpression) super.withLeftExpression(expression); + } + + @Override + public XorExpression withRightExpression(Expression expression) { + return (XorExpression) super.withRightExpression(expression); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String getStringExpression() { + return "XOR"; + } + +} 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 d7561b735..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 @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; @@ -34,47 +22,102 @@ public class Between extends ASTNodeAccessImpl implements Expression { private boolean not = false; private Expression betweenExpressionStart; private Expression betweenExpressionEnd; + private boolean usingSymmetric = false; + private boolean usingAsymmetric = false; public Expression getBetweenExpressionEnd() { return betweenExpressionEnd; } + public void setBetweenExpressionEnd(Expression expression) { + betweenExpressionEnd = expression; + } + public Expression getBetweenExpressionStart() { return betweenExpressionStart; } + public void setBetweenExpressionStart(Expression expression) { + betweenExpressionStart = expression; + } + public Expression getLeftExpression() { return leftExpression; } + public void setLeftExpression(Expression expression) { + leftExpression = expression; + } + public boolean isNot() { return not; } - public void setBetweenExpressionEnd(Expression expression) { - betweenExpressionEnd = expression; + public void setNot(boolean b) { + not = b; } - public void setBetweenExpressionStart(Expression expression) { - betweenExpressionStart = expression; + public boolean isUsingSymmetric() { + return usingSymmetric; } - public void setLeftExpression(Expression expression) { - leftExpression = expression; + public Between setUsingSymmetric(boolean usingSymmetric) { + this.usingSymmetric = usingSymmetric; + return this; } - public void setNot(boolean b) { - not = b; + public boolean isUsingAsymmetric() { + return usingAsymmetric; + } + + public Between setUsingAsymmetric(boolean usingAsymmetric) { + this.usingAsymmetric = usingAsymmetric; + return this; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return leftExpression + " " + (not ? "NOT " : "") + "BETWEEN " + betweenExpressionStart + " AND " + return leftExpression + " " + (not ? "NOT " : "") + "BETWEEN " + + (usingSymmetric ? "SYMMETRIC " : "") + (usingAsymmetric ? "ASYMMETRIC " : "") + + betweenExpressionStart + + " AND " + betweenExpressionEnd; } + + public Between withLeftExpression(Expression leftExpression) { + this.setLeftExpression(leftExpression); + return this; + } + + public Between withNot(boolean not) { + this.setNot(not); + return this; + } + + public Between withBetweenExpressionStart(Expression betweenExpressionStart) { + this.setBetweenExpressionStart(betweenExpressionStart); + return this; + } + + public Between withBetweenExpressionEnd(Expression betweenExpressionEnd) { + this.setBetweenExpressionEnd(betweenExpressionEnd); + return this; + } + + public E getBetweenExpressionEnd(Class type) { + return type.cast(getBetweenExpressionEnd()); + } + + public E getBetweenExpressionStart(Class type) { + return type.cast(getBetweenExpressionStart()); + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperator.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperator.java index 1f0b6f35f..d15081101 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ComparisonOperator.java @@ -1,26 +1,16 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; + public abstract class ComparisonOperator extends OldOracleJoinBinaryExpression { private final String operator; @@ -29,8 +19,34 @@ public ComparisonOperator(String operator) { this.operator = operator; } + public ComparisonOperator(String operator, Expression left, Expression right) { + this(operator); + setLeftExpression(left); + setRightExpression(right); + } + @Override public String getStringExpression() { return operator; } + + @Override + public ComparisonOperator withLeftExpression(Expression arg0) { + return (ComparisonOperator) super.withLeftExpression(arg0); + } + + @Override + public ComparisonOperator withRightExpression(Expression arg0) { + return (ComparisonOperator) super.withRightExpression(arg0); + } + + @Override + public ComparisonOperator withOldOracleJoinSyntax(int oldOracleJoinSyntax) { + return (ComparisonOperator) super.withOldOracleJoinSyntax(oldOracleJoinSyntax); + } + + @Override + public ComparisonOperator withOraclePriorPosition(int oraclePriorPosition) { + return (ComparisonOperator) super.withOraclePriorPosition(oraclePriorPosition); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ContainedBy.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ContainedBy.java new file mode 100644 index 000000000..15562a408 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ContainedBy.java @@ -0,0 +1,25 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class ContainedBy extends ComparisonOperator { + + public ContainedBy() { + super("<&"); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} + diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Contains.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Contains.java new file mode 100644 index 000000000..dbfda1027 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Contains.java @@ -0,0 +1,25 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class Contains extends ComparisonOperator { + + public Contains() { + super("&>"); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} + diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/CosineSimilarity.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/CosineSimilarity.java new file mode 100644 index 000000000..00aad962d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/CosineSimilarity.java @@ -0,0 +1,28 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class CosineSimilarity extends ComparisonOperator { + + public CosineSimilarity() { + super("<=>"); + } + + public CosineSimilarity(String operator) { + super(operator); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/DoubleAnd.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/DoubleAnd.java new file mode 100644 index 000000000..372e123b1 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/DoubleAnd.java @@ -0,0 +1,24 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class DoubleAnd extends ComparisonOperator { + + public DoubleAnd() { + super("&&"); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/EqualsTo.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/EqualsTo.java index c23fbd578..8f80f1be8 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/EqualsTo.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/EqualsTo.java @@ -1,26 +1,15 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class EqualsTo extends ComparisonOperator { @@ -29,8 +18,34 @@ public EqualsTo() { super("="); } + public EqualsTo(Expression left, Expression right) { + this(); + setLeftExpression(left); + setRightExpression(right); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public EqualsTo withLeftExpression(Expression expression) { + return (EqualsTo) super.withLeftExpression(expression); + } + + @Override + public EqualsTo withRightExpression(Expression expression) { + return (EqualsTo) super.withRightExpression(expression); + } + + @Override + public EqualsTo withOldOracleJoinSyntax(int arg0) { + return (EqualsTo) super.withOldOracleJoinSyntax(arg0); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public EqualsTo withOraclePriorPosition(int arg0) { + return (EqualsTo) super.withOraclePriorPosition(arg0); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExcludesExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExcludesExpression.java new file mode 100644 index 000000000..847ff087c --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExcludesExpression.java @@ -0,0 +1,78 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class ExcludesExpression extends ASTNodeAccessImpl implements Expression { + + private Expression leftExpression; + private Expression rightExpression; + + public ExcludesExpression() {} + + public ExcludesExpression(Expression leftExpression, Expression rightExpression) { + this.leftExpression = leftExpression; + this.rightExpression = rightExpression; + } + + public Expression getLeftExpression() { + return leftExpression; + } + + public final void setLeftExpression(Expression expression) { + leftExpression = expression; + } + + public ExcludesExpression withLeftExpression(Expression expression) { + this.setLeftExpression(expression); + return this; + } + + public Expression getRightExpression() { + return rightExpression; + } + + public void setRightExpression(Expression rightExpression) { + this.rightExpression = rightExpression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + StringBuilder statementBuilder = new StringBuilder(); + statementBuilder.append(leftExpression); + + statementBuilder.append(" "); + statementBuilder.append("EXCLUDES "); + + statementBuilder.append(rightExpression); + return statementBuilder.toString(); + } + + public ExcludesExpression withRightExpression(Expression rightExpression) { + this.setRightExpression(rightExpression); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } + + public E getRightExpression(Class type) { + return type.cast(getRightExpression()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExistsExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExistsExpression.java index b556bcbea..c8d83f1d5 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExistsExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ExistsExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; @@ -27,8 +15,8 @@ public class ExistsExpression extends ASTNodeAccessImpl implements Expression { - private Expression rightExpression; - private boolean not = false; + protected Expression rightExpression; + protected boolean not = false; public Expression getRightExpression() { return rightExpression; @@ -47,8 +35,8 @@ public void setNot(boolean b) { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } public String getStringExpression() { @@ -59,4 +47,18 @@ public String getStringExpression() { public String toString() { return getStringExpression() + " " + rightExpression.toString(); } + + public ExistsExpression withRightExpression(Expression rightExpression) { + this.setRightExpression(rightExpression); + return this; + } + + public ExistsExpression withNot(boolean not) { + this.setNot(not); + return this; + } + + public E getRightExpression(Class type) { + return type.cast(getRightExpression()); + } } 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 d831bf070..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 @@ -1,65 +1,112 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.Node; + +import java.io.Serializable; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; -import net.sf.jsqlparser.expression.Expression; -import net.sf.jsqlparser.statement.select.PlainSelect; - /** * A list of expressions, as in SELECT A FROM TAB WHERE B IN (expr1,expr2,expr3) */ -public class ExpressionList implements ItemsList { +public class ExpressionList extends ArrayList + implements Expression, Serializable { + private transient Node node; - private List expressions; + public ExpressionList(Collection expressions) { + addAll(expressions); + } - public ExpressionList() { + public ExpressionList(List expressions) { + super(expressions); } - public ExpressionList(List expressions) { - this.expressions = expressions; + public ExpressionList(T... expressions) { + this(Arrays.asList(expressions)); } - - public ExpressionList(Expression ... expressions) { - this.expressions = Arrays.asList(expressions); + + @Deprecated + public boolean isUsingBrackets() { + return false; } - public List getExpressions() { - return expressions; + @Deprecated + public List getExpressions() { + return this; } - public void setExpressions(List list) { - expressions = list; + @Deprecated + public void setExpressions(List expressions) { + this.clear(); + this.addAll(expressions); } - @Override - public void accept(ItemsListVisitor itemsListVisitor) { - itemsListVisitor.visit(this); + public ExpressionList addExpression(T expression) { + this.add(expression); + return this; + } + + public ExpressionList addExpressions(T... expressions) { + addAll(Arrays.asList(expressions)); + return this; + } + + public ExpressionList addExpressions(Collection expressions) { + addAll(expressions); + return this; + } + + public ExpressionList withExpressions(T... expressions) { + this.clear(); + return addExpressions(expressions); + } + + public ExpressionList withExpressions(Collection expressions) { + this.clear(); + return addExpressions(expressions); + } + + public StringBuilder appendTo(StringBuilder builder) { + for (int i = 0; i < size(); i++) { + if (i > 0) { + builder.append(", "); + } + builder.append(get(i)); + } + return builder; } @Override public String toString() { - return PlainSelect.getStringList(expressions, true, true); + return appendTo(new StringBuilder()).toString(); + } + + + @Override + public Node getASTNode() { + return node; + } + + @Override + public void setASTNode(Node node) { + this.node = node; + } + + @Override + public K accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearch.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearch.java new file mode 100644 index 000000000..0bf79f0ec --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/FullTextSearch.java @@ -0,0 +1,121 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Optional; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.JdbcNamedParameter; +import net.sf.jsqlparser.expression.JdbcParameter; +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; + +public class FullTextSearch extends ASTNodeAccessImpl implements Expression { + + private ExpressionList _matchColumns; + private Expression _againstValue; + private String _searchModifier; + + public FullTextSearch() { + + } + + public ExpressionList getMatchColumns() { + return this._matchColumns; + } + + public void setMatchColumns(ExpressionList columns) { + this._matchColumns = columns; + } + + public Expression getAgainstValue() { + return this._againstValue; + } + + public void setAgainstValue(Expression val) { + this._againstValue = val; + } + + public void setAgainstValue(StringValue val) { + setAgainstValue((Expression) val); + } + + public void setAgainstValue(JdbcNamedParameter val) { + setAgainstValue((Expression) val); + } + + public void setAgainstValue(JdbcParameter val) { + setAgainstValue((Expression) val); + } + + public String getSearchModifier() { + return this._searchModifier; + } + + public void setSearchModifier(String val) { + this._searchModifier = val; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + // Build a list of matched columns + String columnsListCommaSeperated = ""; + Iterator iterator = this._matchColumns.iterator(); + while (iterator.hasNext()) { + Column col = iterator.next(); + columnsListCommaSeperated += col.getFullyQualifiedName(); + if (iterator.hasNext()) { + columnsListCommaSeperated += ","; + } + } + + return "MATCH (" + columnsListCommaSeperated + ") AGAINST (" + this._againstValue + + (this._searchModifier != null ? " " + this._searchModifier : "") + ")"; + } + + public FullTextSearch withMatchColumns(ExpressionList matchColumns) { + this.setMatchColumns(matchColumns); + return this; + } + + public FullTextSearch withAgainstValue(StringValue againstValue) { + return withAgainstValue((Expression) againstValue); + } + + public FullTextSearch withAgainstValue(Expression againstValue) { + this.setAgainstValue(againstValue); + return this; + } + + public FullTextSearch withSearchModifier(String searchModifier) { + this.setSearchModifier(searchModifier); + return this; + } + + public FullTextSearch addMatchColumns(Column... matchColumns) { + return this.addMatchColumns(Arrays.asList(matchColumns)); + } + + public FullTextSearch addMatchColumns(Collection matchColumns) { + ExpressionList collection = + Optional.ofNullable(getMatchColumns()).orElseGet(ExpressionList::new); + collection.addAll(matchColumns); + return this.withMatchColumns(collection); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GeometryDistance.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GeometryDistance.java new file mode 100644 index 000000000..9f8438ab6 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GeometryDistance.java @@ -0,0 +1,28 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class GeometryDistance extends ComparisonOperator { + + public GeometryDistance() { + super("<->"); + } + + public GeometryDistance(String operator) { + super(operator); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThan.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThan.java index bb0e44577..3599ba45d 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThan.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThan.java @@ -1,26 +1,15 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class GreaterThan extends ComparisonOperator { @@ -29,8 +18,32 @@ public GreaterThan() { super(">"); } + public GreaterThan(Expression leftExpression, Expression rightExpression) { + super(">", leftExpression, rightExpression); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public GreaterThan withLeftExpression(Expression arg0) { + return (GreaterThan) super.withLeftExpression(arg0); + } + + @Override + public GreaterThan withRightExpression(Expression arg0) { + return (GreaterThan) super.withRightExpression(arg0); + } + + @Override + public GreaterThan withOldOracleJoinSyntax(int arg0) { + return (GreaterThan) super.withOldOracleJoinSyntax(arg0); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public GreaterThan withOraclePriorPosition(int arg0) { + return (GreaterThan) super.withOraclePriorPosition(arg0); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThanEquals.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThanEquals.java index ad30668b2..39d1c8c97 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThanEquals.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/GreaterThanEquals.java @@ -1,26 +1,15 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class GreaterThanEquals extends ComparisonOperator { @@ -33,8 +22,32 @@ public GreaterThanEquals(String operator) { super(operator); } + public GreaterThanEquals(Expression leftExpression, Expression rightExpression) { + super(">=", leftExpression, rightExpression); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public GreaterThanEquals withLeftExpression(Expression arg0) { + return (GreaterThanEquals) super.withLeftExpression(arg0); + } + + @Override + public GreaterThanEquals withRightExpression(Expression arg0) { + return (GreaterThanEquals) super.withRightExpression(arg0); + } + + @Override + public GreaterThanEquals withOldOracleJoinSyntax(int arg0) { + return (GreaterThanEquals) super.withOldOracleJoinSyntax(arg0); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public GreaterThanEquals withOraclePriorPosition(int arg0) { + return (GreaterThanEquals) super.withOraclePriorPosition(arg0); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java index 06277a979..743d8a0aa 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/InExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; @@ -25,50 +13,57 @@ import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -public class InExpression extends ASTNodeAccessImpl implements Expression, SupportsOldOracleJoinSyntax { +public class InExpression extends ASTNodeAccessImpl + implements Expression, SupportsOldOracleJoinSyntax { private Expression leftExpression; - private ItemsList leftItemsList; - private ItemsList rightItemsList; + private boolean global = false; private boolean not = false; - + private Expression rightExpression; private int oldOracleJoinSyntax = NO_ORACLE_JOIN; - public InExpression() { + public InExpression() {} + + public InExpression(Expression leftExpression, Expression rightExpression) { + this.leftExpression = leftExpression; + this.rightExpression = rightExpression; } - public InExpression(Expression leftExpression, ItemsList itemsList) { - setLeftExpression(leftExpression); - setRightItemsList(itemsList); + @Override + public int getOldOracleJoinSyntax() { + return oldOracleJoinSyntax; } @Override public void setOldOracleJoinSyntax(int oldOracleJoinSyntax) { this.oldOracleJoinSyntax = oldOracleJoinSyntax; if (oldOracleJoinSyntax < 0 || oldOracleJoinSyntax > 1) { - throw new IllegalArgumentException("unexpected join type for oracle found with IN (type=" + oldOracleJoinSyntax + ")"); + throw new IllegalArgumentException( + "unexpected join type for oracle found with IN (type=" + oldOracleJoinSyntax + + ")"); } } - @Override - public int getOldOracleJoinSyntax() { - return oldOracleJoinSyntax; + public Expression getLeftExpression() { + return leftExpression; } - public ItemsList getRightItemsList() { - return rightItemsList; + public final void setLeftExpression(Expression expression) { + leftExpression = expression; } - public Expression getLeftExpression() { - return leftExpression; + public InExpression withLeftExpression(Expression expression) { + this.setLeftExpression(expression); + return this; } - public final void setRightItemsList(ItemsList list) { - rightItemsList = list; + public boolean isGlobal() { + return global; } - public final void setLeftExpression(Expression expression) { - leftExpression = expression; + public InExpression setGlobal(boolean b) { + global = b; + return this; } public boolean isNot() { @@ -79,17 +74,17 @@ public void setNot(boolean b) { not = b; } - public ItemsList getLeftItemsList() { - return leftItemsList; + public Expression getRightExpression() { + return rightExpression; } - public void setLeftItemsList(ItemsList leftItemsList) { - this.leftItemsList = leftItemsList; + public void setRightExpression(Expression rightExpression) { + this.rightExpression = rightExpression; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } private String getLeftExpressionString() { @@ -98,7 +93,19 @@ private String getLeftExpressionString() { @Override public String toString() { - return (leftExpression == null ? leftItemsList : getLeftExpressionString()) + " " + (not ? "NOT " : "") + "IN " + rightItemsList + ""; + StringBuilder statementBuilder = new StringBuilder(); + statementBuilder.append(getLeftExpressionString()); + + statementBuilder.append(" "); + if (global) { + statementBuilder.append("GLOBAL "); + } + if (not) { + statementBuilder.append("NOT "); + } + statementBuilder.append("IN "); + statementBuilder.append(rightExpression); + return statementBuilder.toString(); } @Override @@ -112,4 +119,39 @@ public void setOraclePriorPosition(int priorPosition) { throw new IllegalArgumentException("unexpected prior for oracle found"); } } + + public InExpression withRightExpression(Expression rightExpression) { + this.setRightExpression(rightExpression); + return this; + } + + @Override + public InExpression withOldOracleJoinSyntax(int oldOracleJoinSyntax) { + this.setOldOracleJoinSyntax(oldOracleJoinSyntax); + return this; + } + + @Override + public InExpression withOraclePriorPosition(int priorPosition) { + this.setOraclePriorPosition(priorPosition); + return this; + } + + public InExpression withGlobal(boolean global) { + this.setGlobal(global); + return this; + } + + public InExpression withNot(boolean not) { + this.setNot(not); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } + + public E getRightExpression(Class type) { + return type.cast(getRightExpression()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IncludesExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IncludesExpression.java new file mode 100644 index 000000000..b0b260e72 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IncludesExpression.java @@ -0,0 +1,79 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class IncludesExpression extends ASTNodeAccessImpl + implements Expression { + + private Expression leftExpression; + private Expression rightExpression; + + public IncludesExpression() {} + + public IncludesExpression(Expression leftExpression, Expression rightExpression) { + this.leftExpression = leftExpression; + this.rightExpression = rightExpression; + } + + public Expression getLeftExpression() { + return leftExpression; + } + + public final void setLeftExpression(Expression expression) { + leftExpression = expression; + } + + public IncludesExpression withLeftExpression(Expression expression) { + this.setLeftExpression(expression); + return this; + } + + public Expression getRightExpression() { + return rightExpression; + } + + public void setRightExpression(Expression rightExpression) { + this.rightExpression = rightExpression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + StringBuilder statementBuilder = new StringBuilder(); + statementBuilder.append(leftExpression); + + statementBuilder.append(" "); + statementBuilder.append("INCLUDES "); + + statementBuilder.append(rightExpression); + return statementBuilder.toString(); + } + + public IncludesExpression withRightExpression(Expression rightExpression) { + this.setRightExpression(rightExpression); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } + + public E getRightExpression(Class type) { + return type.cast(getRightExpression()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsBooleanExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsBooleanExpression.java new file mode 100644 index 000000000..3c8336533 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsBooleanExpression.java @@ -0,0 +1,78 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class IsBooleanExpression extends ASTNodeAccessImpl implements Expression { + + private Expression leftExpression; + private boolean not = false; + private boolean isTrue = false; + + public Expression getLeftExpression() { + return leftExpression; + } + + public void setLeftExpression(Expression expression) { + leftExpression = expression; + } + + public boolean isNot() { + return not; + } + + public void setNot(boolean b) { + not = b; + } + + public boolean isTrue() { + return isTrue; + } + + public void setIsTrue(boolean isTrue) { + this.isTrue = isTrue; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + if (isTrue()) { + return leftExpression + " IS" + (not ? " NOT" : "") + " TRUE"; + } else { + return leftExpression + " IS" + (not ? " NOT" : "") + " FALSE"; + } + } + + public IsBooleanExpression withIsTrue(boolean isTrue) { + this.setIsTrue(isTrue); + return this; + } + + public IsBooleanExpression withLeftExpression(Expression leftExpression) { + this.setLeftExpression(leftExpression); + return this; + } + + public IsBooleanExpression withNot(boolean not) { + this.setNot(not); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsDistinctExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsDistinctExpression.java new file mode 100644 index 000000000..60add6b6e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsDistinctExpression.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class IsDistinctExpression extends BinaryExpression { + + private boolean not = false; + + public boolean isNot() { + return not; + } + + public void setNot(boolean b) { + not = b; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String getStringExpression() { + return " IS " + (isNot() ? "NOT " : "") + "DISTINCT FROM "; + } + + @Override + public String toString() { + String retval = getLeftExpression() + getStringExpression() + getRightExpression(); + return retval; + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpression.java index a45df7a1b..393f9f194 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsNullExpression.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; @@ -24,25 +12,38 @@ import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.schema.Column; public class IsNullExpression extends ASTNodeAccessImpl implements Expression { private Expression leftExpression; private boolean not = false; private boolean useIsNull = false; + private boolean useNotNull = false; - public Expression getLeftExpression() { - return leftExpression; + public IsNullExpression() {} + + public IsNullExpression(Expression leftExpression) { + this.leftExpression = leftExpression; } - public boolean isNot() { - return not; + public IsNullExpression(String columnName, boolean not) { + this.leftExpression = new Column(columnName); + this.not = not; + } + + public Expression getLeftExpression() { + return leftExpression; } public void setLeftExpression(Expression expression) { leftExpression = expression; } + public boolean isNot() { + return not; + } + public void setNot(boolean b) { not = b; } @@ -55,17 +56,47 @@ public void setUseIsNull(boolean useIsNull) { this.useIsNull = useIsNull; } + public boolean isUseNotNull() { + return useNotNull; + } + + public IsNullExpression setUseNotNull(boolean useNotNull) { + this.useNotNull = useNotNull; + return this; + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - if (isUseIsNull()) { + if (useNotNull) { + return leftExpression + " NOTNULL"; + } else if (useIsNull) { return leftExpression + (not ? " NOT" : "") + " ISNULL"; } else { return leftExpression + " IS " + (not ? "NOT " : "") + "NULL"; } } + + public IsNullExpression withUseIsNull(boolean useIsNull) { + this.setUseIsNull(useIsNull); + return this; + } + + public IsNullExpression withLeftExpression(Expression leftExpression) { + this.setLeftExpression(leftExpression); + return this; + } + + public IsNullExpression withNot(boolean not) { + this.setNot(not); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpression.java new file mode 100644 index 000000000..506d6e246 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/IsUnknownExpression.java @@ -0,0 +1,60 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class IsUnknownExpression extends ASTNodeAccessImpl implements Expression { + + private Expression leftExpression; + private boolean isNot = false; + + public Expression getLeftExpression() { + return leftExpression; + } + + public void setLeftExpression(Expression expression) { + leftExpression = expression; + } + + public boolean isNot() { + return isNot; + } + + public void setNot(boolean isNot) { + this.isNot = isNot; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return leftExpression + " IS" + (isNot ? " NOT" : "") + " UNKNOWN"; + } + + public IsUnknownExpression withLeftExpression(Expression leftExpression) { + this.setLeftExpression(leftExpression); + return this; + } + + public IsUnknownExpression withNot(boolean isNot) { + this.setNot(isNot); + return this; + } + + public E getLeftExpression(Class type) { + return type.cast(getLeftExpression()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsList.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsList.java deleted file mode 100644 index 655d5f902..000000000 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsList.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2013 JSQLParser - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -package net.sf.jsqlparser.expression.operators.relational; - -/** - * Values of an "INSERT" statement (for example a SELECT or a list of expressions) - */ -public interface ItemsList { - - void accept(ItemsListVisitor itemsListVisitor); -} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsListVisitor.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsListVisitor.java deleted file mode 100644 index 3c630c21f..000000000 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsListVisitor.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2013 JSQLParser - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -package net.sf.jsqlparser.expression.operators.relational; - -import net.sf.jsqlparser.statement.select.SubSelect; - -public interface ItemsListVisitor { - - void visit(SubSelect subSelect); - - void visit(ExpressionList expressionList); - - void visit(MultiExpressionList multiExprList); -} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsListVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsListVisitorAdapter.java deleted file mode 100644 index ff2cf1cc7..000000000 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ItemsListVisitorAdapter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2013 JSQLParser - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -package net.sf.jsqlparser.expression.operators.relational; - -import net.sf.jsqlparser.statement.select.SubSelect; - -public class ItemsListVisitorAdapter implements ItemsListVisitor { - - @Override - public void visit(SubSelect subSelect) { - - } - - @Override - public void visit(ExpressionList expressionList) { - - } - - @Override - public void visit(MultiExpressionList multiExprList) { - for (ExpressionList list : multiExprList.getExprList()) { - visit(list); - } - } -} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/JsonOperator.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/JsonOperator.java index 997961250..94237e8f6 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/JsonOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/JsonOperator.java @@ -1,44 +1,43 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class JsonOperator extends BinaryExpression { - private String op; //"@>" + private String op; // "@>" public JsonOperator(String op) { this.op = op; } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return op; } + + @Override + public JsonOperator withLeftExpression(Expression arg0) { + return (JsonOperator) super.withLeftExpression(arg0); + } + + @Override + public JsonOperator withRightExpression(Expression arg0) { + return (JsonOperator) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java index 23f70196e..f450de1c1 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/LikeExpression.java @@ -1,36 +1,24 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class LikeExpression extends BinaryExpression { - private boolean not = false; - private String escape = null; - private boolean caseInsensitive = false; + private boolean useBinary = false; + private Expression escapeExpression = null; + private KeyWord likeKeyWord = KeyWord.LIKE; - @Override public boolean isNot() { return not; } @@ -39,39 +27,100 @@ public void setNot(boolean b) { not = b; } + public boolean isUseBinary() { + return useBinary; + } + + public LikeExpression setUseBinary(boolean useBinary) { + this.useBinary = useBinary; + return this; + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } + @Deprecated @Override public String getStringExpression() { - return (not ? "NOT " : "") + (caseInsensitive ? "ILIKE" : "LIKE"); + return likeKeyWord.toString(); } @Override public String toString() { - String retval = super.toString(); - if (escape != null) { - retval += " ESCAPE " + "'" + escape + "'"; + String retval = getLeftExpression() + " " + (not ? "NOT " : "") + + (likeKeyWord == KeyWord.SIMILAR_TO ? "SIMILAR TO" : likeKeyWord) + " " + + (useBinary ? "BINARY " : "") + getRightExpression(); + if (escapeExpression != null) { + retval += " ESCAPE " + escapeExpression; } - return retval; } - public String getEscape() { - return escape; + public Expression getEscape() { + return escapeExpression; } - public void setEscape(String escape) { - this.escape = escape; + public void setEscape(Expression escapeExpression) { + this.escapeExpression = escapeExpression; } + @Deprecated public boolean isCaseInsensitive() { - return caseInsensitive; + return likeKeyWord == KeyWord.ILIKE; } + @Deprecated public void setCaseInsensitive(boolean caseInsensitive) { - this.caseInsensitive = caseInsensitive; + this.likeKeyWord = KeyWord.ILIKE; + } + + public KeyWord getLikeKeyWord() { + return likeKeyWord; + } + + public LikeExpression setLikeKeyWord(KeyWord likeKeyWord) { + this.likeKeyWord = likeKeyWord; + return this; + } + + public LikeExpression setLikeKeyWord(String likeKeyWord) { + this.likeKeyWord = KeyWord.from(likeKeyWord); + return this; + } + + public LikeExpression withEscape(Expression escape) { + this.setEscape(escape); + return this; + } + + @Deprecated + public LikeExpression withCaseInsensitive(boolean caseInsensitive) { + this.setCaseInsensitive(caseInsensitive); + return this; + } + + public LikeExpression withNot(boolean not) { + this.setNot(not); + return this; + } + + @Override + public LikeExpression withLeftExpression(Expression arg0) { + return (LikeExpression) super.withLeftExpression(arg0); + } + + @Override + public LikeExpression withRightExpression(Expression arg0) { + return (LikeExpression) super.withRightExpression(arg0); + } + + public enum KeyWord { + LIKE, ILIKE, RLIKE, REGEXP_LIKE, REGEXP, SIMILAR_TO, MATCH_ANY, MATCH_ALL, MATCH_PHRASE, MATCH_PHRASE_PREFIX, MATCH_REGEXP; + + public static KeyWord from(String keyword) { + return Enum.valueOf(KeyWord.class, keyword.toUpperCase().replaceAll("\\s+", "_")); + } } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Matches.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Matches.java index 2da8a0fdc..1388fa51f 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Matches.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Matches.java @@ -1,37 +1,46 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class Matches extends OldOracleJoinBinaryExpression { @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String getStringExpression() { return "@@"; } + + @Override + public Matches withLeftExpression(Expression arg0) { + return (Matches) super.withLeftExpression(arg0); + } + + @Override + public Matches withRightExpression(Expression arg0) { + return (Matches) super.withRightExpression(arg0); + } + + @Override + public Matches withOldOracleJoinSyntax(int oldOracleJoinSyntax) { + return (Matches) super.withOldOracleJoinSyntax(oldOracleJoinSyntax); + } + + @Override + public Matches withOraclePriorPosition(int oraclePriorPosition) { + return (Matches) super.withOraclePriorPosition(oraclePriorPosition); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MemberOfExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MemberOfExpression.java new file mode 100644 index 000000000..d602e6278 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MemberOfExpression.java @@ -0,0 +1,63 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public class MemberOfExpression extends ASTNodeAccessImpl implements Expression { + + Expression leftExpression; + Expression rightExpression; + boolean isNot; + + public MemberOfExpression(Expression leftExpression, Expression rightExpression) { + this.leftExpression = leftExpression; + this.rightExpression = rightExpression; + } + + public Expression getLeftExpression() { + return leftExpression; + } + + public MemberOfExpression setLeftExpression(Expression leftExpression) { + this.leftExpression = leftExpression; + return this; + } + + public Expression getRightExpression() { + return rightExpression; + } + + public MemberOfExpression setRightExpression(Expression rightExpression) { + this.rightExpression = rightExpression; + return this; + } + + public boolean isNot() { + return isNot; + } + + public MemberOfExpression setNot(boolean not) { + isNot = not; + return this; + } + + @Override + public String toString() { + return leftExpression + " MEMBER OF " + rightExpression; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThan.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThan.java index 950733ad1..3f6ddd267 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThan.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThan.java @@ -1,26 +1,15 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class MinorThan extends ComparisonOperator { @@ -29,8 +18,32 @@ public MinorThan() { super("<"); } + public MinorThan(Expression leftExpression, Expression rightExpression) { + super("<", leftExpression, rightExpression); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public MinorThan withLeftExpression(Expression arg0) { + return (MinorThan) super.withLeftExpression(arg0); + } + + @Override + public MinorThan withRightExpression(Expression arg0) { + return (MinorThan) super.withRightExpression(arg0); + } + + @Override + public MinorThan withOldOracleJoinSyntax(int arg0) { + return (MinorThan) super.withOldOracleJoinSyntax(arg0); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public MinorThan withOraclePriorPosition(int arg0) { + return (MinorThan) super.withOraclePriorPosition(arg0); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThanEquals.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThanEquals.java index 39dd64766..5318a0d27 100755 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThanEquals.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MinorThanEquals.java @@ -1,26 +1,15 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class MinorThanEquals extends ComparisonOperator { @@ -33,8 +22,32 @@ public MinorThanEquals(String operator) { super(operator); } + public MinorThanEquals(Expression leftExpression, Expression rightExpression) { + super("<=", leftExpression, rightExpression); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public MinorThanEquals withLeftExpression(Expression arg0) { + return (MinorThanEquals) super.withLeftExpression(arg0); + } + + @Override + public MinorThanEquals withRightExpression(Expression arg0) { + return (MinorThanEquals) super.withRightExpression(arg0); + } + + @Override + public MinorThanEquals withOldOracleJoinSyntax(int arg0) { + return (MinorThanEquals) super.withOldOracleJoinSyntax(arg0); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public MinorThanEquals withOraclePriorPosition(int arg0) { + return (MinorThanEquals) super.withOraclePriorPosition(arg0); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MultiExpressionList.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/MultiExpressionList.java deleted file mode 100644 index 0ff7f477b..000000000 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/MultiExpressionList.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2013 JSQLParser - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -package net.sf.jsqlparser.expression.operators.relational; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import net.sf.jsqlparser.expression.Expression; - -/** - * A list of ExpressionList items. e.g. multi values of insert statements. This one allows only - * equally sized ExpressionList. - * - * @author toben - */ -public class MultiExpressionList implements ItemsList { - - private List exprList; - - public MultiExpressionList() { - this.exprList = new ArrayList(); - } - - @Override - public void accept(ItemsListVisitor itemsListVisitor) { - itemsListVisitor.visit(this); - } - - public List getExprList() { - return exprList; - } - - public void addExpressionList(ExpressionList el) { - if (!exprList.isEmpty() - && exprList.get(0).getExpressions().size() != el.getExpressions().size()) { - throw new IllegalArgumentException("different count of parameters"); - } - exprList.add(el); - } - - public void addExpressionList(List list) { - addExpressionList(new ExpressionList(list)); - } - - public void addExpressionList(Expression expr) { - addExpressionList(new ExpressionList(Arrays.asList(expr))); - } - - @Override - public String toString() { - StringBuilder b = new StringBuilder(); - for (Iterator it = exprList.iterator(); it.hasNext();) { - b.append(it.next().toString()); - if (it.hasNext()) { - b.append(", "); - } - } - return b.toString(); - } -} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/NamedExpressionList.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/NamedExpressionList.java new file mode 100644 index 000000000..e7473cf0d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/NamedExpressionList.java @@ -0,0 +1,70 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.Expression; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +/** + * A list of named expressions, as in as in select substr('xyzzy' from 2 for 3) + */ +public class NamedExpressionList extends ExpressionList { + private List names; + + public List getNames() { + return names; + } + + public void setNames(List list) { + names = list; + } + + @Override + public String toString() { + + StringBuilder ret = new StringBuilder(); + ret.append("("); + for (int i = 0; i < size(); i++) { + if (i > 0) { + ret.append(" "); + } + if (!names.get(i).equals("")) { + ret.append(names.get(i)).append(" ").append(get(i)); + } else { + ret.append(get(i)); + } + } + ret.append(")"); + + return ret.toString(); + } + + public NamedExpressionList withNames(List names) { + this.setNames(names); + return this; + } + + public NamedExpressionList addNames(String... names) { + List collection = Optional.ofNullable(getNames()).orElseGet(ArrayList::new); + Collections.addAll(collection, names); + return this.withNames(collection); + } + + public NamedExpressionList addNames(Collection names) { + List collection = Optional.ofNullable(getNames()).orElseGet(ArrayList::new); + collection.addAll(names); + return this.withNames(collection); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/NotEqualsTo.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/NotEqualsTo.java index 3ff92d3f5..c6e1ef3cb 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/NotEqualsTo.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/NotEqualsTo.java @@ -1,26 +1,15 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class NotEqualsTo extends ComparisonOperator { @@ -33,8 +22,34 @@ public NotEqualsTo(String operator) { super(operator); } + public NotEqualsTo(Expression left, Expression right) { + this(); + setLeftExpression(left); + setRightExpression(right); + } + + @Override + public NotEqualsTo withLeftExpression(Expression expression) { + return (NotEqualsTo) super.withLeftExpression(expression); + } + + @Override + public NotEqualsTo withRightExpression(Expression expression) { + return (NotEqualsTo) super.withRightExpression(expression); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public NotEqualsTo withOldOracleJoinSyntax(int arg0) { + return (NotEqualsTo) super.withOldOracleJoinSyntax(arg0); + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public NotEqualsTo withOraclePriorPosition(int arg0) { + return (NotEqualsTo) super.withOraclePriorPosition(arg0); } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/OldOracleJoinBinaryExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/OldOracleJoinBinaryExpression.java index c620a62e9..46b093b7d 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/OldOracleJoinBinaryExpression.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/OldOracleJoinBinaryExpression.java @@ -1,47 +1,28 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; import net.sf.jsqlparser.expression.BinaryExpression; -import static net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax.ORACLE_PRIOR_START; +import net.sf.jsqlparser.expression.Expression; -public abstract class OldOracleJoinBinaryExpression extends BinaryExpression implements SupportsOldOracleJoinSyntax { +public abstract class OldOracleJoinBinaryExpression extends BinaryExpression + implements SupportsOldOracleJoinSyntax { private int oldOracleJoinSyntax = NO_ORACLE_JOIN; private int oraclePriorPosition = NO_ORACLE_PRIOR; - @Override - public void setOldOracleJoinSyntax(int oldOracleJoinSyntax) { - this.oldOracleJoinSyntax = oldOracleJoinSyntax; - if (oldOracleJoinSyntax < 0 || oldOracleJoinSyntax > 2) { - throw new IllegalArgumentException("unknown join type for oracle found (type=" + oldOracleJoinSyntax + ")"); - } - } - @Override public String toString() { - return (isNot() ? "NOT " : "") - + (oraclePriorPosition == ORACLE_PRIOR_START ? "PRIOR " : "") + return // (isNot() ? "NOT " : "") + (oraclePriorPosition == ORACLE_PRIOR_START ? "PRIOR " : "") + getLeftExpression() + (oldOracleJoinSyntax == ORACLE_JOIN_RIGHT ? "(+)" : "") + " " + getStringExpression() + " " @@ -55,6 +36,15 @@ public int getOldOracleJoinSyntax() { return oldOracleJoinSyntax; } + @Override + public void setOldOracleJoinSyntax(int oldOracleJoinSyntax) { + this.oldOracleJoinSyntax = oldOracleJoinSyntax; + if (oldOracleJoinSyntax < 0 || oldOracleJoinSyntax > 2) { + throw new IllegalArgumentException( + "unknown join type for oracle found (type=" + oldOracleJoinSyntax + ")"); + } + } + @Override public int getOraclePriorPosition() { return oraclePriorPosition; @@ -64,4 +54,24 @@ public int getOraclePriorPosition() { public void setOraclePriorPosition(int oraclePriorPosition) { this.oraclePriorPosition = oraclePriorPosition; } + + public OldOracleJoinBinaryExpression withOldOracleJoinSyntax(int oldOracleJoinSyntax) { + this.setOldOracleJoinSyntax(oldOracleJoinSyntax); + return this; + } + + public OldOracleJoinBinaryExpression withOraclePriorPosition(int oraclePriorPosition) { + this.setOraclePriorPosition(oraclePriorPosition); + return this; + } + + @Override + public OldOracleJoinBinaryExpression withLeftExpression(Expression arg0) { + return (OldOracleJoinBinaryExpression) super.withLeftExpression(arg0); + } + + @Override + public OldOracleJoinBinaryExpression withRightExpression(Expression arg0) { + return (OldOracleJoinBinaryExpression) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/ParenthesedExpressionList.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ParenthesedExpressionList.java new file mode 100644 index 000000000..dc71ea6ad --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/ParenthesedExpressionList.java @@ -0,0 +1,42 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2023 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.select.PlainSelect; + +import java.util.Arrays; +import java.util.Collection; + +public class ParenthesedExpressionList extends ExpressionList { + public ParenthesedExpressionList() {} + + public ParenthesedExpressionList(ExpressionList expressions) { + addAll(expressions); + } + + @SafeVarargs + public ParenthesedExpressionList(T... expressions) { + addAll(Arrays.asList(expressions)); + } + + public ParenthesedExpressionList(Collection expressions) { + addAll(expressions); + } + + public static ParenthesedExpressionList from(ExpressionList expressions) { + return new ParenthesedExpressionList<>(expressions); + } + + @Override + public String toString() { + return PlainSelect.getStringList(this, true, true); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/Plus.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Plus.java new file mode 100644 index 000000000..e3362d950 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/Plus.java @@ -0,0 +1,30 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class Plus extends BinaryExpression { + public Plus(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + + @Override + public String getStringExpression() { + return "PLUS"; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/PriorTo.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/PriorTo.java new file mode 100644 index 000000000..267f158fd --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/PriorTo.java @@ -0,0 +1,30 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class PriorTo extends BinaryExpression { + public PriorTo(Expression leftExpression, Expression rightExpression) { + super(leftExpression, rightExpression); + } + + @Override + public String getStringExpression() { + return "PRIOR TO"; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperator.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperator.java index 27f0fff32..786f60407 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperator.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperator.java @@ -1,27 +1,18 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; +import java.util.Objects; + import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; public class RegExpMatchOperator extends BinaryExpression { @@ -29,10 +20,8 @@ public class RegExpMatchOperator extends BinaryExpression { private RegExpMatchOperatorType operatorType; public RegExpMatchOperator(RegExpMatchOperatorType operatorType) { - if (operatorType == null) { - throw new NullPointerException(); - } - this.operatorType = operatorType; + this.operatorType = Objects.requireNonNull(operatorType, + "The provided RegExpMatchOperatorType must not be NULL."); } public RegExpMatchOperatorType getOperatorType() { @@ -40,8 +29,8 @@ public RegExpMatchOperatorType getOperatorType() { } @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override @@ -60,4 +49,14 @@ public String getStringExpression() { } return null; } + + @Override + public RegExpMatchOperator withLeftExpression(Expression arg0) { + return (RegExpMatchOperator) super.withLeftExpression(arg0); + } + + @Override + public RegExpMatchOperator withRightExpression(Expression arg0) { + return (RegExpMatchOperator) super.withRightExpression(arg0); + } } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperatorType.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperatorType.java index 764ce845a..c22f05eee 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperatorType.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMatchOperatorType.java @@ -1,34 +1,17 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2014 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; /** * PostgresSQL match operators. - * - * @author toben */ public enum RegExpMatchOperatorType { - MATCH_CASESENSITIVE, - MATCH_CASEINSENSITIVE, - NOT_MATCH_CASESENSITIVE, - NOT_MATCH_CASEINSENSITIVE + MATCH_CASESENSITIVE, MATCH_CASEINSENSITIVE, NOT_MATCH_CASESENSITIVE, NOT_MATCH_CASEINSENSITIVE } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMySQLOperator.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMySQLOperator.java deleted file mode 100644 index 4ebe454fb..000000000 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/RegExpMySQLOperator.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2014 JSQLParser - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -package net.sf.jsqlparser.expression.operators.relational; - -import net.sf.jsqlparser.expression.BinaryExpression; -import net.sf.jsqlparser.expression.ExpressionVisitor; - -public class RegExpMySQLOperator extends BinaryExpression { - - private RegExpMatchOperatorType operatorType; - private boolean useRLike = false; - - public RegExpMySQLOperator(RegExpMatchOperatorType operatorType) { - if (operatorType == null) { - throw new NullPointerException(); - } - this.operatorType = operatorType; - } - - public RegExpMatchOperatorType getOperatorType() { - return operatorType; - } - - public boolean isUseRLike() { - return useRLike; - } - - public RegExpMySQLOperator useRLike() { - useRLike = true; - return this; - } - - @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); - } - - @Override - public String getStringExpression() { - return (useRLike ? "RLIKE" : "REGEXP") - + (operatorType == RegExpMatchOperatorType.MATCH_CASESENSITIVE ? " BINARY" : ""); - } -} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/SimilarToExpression.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/SimilarToExpression.java new file mode 100644 index 000000000..0818d75c0 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/SimilarToExpression.java @@ -0,0 +1,77 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class SimilarToExpression extends BinaryExpression { + + private boolean not = false; + private String escape = null; + + public boolean isNot() { + return not; + } + + public void setNot(boolean b) { + not = b; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String getStringExpression() { + return "SIMILAR TO"; + } + + @Override + public String toString() { + String retval = getLeftExpression() + " " + (not ? "NOT " : "") + getStringExpression() + + " " + getRightExpression(); + if (escape != null) { + retval += " ESCAPE " + "'" + escape + "'"; + } + + return retval; + } + + public String getEscape() { + return escape; + } + + public void setEscape(String escape) { + this.escape = escape; + } + + public SimilarToExpression withEscape(String escape) { + this.setEscape(escape); + return this; + } + + public SimilarToExpression withNot(boolean not) { + this.setNot(not); + return this; + } + + @Override + public SimilarToExpression withLeftExpression(Expression arg0) { + return (SimilarToExpression) super.withLeftExpression(arg0); + } + + @Override + public SimilarToExpression withRightExpression(Expression arg0) { + return (SimilarToExpression) super.withRightExpression(arg0); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/SupportsOldOracleJoinSyntax.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/SupportsOldOracleJoinSyntax.java index 970bb2ef6..9b8777dcc 100644 --- a/src/main/java/net/sf/jsqlparser/expression/operators/relational/SupportsOldOracleJoinSyntax.java +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/SupportsOldOracleJoinSyntax.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.expression.operators.relational; @@ -34,7 +22,11 @@ public interface SupportsOldOracleJoinSyntax { void setOldOracleJoinSyntax(int oldOracleJoinSyntax); + SupportsOldOracleJoinSyntax withOldOracleJoinSyntax(int oldOracleJoinSyntax); + int getOraclePriorPosition(); void setOraclePriorPosition(int priorPosition); + + SupportsOldOracleJoinSyntax withOraclePriorPosition(int priorPosition); } diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLLeftJoin.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLLeftJoin.java new file mode 100644 index 000000000..aa1b90e16 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLLeftJoin.java @@ -0,0 +1,24 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class TSQLLeftJoin extends ComparisonOperator { + + public TSQLLeftJoin() { + super("*="); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLRightJoin.java b/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLRightJoin.java new file mode 100644 index 000000000..fcb3e9dc4 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/operators/relational/TSQLRightJoin.java @@ -0,0 +1,24 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression.operators.relational; + +import net.sf.jsqlparser.expression.ExpressionVisitor; + +public class TSQLRightJoin extends ComparisonOperator { + + public TSQLRightJoin() { + super("=*"); + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java index 2d540d39a..53eb89bb7 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java +++ b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccess.java @@ -1,51 +1,19 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2015 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ - /* - * Copyright (C) 2015 JSQLParser. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ package net.sf.jsqlparser.parser; -/** - * - * @author toben - */ -public interface ASTNodeAccess { +import java.io.Serializable; + +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 2ade908e5..6ef61996b 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java +++ b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java @@ -1,42 +1,73 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2015 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.parser; -/** - * - * @author toben - */ +import java.util.Set; +import java.util.TreeSet; + public class ASTNodeAccessImpl implements ASTNodeAccess { - private 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; } + public StringBuilder appendTo(StringBuilder builder) { + // don't add spaces around the following punctuation + final Set punctuation = new TreeSet<>(Set.of(".", "[", "]")); + + 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) + && (prevToken == null || !punctuation.contains(prevToken.image))) { + builder.append(" "); + } + builder.append(token.image); + prevToken = token; + token = token.next; + } + } + return builder; + } + + public ASTNodeAccess getParent() { + Node parent = (Node) node.jjtGetParent(); + while (parent.jjtGetValue() == null) { + parent = (Node) parent.jjtGetParent(); + } + + return ASTNodeAccess.class.cast(parent.jjtGetValue()); + } + + public T getParent(Class clazz) { + Node parent = (Node) node.jjtGetParent(); + while (parent.jjtGetValue() == null || !clazz.isInstance(parent.jjtGetValue())) { + parent = (Node) parent.jjtGetParent(); + } + + return clazz.cast(parent.jjtGetValue()); + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } } diff --git a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java new file mode 100644 index 000000000..45580cb5e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java @@ -0,0 +1,152 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.parser; + +import net.sf.jsqlparser.parser.feature.Feature; +import net.sf.jsqlparser.parser.feature.FeatureConfiguration; + +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractJSqlParser

{ + + protected int jdbcParameterIndex = 0; + protected boolean errorRecovery = false; + protected List parseErrors = new ArrayList<>(); + + public enum Dialect { + ORACLE, EXASOL + } + + public P withSquareBracketQuotation() { + return withFeature(Feature.allowSquareBracketQuotation, true); + } + + public P withSquareBracketQuotation(boolean allowSquareBracketQuotation) { + return withFeature(Feature.allowSquareBracketQuotation, allowSquareBracketQuotation); + } + + public P withAllowComplexParsing() { + return withFeature(Feature.allowComplexParsing, true); + } + + public P withAllowComplexParsing(boolean allowComplexParsing) { + return withFeature(Feature.allowComplexParsing, allowComplexParsing); + } + + public P withComplexParsing() { + return withFeature(Feature.allowComplexParsing, true); + } + + public P withComplexParsing(boolean allowComplexParsing) { + return withFeature(Feature.allowComplexParsing, allowComplexParsing); + } + + public P withUnsupportedStatements() { + return withFeature(Feature.allowUnsupportedStatements, true); + } + + public P withUnsupportedStatements(boolean allowUnsupportedStatements) { + return withFeature(Feature.allowUnsupportedStatements, allowUnsupportedStatements); + } + + 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); + } + + public P withBackslashEscapeCharacter(boolean allowBackslashEscapeCharacter) { + return withFeature(Feature.allowBackslashEscapeCharacter, allowBackslashEscapeCharacter); + } + + public P withUnparenthesizedSubSelects() { + return withFeature(Feature.allowUnparenthesizedSubSelects, true); + } + + public P withUnparenthesizedSubSelects(boolean allowUnparenthesizedSubSelects) { + return withFeature(Feature.allowUnparenthesizedSubSelects, allowUnparenthesizedSubSelects); + } + + public P withFeature(Feature f, boolean enabled) { + getConfiguration().setValue(f, enabled); + return me(); + } + + public P withFeature(Feature f, long value) { + getConfiguration().setValue(f, 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) { + return getConfiguration().getAsBoolean(f); + } + + 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; + } + + public P withErrorRecovery() { + this.errorRecovery = true; + return me(); + } + + public P withErrorRecovery(boolean errorRecovery) { + this.errorRecovery = errorRecovery; + return me(); + } + + public List getParseErrors() { + return parseErrors; + } +} diff --git a/src/main/java/net/sf/jsqlparser/parser/BaseToken.java b/src/main/java/net/sf/jsqlparser/parser/BaseToken.java index 68b9c63ca..6972f0a5c 100644 --- a/src/main/java/net/sf/jsqlparser/parser/BaseToken.java +++ b/src/main/java/net/sf/jsqlparser/parser/BaseToken.java @@ -1,49 +1,16 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2017 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ - /* - * Copyright (C) 2017 JSQLParser. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ package net.sf.jsqlparser.parser; -/** - * - * @author toben - */ public class BaseToken { + public int absoluteBegin = 0; public int absoluteEnd = 0; } diff --git a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserManager.java b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserManager.java index 4c122d157..fb0bf2115 100644 --- a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserManager.java +++ b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserManager.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.parser; @@ -26,9 +14,6 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.statement.Statement; -/** - * A JSqlParser implementation that uses a parser generated by JavaCC - */ public class CCJSqlParserManager implements JSqlParser { @Override diff --git a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java index a5f889421..bdb25eeb4 100644 --- a/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java +++ b/src/main/java/net/sf/jsqlparser/parser/CCJSqlParserUtil.java @@ -1,30 +1,33 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.parser; +import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.util.Stack; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; @@ -33,31 +36,123 @@ * * @author toben */ + +@SuppressWarnings("PMD.CyclomaticComplexity") public final class CCJSqlParserUtil { + public final static Logger LOGGER = Logger.getLogger(CCJSqlParserUtil.class.getName()); - private CCJSqlParserUtil() { + static { + LOGGER.setLevel(Level.OFF); } + private CCJSqlParserUtil() {} + public static Statement parse(Reader statementReader) throws JSQLParserException { + ExecutorService executorService = Executors.newSingleThreadExecutor(); + Statement statement; CCJSqlParser parser = new CCJSqlParser(new StreamProvider(statementReader)); try { - return parser.Statement(); - } catch (Exception ex) { - throw new JSQLParserException(ex); + statement = parseStatement(parser, executorService); + } finally { + executorService.shutdown(); } + return statement; } public static Statement parse(String sql) throws JSQLParserException { - CCJSqlParser parser = new CCJSqlParser(new StringProvider(sql)); + return parse(sql, null); + } + + /** + * Parses an sql statement while allowing via consumer to configure the used parser before. + *

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

+ * {@code + * CCJSqlParserUtil.parse("select * from [mytable]", parser -> parser.withSquareBracketQuotation(true)); + * } + * + * @param sql + * @param consumer + * @return + * @throws JSQLParserException + */ + public static Statement parse(String sql, Consumer consumer) + throws JSQLParserException { + + if (sql == null || sql.isEmpty()) { + return null; + } + + ExecutorService executorService = Executors.newSingleThreadExecutor(); + Statement statement; try { - return parser.Statement(); - } catch (Exception ex) { - throw new JSQLParserException(ex); + statement = parse(sql, executorService, consumer); + } finally { + executorService.shutdown(); + } + return statement; + } + + public static Statement parse(String sql, ExecutorService executorService, + Consumer consumer) + throws JSQLParserException { + if (sql == null || sql.isEmpty()) { + return null; + } + + Statement statement; + // first, try to parse fast and simple + CCJSqlParser parser = newParser(sql); + if (consumer != null) { + consumer.accept(parser); + } + 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 + && (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); + if (consumer != null) { + consumer.accept(parser); + } + statement = parseStatement(parser.withAllowComplexParsing(true), executorService); + } else { + throw ex; + } + } + return statement; + } + + public static CCJSqlParser newParser(String sql) { + if (sql == null || sql.isEmpty()) { + return null; } + + return new CCJSqlParser(new StringProvider(sql)); + } + + public static CCJSqlParser newParser(InputStream is) throws IOException { + return new CCJSqlParser(new StreamProvider(is)); + } + + public static CCJSqlParser newParser(InputStream is, String encoding) throws IOException { + return new CCJSqlParser(new StreamProvider(is, encoding)); } public static Node parseAST(String sql) throws JSQLParserException { - CCJSqlParser parser = new CCJSqlParser(new StringProvider(sql)); + if (sql == null || sql.isEmpty()) { + return null; + } + + CCJSqlParser parser = newParser(sql); try { parser.Statement(); return parser.jjtree.rootNode(); @@ -68,7 +163,7 @@ public static Node parseAST(String sql) throws JSQLParserException { public static Statement parse(InputStream is) throws JSQLParserException { try { - CCJSqlParser parser = new CCJSqlParser(new StreamProvider(is)); + CCJSqlParser parser = newParser(is); return parser.Statement(); } catch (Exception ex) { throw new JSQLParserException(ex); @@ -77,47 +172,89 @@ public static Statement parse(InputStream is) throws JSQLParserException { public static Statement parse(InputStream is, String encoding) throws JSQLParserException { try { - CCJSqlParser parser = new CCJSqlParser(new StreamProvider(is, encoding)); + CCJSqlParser parser = newParser(is, encoding); return parser.Statement(); } catch (Exception ex) { throw new JSQLParserException(ex); } } - /** - * Parse an expression. - * - * @param expression - * @return - * @throws JSQLParserException - */ public static Expression parseExpression(String expression) throws JSQLParserException { + if (expression == null || expression.isEmpty()) { + return null; + } + return parseExpression(expression, true); } - - public static Expression parseExpression(String expression, boolean allowPartialParse) throws JSQLParserException { - CCJSqlParser parser = new CCJSqlParser(new StringProvider(expression)); + + public static Expression parseExpression(String expression, boolean allowPartialParse) + throws JSQLParserException { + if (expression == null || expression.isEmpty()) { + return null; + } + + return parseExpression(expression, allowPartialParse, p -> { + }); + } + + @SuppressWarnings("PMD.CyclomaticComplexity") + public static Expression parseExpression(String expressionStr, boolean allowPartialParse, + Consumer consumer) throws JSQLParserException { + if (expressionStr == null || expressionStr.isEmpty()) { + return null; + } + + Expression expression = null; + // first, try to parse fast and simple try { - Expression expr = parser.SimpleExpression(); - if (!allowPartialParse && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { - throw new JSQLParserException("could only parse partial expression " + expr.toString()); + CCJSqlParser parser = newParser(expressionStr).withAllowComplexParsing(false); + if (consumer != null) { + consumer.accept(parser); + } + try { + expression = parser.Expression(); + if (parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { + throw new JSQLParserException( + "could only parse partial expression " + expression.toString()); + } + } catch (ParseException ex) { + throw new JSQLParserException(ex); + } + } catch (JSQLParserException ex1) { + // when fast simple parsing fails, try complex parsing but only if it has a chance to + // succeed + 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 expr; - } catch (JSQLParserException ex) { - throw ex; - } catch (ParseException ex) { - throw new JSQLParserException(ex); } + return expression; } /** - * Parse an conditional expression. This is the expression after a where clause. + * Parse an conditional expression. This is the expression after a where clause. Partial parsing + * is enabled. * * @param condExpr - * @return - * @throws JSQLParserException + * @return the expression parsed + * @see #parseCondExpression(String, boolean) */ public static Expression parseCondExpression(String condExpr) throws JSQLParserException { + if (condExpr == null || condExpr.isEmpty()) { + return null; + } return parseCondExpression(condExpr, true); } @@ -126,33 +263,279 @@ public static Expression parseCondExpression(String condExpr) throws JSQLParserE * * @param condExpr * @param allowPartialParse false: needs the whole string to be processed. - * @return + * @return the expression parsed + * @see #parseCondExpression(String) */ - public static Expression parseCondExpression(String condExpr, boolean allowPartialParse) throws JSQLParserException { - CCJSqlParser parser = new CCJSqlParser(new StringProvider(condExpr)); + public static Expression parseCondExpression(String condExpr, boolean allowPartialParse) + throws JSQLParserException { + if (condExpr == null || condExpr.isEmpty()) { + return null; + } + return parseCondExpression(condExpr, allowPartialParse, p -> { + }); + } + + @SuppressWarnings("PMD.CyclomaticComplexity") + public static Expression parseCondExpression(String conditionalExpressionStr, + boolean allowPartialParse, Consumer consumer) throws JSQLParserException { + if (conditionalExpressionStr == null || conditionalExpressionStr.isEmpty()) { + return null; + } + + Expression expression = null; + // first, try to parse fast and simple try { - Expression expr = parser.Expression(); - if (!allowPartialParse && parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { - throw new JSQLParserException("could only parse partial expression " + expr.toString()); + CCJSqlParser parser = + newParser(conditionalExpressionStr).withAllowComplexParsing(false); + if (consumer != null) { + consumer.accept(parser); } - return expr; - } catch (JSQLParserException ex) { - throw ex; - } catch (ParseException ex) { + try { + expression = parser.Expression(); + if (parser.getNextToken().kind != CCJSqlParserTokenManager.EOF) { + throw new JSQLParserException( + "could only parse partial expression " + expression.toString()); + } + } catch (ParseException ex) { + throw new JSQLParserException(ex); + } + } catch (JSQLParserException ex1) { + 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; + } + + /** + * @param parser the Parser armed with a Statement text + * @param executorService the Executor Service for parsing within a Thread + * @return the parsed Statement + * @throws JSQLParserException when either the Statement can't be parsed or the configured + * timeout is reached + */ + + public static Statement parseStatement(CCJSqlParser parser, ExecutorService executorService) + throws JSQLParserException { + Statement statement; + Future future = executorService.submit(new Callable() { + @Override + public Statement call() throws ParseException { + return parser.Statement(); + } + }); + try { + statement = future.get(parser.getAsLong(Feature.timeOut), + TimeUnit.MILLISECONDS); + } catch (TimeoutException ex) { + parser.interrupted = true; + future.cancel(true); + throw new JSQLParserException("Time out occurred.", ex); + } catch (Exception ex) { throw new JSQLParserException(ex); } + return statement; } /** * Parse a statement list. + * + * @return the statements parsed */ public static Statements parseStatements(String sqls) throws JSQLParserException { - CCJSqlParser parser = new CCJSqlParser(new StringProvider(sqls)); + if (sqls == null || sqls.isEmpty()) { + return null; + } + + return parseStatements(sqls, null); + } + + public static Statements parseStatements(String sqls, Consumer consumer) + throws JSQLParserException { + if (sqls == null || sqls.isEmpty()) { + return null; + } + + ExecutorService executorService = Executors.newSingleThreadExecutor(); + final Statements statements = parseStatements(sqls, executorService, consumer); + executorService.shutdown(); + + return statements; + } + + /** + * Parse a statement list. + * + * @return the statements parsed + */ + public static Statements parseStatements(String sqls, ExecutorService executorService, + Consumer consumer) + throws JSQLParserException { + if (sqls == null || sqls.isEmpty()) { + return null; + } + + Statements statements = null; + CCJSqlParser parser = newParser(sqls); + if (consumer != null) { + consumer.accept(parser); + } + boolean allowComplex = parser.getAsBoolean(Feature.allowComplexParsing); + int allowedNestingDepth = parser.getAsInt(Feature.allowedNestingDepth); + + // first, try to parse fast and simple + try { + statements = parseStatements(parser.withAllowComplexParsing(false), executorService); + } catch (JSQLParserException ex) { + // when fast simple parsing fails, try complex parsing but only if it has a chance to + // succeed + 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) { + consumer.accept(parser); + } + statements = parseStatements(parser.withAllowComplexParsing(true), executorService); + } + } + return statements; + } + + /** + * @param parser the Parser armed with a Statement text + * @param executorService the Executor Service for parsing within a Thread + * @return the Statements (representing a List of single statements) + * @throws JSQLParserException when either the Statement can't be parsed or the configured + * timeout is reached + */ + public static Statements parseStatements(CCJSqlParser parser, ExecutorService executorService) + throws JSQLParserException { + Statements statements = null; + Future future = executorService.submit(new Callable() { + @Override + public Statements call() throws ParseException { + return parser.Statements(); + } + }); try { - return parser.Statements(); + statements = future.get(parser.getAsLong(Feature.timeOut), + TimeUnit.MILLISECONDS); + } catch (TimeoutException ex) { + parser.interrupted = true; + future.cancel(true); + throw new JSQLParserException("Time out occurred.", ex); } catch (Exception ex) { throw new JSQLParserException(ex); } + return statements; + } + + public static void streamStatements(StatementListener listener, InputStream is, String encoding) + throws JSQLParserException { + try { + CCJSqlParser parser = newParser(is, encoding); + do { + Statement stmt = parser.SingleStatement(); + listener.accept(stmt); + if (parser.getToken(1).kind == CCJSqlParserTokenManager.ST_SEMICOLON) { + parser.getNextToken(); + } + + } while (parser.getToken(1).kind != CCJSqlParserTokenManager.EOF); + } catch (Exception ex) { + throw new JSQLParserException(ex); + } + } + + public static int getNestingDepth(String sql) { + int maxlevel = 0; + int level = 0; + + char[] chars = sql.toCharArray(); + for (char c : chars) { + switch (c) { + case '(': + level++; + break; + case ')': + if (maxlevel < level) { + maxlevel = level; + } + level--; + break; + default: + // Codazy/PMD insists in a Default statement + } + } + return maxlevel; + } + + public static int getUnbalancedPosition(String text) { + Stack stack = new Stack<>(); + boolean insideQuote = false; + + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (c == '"' || c == '\'') { + if (!insideQuote) { + stack.push(c); // Add quote to stack + } else if (stack.peek() == c) { + stack.pop(); // Matching quote found, remove from stack + } + insideQuote = !insideQuote; // Toggle insideQuote flag + } else if (!insideQuote && (c == '(' || c == '[' || c == '{')) { + stack.push(c); // Add opening bracket to stack + } else if (!insideQuote && (c == ')' || c == ']' || c == '}')) { + if (stack.isEmpty()) { + return i; // Return position of unbalanced closing bracket + } + char top = stack.pop(); + if (c == ')' && top != '(' || c == ']' && top != '[' || c == '}' && top != '{') { + return i; // Return position of unbalanced closing bracket + } + } + } + + if (!stack.isEmpty()) { + char unbalanced = stack.peek(); + for (int i = 0; i < text.length(); i++) { + if (text.charAt(i) == unbalanced) { + return i; // Return position of unbalanced opening bracket or quote + } + } + } + + return -1; // Return -1 if all brackets and quotes are balanced + } + + public static String sanitizeSingleSql(String sqlStr) { + final Pattern SQL_DELIMITER_SPLIT = + Pattern.compile("((?:'[^']*+'|[^\\n])*+)"); + final StringBuilder builder = new StringBuilder(); + final Matcher matcher = SQL_DELIMITER_SPLIT.matcher(sqlStr); + while (matcher.find()) { + for (int i = 1; i <= matcher.groupCount(); i++) { + if (!matcher.group(i).isEmpty()) { + builder.append("\n").append(matcher.group(i)); + } + } + } + return builder.toString(); } } diff --git a/src/main/java/net/sf/jsqlparser/parser/JSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/JSqlParser.java index b7e4e25dc..8a2aa9538 100644 --- a/src/main/java/net/sf/jsqlparser/parser/JSqlParser.java +++ b/src/main/java/net/sf/jsqlparser/parser/JSqlParser.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.parser; @@ -26,9 +14,6 @@ import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.statement.Statement; -/** - * Every parser must implements this interface - */ public interface JSqlParser { Statement parse(Reader statementReader) throws JSQLParserException; diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java new file mode 100644 index 000000000..5bdb93830 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -0,0 +1,224 @@ +/*- + * #%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.parser; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utilities for querying the parser's reserved and non-reserved keyword sets. + * + *

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

+ * Reserved keywords are determined by scanning the Grammar file for all simple string token + * definitions ({@code }) and subtracting the non-reserved set. + */ +public class ParserKeywordsUtils { + + private static final CharsetEncoder ASCII_ENCODER = StandardCharsets.US_ASCII.newEncoder(); + + /** Matches a pure keyword image: word characters, at least two characters, pure US-ASCII. */ + private static final Pattern KEYWORD_PATTERN = Pattern.compile("[A-Za-z_][A-Za-z_0-9]+"); + + /** + * Matches simple token definitions in the grammar: {@code }. Group 1 captures + * the string value. Only matches definitions where the value is a plain quoted string — + * compound regex tokens like {@code } won't match. + */ + private static final Pattern SIMPLE_TOKEN_PATTERN = + Pattern.compile("", Pattern.MULTILINE); + + private ParserKeywordsUtils() { + // utility class + } + + /** + * Returns the set of non-reserved keywords, i.e. tokens whose kind lies between + * {@code MIN_NON_RESERVED_WORD} and {@code MAX_NON_RESERVED_WORD}. These keywords can be used + * as unquoted identifiers. + */ + public static TreeSet getNonReservedKeywords() { + TreeSet keywords = new TreeSet<>(); + String[] images = CCJSqlParserConstants.tokenImage; + + for (int kind = CCJSqlParserConstants.MIN_NON_RESERVED_WORD + + 1; kind < CCJSqlParserConstants.MAX_NON_RESERVED_WORD; kind++) { + String image = extractKeyword(images[kind]); + if (image != null && isKeywordImage(image)) { + keywords.add(image); + } + } + return keywords; + } + + /** + * Returns the set of reserved keywords by scanning the Grammar file for all simple + * string token definitions and subtracting the non-reserved keywords. + * + * @param grammarFile the {@code .jjt} grammar file + * @return reserved keyword strings + * @throws IOException if reading the grammar file fails + */ + public static TreeSet getReservedKeywords(File grammarFile) throws IOException { + TreeSet allSimple = getAllSimpleKeywords(grammarFile); + allSimple.removeAll(getNonReservedKeywords()); + return allSimple; + } + + /** + * Returns all simple string keywords defined in the grammar file. Scans for + * {@code } patterns and collects the string values. + * + * @param grammarFile the {@code .jjt} grammar file + * @return all simple keyword strings + * @throws IOException if reading the grammar file fails + */ + public static TreeSet getAllSimpleKeywords(File grammarFile) throws IOException { + TreeSet keywords = new TreeSet<>(); + String content = Files.readString(grammarFile.toPath(), StandardCharsets.UTF_8); + + Matcher matcher = SIMPLE_TOKEN_PATTERN.matcher(content); + while (matcher.find()) { + String value = matcher.group(1); + if (isKeywordImage(value) && ASCII_ENCODER.canEncode(value)) { + keywords.add(value); + } + } + return keywords; + } + + /** + * Checks whether the given token kind is a non-reserved keyword that can be used as an unquoted + * identifier. + */ + public static boolean isNonReservedKeyword(int tokenKind) { + return tokenKind > CCJSqlParserConstants.MIN_NON_RESERVED_WORD + && tokenKind < CCJSqlParserConstants.MAX_NON_RESERVED_WORD; + } + + /** + * Writes a reStructuredText documentation file listing all reserved keywords. + * + * @param grammarFile the {@code .jjt} grammar file + * @param rstFile the output {@code .rst} file to write + * @throws IOException if reading or writing fails + */ + public static void writeKeywordsDocumentationFile(File grammarFile, File rstFile) + throws IOException { + TreeSet reserved = getReservedKeywords(grammarFile); + + StringBuilder builder = new StringBuilder(); + builder.append("***********************\n"); + builder.append("Reserved Keywords\n"); + builder.append("***********************\n"); + builder.append("\n"); + + builder.append( + "The following Keywords are **reserved** in JSQLParser-|JSQLPARSER_VERSION| and must not be used for **Naming Objects**: \n"); + builder.append("\n"); + + builder.append("+---------------------------+\n"); + builder.append("| **Keyword** |\n"); + builder.append("+---------------------------+\n"); + + for (String keyword : reserved) { + builder.append("| ").append(rightPadding(keyword, ' ', 25)).append(" |\n"); + builder.append("+---------------------------+\n"); + } + + try (FileWriter fileWriter = new FileWriter(rstFile)) { + fileWriter.append(builder); + fileWriter.flush(); + } + } + + public static String rightPadding(String input, char ch, int length) { + return String.format("%" + (-length) + "s", input).replace(' ', ch); + } + + /** + * Entry point for the {@code updateKeywords} Gradle/Maven task. + * + *

+ * Usage: {@code java net.sf.jsqlparser.parser.ParserKeywordsUtils } + * + * @param args {@code args[0]}: path to the grammar file, {@code args[1]}: path to the output + * RST file + * @throws Exception if reading or writing fails + */ + public static void main(String[] args) throws Exception { + if (args.length < 2) { + throw new IllegalArgumentException( + "Usage: ParserKeywordsUtils "); + } + + File grammarFile = new File(args[0]); + if (!grammarFile.canRead()) { + throw new IOException("Cannot read grammar file: " + grammarFile); + } + + File rstFile = new File(args[1]); + rstFile.getParentFile().mkdirs(); + writeKeywordsDocumentationFile(grammarFile, rstFile); + + System.out.println("Reserved keywords: " + getReservedKeywords(grammarFile).size()); + System.out.println("Non-reserved keywords: " + getNonReservedKeywords().size()); + System.out.println("Written to: " + rstFile.getAbsolutePath()); + } + + /** + * Extracts the keyword string from a {@code tokenImage} entry. + * + *

+ * JavaCC renders inline BNF token declarations as {@code } in {@code tokenImage}. + * Stripping the {@code K_} prefix and angle brackets yields the keyword string. + * + * @return the keyword string, or {@code null} if the entry is not a {@code K_} token + */ + private static String extractKeyword(String tokenImage) { + if (tokenImage == null || tokenImage.length() < 5) { + return null; + } + + // Format: → ACTION + if (tokenImage.charAt(0) == '<' + && tokenImage.charAt(tokenImage.length() - 1) == '>' + && tokenImage.startsWith(". + * 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; /** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). + * An implementation of interface CharStream, where the stream is assumed to contain only ASCII + * characters (without unicode processing). */ -public class SimpleCharStream { +public class SimpleCharStream { /** * Whether parser is static. */ - @SuppressWarnings("checkstyle:constantname") public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; /** * 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; protected boolean prevCharIsLF = false; - protected Provider inputStream; - protected char[] buffer; protected int maxNextCharInd = 0; protected int inBuf = 0; protected int tabSize = 1; protected boolean trackLineColumn = true; - protected int totalCharsRead = 0; protected int absoluteTokenBegin = 0; + int bufsize; + int available; + int tokenBegin; - public void setTabSize(int i) { - tabSize = i; + /** + * Constructor. + */ + public SimpleCharStream(Provider dstream, int startline, int startcolumn, int buffersize) { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + } + + /** + * Constructor. + */ + public SimpleCharStream(Provider dstream, int startline, int startcolumn) { + this(dstream, startline, startcolumn, 4096); + } + + /** + * Constructor. + */ + public SimpleCharStream(Provider dstream) { + this(dstream, 1, 1, 4096); } public int getTabSize() { return tabSize; } + public void setTabSize(int i) { + tabSize = i; + } + public final int getAbsoluteTokenBegin() { return absoluteTokenBegin; } 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) { @@ -109,6 +118,7 @@ protected void ExpandBuff(boolean wrapAround) { throw new Error(t.getMessage()); } + bufsize += 2048; available = bufsize; tokenBegin = 0; @@ -142,7 +152,6 @@ protected void FillBuff() throws java.io.IOException { } else { maxNextCharInd += i; } - return; } catch (java.io.IOException e) { --bufpos; backup(0); @@ -160,7 +169,9 @@ public char BeginToken() throws java.io.IOException { tokenBegin = -1; char c = readChar(); tokenBegin = bufpos; + absoluteTokenBegin = totalCharsRead; + return c; } @@ -188,7 +199,7 @@ protected void UpdateLineColumn(char c) { break; case '\t': column--; - column += tabSize - (column % tabSize); + column += tabSize - column % tabSize; break; default: break; @@ -210,6 +221,7 @@ public char readChar() throws java.io.IOException { } totalCharsRead++; + return buffer[bufpos]; } @@ -227,7 +239,8 @@ public char readChar() throws java.io.IOException { @Deprecated /** - * @deprecated @see #getEndColumn + * @deprecated + * @see #getEndColumn */ public int getColumn() { @@ -236,7 +249,8 @@ public int getColumn() { @Deprecated /** - * @deprecated @see #getEndLine + * @deprecated + * @see #getEndLine */ public int getLine() { @@ -283,41 +297,10 @@ public void backup(int amount) { } } - /** - * Constructor. - */ - public SimpleCharStream(Provider dstream, int startline, - int startcolumn, int buffersize) { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - /** - * Constructor. - */ - public SimpleCharStream(Provider dstream, int startline, - int startcolumn) { - this(dstream, startline, startcolumn, 4096); - } - - /** - * Constructor. - */ - public SimpleCharStream(Provider dstream) { - this(dstream, 1, 1, 4096); - } - /** * Reinitialise. */ - public void ReInit(Provider dstream, int startline, - int startcolumn, int buffersize) { + public void ReInit(Provider dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; line = startline; column = startcolumn - 1; @@ -336,8 +319,7 @@ public void ReInit(Provider dstream, int startline, /** * Reinitialise. */ - public void ReInit(Provider dstream, int startline, - int startcolumn) { + public void ReInit(Provider dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } @@ -348,6 +330,7 @@ public void ReInit(Provider dstream) { ReInit(dstream, 1, 1, 4096); } + /** * Get token literal value. */ @@ -369,8 +352,7 @@ public char[] GetSuffix(int len) { 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, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1); System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); } @@ -389,7 +371,6 @@ public void Done() { /** * Method to adjust line and column numbers for the start of a token. */ - @SuppressWarnings("checkstyle:parameterassignment") public void adjustBeginLineColumn(int newLine, int newCol) { int start = tokenBegin; int len; @@ -402,8 +383,8 @@ 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]) { @@ -439,4 +420,4 @@ void setTrackLineColumn(boolean tlc) { trackLineColumn = tlc; } } -/* JavaCC - OriginalChecksum=47e65cd0a1ed785f7a51c9e0c60893c9 (do not edit this line) */ +/* JavaCC - OriginalChecksum=0cd74e5ad7a4ccb9188541ab8f8b35eb (do not edit this line) */ diff --git a/src/main/java/net/sf/jsqlparser/parser/StatementListener.java b/src/main/java/net/sf/jsqlparser/parser/StatementListener.java new file mode 100644 index 000000000..3e26a0018 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/parser/StatementListener.java @@ -0,0 +1,20 @@ +/*- + * #%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.parser; + +import net.sf.jsqlparser.statement.Statement; + +/** + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public interface StatementListener { + + void accept(Statement statement); +} diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java new file mode 100644 index 000000000..d786f5170 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -0,0 +1,856 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.parser.feature; + +import net.sf.jsqlparser.expression.Function; +import net.sf.jsqlparser.expression.JdbcNamedParameter; +import net.sf.jsqlparser.expression.JdbcParameter; +import net.sf.jsqlparser.expression.OracleHierarchicalExpression; +import net.sf.jsqlparser.expression.OracleHint; +import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax; +import net.sf.jsqlparser.statement.Block; +import net.sf.jsqlparser.statement.Commit; +import net.sf.jsqlparser.statement.CreateFunctionalStatement; +import net.sf.jsqlparser.statement.DeclareStatement; +import net.sf.jsqlparser.statement.DescribeStatement; +import net.sf.jsqlparser.statement.ExplainStatement; +import net.sf.jsqlparser.statement.ResetStatement; +import net.sf.jsqlparser.statement.SetStatement; +import net.sf.jsqlparser.statement.ShowColumnsStatement; +import net.sf.jsqlparser.statement.ShowStatement; +import net.sf.jsqlparser.statement.UseStatement; +import net.sf.jsqlparser.statement.alter.Alter; +import net.sf.jsqlparser.statement.alter.sequence.AlterSequence; +import net.sf.jsqlparser.statement.analyze.Analyze; +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.procedure.CreateProcedure; +import net.sf.jsqlparser.statement.create.schema.CreateSchema; +import net.sf.jsqlparser.statement.create.sequence.CreateSequence; +import net.sf.jsqlparser.statement.create.synonym.CreateSynonym; +import net.sf.jsqlparser.statement.create.table.CreateTable; +import net.sf.jsqlparser.statement.create.view.AlterView; +import net.sf.jsqlparser.statement.create.view.CreateView; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.drop.Drop; +import net.sf.jsqlparser.statement.execute.Execute; +import net.sf.jsqlparser.statement.grant.Grant; +import net.sf.jsqlparser.statement.merge.Merge; +import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; +import net.sf.jsqlparser.statement.select.Fetch; +import net.sf.jsqlparser.statement.select.First; +import net.sf.jsqlparser.statement.select.KSQLWindow; +import net.sf.jsqlparser.statement.select.Limit; +import net.sf.jsqlparser.statement.select.Offset; +import net.sf.jsqlparser.statement.select.OptimizeFor; +import net.sf.jsqlparser.statement.select.Pivot; +import net.sf.jsqlparser.statement.select.PivotXml; +import net.sf.jsqlparser.statement.select.Skip; +import net.sf.jsqlparser.statement.select.TableFunction; +import net.sf.jsqlparser.statement.select.Top; +import net.sf.jsqlparser.statement.select.UnPivot; +import net.sf.jsqlparser.statement.show.*; +import net.sf.jsqlparser.statement.truncate.Truncate; +import net.sf.jsqlparser.statement.update.Update; +import net.sf.jsqlparser.statement.upsert.Upsert; + +public enum Feature { + + // SQL KEYWORD FEATURES + /** + * "SELECT" + */ + select, + /** + * "GROUP BY" + */ + selectGroupBy, + /** + * "GROUPING SETS" + */ + selectGroupByGroupingSets, + /** + * "HAVING" + */ + selectHaving, + /** + * "INTO table(, table)*" + */ + selectInto, + + /** + * @see Limit + */ + limit, + /** + * "LIMIT NULL" + * + * @see Limit#isLimitNull() + */ + limitNull, + /** + * "LIMIT ALL" + * + * @see Limit#isLimitAll() + */ + limitAll, + /** + * "LIMIT offset, limit" + * + * @see Limit#getOffset() + */ + limitOffset, + /** + * "OFFSET offset" + * + * @see Offset + */ + offset, + /** + * "OFFSET offset param" where param is ROW | ROWS + * + * @see Offset#getOffsetParam() + */ + offsetParam, + + /** + * @see Fetch + */ + fetch, + /** + * "FETCH FIRST row_count (ROW | ROWS) ONLY" + * + * @see Fetch#isFetchParamFirst() + */ + fetchFirst, + /** + * "FETCH NEXT row_count (ROW | ROWS) ONLY" if not {@link #fetchFirst} + * + * @see Fetch#isFetchParamFirst() + */ + fetchNext, + + /** + * "JOIN" + */ + join, + /** + * join tables by ", OUTER" placing the join specification in WHERE-clause + */ + joinOuterSimple, + /** + * join tables by "," placing the join specification in WHERE-clause + */ + joinSimple, + /** + * "RIGHT" join + */ + joinRight, + /** + * "NATURAL" join + */ + joinNatural, + /** + * "FULL" join + */ + joinFull, + /** + * "LEFT" join + */ + joinLeft, + /** + * "CROSS" join + */ + joinCross, + /** + * "OUTER" join + */ + joinOuter, + /** + * "SEMI" join + */ + joinSemi, + /** + * "INNER" join + */ + joinInner, + /** + * "STRAIGHT_JOIN" join + */ + joinStraight, + /** + * "APPLY" join + */ + joinApply, + + joinWindow, joinUsingColumns, + + /** + * "SKIP variable" | "SKIP ?" | "SKIP rowCount" + * + * @see Skip + */ + skip, + /** + * "FIRST" \?|[0-9]+|variable or "LIMIT" \?|[0-9]+|variable + * + * @see First + */ + first, + /** + * "TOP" ? "PERCENT" + * + * @see Top + */ + top, + /** + * "OPTIMIZE FOR rowCount ROWS" + * + * @see OptimizeFor + */ + optimizeFor, + + /** + * "UNIQUE" keyword + */ + selectUnique, + /** + * "DISTINCT" keyword + */ + distinct, + /** + * "DISTINCT ON (col1, ...)" + */ + distinctOn, + + /** + * "ORDER BY" + */ + orderBy, + /** + * "ORDER BY expression [ NULLS { FIRST | LAST } ]" + */ + orderByNullOrdering, + + /** + * "FOR UPDATE" + */ + selectForUpdate, + + /** + * "FOR SHARE" + */ + selectForShare, + + /** + * "FOR KEY SHARE" + */ + selectForKeyShare, + + /** + * "NO KEY UPDATE" + */ + selectForNoKeyUpdate, + + /** + * "FOR UPDATE OF table" + */ + selectForUpdateOfTable, + /** + * "FOR UPDATE WAIT timeout" + */ + selectForUpdateWait, + /** + * "FOR UPDATE NOWAIT" + */ + selectForUpdateNoWait, + /** + * "FOR UPDATE SKIP LOCKED" + */ + selectForUpdateSkipLocked, + + + /** + * SQL "INSERT" statement is allowed + */ + insert, + /** + * "INSERT .. SELECT" + */ + insertFromSelect, + /** + * "LOW_PRIORITY | DELAYED | HIGH_PRIORITY | IGNORE" + */ + insertModifierPriority, + /** + * "IGNORE" + */ + insertModifierIgnore, + /** + * "INSERT .. SET" + */ + insertUseSet, + /** + * "ON DUPLICATE KEY UPDATE" + */ + insertUseDuplicateKeyUpdate, + /** + * "RETURNING *" + */ + insertReturningAll, + /** + * "RETURNING expr(, expr)*" + * + * @see net.sf.jsqlparser.expression.operators.relational.ExpressionList + */ + insertReturningExpressionList, + + /** + * "VALUES" + */ + insertValues, + /** + * @see net.sf.jsqlparser.statement.select.Values + */ + values, + + /** + * SQL "TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]“ + */ + tableStatement, + + /** + * SQL "UPDATE" statement is allowed + * + * @see Update + */ + update, + /** + * "UPDATE table1 SET ... FROM table2 + */ + updateFrom, + /** + * "UPDATE table1, table2 ..." + */ + updateJoins, + /** + * UPDATE table SET (col, ...) = (SELECT col, ... )" + */ + updateUseSelect, updateOrderBy, updateLimit, + /** + * "RETURNING expr(, expr)*" + * + * @see net.sf.jsqlparser.statement.select.SelectItem + */ + updateReturning, + /** + * SQL "DELETE" statement is allowed + * + * @see Delete + */ + delete, + /** + * "DELETE FROM table1, table1 ..." + */ + deleteJoin, + /** + * "DELETE table1, table1 FROM table ..." + */ + deleteTables, + /** + * "LIMIT row_count" + */ + deleteLimit, + /** + * "ORDER BY ..." + */ + deleteOrderBy, + /** + * "RETURNING expr(, expr)*" + * + * @see net.sf.jsqlparser.statement.select.SelectItem + */ + deleteReturningExpressionList, + + /** + * SQL "UPSERT" statement is allowed + * + * @see Upsert + * @see https://wiki.postgresql.org/wiki/UPSERT + */ + upsert, + /** + * SQL "MERGE" statement is allowed + * + * @see Merge + */ + merge, + + /** + * SQL "ALTER" statement is allowed + * + * @see Alter + */ + alterTable, + /** + * SQL "ALTER SEQUENCE" statement is allowed + * + * @see AlterSequence + */ + alterSequence, + /** + * SQL "ALTER VIEW" statement is allowed + * + * @see AlterView + */ + alterView, + + /** + * SQL "REFRESH MATERIALIZED VIEW" statement is allowed + * + * @see RefreshMaterializedViewStatement + */ + refreshMaterializedView, refreshMaterializedWithDataView, refreshMaterializedWithNoDataView, + + /** + * SQL "REPLACE VIEW" statement is allowed + * + * @see AlterView + */ + alterViewReplace, + /** + * SQL "ALTER INDEX" statement is allowed + */ + alterIndex, + + + /** + * SQL "ANALYZE" statement is allowed + * + * @see Analyze + */ + analyze, + + /** + * SQL "TRUNCATE" statement is allowed + * + * @see Truncate + */ + truncate, + /** + * SQL "CALL|EXEC|EXECUTE" stored procedure is allowed + * + * @see Execute + */ + execute, executeExec, executeCall, executeExecute, + + /** + * SQL "EXECUTE" statement is allowed + */ + executeStatement, + /** + * SQL "EXECUTE IMMEDIATE" statement is allowed + */ + executeStatementImmediate, + + executeUsing, + /** + * SQL "REPLACE" statement is allowed + */ + @Deprecated + replace, + /** + * SQL "DROP" statement is allowed + * + * @see Drop + */ + drop, dropTable, dropIndex, dropView, dropSchema, dropSequence, dropTableIfExists, dropIndexIfExists, dropViewIfExists, dropSchemaIfExists, dropSequenceIfExists, + + /** + * SQL "CREATE SCHEMA" statement is allowed + * + * @see CreateSchema + */ + createSchema, + /** + * SQL "CREATE VIEW" statement is allowed + * + * @see CreateView + */ + createView, + /** + * "CREATE FORCE VIEW" + */ + createViewForce, + /** + * "CREATE TEMPORARAY VIEW" + */ + createViewTemporary, + /** + * "CREATE OR REPLACE VIEW" + */ + createOrReplaceView, + /** + * SQL "CREATE MATERIALIZED VIEW" statement is allowed + */ + createViewMaterialized, + + /** + * SQL "CREATE VIEW(x comment 'x', y comment 'y') comment 'view'" statement is allowed + */ + createViewWithComment, + + /** + * SQL "CREATE TABLE" statement is allowed + * + * @see CreateTable + */ + createTable, + /** + * "CREATE GLOBAL UNLOGGED" + */ + createTableUnlogged, + /** + * i.e. "CREATE GLOBAL TEMPORARY TABLE", "CREATE SHARDED TABLE" + */ + createTableCreateOptionStrings, + /** + * i.e. "ENGINE = InnoDB AUTO_INCREMENT = 8761 DEFAULT CHARSET = utf8" + */ + createTableTableOptionStrings, + /** + * "CREATE TABLE IF NOT EXISTS table" + */ + createTableIfNotExists, + /** + * " ROW MOVEMENT" + */ + createTableRowMovement, + /** + * "CREATE TABLE (colspec) SELECT ... + */ + createTableFromSelect, + /** + * SQL "CREATE INDEX" statement is allowed + * + * @see CreateIndex + */ + createIndex, + /** + * SQL "CREATE SEQUENCE" statement is allowed + * + * @see CreateSequence + */ + createSequence, + /** + * SQL "CREATE SYNONYM" statement is allowed + * + * @see CreateSynonym + */ + createSynonym, + /** + * SQL "CREATE TRIGGER" statement is allowed + */ + createTrigger, + /** + * SQL "COMMIT" statement is allowed + * + * @see Commit + */ + commit, + /** + * SQL "COMMENT ON" statement is allowed + * + * @see Comment + */ + comment, + /** + * "COMMENT ON table" + */ + commentOnTable, + /** + * "COMMENT ON column" + */ + commentOnColumn, + /** + * "COMMENT ON view" + */ + commentOnView, + + /** + * SQL "DESCRIBE" statement is allowed + * + * @see DescribeStatement + */ + describe, + + /** + * SQL "DESC" statement is allowed + * + * @see DescribeStatement + */ + desc, + + /** + * SQL "EXPLAIN" statement is allowed + * + * @see ExplainStatement + */ + explain, + /** + * @see ShowStatement + */ + show, + /** + * @see ShowTablesStatement + */ + showTables, + /** + * @see ShowColumnsStatement + */ + showColumns, + /** + * @see ShowIndexStatement + */ + showIndex, + /** + * @see UseStatement + */ + use, + /** + * @see Grant + */ + grant, + /** + * @see Function + */ + function, + /** + * @see CreateFunction + */ + createFunction, + /** + * @see CreateProcedure + */ + createProcedure, + /** + * @see CreateFunctionalStatement + */ + functionalStatement, + /** + * SQL block starting with "BEGIN" and ends with "END" statement is allowed + * + * @see Block + */ + block, + /** + * @see DeclareStatement + */ + declare, + /** + * @see SetStatement + */ + set, + /** + * @see ResetStatement + */ + reset, + /** + * @see Pivot + */ + pivot, + /** + * @see UnPivot + */ + unpivot, + /** + * @see PivotXml + */ + pivotXml, + + setOperation, setOperationUnion, setOperationIntersect, setOperationExcept, setOperationMinus, + + /** + * "WITH name query" + */ + withItem, withItemRecursive, + + lateralSubSelect, + /** + * @see net.sf.jsqlparser.statement.select.Values + */ + valuesList, + /** + * @see TableFunction + */ + tableFunction, + + // JDBC + /** + * @see JdbcParameter + */ + jdbcParameter, + /** + * @see JdbcNamedParameter + */ + jdbcNamedParameter, + + // EXPRESSIONS + /** + * "LIKE" + */ + exprLike, + /** + * "SIMILAR TO" + */ + exprSimilarTo, + + // VENDOR SPECIFIC SYNTAX FEATURES + + /** + * @see KSQLWindow + */ + kSqlWindow, + + // ORACLE + + /** + * allows old oracle join syntax (+) + * + * @see SupportsOldOracleJoinSyntax + */ + oracleOldJoinSyntax, + /** + * allows oracle prior position + * + * @see SupportsOldOracleJoinSyntax + */ + oraclePriorPosition, + /** + * @see OracleHint + */ + oracleHint, + /** + * oracle SQL "CONNECT BY" + * + * @see OracleHierarchicalExpression + */ + oracleHierarchicalExpression, oracleOrderBySiblings, + + // MYSQL + + mySqlHintStraightJoin, mysqlSqlCacheFlag, mysqlCalcFoundRows, + + // SQLSERVER + + /** + * "FOR XML PATH(...)" + */ + selectForXmlPath, + + /** + * allows square brackets for names, disabled by default + */ + allowSquareBracketQuotation(false), + + /** + * allow parsing of RDBMS specific syntax by switching off SQL Standard Compliant Syntax + */ + allowPostgresSpecificSyntax(false), + + // PERFORMANCE + + /** + * allows complex expression parameters or named parameters for functions will be switched off, + * when deep nesting of functions is detected + */ + allowComplexParsing(true), + + /** + * allows passing through Unsupported Statements as a plain List of Tokens needs to be switched + * off, when VALIDATING statements or parsing blocks + */ + allowUnsupportedStatements(false), + + timeOut(8000), + + /** + * allows Backslash '\' as Escape Character + */ + allowBackslashEscapeCharacter(false), + + /** + * allows sub selects without parentheses, e.g. `select * from dual where 1 = select 1` + */ + allowUnparenthesizedSubSelects(false), + + /** + * maximum nesting depth for trying complex parsing, can bet set to -1 to ignore + */ + allowedNestingDepth(10), + + dialect(null), + + /** + * "IMPORT" + */ + imprt, + + /** + * "EXPORT" + */ + export, + + /** + * MySQL allows a ',' as a separator between key and value entries. We allow that by default, + * but it can be disabled here + */ + allowCommaAsKeyValueSeparator(true), + + /** + * DB2 and Oracle allow Expressions as JSON_OBJECT key values. This clashes with Informix and + * Snowflake Json-Extraction syntax + */ + allowExpressionAsJsonObjectKey(false) + + ; + + private final Object value; + private final boolean configurable; + + /** + * a feature which can't configured within the parser + */ + Feature() { + this.value = null; + this.configurable = false; + } + + /** + * a feature which can be configured by {@link FeatureConfiguration} + * + * @param value The Value Object of the Parameter. + */ + Feature(Object value) { + this.value = value; + this.configurable = true; + } + + public Object getDefaultValue() { + return value; + } + + public boolean isConfigurable() { + return configurable; + } + +} diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java new file mode 100644 index 000000000..0106431cc --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureConfiguration.java @@ -0,0 +1,80 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.parser.feature; + +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class FeatureConfiguration { + + private static final Logger LOG = Logger.getLogger(FeatureConfiguration.class.getName()); + + private final Map featureEnabled = new EnumMap<>(Feature.class); + + public FeatureConfiguration() { + // set default-value for all switchable features + EnumSet.allOf(Feature.class).stream().filter(Feature::isConfigurable) + .forEach(f -> setValue(f, f.getDefaultValue())); + } + + /** + * @param feature + * @param value + * @return this + */ + public FeatureConfiguration setValue(Feature feature, Object value) { + if (feature.isConfigurable()) { + featureEnabled.put(feature, value); + } else { + if (LOG.isLoggable(Level.WARNING)) { + LOG.warning(feature.name() + " is not switchable - cannot set enabled = " + value); + } + } + return this; + } + + /** + * @param feature + * @return the configured feature value - can be null + * @throws IllegalStateException - if given {@link Feature#isConfigurable()} == false + */ + public Object getValue(Feature feature) { + if (feature.isConfigurable()) { + return featureEnabled.get(feature); + } else { + throw new IllegalStateException("The feature " + feature + " is not configurable!"); + } + } + + public boolean getAsBoolean(Feature f) { + return Boolean.parseBoolean(String.valueOf(getValue(f))); + } + + public Long getAsLong(Feature f) { + return Long.valueOf(String.valueOf(getValue(f))); + } + + public int getAsInt(Feature f) { + return Integer.parseInt(String.valueOf(getValue(f))); + } + + public Integer getAsInteger(Feature f) { + return Integer.parseInt(String.valueOf(getValue(f))); + } + + public String getAsString(Feature f) { + Object value = getValue(f); + return value == null ? null : String.valueOf(value); + } + +} diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/FeatureSet.java b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureSet.java new file mode 100644 index 000000000..551e0c575 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/parser/feature/FeatureSet.java @@ -0,0 +1,60 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.parser.feature; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed; + +public interface FeatureSet { + + Set getFeatures(); + + /** + * @return true if the feature is identical to one of the features contained in + * this set, false otherwise + */ + default boolean contains(Feature feature) { + return getFeatures().contains(feature); + } + + /** + * @return a new {@link HashSet} with a copy of supported features + */ + default Set getFeaturesClone() { + return new HashSet<>(getFeatures()); + } + + /** + * @param features + * @return all features within this feature set which are not contained in given set + */ + default Set getNotContained(Collection features) { + Set f = getFeaturesClone(); + f.removeAll(features); + return f; + } + + /** + * @param features + * @return all features within this feature set which are contained in given set too. + */ + default Set retainAll(Collection features) { + Set f = getFeaturesClone(); + f.retainAll(features); + return f; + } + + default ModifyableFeatureSet copy() { + return new FeaturesAllowed().add(this.getFeatures()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/ModifyableFeatureSet.java b/src/main/java/net/sf/jsqlparser/parser/feature/ModifyableFeatureSet.java new file mode 100644 index 000000000..7c1954f0d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/parser/feature/ModifyableFeatureSet.java @@ -0,0 +1,60 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.parser.feature; + +import java.util.Collection; + +public interface ModifyableFeatureSet extends FeatureSet { + + /** + * @param featureSets + * @return this + */ + ModifyableFeatureSet add(FeatureSet... featureSets); + + /** + * @param features + * @return this + */ + ModifyableFeatureSet add(Feature... features); + + /** + * @param features + * @return this + */ + ModifyableFeatureSet add(Collection features); + + /** + * @param featureSets + * @return this + */ + ModifyableFeatureSet remove(FeatureSet... featureSets); + + /** + * @param features + * @return this + */ + ModifyableFeatureSet remove(Feature... features); + + /** + * @param features + * @return this + */ + ModifyableFeatureSet remove(Collection features); + + /** + * makes the inner {@link Feature}-set unmodifiable + * + * @return this + * @see #copy() + */ + FeatureSet unmodifyable(); + +} diff --git a/src/main/java/net/sf/jsqlparser/schema/Column.java b/src/main/java/net/sf/jsqlparser/schema/Column.java index ea555cb57..33240ac52 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Column.java +++ b/src/main/java/net/sf/jsqlparser/schema/Column.java @@ -1,40 +1,42 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.schema; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import net.sf.jsqlparser.expression.*; +import net.sf.jsqlparser.expression.ArrayConstructor; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; +import net.sf.jsqlparser.statement.ReturningReferenceType; /** * A column. It can have the table name it belongs to. */ -public final class Column extends ASTNodeAccessImpl implements Expression, MultiPartName { +public class Column extends ASTNodeAccessImpl implements Expression, MultiPartName { private Table table; private String columnName; + private String commentText; + private ArrayConstructor arrayConstructor; + private String tableDelimiter = "."; + private int oldOracleJoinSyntax = SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN; + private ReturningReferenceType returningReferenceType = null; + private String returningQualifier = null; - public Column() { - } + // holds the physical table when resolved against an actual schema information + private Table resolvedTable = null; + + public Column() {} public Column(Table table, String columnName) { setTable(table); @@ -42,19 +44,86 @@ public Column(Table table, String columnName) { } public Column(List nameParts) { - this(nameParts.size() > 1 - ? new Table(nameParts.subList(0, nameParts.size() - 1)) : null, + this(nameParts, nameParts.size() > 1 ? Collections.nCopies(nameParts.size() - 1, ".") + : new ArrayList<>()); + } + + public Column(List nameParts, List delimiters) { + this( + nameParts.size() > 1 ? new Table(nameParts.subList(0, nameParts.size() - 1), + delimiters.subList(0, delimiters.size() - 1)) : null, nameParts.get(nameParts.size() - 1)); + setTableDelimiter(delimiters.isEmpty() ? "." : delimiters.get(delimiters.size() - 1)); } public Column(String columnName) { - this(null, columnName); + this(); + setColumnName(columnName); + } + + public ArrayConstructor getArrayConstructor() { + return arrayConstructor; + } + + public Column setArrayConstructor(ArrayConstructor arrayConstructor) { + this.arrayConstructor = arrayConstructor; + return this; } + /** + * Retrieve the information regarding the {@code Table} this {@code Column} does belong to, if + * any can be inferred. + *

+ * The inference is based only on local information, and not on the whole SQL command. For + * example, consider the following query:

+ * + *
+     *  SELECT x FROM Foo
+     * 
+ * + *
Given the {@code Column} called {@code x}, this method would return + * {@code null}, and not the info about the table {@code Foo}. On the other hand, consider: + *
+ * + *
+     *  SELECT t.x FROM Foo t
+     * 
+ * + *
Here, we will get a {@code Table} object for a table called {@code t}. But + * because the inference is local, such object will not know that {@code t} is just an alias for + * {@code Foo}. + * + * @return an instance of {@link net.sf.jsqlparser.schema.Table} representing the table this + * column does belong to, if it can be inferred. Can be {@code null}. + */ public Table getTable() { return table; } + public String getTableName() { + return table != null ? table.getName() : null; + } + + public String getUnquotedTableName() { + return table != null ? table.getUnquotedName() : null; + } + + public String getSchemaName() { + return table != null ? table.getSchemaName() : null; + } + + public String getUnquotedSchemaName() { + return table != null ? table.getUnquotedSchemaName() : null; + } + + public String getCatalogName() { + return table != null ? table.getCatalogName() : null; + } + + public String getUnquotedCatalogName() { + return table != null ? table.getUnquotedCatalogName() : null; + } + public void setTable(Table table) { this.table = table; } @@ -63,25 +132,94 @@ public String getColumnName() { return columnName; } - public void setColumnName(String string) { - columnName = string; + public String getUnquotedColumnName() { + return MultiPartName.unquote(columnName); + } + + public void setColumnName(String name) { + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + // however, some people believe that Dots in Names are a good idea, so provide a switch-off + boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null || + !List + .of("0", "N", "n", "FALSE", "false", "OFF", "off") + .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + + setName(name, splitNamesOnDelimiter); + } + + public void setName(String name, boolean splitNamesOnDelimiter) { + if (MultiPartName.isQuoted(name) && name.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(name).split("\\."); + switch (parts.length) { + case 3: + this.table = new Table("\"" + parts[0] + "\".\"" + parts[1] + "\""); + this.columnName = "\"" + parts[2] + "\""; + break; + case 2: + this.table = new Table("\"" + parts[0] + "\""); + this.columnName = "\"" + parts[1] + "\""; + break; + case 1: + this.columnName = "\"" + parts[0] + "\""; + break; + default: + throw new RuntimeException("Invalid column name: " + name); + } + } else if (name.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(name).split("\\."); + switch (parts.length) { + case 3: + this.table = new Table(parts[0] + "." + parts[1]); + this.columnName = parts[2]; + break; + case 2: + this.table = new Table(parts[0]); + this.columnName = parts[1]; + break; + case 1: + this.columnName = parts[0]; + break; + default: + throw new RuntimeException("Invalid column name: " + name); + } + } else { + this.columnName = name; + } + } + + public String getTableDelimiter() { + return tableDelimiter; + } + + 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 getName(false); + return getFullyQualifiedName(false); } - /** - * Get name with out without using aliases. - * - * @param aliases - * @return - */ - public String getName(boolean aliases) { + @Override + public String getUnquotedName() { + return MultiPartName.unquote(columnName); + } + + public String getFullyQualifiedName(boolean aliases) { StringBuilder fqn = new StringBuilder(); - if (table != null) { + if (returningQualifier != null) { + fqn.append(returningQualifier); + } else if (table != null) { if (table.getAlias() != null && aliases) { fqn.append(table.getAlias().getName()); } else { @@ -89,21 +227,119 @@ public String getName(boolean aliases) { } } if (fqn.length() > 0) { - fqn.append('.'); + fqn.append(tableDelimiter); } if (columnName != null) { fqn.append(columnName); } + + if (commentText != null) { + fqn.append(" COMMENT "); + fqn.append(commentText); + } + + if (arrayConstructor != null) { + fqn.append(arrayConstructor); + } + return fqn.toString(); } + // old and confusing, don't use it! + @Deprecated + public String getName(boolean aliases) { + return columnName; + } + @Override - public void accept(ExpressionVisitor expressionVisitor) { - expressionVisitor.visit(this); + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); } @Override public String toString() { - return getName(true); + return getFullyQualifiedName(true) + + (oldOracleJoinSyntax != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN ? "(+)" : "") + + (commentText != null ? " /* " + commentText + "*/ " : ""); + } + + public Column withTable(Table table) { + this.setTable(table); + return this; + } + + public Column withColumnName(String columnName) { + this.setColumnName(columnName); + return this; + } + + public Column withCommentText(String commentText) { + this.setCommentText(commentText); + return this; + } + + public Column withTableDelimiter(String delimiter) { + this.setTableDelimiter(delimiter); + return this; + } + + public Column withOldOracleJoinSyntax(int oldOracleJoinSyntax) { + this.setOldOracleJoinSyntax(oldOracleJoinSyntax); + return this; + } + + public ReturningReferenceType getReturningReferenceType() { + return returningReferenceType; + } + + public Column setReturningReferenceType(ReturningReferenceType returningReferenceType) { + this.returningReferenceType = returningReferenceType; + return this; + } + + public String getReturningQualifier() { + return returningQualifier; + } + + public Column setReturningQualifier(String returningQualifier) { + this.returningQualifier = returningQualifier; + return this; + } + + public Column withReturningReference(ReturningReferenceType returningReferenceType, + String returningQualifier) { + this.returningReferenceType = returningReferenceType; + this.returningQualifier = returningQualifier; + return this; + } + + public String getCommentText() { + return commentText; + } + + public void setCommentText(String commentText) { + this.commentText = commentText; + } + + /** + * Gets the actual table when resolved against a physical schema information. + * + * @return the actual table when resolved against a physical schema information + */ + public Table getResolvedTable() { + return resolvedTable; + } + + /** + * Sets resolved table. + * + * @param resolvedTable the resolved table + * @return this column + */ + public Column setResolvedTable(Table resolvedTable) { + // clone, not reference + this.resolvedTable = + resolvedTable != null ? new Table(resolvedTable.getFullyQualifiedName()) : null; + return this; } } diff --git a/src/main/java/net/sf/jsqlparser/schema/Database.java b/src/main/java/net/sf/jsqlparser/schema/Database.java index 5035b4fdd..c566b744f 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Database.java +++ b/src/main/java/net/sf/jsqlparser/schema/Database.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.schema; @@ -69,8 +57,23 @@ public String getFullyQualifiedName() { return fqn; } + @Override + public String getUnquotedName() { + return MultiPartName.unquote(databaseName); + } + @Override public String toString() { return getFullyQualifiedName(); } + + public Database withServer(Server server) { + this.setServer(server); + return this; + } + + public Database withDatabaseName(String databaseName) { + this.setDatabaseName(databaseName); + 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 b238c755d..ce954780d 100644 --- a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java +++ b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java @@ -1,27 +1,60 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.schema; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public interface MultiPartName { + Pattern LEADING_TRAILING_QUOTES_PATTERN = Pattern.compile("^[\"\\[`]+|[\"\\]`]+$"); + Pattern BACKTICK_PATTERN = Pattern.compile("`([^`]*)`"); + + /** + * Removes leading and trailing quotes from a SQL quoted identifier + * + * @param quotedIdentifier the quoted identifier + * @return the pure identifier without quotes + */ + static String unquote(String quotedIdentifier) { + return quotedIdentifier != null + ? LEADING_TRAILING_QUOTES_PATTERN.matcher(quotedIdentifier).replaceAll("") + : null; + } + + static boolean isQuoted(String identifier) { + return identifier != null && LEADING_TRAILING_QUOTES_PATTERN.matcher(identifier).find(); + } String getFullyQualifiedName(); + + String getUnquotedName(); + + + static String replaceBackticksWithDoubleQuotes(String input) { + if (input == null || input.isEmpty()) { + return input; + } + + Matcher matcher = BACKTICK_PATTERN.matcher(input); + StringBuilder sb = new StringBuilder(); + int lastEnd = 0; + + while (matcher.find()) { + sb.append(input, lastEnd, matcher.start()); // text before match + sb.append('"').append(matcher.group(1)).append('"'); // replace with double quotes + lastEnd = matcher.end(); + } + + sb.append(input.substring(lastEnd)); // append remaining text + return sb.toString(); + } + + } diff --git a/src/main/java/net/sf/jsqlparser/schema/Partition.java b/src/main/java/net/sf/jsqlparser/schema/Partition.java new file mode 100644 index 000000000..2666a6e81 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/schema/Partition.java @@ -0,0 +1,66 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.schema; + +import net.sf.jsqlparser.expression.Expression; + +import java.util.Collection; +import java.util.Objects; + +public class Partition { + protected Column column; + protected Expression value; + + public Partition() { + + } + + public Partition(Column column, Expression value) { + this.column = column; + this.value = value; + } + + public static void appendPartitionsTo(StringBuilder builder, + Collection partitions) { + int j = 0; + for (Partition partition : partitions) { + partition.appendTo(builder, j); + j++; + } + } + + public Column getColumn() { + return column; + } + + public void setColumn(Column column) { + this.column = Objects.requireNonNull(column); + } + + public Expression getValue() { + return value; + } + + public void setValue(Expression value) { + this.value = Objects.requireNonNull(value); + } + + + @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPath"}) + void appendTo(StringBuilder builder, int j) { + if (j > 0) { + builder.append(", "); + } + builder.append(column.getColumnName()); + if (value != null) { + builder.append(" = ").append(value); + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/schema/Sequence.java b/src/main/java/net/sf/jsqlparser/schema/Sequence.java new file mode 100644 index 000000000..764294db6 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/schema/Sequence.java @@ -0,0 +1,239 @@ +/*- + * #%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.schema; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +/** + * Represents the database type for a {@code SEQUENCE} + */ +public class Sequence extends ASTNodeAccessImpl implements MultiPartName { + + private static final int NAME_IDX = 0; + private static final int SCHEMA_IDX = 1; + private static final int DATABASE_IDX = 2; + private static final int SERVER_IDX = 3; + private List partItems = new ArrayList<>(); + + private List parameters; + private String dataType; + + public Sequence() {} + + public Sequence(List partItems) { + this.partItems = new ArrayList<>(partItems); + Collections.reverse(this.partItems); + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public String getDataType() { + return dataType; + } + + public void setDataType(String dataType) { + this.dataType = dataType; + } + + public Sequence withDataType(String dataType) { + this.setDataType(dataType); + return this; + } + + public Database getDatabase() { + return new Database(getIndex(DATABASE_IDX)); + } + + public void setDatabase(Database database) { + setIndex(DATABASE_IDX, database.getDatabaseName()); + if (database.getServer() != null) { + setIndex(SERVER_IDX, database.getServer().getFullyQualifiedName()); + } + } + + public Sequence withDatabase(Database database) { + setDatabase(database); + return this; + } + + public String getSchemaName() { + return getIndex(SCHEMA_IDX); + } + + public void setSchemaName(String string) { + setIndex(SCHEMA_IDX, string); + } + + public Sequence withSchemaName(String string) { + setSchemaName(string); + return this; + } + + public String getName() { + return getIndex(NAME_IDX); + } + + public void setName(String string) { + setIndex(NAME_IDX, string); + } + + public Sequence withName(String string) { + setName(string); + return this; + } + + private void setIndex(int idx, String value) { + int size = partItems.size(); + for (int i = 0; i < idx - size + 1; i++) { + partItems.add(null); + } + partItems.set(idx, value); + } + + private String getIndex(int idx) { + if (idx < partItems.size()) { + return partItems.get(idx); + } else { + return null; + } + } + + @Override + public String getFullyQualifiedName() { + StringBuilder fqn = new StringBuilder(); + + for (int i = partItems.size() - 1; i >= 0; i--) { + String part = partItems.get(i); + if (part == null) { + part = ""; + } + fqn.append(part); + if (i != 0) { + fqn.append("."); + } + } + + return fqn.toString(); + } + + @Override + public String getUnquotedName() { + return MultiPartName.unquote(partItems.get(NAME_IDX)); + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(getFullyQualifiedName()); + if (dataType != null) { + sql.append(" AS ").append(dataType); + } + if (parameters != null) { + for (Sequence.Parameter parameter : parameters) { + sql.append(" ").append(parameter.formatParameter()); + } + } + return sql.toString(); + } + + public Sequence withParameters(List parameters) { + this.setParameters(parameters); + return this; + } + + public Sequence addParameters(Parameter... parameters) { + List collection = Optional.ofNullable(getParameters()).orElseGet(ArrayList::new); + Collections.addAll(collection, parameters); + return this.withParameters(collection); + } + + public Sequence addParameters(Collection parameters) { + List collection = Optional.ofNullable(getParameters()).orElseGet(ArrayList::new); + collection.addAll(parameters); + return this.withParameters(collection); + } + + /** + * The available parameters to a sequence + */ + public enum ParameterType { + 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()); + } + } + + /** + * Represents a parameter when declaring a sequence + */ + public static class Parameter { + + private final ParameterType option; + private Long value; + + public Parameter(ParameterType option) { + this.option = option; + } + + public Long getValue() { + return value; + } + + public void setValue(Long value) { + this.value = value; + } + + 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"); + } else { + return "RESTART"; + } + case MAXVALUE: + case MINVALUE: + case CACHE: + return prefix(option.name()); + default: + // fallthrough just return option name + return option.name(); + } + } + + private String prefix(String prefix) { + return prefix + " " + value; + } + + public Parameter withValue(Long value) { + this.setValue(value); + return this; + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/schema/Server.java b/src/main/java/net/sf/jsqlparser/schema/Server.java index 7b83ab678..9ac9bd2d2 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Server.java +++ b/src/main/java/net/sf/jsqlparser/schema/Server.java @@ -1,22 +1,10 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.schema; @@ -25,11 +13,13 @@ public final class Server implements MultiPartName { - public static final Pattern SERVER_PATTERN = Pattern. - compile("\\[([^\\]]+?)(?:\\\\([^\\]]+))?\\]"); + public static final Pattern SERVER_PATTERN = + Pattern.compile("\\[([^\\]]+?)(?:\\\\([^\\]]+))?\\]"); private String serverName; + private String instanceName; + private String simpleName; public Server(String serverAndInstanceName) { @@ -67,8 +57,8 @@ public void setInstanceName(String instanceName) { @Override public String getFullyQualifiedName() { - if (serverName != null && !serverName.isEmpty() && instanceName != null && !instanceName. - isEmpty()) { + if (serverName != null && !serverName.isEmpty() && instanceName != null + && !instanceName.isEmpty()) { return String.format("[%s\\%s]", serverName, instanceName); } else if (serverName != null && !serverName.isEmpty()) { return String.format("[%s]", serverName); @@ -79,8 +69,23 @@ public String getFullyQualifiedName() { } } + @Override + public String getUnquotedName() { + return MultiPartName.unquote(serverName); + } + @Override public String toString() { return getFullyQualifiedName(); } + + public Server withServerName(String serverName) { + this.setServerName(serverName); + return this; + } + + public Server withInstanceName(String instanceName) { + this.setInstanceName(instanceName); + return this; + } } diff --git a/src/main/java/net/sf/jsqlparser/schema/Synonym.java b/src/main/java/net/sf/jsqlparser/schema/Synonym.java new file mode 100644 index 000000000..b052588c8 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/schema/Synonym.java @@ -0,0 +1,119 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.schema; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Synonym extends ASTNodeAccessImpl implements MultiPartName { + + private static final int NAME_IDX = 0; + private static final int SCHEMA_IDX = 1; + private static final int DATABASE_IDX = 2; + private static final int SERVER_IDX = 3; + private List partItems = new ArrayList<>(); + + public Synonym() {} + + public Synonym(List partItems) { + this.partItems = new ArrayList<>(partItems); + Collections.reverse(this.partItems); + } + + public Database getDatabase() { + return new Database(getIndex(DATABASE_IDX)); + } + + public void setDatabase(Database database) { + setIndex(DATABASE_IDX, database.getDatabaseName()); + if (database.getServer() != null) { + setIndex(SERVER_IDX, database.getServer().getFullyQualifiedName()); + } + } + + public Synonym withDatabase(Database database) { + setDatabase(database); + return this; + } + + public String getSchemaName() { + return getIndex(SCHEMA_IDX); + } + + public void setSchemaName(String string) { + setIndex(SCHEMA_IDX, string); + } + + public Synonym withSchemaName(String string) { + setSchemaName(string); + return this; + } + + public String getName() { + return getIndex(NAME_IDX); + } + + public void setName(String string) { + setIndex(NAME_IDX, string); + } + + public Synonym withName(String string) { + setName(string); + return this; + } + + private void setIndex(int idx, String value) { + int size = partItems.size(); + for (int i = 0; i < idx - size + 1; i++) { + partItems.add(null); + } + partItems.set(idx, value); + } + + private String getIndex(int idx) { + if (idx < partItems.size()) { + return partItems.get(idx); + } else { + return null; + } + } + + @Override + public String getFullyQualifiedName() { + StringBuilder fqn = new StringBuilder(); + + for (int i = partItems.size() - 1; i >= 0; i--) { + String part = partItems.get(i); + if (part == null) { + part = ""; + } + fqn.append(part); + if (i != 0) { + fqn.append("."); + } + } + + return fqn.toString(); + } + + @Override + public String getUnquotedName() { + return MultiPartName.unquote(partItems.get(NAME_IDX)); + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(getFullyQualifiedName()); + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 36ea7e98a..1de14a8a5 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -1,98 +1,286 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2013 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.schema; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; -import net.sf.jsqlparser.expression.*; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.MySQLIndexHint; +import net.sf.jsqlparser.expression.SQLServerHints; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -import net.sf.jsqlparser.statement.select.*; +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; +import net.sf.jsqlparser.statement.select.Pivot; +import net.sf.jsqlparser.statement.select.SampleClause; +import net.sf.jsqlparser.statement.select.UnPivot; /** * 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; + private static final int DATABASE_IDX = 2; + private static final int SERVER_IDX = 3; private List partItems = new ArrayList<>(); + 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; - private MySQLIndexHint hint; - public Table() { - } + private UnPivot unpivot; + private MySQLIndexHint mysqlHints; + + private SQLServerHints sqlServerHints; + + // holds the physical table when resolved against an actual schema information + private Table resolvedTable = null; + + public Table() {} + + /** + * Instantiates a new Table. + * + * Sets the table name, splitting it into parts (catalog, schema, name) on `.` dots when quoted + * unless the system property `SPLIT_NAMES_ON_DELIMITER` points to `FALSE` + * + * @param name the table name, optionally quoted + */ public Table(String name) { - setIndex(NAME_IDX, name); + setName(name); + } + + public Table(String name, boolean splitNamesOnDelimiter) { + setName(name, splitNamesOnDelimiter); } public Table(String schemaName, String name) { - setIndex(NAME_IDX, name); - setIndex(SCHEMA_IDX, schemaName); + setSchemaName(schemaName); + setName(name); } public Table(Database database, String schemaName, String name) { - setIndex(NAME_IDX, name); - setIndex(SCHEMA_IDX, schemaName); - setIndex(DATABASE_IDX, database.getDatabaseName()); - setIndex(SERVER_IDX, database.getServer().getFullyQualifiedName()); + setDatabase(database); + setSchemaName(schemaName); + setName(name); + } + + public Table(String catalogName, String schemaName, String tableName) { + setSchemaName(schemaName); + setDatabase(new Database(catalogName)); + setName(tableName); } public Table(List partItems) { - this.partItems = new ArrayList<>(partItems); - Collections.reverse(this.partItems); + if (partItems.size() == 1) { + setName(partItems.get(0)); + } else { + this.partItems = new ArrayList<>(partItems); + Collections.reverse(this.partItems); + } + } + + public Table(List partItems, List partDelimiters) { + if (partItems.size() == 1) { + setName(partItems.get(0)); + } else { + if (partDelimiters.size() != partItems.size() - 1) { + throw new IllegalArgumentException( + "the length of the delimiters list must be 1 less than nameParts"); + } + this.partItems = new ArrayList<>(partItems); + this.partDelimiters = new ArrayList<>(partDelimiters); + Collections.reverse(this.partItems); + Collections.reverse(this.partDelimiters); + } + } + + public String getCatalogName() { + return getIndex(DATABASE_IDX); } public Database getDatabase() { return new Database(getIndex(DATABASE_IDX)); } + public String getDatabaseName() { + return getIndex(DATABASE_IDX); + } + + public String getUnquotedCatalogName() { + return MultiPartName.unquote(getDatabaseName()); + } + + public String getUnquotedDatabaseName() { + return MultiPartName.unquote(getDatabaseName()); + } + public void setDatabase(Database database) { setIndex(DATABASE_IDX, database.getDatabaseName()); + if (database.getServer() != null) { + setIndex(SERVER_IDX, database.getServer().getFullyQualifiedName()); + } + } + + public Table setDatabaseName(String databaseName) { + this.setDatabase(new Database(databaseName)); + return this; + } + + public Table withDatabase(Database database) { + setDatabase(database); + return this; } public String getSchemaName() { return getIndex(SCHEMA_IDX); } - public void setSchemaName(String string) { - setIndex(SCHEMA_IDX, string); + public String getUnquotedSchemaName() { + return MultiPartName.unquote(getSchemaName()); + } + + public Table setSchemaName(String schemaName) { + if (schemaName == null) { + setIndex(SCHEMA_IDX, null); + return this; + } + + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + // however, some people believe that Dots in Names are a good idea, so provide a switch-off + boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null || + !List + .of("0", "N", "n", "FALSE", "false", "OFF", "off") + .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + + if (MultiPartName.isQuoted(schemaName) && schemaName.contains(".") + && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(schemaName).split("\\."); + switch (parts.length) { + case 2: + setIndex(DATABASE_IDX, "\"" + parts[0] + "\""); + setIndex(SCHEMA_IDX, "\"" + parts[1] + "\""); + break; + case 1: + setIndex(SCHEMA_IDX, "\"" + parts[0] + "\""); + break; + default: + throw new RuntimeException("Invalid schema name: " + schemaName); + } + } else if (schemaName.contains(".") && splitNamesOnDelimiter) { + String[] parts = MultiPartName.unquote(schemaName).split("\\."); + switch (parts.length) { + case 2: + setIndex(DATABASE_IDX, parts[0]); + setIndex(SCHEMA_IDX, parts[1]); + break; + case 1: + setIndex(SCHEMA_IDX, parts[0]); + break; + default: + throw new RuntimeException("Invalid schema name: " + schemaName); + } + } else { + this.setIndex(SCHEMA_IDX, schemaName); + } + return this; + } + + public Table withSchemaName(String schemaName) { + setSchemaName(schemaName); + return this; } public String getName() { - return getIndex(NAME_IDX); + String name = getIndex(NAME_IDX); + if (name != null && name.contains("@")) { + int pos = name.lastIndexOf('@'); + if (pos > 0) { + name = name.substring(0, pos); + } + } + return name; } - public void setName(String string) { - setIndex(NAME_IDX, string); + + /** + * Sets the table name, splitting it into parts (catalog, schema, name) on `.` dots when quoted + * unless the system property `SPLIT_NAMES_ON_DELIMITER` points to `FALSE` + * + * @param name the table name, optionally quoted + */ + public void setName(String name) { + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + // however, some people believe that Dots in Names are a good idea, so provide a switch-off + boolean splitNamesOnDelimiter = System.getProperty("SPLIT_NAMES_ON_DELIMITER") == null || + !List + .of("0", "N", "n", "FALSE", "false", "OFF", "off") + .contains(System.getProperty("SPLIT_NAMES_ON_DELIMITER")); + + setName(name, splitNamesOnDelimiter); + } + + public void setName(String name, boolean splitNamesOnDelimiter) { + if (MultiPartName.isQuoted(name) && name.contains(".") && splitNamesOnDelimiter) { + partItems.clear(); + for (String unquotedIdentifier : MultiPartName.unquote(name).split("\\.")) { + partItems.add("\"" + unquotedIdentifier + "\""); + } + Collections.reverse(partItems); + } else if (name.contains(".") && splitNamesOnDelimiter) { + partItems.clear(); + partItems.addAll(Arrays.asList(MultiPartName.unquote(name).split("\\."))); + Collections.reverse(partItems); + } else { + setIndex(NAME_IDX, name); + } + } + + public String getDBLinkName() { + String name = getIndex(NAME_IDX); + if (name != null && name.contains("@")) { + int pos = name.lastIndexOf('@'); + if (pos > 0) { + name = name.substring(pos + 1); + } + } + return name; + } + + public Table withName(String name) { + this.setName(name); + return this; } @Override @@ -105,11 +293,30 @@ 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) { - for (int i = 0; i < idx - partItems.size() + 1; i++) { + int size = partItems.size(); + for (int i = 0; i < idx - size + 1; i++) { partItems.add(null); } - partItems.set(idx, value); + + if (value == null && idx == partItems.size() - 1) { + partItems.remove(idx); + } else { + partItems.set(idx, value); + } } private String getIndex(int idx) { @@ -124,14 +331,21 @@ private String getIndex(int idx) { public String getFullyQualifiedName() { StringBuilder fqn = new StringBuilder(); - for (int i = partItems.size()-1 ; i >=0; i--) { + // remove any leading empty items + // only middle items can be suppressed (e.g. dbo..MY_TABLE ) + while (!partItems.isEmpty() && (partItems.get(partItems.size() - 1) == null + || partItems.get(partItems.size() - 1).isEmpty())) { + partItems.remove(partItems.size() - 1); + } + + for (int i = partItems.size() - 1; i >= 0; i--) { String part = partItems.get(i); if (part == null) { part = ""; } fqn.append(part); if (i != 0) { - fqn.append("."); + fqn.append(partDelimiters.isEmpty() ? "." : partDelimiters.get(i - 1)); } } @@ -139,12 +353,26 @@ public String getFullyQualifiedName() { } @Override - public void accept(FromItemVisitor fromItemVisitor) { - fromItemVisitor.visit(this); + public String getUnquotedName() { + return MultiPartName.unquote(getName()); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + public T accept(IntoTableVisitor intoTableVisitor, S context) { + return intoTableVisitor.visit(this, context); + } + + public String getTimeTravel() { + return timeTravelStr; } - public void accept(IntoTableVisitor intoTableVisitor) { - intoTableVisitor.visit(this); + public Table setTimeTravel(String timeTravelStr) { + this.timeTravelStr = timeTravelStr; + return this; } @Override @@ -157,19 +385,183 @@ public void setPivot(Pivot pivot) { this.pivot = pivot; } + @Override + public UnPivot getUnPivot() { + return this.unpivot; + } + + @Override + public void setUnPivot(UnPivot unpivot) { + this.unpivot = unpivot; + } + public MySQLIndexHint getIndexHint() { - return hint; + return mysqlHints; + } + + public Table withHint(MySQLIndexHint hint) { + setHint(hint); + return this; } public void setHint(MySQLIndexHint hint) { - this.hint = hint; + this.mysqlHints = hint; + } + + public SQLServerHints getSqlServerHints() { + return sqlServerHints; + } + + public void setSqlServerHints(SQLServerHints sqlServerHints) { + this.sqlServerHints = sqlServerHints; + } + + public SampleClause getSampleClause() { + return sampleClause; + } + + public Table setSampleClause(SampleClause sampleClause) { + this.sampleClause = sampleClause; + return this; + } + + 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); + } + + if (pivot != null) { + builder.append(" ").append(pivot); + } + + if (unpivot != null) { + builder.append(" ").append(unpivot); + } + + if (mysqlHints != null) { + builder.append(mysqlHints); + } + + if (sqlServerHints != null) { + builder.append(sqlServerHints); + } + return builder; } @Override public String toString() { - return getFullyQualifiedName() - + ((alias != null) ? alias.toString() : "") - + ((pivot != null) ? " " + pivot : "") - + ((hint != null) ? hint.toString() : ""); + return appendTo(new StringBuilder()).toString(); + } + + @Override + public Table withUnPivot(UnPivot unpivot) { + return (Table) FromItem.super.withUnPivot(unpivot); + } + + @Override + public Table withAlias(Alias alias) { + return (Table) FromItem.super.withAlias(alias); + } + + @Override + public Table withPivot(Pivot pivot) { + return (Table) FromItem.super.withPivot(pivot); + } + + public Table withSqlServerHints(SQLServerHints sqlServerHints) { + this.setSqlServerHints(sqlServerHints); + return this; + } + + public List getNameParts() { + return partItems; + } + + public List getNamePartDelimiters() { + return partDelimiters; + } + + /** + * Gets the actual table when resolved against a physical schema information. + * + * @return the actual table when resolved against a physical schema information + */ + public Table getResolvedTable() { + return resolvedTable; + } + + /** + * Sets resolved table. + * + * @param resolvedTable the resolved table + * @return this table + */ + public Table setResolvedTable(Table resolvedTable) { + // clone, not reference + if (resolvedTable != null) { + this.resolvedTable = new Table(resolvedTable.getFullyQualifiedName()); + } + return this; + } + + /** + * Sets a table's catalog and schema only when not set. Useful for setting CURRENT_SCHEMA() and + * CURRENT_DATABASE() + * + * @param currentCatalogName the catalog name + * @param currentSchemaName the schema name + * @return the provided table + */ + public Table setUnsetCatalogAndSchema(String currentCatalogName, String currentSchemaName) { + String databaseName = getDatabaseName(); + if (databaseName == null || databaseName.isEmpty()) { + setDatabaseName(currentCatalogName); + } + + String schemaName = getSchemaName(); + if (schemaName == null || schemaName.isEmpty()) { + setSchemaName(currentSchemaName); + } + return this; + } + + /** + * Sets a tables' catalog and schema only when not set. Useful for setting CURRENT_SCHEMA() and + * CURRENT_DATABASE() + * + * @param currentCatalogName the current catalog name + * @param currentSchemaName the current schema name + * @param tables the tables + * @return the tables + */ + public static Table[] setUnsetCatalogAndSchema(String currentCatalogName, + String currentSchemaName, Table... tables) { + for (Table t : tables) { + if (t != null) { + t.setUnsetCatalogAndSchema(currentCatalogName, currentSchemaName); + } + } + return tables; + } + + @Override + public Table clone() { + Table clone = new Table(this.getFullyQualifiedName()); + clone.setResolvedTable(this.resolvedTable != null ? this.resolvedTable.clone() : null); + return clone; } } diff --git a/src/main/java/net/sf/jsqlparser/statement/Block.java b/src/main/java/net/sf/jsqlparser/statement/Block.java new file mode 100644 index 000000000..83b9a2347 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/Block.java @@ -0,0 +1,59 @@ +/*- + * #%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 class Block implements Statement { + private boolean hasSemicolonAfterEnd = false; + + private Statements statements; + + public Statements getStatements() { + return statements; + } + + public void setStatements(Statements statements) { + this.statements = statements; + } + + public boolean hasSemicolonAfterEnd() { + return hasSemicolonAfterEnd; + } + + public void setSemicolonAfterEnd(boolean hasSemicolonAfterEnd) { + this.hasSemicolonAfterEnd = hasSemicolonAfterEnd; + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + public StringBuilder appendTo(StringBuilder builder) { + builder.append("BEGIN\n"); + if (statements != null) { + builder.append(statements); + } + builder.append("END"); + if (hasSemicolonAfterEnd) { + builder.append(";"); + } + return builder; + } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } + + public Block withStatements(Statements statements) { + this.setStatements(statements); + return this; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java b/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java new file mode 100644 index 000000000..08c7f4d1d --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CSVColumn.java @@ -0,0 +1,91 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class CSVColumn { + private Long startIndex; + private Long endIndex; + private StringValue format; + private String delimit; + + public CSVColumn(Long startIndex, Long endIndex) { + this.startIndex = startIndex; + this.endIndex = endIndex; + } + + public CSVColumn(Long index) { + this(index, null); + } + + public Long getStartIndex() { + return startIndex; + } + + public void setStartIndex(Long startIndex) { + this.startIndex = startIndex; + } + + public Long getIndex() { + return getStartIndex(); + } + + public void setIndex(Long index) { + setStartIndex(index); + } + + public Long getEndIndex() { + return endIndex; + } + + public void setEndIndex(Long endIndex) { + this.endIndex = endIndex; + } + + public StringValue getFormat() { + return format; + } + + public void setFormat(StringValue format) { + this.format = format; + } + + public String getDelimit() { + return delimit; + } + + public void setDelimit(String delimit) { + this.delimit = delimit; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(startIndex); + if (endIndex != null) { + sql.append(" .. "); + sql.append(endIndex); + } else if (format != null || delimit != null) { + if (format != null) { + sql.append(" FORMAT = "); + sql.append(format); + } + + if (delimit != null) { + sql.append(" DELIMIT = "); + sql.append(delimit); + } + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java b/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java new file mode 100644 index 000000000..697368f83 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CSVFileDestination.java @@ -0,0 +1,75 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class CSVFileDestination implements ErrorDestination { + private ConnectionDefinition connectionDefinition; + private boolean local; + private boolean secure; + private StringValue file; + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public boolean isLocal() { + return local; + } + + public void setLocal(boolean local) { + this.local = local; + } + + public boolean isSecure() { + return secure; + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public StringValue getFile() { + return file; + } + + public void setFile(StringValue file) { + this.file = file; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (local) { + sql.append("LOCAL "); + if (secure) { + sql.append("SECURE "); + } + } + + sql.append("CSV"); + + if (connectionDefinition != null) { + sql.append(" "); + sql.append(connectionDefinition); + } + + sql.append(" FILE "); + sql.append(file); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java b/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java new file mode 100644 index 000000000..7aabbb060 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CertificateVerification.java @@ -0,0 +1,67 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2025 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class CertificateVerification implements Serializable { + private Boolean ignoreCertificate; + private StringValue publicKey; + + public StringValue getPublicKey() { + return publicKey; + } + + public void setPublicKey(StringValue publicKey) { + this.publicKey = publicKey; + } + + public Boolean getIgnoreCertificate() { + return ignoreCertificate; + } + + public void setIgnoreCertificate(Boolean ignoreCertificate) { + this.ignoreCertificate = ignoreCertificate; + } + + public Boolean getVerifyCertificate() { + return !ignoreCertificate; + } + + public void setVerifyCertificate(Boolean verifyCertificate) { + this.ignoreCertificate = !verifyCertificate; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (ignoreCertificate != null) { + if (ignoreCertificate) { + sql.append("IGNORE "); + } else { + sql.append("VERIFY "); + } + sql.append("CERTIFICATE"); + } + + if (publicKey != null) { + if (ignoreCertificate != null) { + sql.append(" "); + } + sql.append("PUBLIC KEY "); + sql.append(publicKey); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java b/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java new file mode 100644 index 000000000..82b65fbd7 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CloudConnectionDefinition.java @@ -0,0 +1,37 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +public class CloudConnectionDefinition extends ConnectionDefinition { + private String storage; + + public String getStorage() { + return storage; + } + + public void setStorage(String storage) { + this.storage = storage; + } + + @Override + public void setCertificateVerification(CertificateVerification certificateVerification) {} + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("AT CLOUD "); + sql.append(storage); + sql.append(" "); + appendConnectionDefinition(sql); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/Commit.java b/src/main/java/net/sf/jsqlparser/statement/Commit.java index 66116a4bc..7ce465053 100644 --- a/src/main/java/net/sf/jsqlparser/statement/Commit.java +++ b/src/main/java/net/sf/jsqlparser/statement/Commit.java @@ -1,32 +1,20 @@ -/* +/*- * #%L * JSQLParser library * %% - * Copyright (C) 2004 - 2017 JSQLParser + * Copyright (C) 2004 - 2019 JSQLParser * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 * #L% */ package net.sf.jsqlparser.statement; public class Commit implements Statement { @Override - public void accept(StatementVisitor statementVisitor) { - statementVisitor.visit(this); + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); } - + @Override public String toString() { return "COMMIT"; diff --git a/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java b/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java new file mode 100644 index 000000000..f2887cf82 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ConnectionDefinition.java @@ -0,0 +1,91 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.io.Serializable; + +public class ConnectionDefinition implements Serializable { + private String connectionObjectName; + private StringValue connectionDefinition; + private UserIdentification userIdentification; + private CertificateVerification certificateVerification; + + public String getConnectionObjectName() { + return connectionObjectName; + } + + public void setConnectionObjectName(String connectionObjectName) { + this.connectionObjectName = connectionObjectName; + } + + public StringValue getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(StringValue connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public void setConnection(String connectionObjectName) { + this.connectionObjectName = connectionObjectName; + } + + public void setConnection(StringValue connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public UserIdentification getUserIdentification() { + return userIdentification; + } + + public void setUserIdentification(UserIdentification userIdentification) { + this.userIdentification = userIdentification; + } + + public CertificateVerification getCertificateVerification() { + return certificateVerification; + } + + public void setCertificateVerification(CertificateVerification certificateVerification) { + this.certificateVerification = certificateVerification; + } + + protected StringBuilder appendConnectionDefinition(StringBuilder sql) { + if (connectionObjectName != null) { + sql.append(connectionObjectName); + } else if (connectionDefinition != null) { + sql.append(connectionDefinition); + } + + if (userIdentification != null) { + sql.append(" "); + sql.append(userIdentification); + } + + if (certificateVerification != null) { + sql.append(" "); + sql.append(certificateVerification); + } + + return sql; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append("AT "); + appendConnectionDefinition(sql); + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java b/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java new file mode 100644 index 000000000..f0e0d0cf1 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ConnectionFileDefinition.java @@ -0,0 +1,60 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +import java.util.List; + +public class ConnectionFileDefinition { + private ConnectionDefinition connectionDefinition; + private List filePaths; + + public ConnectionFileDefinition(List filePaths) { + this(null, filePaths); + } + + public ConnectionFileDefinition(ConnectionDefinition connectionDefinition, + List filePaths) { + this.connectionDefinition = connectionDefinition; + this.filePaths = filePaths; + } + + public ConnectionDefinition getConnectionDefinition() { + return connectionDefinition; + } + + public void setConnectionDefinition(ConnectionDefinition connectionDefinition) { + this.connectionDefinition = connectionDefinition; + } + + public List getFilePaths() { + return filePaths; + } + + public void setFilePaths(List filePaths) { + this.filePaths = filePaths; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (connectionDefinition != null) { + sql.append(connectionDefinition); + } + + for (StringValue filePath : filePaths) { + sql.append(" FILE ").append(filePath); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/CreateFunctionalStatement.java b/src/main/java/net/sf/jsqlparser/statement/CreateFunctionalStatement.java new file mode 100644 index 000000000..536a2b68f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/CreateFunctionalStatement.java @@ -0,0 +1,120 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +/** + * A base for the declaration of function like statements + */ +public abstract class CreateFunctionalStatement implements Statement { + + private String kind; + private boolean orReplace = false; + + private List functionDeclarationParts; + + protected CreateFunctionalStatement(String kind) { + this.kind = kind; + } + + protected CreateFunctionalStatement(String kind, List functionDeclarationParts) { + this(false, kind, functionDeclarationParts); + } + + protected CreateFunctionalStatement(boolean orReplace, String kind, + List functionDeclarationParts) { + this.orReplace = orReplace; + this.kind = kind; + this.functionDeclarationParts = functionDeclarationParts; + } + + /** + * @return the declaration parts after {@code CREATE FUNCTION|PROCEDURE} + */ + public List getFunctionDeclarationParts() { + return functionDeclarationParts; + } + + public void setFunctionDeclarationParts(List functionDeclarationParts) { + this.functionDeclarationParts = functionDeclarationParts; + } + + /** + * @return the kind of functional statement + */ + public String getKind() { + return kind; + } + + public void setOrReplace(boolean orReplace) { + this.orReplace = orReplace; + } + + /** + * @return a whitespace appended String with the declaration parts with some minimal formatting. + */ + public String formatDeclaration() { + StringBuilder declaration = new StringBuilder(); + int currIndex = 0; + while (currIndex < functionDeclarationParts.size()) { + String token = functionDeclarationParts.get(currIndex); + declaration.append(token); + // if the next token is a ; don't put a space + if (currIndex + 1 < functionDeclarationParts.size()) { + // peek ahead just to format nicely + String nextToken = functionDeclarationParts.get(currIndex + 1); + if (!nextToken.equals(";")) { + declaration.append(" "); + } + } + currIndex++; + } + return declaration.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public String toString() { + return "CREATE " + + (orReplace ? "OR REPLACE " : "") + + kind + " " + formatDeclaration(); + } + + public CreateFunctionalStatement withFunctionDeclarationParts( + List functionDeclarationParts) { + this.setFunctionDeclarationParts(functionDeclarationParts); + return this; + } + + public CreateFunctionalStatement addFunctionDeclarationParts( + String... functionDeclarationParts) { + List collection = + Optional.ofNullable(getFunctionDeclarationParts()).orElseGet(ArrayList::new); + Collections.addAll(collection, functionDeclarationParts); + return this.withFunctionDeclarationParts(collection); + } + + public CreateFunctionalStatement addFunctionDeclarationParts( + Collection functionDeclarationParts) { + List collection = + Optional.ofNullable(getFunctionDeclarationParts()).orElseGet(ArrayList::new); + collection.addAll(functionDeclarationParts); + return this.withFunctionDeclarationParts(collection); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/DBMSType.java b/src/main/java/net/sf/jsqlparser/statement/DBMSType.java new file mode 100644 index 000000000..4b3d667da --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/DBMSType.java @@ -0,0 +1,52 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.StringValue; + +public class DBMSType implements SourceDestinationType { + private final Kind dbmsType; + private StringValue jdbcDriverDefinition; + + public DBMSType(String dbmsType) { + this(dbmsType, null); + } + + public DBMSType(String dbmsType, String jdbcDriverDefinition) { + this.dbmsType = Kind.valueOf(dbmsType.toUpperCase()); + if (jdbcDriverDefinition != null) { + this.jdbcDriverDefinition = new StringValue(jdbcDriverDefinition); + } + } + + private enum Kind { + EXA, ORA, JDBC + } + + public StringValue getJDBCDriverDefinition() { + return jdbcDriverDefinition; + } + + public void setJDBCDriverDefinition(StringValue jdbcDriverDefinition) { + this.jdbcDriverDefinition = jdbcDriverDefinition; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + sql.append(dbmsType); + if (jdbcDriverDefinition != null) { + sql.append(" DRIVER = ").append(jdbcDriverDefinition); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/DeclareStatement.java b/src/main/java/net/sf/jsqlparser/statement/DeclareStatement.java new file mode 100644 index 000000000..27537bc5f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/DeclareStatement.java @@ -0,0 +1,231 @@ +/*- + * #%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 java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.UserVariable; +import net.sf.jsqlparser.statement.create.table.ColDataType; +import net.sf.jsqlparser.statement.create.table.ColumnDefinition; + +public final class DeclareStatement implements Statement { + + private UserVariable userVariable = null; + private DeclareType declareType = DeclareType.TYPE; + private String typeName; + private List typeDefExprList = new ArrayList<>(); + private List columnDefinitions = new ArrayList<>(); + + public DeclareStatement() {} + + public UserVariable getUserVariable() { + return userVariable; + } + + public void setUserVariable(UserVariable userVariable) { + this.userVariable = userVariable; + } + + /** + * @return the {@link DeclareType} + * @deprecated use {@link #getDeclareType()} + */ + @Deprecated + public DeclareType getType() { + return getDeclareType(); + } + + /** + * @return the {@link DeclareType} + */ + public DeclareType getDeclareType() { + return declareType; + } + + public void setDeclareType(DeclareType declareType) { + this.declareType = declareType; + } + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public void addType(ColDataType colDataType, Expression defaultExpr) { + addTypeDefExprList(new TypeDefExpr(colDataType, defaultExpr)); + } + + public void addType(UserVariable userVariable, ColDataType colDataType, + Expression defaultExpr) { + addTypeDefExprList(new TypeDefExpr(userVariable, colDataType, defaultExpr)); + } + + public DeclareStatement addTypeDefExprList(TypeDefExpr... typeDefExpressions) { + List collection = + Optional.ofNullable(getTypeDefExprList()).orElseGet(ArrayList::new); + Collections.addAll(collection, typeDefExpressions); + return this.withTypeDefExprList(collection); + } + + public DeclareStatement addTypeDefExprList( + Collection typeDefExpressions) { + List collection = + Optional.ofNullable(getTypeDefExprList()).orElseGet(ArrayList::new); + collection.addAll(typeDefExpressions); + return this.withTypeDefExprList(collection); + } + + public DeclareStatement withTypeDefExprList(List typeDefExpressions) { + setTypeDefExprList(typeDefExpressions); + return this; + } + + public List getTypeDefExprList() { + return this.typeDefExprList; + } + + public void setTypeDefExprList(List expr) { + this.typeDefExprList = expr; + } + + public void addColumnDefinition(ColumnDefinition colDef) { + columnDefinitions.add(colDef); + } + + public List getColumnDefinitions() { + return columnDefinitions; + } + + public void setColumnDefinitions(List columnDefinitions) { + this.columnDefinitions = columnDefinitions; + } + + public List getTypeDefinitions() { + return typeDefExprList; + } + + + + @Override + public String toString() { + StringBuilder b = new StringBuilder("DECLARE "); + if (declareType == DeclareType.AS) { + b.append(userVariable.toString()); + b.append(" AS ").append(typeName); + } else { + if (declareType == DeclareType.TABLE) { + b.append(userVariable.toString()); + b.append(" TABLE ("); + for (int i = 0; i < columnDefinitions.size(); i++) { + if (i > 0) { + b.append(", "); + } + b.append(columnDefinitions.get(i).toString()); + } + b.append(")"); + } else { + for (int i = 0; i < typeDefExprList.size(); i++) { + if (i > 0) { + b.append(", "); + } + final TypeDefExpr type = typeDefExprList.get(i); + if (type.userVariable != null) { + b.append(type.userVariable.toString()).append(" "); + } + b.append(type.colDataType.toString()); + if (type.defaultExpr != null) { + b.append(" = ").append(type.defaultExpr.toString()); + } + } + } + } + return b.toString(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + public DeclareStatement withUserVariable(UserVariable userVariable) { + this.setUserVariable(userVariable); + return this; + } + + public DeclareStatement withTypeName(String typeName) { + this.setTypeName(typeName); + return this; + } + + public DeclareStatement withDeclareType(DeclareType declareType) { + this.setDeclareType(declareType); + return this; + } + + public DeclareStatement withColumnDefinitions(List columnDefinitions) { + this.setColumnDefinitions(columnDefinitions); + return this; + } + + public DeclareStatement addColumnDefinitions(ColumnDefinition... statements) { + List collection = + Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); + Collections.addAll(collection, statements); + return this.withColumnDefinitions(collection); + } + + + public DeclareStatement addColumnDefinitions( + Collection columnDefinitions) { + List collection = + Optional.ofNullable(getColumnDefinitions()).orElseGet(ArrayList::new); + collection.addAll(columnDefinitions); + return this.withColumnDefinitions(collection); + } + + public static class TypeDefExpr implements Serializable { + + public final UserVariable userVariable; + public final ColDataType colDataType; + public final Expression defaultExpr; + + public TypeDefExpr(ColDataType colDataType, Expression defaultExpr) { + this(null, colDataType, defaultExpr); + } + + public TypeDefExpr(UserVariable userVariable, ColDataType colDataType, + Expression defaultExpr) { + this.userVariable = userVariable; + this.colDataType = colDataType; + this.defaultExpr = defaultExpr; + } + + public UserVariable getUserVariable() { + return userVariable; + } + + public ColDataType getColDataType() { + return colDataType; + } + + public Expression getDefaultExpr() { + return defaultExpr; + } + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/DeclareType.java b/src/main/java/net/sf/jsqlparser/statement/DeclareType.java new file mode 100644 index 000000000..5208a333a --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/DeclareType.java @@ -0,0 +1,21 @@ +/*- + * #%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; + +/** + * @author tobens + */ +public enum DeclareType { + TABLE, AS, TYPE; + + public static DeclareType from(String type) { + return Enum.valueOf(DeclareType.class, type.toUpperCase()); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java b/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java new file mode 100644 index 000000000..10a92764c --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java @@ -0,0 +1,58 @@ +/*- + * #%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.schema.Table; + +public class DescribeStatement implements Statement { + + private Table table; + private String describeType; + + public DescribeStatement() { + // empty constructor + } + + public DescribeStatement(Table table) { + this.table = table; + } + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + @Override + public String toString() { + return this.describeType + " " + table.getFullyQualifiedName(); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + public DescribeStatement withTable(Table table) { + this.setTable(table); + return this; + } + + public String getDescribeType() { + return describeType; + } + + public DescribeStatement setDescribeType(String describeType) { + this.describeType = describeType; + return this; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java b/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java new file mode 100644 index 000000000..92db1a3dc --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ErrorClause.java @@ -0,0 +1,90 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +import net.sf.jsqlparser.expression.Expression; + +import java.io.Serializable; + +public class ErrorClause implements Serializable { + private ErrorDestination errorDestination; + private Expression expression; + private RejectClause rejectClause; + private boolean replace; + private boolean truncate; + + public ErrorDestination getErrorDestination() { + return errorDestination; + } + + public void setErrorDestination(ErrorDestination errorDestination) { + this.errorDestination = errorDestination; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public RejectClause getRejectClause() { + return rejectClause; + } + + public void setRejectClause(RejectClause rejectClause) { + this.rejectClause = rejectClause; + } + + public boolean isReplace() { + return replace; + } + + public void setReplace(boolean replace) { + this.replace = replace; + } + + public boolean isTruncate() { + return truncate; + } + + public void setTruncate(boolean truncate) { + this.truncate = truncate; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + + if (errorDestination != null) { + sql.append("ERRORS INTO "); + sql.append(errorDestination); + if (expression != null) { + sql.append(" ("); + sql.append(expression); + sql.append(")"); + } + + if (replace) { + sql.append(" REPLACE"); + } else if (truncate) { + sql.append(" TRUNCATE"); + } + } + + if (rejectClause != null) { + sql.append(" "); + sql.append(rejectClause); + } + + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java b/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java new file mode 100644 index 000000000..258a39ebb --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ErrorDestination.java @@ -0,0 +1,13 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2022 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement; + +public interface ErrorDestination { +} diff --git a/src/main/java/net/sf/jsqlparser/statement/ExplainStatement.java b/src/main/java/net/sf/jsqlparser/statement/ExplainStatement.java new file mode 100644 index 000000000..544aedf67 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/ExplainStatement.java @@ -0,0 +1,183 @@ +/*- + * #%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 java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.stream.Collectors; +import net.sf.jsqlparser.schema.Table; + +/** + * An {@code EXPLAIN} statement + */ +public class ExplainStatement implements Statement { + private String keyword; + private Statement statement; + private LinkedHashMap options; + private Table table; + + public ExplainStatement(String keyword) { + this.keyword = keyword; + } + + public ExplainStatement() { + this("EXPLAIN"); + } + + public ExplainStatement(String keyword, Table table) { + this.keyword = keyword; + this.table = table; + } + + public ExplainStatement(String keyword, Statement statement, List