This is an automated email from the ASF dual-hosted git repository.
amashenkov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new fed2b3e103 IGNITE-21964 Extend test coverage for SQL
E031-01(Identifiers. Delimited identifiers) (#3899)
fed2b3e103 is described below
commit fed2b3e10368a5a375bbef7b9282cb188a90b07f
Author: Andrew V. Mashenkov <[email protected]>
AuthorDate: Mon Jun 17 10:59:05 2024 +0300
IGNITE-21964 Extend test coverage for SQL E031-01(Identifiers. Delimited
identifiers) (#3899)
---
.../apache/ignite/lang/util/IgniteNameUtils.java | 40 ++++-
.../ignite/internal/util/IgniteNameUtilsTest.java | 8 +-
.../internal/sql/engine/ItCreateTableDdlTest.java | 31 ++++
.../identifiers/test_delimited_identifiers.test | 173 +++++++++++++++++++++
4 files changed, 244 insertions(+), 8 deletions(-)
diff --git
a/modules/api/src/main/java/org/apache/ignite/lang/util/IgniteNameUtils.java
b/modules/api/src/main/java/org/apache/ignite/lang/util/IgniteNameUtils.java
index 089f26b691..7c7c3e13ad 100644
--- a/modules/api/src/main/java/org/apache/ignite/lang/util/IgniteNameUtils.java
+++ b/modules/api/src/main/java/org/apache/ignite/lang/util/IgniteNameUtils.java
@@ -81,7 +81,25 @@ public final class IgniteNameUtils {
* @return Quoted object name.
*/
public static String quote(String name) {
- return "\"" + name + "\"";
+ if (name == null || name.isEmpty()) {
+ return name;
+ }
+
+ if (name.chars().noneMatch(cp -> cp == '\"')) {
+ return '\"' + name + '\"';
+ }
+
+ StringBuilder sb = new StringBuilder(name.length() + 2).append('\"');
+ for (int currentPosition = 0; currentPosition < name.length();
currentPosition++) {
+ char ch = name.charAt(currentPosition);
+ if (ch == '\"') {
+ sb.append('\"');
+ }
+ sb.append(ch);
+ }
+ sb.append('\"');
+
+ return sb.toString();
}
/**
@@ -92,9 +110,21 @@ public final class IgniteNameUtils {
* @return Quoted object name.
*/
public static String quoteIfNeeded(String name) {
- String simpleName = parseSimpleName(name);
+ if (name == null || name.isEmpty()) {
+ return null;
+ }
+
+ if (name.charAt(0) == '\"') {
+ String simpleName = parseSimpleName(name);
+
+ return name.equals(quote(simpleName)) ? name : quote(name);
+ }
+
+ if (!NAME_PATTER.matcher(name).matches()) {
+ return quote(name);
+ }
- return name.equals(simpleName) || name.equals(quote(simpleName)) ?
name : quote(name);
+ return name.toUpperCase().equals(name) ? name : quote(name); // NOPMD
}
/**
@@ -147,8 +177,8 @@ public final class IgniteNameUtils {
if (hasNextChar() && nextChar() == '"') { // quote is
escaped
sb.append(source, start, currentPosition + 1);
- currentPosition += 2;
- start = currentPosition;
+ start = currentPosition + 2;
+ currentPosition += 1;
continue;
} else if (!hasNextChar() || nextChar() == '.') {
diff --git
a/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteNameUtilsTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteNameUtilsTest.java
index 34afbc4962..798d1457f2 100644
---
a/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteNameUtilsTest.java
+++
b/modules/core/src/test/java/org/apache/ignite/internal/util/IgniteNameUtilsTest.java
@@ -50,7 +50,7 @@ public class IgniteNameUtilsTest {
@ParameterizedTest
@ValueSource(strings = {
- "f.f", "f f", "f\"f", "f\"\"f", "\"foo", "\"fo\"o"
+ "f.f", "f f", "f\"f", "f\"\"f", "\"foo", "\"fo\"o\""
})
public void malformedSimpleNames(String source) {
IllegalArgumentException ex =
assertThrows(IllegalArgumentException.class, () ->
IgniteNameUtils.parseSimpleName(source));
@@ -62,8 +62,10 @@ public class IgniteNameUtilsTest {
@ParameterizedTest
@CsvSource({
- "foo, \"foo\"", "fOo, \"fOo\"", "FOO, FOO", "\"FOO\", \"FOO\"",
"1o0, \"1o0\"", "@#$, @#$",
- "\"foo\", \"foo\"", "\"fOo\", \"fOo\"", "\"f.f\", \"f.f\""
+ "foo, \"foo\"", "fOo, \"fOo\"", "FOO, FOO", "\"FOO\", \"FOO\"",
"1o0, \"1o0\"", "@#$, \"@#$\"",
+ "\"foo\", \"foo\"", "\"fOo\", \"fOo\"", "\"f.f\", \"f.f\"",
+ "foo\"bar\", \"foo\"\"bar\"\"\"", "\"foo\"\"bar\"\"\",
\"foo\"\"bar\"\"\"",
+ "foo\"bar, \"foo\"\"bar\"", "\"foo\"\"bar\", \"foo\"\"bar\""
})
public void quoteIfNeeded(String source, String expected) {
assertThat(IgniteNameUtils.quoteIfNeeded(source), equalTo(expected));
diff --git
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
index a6bc7cbacc..82191c3b7c 100644
---
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
+++
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/ItCreateTableDdlTest.java
@@ -25,8 +25,11 @@ import static
org.apache.ignite.internal.sql.engine.util.SqlTestUtils.assertThro
import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_PARSE_ERR;
import static org.apache.ignite.lang.ErrorGroups.Sql.STMT_VALIDATION_ERR;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.List;
import java.util.Objects;
@@ -39,6 +42,8 @@ import
org.apache.ignite.internal.catalog.descriptors.CatalogZoneDescriptor;
import org.apache.ignite.internal.schema.Column;
import org.apache.ignite.internal.sql.BaseSqlIntegrationTest;
import org.apache.ignite.sql.SqlException;
+import org.apache.ignite.table.Table;
+import org.apache.ignite.table.Tuple;
import org.apache.ignite.tx.Transaction;
import org.apache.ignite.tx.TransactionOptions;
import org.junit.jupiter.api.AfterEach;
@@ -415,6 +420,32 @@ public class ItCreateTableDdlTest extends
BaseSqlIntegrationTest {
);
}
+ @Test
+ public void quotedTableName() {
+ sql("CREATE TABLE \"table Test\" (key INT PRIMARY KEY, \"Col 1\"
INT)");
+ sql("CREATE TABLE \"table\"\"Test\"\"\" (key INT PRIMARY KEY,
\"Col\"\"1\"\"\" INT)");
+
+ sql("INSERT INTO \"table Test\" VALUES (1, 1)");
+ sql("INSERT INTO \"table\"\"Test\"\"\" VALUES (1, 2)");
+
+ IgniteImpl node = CLUSTER.node(0);
+
+ assertThrows(IllegalArgumentException.class, () ->
node.tables().table("table Test"));
+ assertThrows(IllegalArgumentException.class, () ->
node.tables().table("table\"Test\""));
+ assertThrows(IllegalArgumentException.class, () ->
node.tables().table("table\"\"Test\"\""));
+
+ Table table = node.tables().table("\"table Test\"");
+ assertNotNull(table);
+ assertThat(table.keyValueView().get(null, Tuple.create().set("key",
1)), equalTo(Tuple.create().set("\"Col 1\"", 1)));
+
+ table = node.tables().table("\"table\"\"Test\"\"\"");
+ assertNotNull(table);
+ assertThat(table.keyValueView().get(null, Tuple.create().set("key",
1)), equalTo(Tuple.create().set("\"Col\"\"1\"\"\"", 2)));
+
+ sql("DROP TABLE \"table Test\"");
+ sql("DROP TABLE \"table\"\"Test\"\"\"");
+ }
+
private static CatalogZoneDescriptor getDefaultZone(IgniteImpl node) {
CatalogManager catalogManager = node.catalogManager();
Catalog catalog =
catalogManager.catalog(catalogManager.activeCatalogVersion(node.clock().nowLong()));
diff --git
a/modules/sql-engine/src/integrationTest/sql/identifiers/test_delimited_identifiers.test
b/modules/sql-engine/src/integrationTest/sql/identifiers/test_delimited_identifiers.test
new file mode 100644
index 0000000000..1811d7262d
--- /dev/null
+++
b/modules/sql-engine/src/integrationTest/sql/identifiers/test_delimited_identifiers.test
@@ -0,0 +1,173 @@
+# name: sql/identifiers/test_identifiers_trailing_underscore.test
+# description: SQL feature E031-01 (Identifiers. Delimited identifiers)
+# group: [identifiers]
+
+statement ok
+PRAGMA enable_verification
+
+statement ok
+CREATE TABLE "Table_Test" ("col_Id" INTEGER, "col_Val" INTEGER, PRIMARY KEY
("col_Id"))
+
+statement ok
+CREATE TABLE "Table Test" ("col Id" INTEGER, "col Val" INTEGER, PRIMARY KEY
("col Id"))
+
+statement ok
+CREATE TABLE "Table""Test""" ("col""Id""" INTEGER, "col""Val""" INTEGER,
PRIMARY KEY ("col""Id"""))
+
+
+
+statement error
+ALTER TABLE Table_Test ADD COLUMN (col1 INTEGER)
+
+statement error
+ALTER TABLE TableTest ADD COLUMN (col1 INTEGER)
+
+statement ok
+ALTER TABLE "Table_Test" ADD COLUMN ("Col_1" INTEGER)
+
+statement ok
+ALTER TABLE "Table Test" ADD COLUMN ("Col 1" INTEGER)
+
+statement ok
+ALTER TABLE "Table""Test""" ADD COLUMN ("Col""1""" INTEGER)
+
+
+
+statement ok
+INSERT INTO "Table_Test" VALUES (1, 1, 1)
+
+statement ok
+INSERT INTO "Table Test" VALUES (2, 2, 2)
+
+statement ok
+INSERT INTO "Table""Test""" VALUES (3, 3, 3)
+
+
+query II
+SELECT "col_Val", "Col_1" FROM "Table_Test"
+----
+1 1
+
+query II
+SELECT "col Val", "Col 1" FROM "Table Test"
+----
+2 2
+
+query II
+SELECT "col""Val""", "Col""1""" FROM "Table""Test"""
+----
+3 3
+
+statement error: Object 'TABLE_TEST' not found
+SELECT "col_Val" FROM Table_Test
+
+statement error: Object 'TableTest' not found
+SELECT "col""Val""" FROM "TableTest"
+
+statement error: Column 'COL_VAL' not found
+SELECT col_Val FROM "Table_Test"
+
+statement error: Column 'colVal' not found
+SELECT "colVal" FROM "Table""Test"""
+
+
+
+statement ok
+CREATE INDEX "Index_Test" on "Table_Test" ("Col_1")
+
+statement ok
+CREATE INDEX "Index Test" on "Table Test" ("Col 1")
+
+statement ok
+CREATE INDEX "Index""Test""" on "Table""Test""" ("Col""1""")
+
+
+statement error: Index with name 'PUBLIC.INDEX_TEST' not found
+DROP INDEX Index_Test
+
+statement error: Index with name 'PUBLIC.IndexTest' not found
+DROP INDEX "IndexTest"
+
+statement ok
+DROP INDEX "Index_Test"
+
+statement ok
+DROP INDEX "Index Test"
+
+statement ok
+DROP INDEX "Index""Test"""
+
+
+
+statement error: Table with name 'PUBLIC.TABLE_TEST' not found
+DROP TABLE Table_Test;
+
+statement error: Table with name 'PUBLIC.TableTest' not found
+DROP TABLE "TableTest";
+
+statement ok
+DROP TABLE "Table_Test";
+
+statement ok
+DROP TABLE "Table Test";
+
+statement ok
+DROP TABLE "Table""Test""";
+
+
+
+statement ok
+CREATE ZONE "zone_Test" WITH STORAGE_PROFILES='default', PARTITIONS=1,
REPLICAS=3
+
+statement ok
+ALTER ZONE "zone_Test" SET REPLICAS = 4
+
+statement ok
+ALTER ZONE "zone_Test" RENAME TO "zone Test"
+
+statement error: Distribution zone with name 'zone_Test' not found
+ALTER ZONE "zone_Test" SET REPLICAS = 3
+
+statement error: Distribution zone with name 'zone_Test' not found
+DROP ZONE "zone_Test"
+
+statement ok
+DROP ZONE "zone Test"
+
+
+statement ok
+CREATE ZONE "zone Test" WITH STORAGE_PROFILES='default', PARTITIONS=1,
REPLICAS=3
+
+statement ok
+ALTER ZONE "zone Test" SET REPLICAS = 4
+
+statement ok
+ALTER ZONE "zone Test" RENAME TO "zone""Test"""
+
+statement error: Distribution zone with name 'zone Test' not found
+ALTER ZONE "zone Test" SET REPLICAS = 3
+
+statement error: Distribution zone with name 'zone Test' not found
+DROP ZONE "zone Test"
+
+statement ok
+DROP ZONE "zone""Test"""
+
+
+statement ok
+CREATE ZONE "zone""Test""" WITH STORAGE_PROFILES='default', PARTITIONS=1,
REPLICAS=3
+
+statement ok
+ALTER ZONE "zone""Test""" SET REPLICAS = 4
+
+statement ok
+ALTER ZONE "zone""Test""" RENAME TO "zone_Test"
+
+statement error: Distribution zone with name 'zone"Test"' not found
+ALTER ZONE "zone""Test""" SET REPLICAS = 3
+
+statement error: Distribution zone with name 'zone"Test"' not found
+DROP ZONE "zone""Test"""
+
+statement ok
+DROP ZONE "zone_Test"