From a8791279827d723b4a5c2ab655f51098814317eb Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Tue, 20 Aug 2024 19:28:44 +0700 Subject: [PATCH] feature: allow parsing BigQuery single pair quotes, e. g. "catalog.schema.tablename" - fixes https://github.com/starlake-ai/jsqltranspiler/issues/31 Signed-off-by: Andreas Reichel Signed-off-by: manticore-projects --- .github/workflows/maven_deploy.yml | 6 ++- .github/workflows/sphinx.yml | 2 +- .gitignore | 1 + build.gradle | 4 -- gradle.properties | 4 +- .../sf/jsqlparser/schema/MultiPartName.java | 4 ++ .../java/net/sf/jsqlparser/schema/Table.java | 46 +++++++++++++------ .../net/sf/jsqlparser/schema/TableTest.java | 30 +++++++++++- 8 files changed, 72 insertions(+), 25 deletions(-) diff --git a/.github/workflows/maven_deploy.yml b/.github/workflows/maven_deploy.yml index 740e80cb1..e63de93eb 100644 --- a/.github/workflows/maven_deploy.yml +++ b/.github/workflows/maven_deploy.yml @@ -14,9 +14,11 @@ jobs: name: Java ${{ matrix.java }} building ... steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Java ${{ matrix.java }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: ${{ matrix.java }} distribution: 'temurin' diff --git a/.github/workflows/sphinx.yml b/.github/workflows/sphinx.yml index ad8bde188..5fb5f9bd3 100644 --- a/.github/workflows/sphinx.yml +++ b/.github/workflows/sphinx.yml @@ -14,7 +14,7 @@ jobs: - name: Install dependencies run: pip install furo myst_parser sphinx-prompt sphinx_substitution_extensions sphinx_issues sphinx_inline_tabs pygments - name: Checkout project sources - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: master fetch-depth: 0 diff --git a/.gitignore b/.gitignore index 20db77d7c..a2b625283 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Generated by maven /target /build +/out # Sphinx Theme related stuff, which shall be downloaded separately /src/site/sphinx/_themes diff --git a/build.gradle b/build.gradle index fdfa2993f..c5d77bf30 100644 --- a/build.gradle +++ b/build.gradle @@ -187,10 +187,6 @@ test { environment = [ 'EXPORT_TEST_TO_FILE': 'True' ] useJUnitPlatform() - jacoco { - excludes = ['net/sf/jsqlparser/parser/CCJSqlParserTokenManager'] - } - // set heap size for the test JVM(s) minHeapSize = "128m" maxHeapSize = "1G" diff --git a/gradle.properties b/gradle.properties index 522c7558e..0716ad888 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,13 +2,13 @@ # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1G -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -org.gradle.caching=true +org.gradle.caching=false # Modularise your project and enable parallel build org.gradle.parallel=true # Enable configure on demand. -org.gradle.configureondemand=true +org.gradle.configureondemand=false # 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 diff --git a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java index 3e644a705..5e3ad5bde 100644 --- a/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java +++ b/src/main/java/net/sf/jsqlparser/schema/MultiPartName.java @@ -26,6 +26,10 @@ static String unquote(String quotedIdentifier) { : null; } + static boolean isQuoted(String identifier) { + return LEADING_TRAILING_QUOTES_PATTERN.matcher(identifier).find(); + } + String getFullyQualifiedName(); String getUnquotedName(); diff --git a/src/main/java/net/sf/jsqlparser/schema/Table.java b/src/main/java/net/sf/jsqlparser/schema/Table.java index 2d8ab6744..e41930bae 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Table.java +++ b/src/main/java/net/sf/jsqlparser/schema/Table.java @@ -63,36 +63,44 @@ public Table(String name) { } public Table(String schemaName, String name) { - setName(name); setSchemaName(schemaName); + setName(name); } public Table(Database database, String schemaName, String name) { - setName(name); - setSchemaName(schemaName); setDatabase(database); + setSchemaName(schemaName); + setName(name); } public Table(String catalogName, String schemaName, String tableName) { - setName(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 (partDelimiters.size() != partItems.size() - 1) { - throw new IllegalArgumentException( - "the length of the delimiters list must be 1 less than nameParts"); + if (partItems.size() == 1) { + setName(partItems.get(0)); + } else { + if (partDelimiters.size() != partItems.size() - 1) { + throw new IllegalArgumentException( + "the length of the delimiters list must be 1 less than nameParts"); + } + this.partItems = new ArrayList<>(partItems); + this.partDelimiters = new ArrayList<>(partDelimiters); + Collections.reverse(this.partItems); + Collections.reverse(this.partDelimiters); } - this.partItems = new ArrayList<>(partItems); - this.partDelimiters = new ArrayList<>(partDelimiters); - Collections.reverse(this.partItems); - Collections.reverse(this.partDelimiters); } public String getCatalogName() { @@ -159,7 +167,17 @@ public String getName() { public void setName(String name) { - setIndex(NAME_IDX, name); + // BigQuery seems to allow things like: `catalogName.schemaName.tableName` in only one pair + // of quotes + if (MultiPartName.isQuoted(name) && name.contains(".")) { + partItems.clear(); + for (String unquotedIdentifier : MultiPartName.unquote(name).split("\\.")) { + partItems.add("\"" + unquotedIdentifier + "\""); + } + Collections.reverse(partItems); + } else { + setIndex(NAME_IDX, name); + } } public String getDBLinkName() { diff --git a/src/test/java/net/sf/jsqlparser/schema/TableTest.java b/src/test/java/net/sf/jsqlparser/schema/TableTest.java index 5a3817251..0f9ff2071 100644 --- a/src/test/java/net/sf/jsqlparser/schema/TableTest.java +++ b/src/test/java/net/sf/jsqlparser/schema/TableTest.java @@ -22,6 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; /** * @@ -65,9 +66,7 @@ public StringBuilder visit(Table tableName, S parameters) { return null; } }; - deparser.visit((PlainSelect) select, null); - } @Test @@ -86,4 +85,31 @@ public void testConstructorDelimitersInappropriateSize() { .hasMessageContaining( "the length of the delimiters list must be 1 less than nameParts"); } + + @Test + void testBigQueryFullQuotedName() throws JSQLParserException { + String sqlStr = "select * from `d.s.t`"; + PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + Table table = (Table) select.getFromItem(); + + assertEquals("\"d\"", table.getCatalogName()); + assertEquals("\"s\"", table.getSchemaName()); + assertEquals("\"t\"", table.getName()); + + assertEquals("d", table.getUnquotedDatabaseName()); + assertEquals("s", table.getUnquotedSchemaName()); + assertEquals("t", table.getUnquotedName()); + + sqlStr = "select * from `s.t`"; + select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr); + table = (Table) select.getFromItem(); + + assertNull(table.getCatalogName()); + assertEquals("\"s\"", table.getSchemaName()); + assertEquals("\"t\"", table.getName()); + + assertNull(table.getUnquotedDatabaseName()); + assertEquals("s", table.getUnquotedSchemaName()); + assertEquals("t", table.getUnquotedName()); + } }