From 89be7b8c148fc06971855e9afbfbda6fb8c85db9 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Fri, 23 Jun 2017 21:59:39 +0300 Subject: [PATCH] IGNITE-5279 Name case sensitivity tests for CREATE INDEX and CREATE TABLE. --- .../DynamicIndexAbstractBasicSelfTest.java | 81 +++++++- .../cache/index/H2DynamicTableSelfTest.java | 182 ++++++++++++++---- 2 files changed, 222 insertions(+), 41 deletions(-) diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java index 0b6b0ca83319a..1c6ced1f31e41 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicIndexAbstractBasicSelfTest.java @@ -17,6 +17,11 @@ package org.apache.ignite.internal.processors.cache.index; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import javax.cache.CacheException; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.Ignition; @@ -32,11 +37,7 @@ import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.schema.SchemaOperationException; import org.apache.ignite.internal.util.typedef.F; - -import javax.cache.CacheException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import org.apache.ignite.testframework.GridTestUtils; import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC; import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; @@ -911,6 +912,76 @@ public void testNonSqlCache() throws Exception { assertNoIndex(STATIC_CACHE_NAME, TBL_NAME, IDX_NAME_1); } + /** + * Test behavior depending on index name case sensitivity. + */ + public void testIndexNameCaseSensitivity() throws Exception { + doTestIndexNameCaseSensitivity("myIdx", false); + + doTestIndexNameCaseSensitivity("myIdx", true); + } + + /** + * Perform a check on given index name considering case sensitivity. + * @param idxName Index name to check. + * @param sensitive Whether index should be created w/case sensitive name or not. + */ + private void doTestIndexNameCaseSensitivity(String idxName, boolean sensitive) throws Exception { + String idxNameSql = (sensitive ? '"' + idxName + '"' : idxName); + + // This one should always work. + assertIndexNameIsValid(idxNameSql, idxNameSql); + + if (sensitive) { + assertIndexNameIsNotValid(idxNameSql, idxName.toUpperCase()); + + assertIndexNameIsNotValid(idxNameSql, idxName.toLowerCase()); + } + else { + assertIndexNameIsValid(idxNameSql, '"' + idxName.toUpperCase() + '"'); + + assertIndexNameIsValid(idxNameSql, idxName.toUpperCase()); + + assertIndexNameIsValid(idxNameSql, idxName.toLowerCase()); + } + } + + /** + * Check that given variant of index name works for DDL context. + * @param idxNameToCreate Name of the index to use in {@code CREATE INDEX}. + * @param checkedIdxName Index name to use in actual check. + */ + private void assertIndexNameIsValid(String idxNameToCreate, String checkedIdxName) throws Exception { + info("Checking index name variant for validity: " + checkedIdxName); + + final QueryIndex idx = index(idxNameToCreate, field(FIELD_NAME_1)); + + dynamicIndexCreate(STATIC_CACHE_NAME, TBL_NAME, idx, true); + + dynamicIndexDrop(STATIC_CACHE_NAME, checkedIdxName, false); + } + + /** + * Check that given variant of index name works for DDL context. + * @param idxNameToCreate Name of the index to use in {@code CREATE INDEX}. + * @param checkedIdxName Index name to use in actual check. + */ + private void assertIndexNameIsNotValid(String idxNameToCreate, final String checkedIdxName) throws Exception { + info("Checking index name variant for invalidity: " + checkedIdxName); + + final QueryIndex idx = index(idxNameToCreate, field(FIELD_NAME_1)); + + dynamicIndexCreate(STATIC_CACHE_NAME, TBL_NAME, idx, true); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + dynamicIndexDrop(STATIC_CACHE_NAME, checkedIdxName, false); + + return null; + } + }, IgniteSQLException.class, "Index doesn't exist: " + checkedIdxName.toUpperCase()); + } + /** * Get node which should be used to start operations. * diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java index ca1c9370b42f4..5975b4e91a80a 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java @@ -53,6 +53,7 @@ import org.apache.ignite.internal.processors.query.schema.SchemaOperationException; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.testframework.GridTestUtils; +import org.h2.jdbc.JdbcSQLException; /** * Tests for CREATE/DROP TABLE. @@ -94,8 +95,8 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { /** {@inheritDoc} */ @Override protected void afterTest() throws Exception { - executeDdl("DROP TABLE IF EXISTS PUBLIC.\"Person\""); - executeDdl("DROP TABLE IF EXISTS PUBLIC.\"City\""); + execute("DROP TABLE IF EXISTS PUBLIC.\"Person\""); + execute("DROP TABLE IF EXISTS PUBLIC.\"City\""); super.afterTest(); } @@ -161,6 +162,115 @@ public void testCreateTableNoTemplate() throws Exception { doTestCreateTable(null, null, CacheMode.PARTITIONED); } + /** + * Test behavior depending on table name case sensitivity. + */ + public void testTableNameCaseSensitivity() { + doTestTableNameCaseSensitivity("Person", false); + + doTestTableNameCaseSensitivity("Person", true); + } + + /** + * Perform a check on given table name considering case sensitivity. + * @param tblName Table name to check. + * @param sensitive Whether table should be created w/case sensitive name or not. + */ + private void doTestTableNameCaseSensitivity(String tblName, boolean sensitive) { + String tblNameSql = (sensitive ? '"' + tblName + '"' : tblName); + + // This one should always work. + assertTableNameIsValid(tblNameSql, tblNameSql); + + if (sensitive) { + assertTableNameIsNotValid(tblNameSql, tblName.toUpperCase()); + + assertTableNameIsNotValid(tblNameSql, tblName.toLowerCase()); + } + else { + assertTableNameIsValid(tblNameSql, '"' + tblName.toUpperCase() + '"'); + + assertTableNameIsValid(tblNameSql, tblName.toUpperCase()); + + assertTableNameIsValid(tblNameSql, tblName.toLowerCase()); + } + } + + /** + * Check that given variant of table name works for DML and DDL contexts, as well as selects. + * @param tblNameToCreate Name of the table to use in {@code CREATE TABLE}. + * @param checkedTblName Table name to use in actual checks. + */ + private void assertTableNameIsValid(String tblNameToCreate, String checkedTblName) { + info("Checking table name variant for validity: " + checkedTblName); + + execute("create table if not exists " + tblNameToCreate + " (id int primary key, name varchar)"); + + execute("MERGE INTO " + checkedTblName + " (id, name) values (1, 'A')"); + + execute("SELECT * FROM " + checkedTblName); + + execute("DROP TABLE " + checkedTblName); + } + + /** + * Check that given variant of table name does not work for DML and DDL contexts, as well as selects. + * @param tblNameToCreate Name of the table to use in {@code CREATE TABLE}. + * @param checkedTblName Table name to use in actual checks. + */ + private void assertTableNameIsNotValid(String tblNameToCreate, String checkedTblName) { + info("Checking table name variant for invalidity: " + checkedTblName); + + execute("create table if not exists " + tblNameToCreate + " (id int primary key, name varchar)"); + + assertCommandThrowsTableNotFound(checkedTblName.toUpperCase(), + "MERGE INTO " + checkedTblName + " (id, name) values (1, 'A')"); + + assertCommandThrowsTableNotFound(checkedTblName.toUpperCase(), "SELECT * FROM " + checkedTblName); + + assertDdlCommandThrowsTableNotFound(checkedTblName.toUpperCase(), "DROP TABLE " + checkedTblName); + } + + /** + * Check that given (non DDL) command throws an exception as expected. + * @param checkedTblName Table name to expect in error message. + * @param cmd Command to execute. + */ + @SuppressWarnings("ThrowableResultOfMethodCallIgnored") + private void assertCommandThrowsTableNotFound(String checkedTblName, final String cmd) { + final Throwable e = GridTestUtils.assertThrowsWithCause(new Callable() { + @Override public Object call() throws Exception { + execute(cmd); + + return null; + } + }, JdbcSQLException.class); + + GridTestUtils.assertThrows(null, new Callable() { + @SuppressWarnings("ConstantConditions") + @Override public Object call() throws Exception { + throw (Exception)e.getCause(); + } + }, JdbcSQLException.class, "Table \"" + checkedTblName + "\" not found"); + } + + /** + * Check that given DDL command throws an exception as expected. + * @param checkedTblName Table name to expect in error message. + * @param cmd Command to execute. + */ + @SuppressWarnings("ThrowableResultOfMethodCallIgnored") + private void assertDdlCommandThrowsTableNotFound(String checkedTblName, final String cmd) { + GridTestUtils.assertThrows(null, new Callable() { + @SuppressWarnings("ConstantConditions") + @Override public Object call() throws Exception { + execute(cmd); + + return null; + } + }, IgniteSQLException.class, "Table doesn't exist: " + checkedTblName); + } + /** * Test that {@code CREATE TABLE} with given template cache name actually creates new cache, * H2 table and type descriptor on all nodes, optionally with cache type check. @@ -169,7 +279,7 @@ public void testCreateTableNoTemplate() throws Exception { * @param mode Expected cache mode, or {@code null} if no check is needed. */ private void doTestCreateTable(String tplCacheName, String cacheGrp, CacheMode mode) { - executeDdl("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + + execute("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + (F.isEmpty(tplCacheName) ? "" : "\"template=" + tplCacheName + "\",") + "\"backups=10,atomicity=atomic\"" + (F.isEmpty(cacheGrp) ? "" : ",\"cacheGroup=" + cacheGrp + '"')); @@ -268,11 +378,11 @@ public void testEmptyCacheGroup() { * @throws Exception if failed. */ public void testCreateTableIfNotExists() throws Exception { - executeDdl("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + + execute("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache\""); - executeDdl("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + + execute("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache\""); } @@ -283,13 +393,13 @@ public void testCreateTableIfNotExists() throws Exception { */ @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public void testCreateExistingTable() throws Exception { - executeDdl("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + + execute("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache\""); GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar" + + execute("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar" + ", \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache\""); @@ -303,11 +413,11 @@ public void testCreateExistingTable() throws Exception { * @throws Exception if failed. */ public void testDropTable() throws Exception { - executeDdl("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + + execute("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache\""); - executeDdl("DROP TABLE \"Person\""); + execute("DROP TABLE \"Person\""); for (int i = 0; i < 4; i++) { IgniteEx node = grid(i); @@ -327,7 +437,7 @@ public void testDropTable() throws Exception { * @throws Exception if failed. */ public void testDropMissingTableIfExists() throws Exception { - executeDdl("DROP TABLE IF EXISTS \"City\""); + execute("DROP TABLE IF EXISTS \"City\""); } /** @@ -338,7 +448,7 @@ public void testDropMissingTableIfExists() throws Exception { public void testDropMissingTable() throws Exception { GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("DROP TABLE \"City\""); + execute("DROP TABLE \"City\""); return null; } @@ -353,7 +463,7 @@ public void testDropMissingTable() throws Exception { public void testDropNonDynamicTable() throws Exception { GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("DROP TABLE PUBLIC.\"Integer\""); + execute("DROP TABLE PUBLIC.\"Integer\""); return null; } @@ -367,7 +477,7 @@ public void testDropNonDynamicTable() throws Exception { */ @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public void testDestroyDynamicSqlCache() throws Exception { - executeDdl("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + + execute("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache\""); @@ -388,7 +498,7 @@ public void testDestroyDynamicSqlCache() throws Exception { */ @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public void testSqlFlagCompatibilityCheck() throws Exception { - executeDdl("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar, \"name\" varchar, \"surname\" varchar, " + + execute("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar, \"name\" varchar, \"surname\" varchar, " + "\"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH \"template=cache\""); GridTestUtils.assertThrows(null, new Callable() { @@ -409,9 +519,9 @@ public void testSqlFlagCompatibilityCheck() throws Exception { */ @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public void testIndexNameConflictCheckDiscovery() throws Exception { - executeDdl(grid(0), "CREATE TABLE \"Person\" (id int primary key, name varchar)"); + execute(grid(0), "CREATE TABLE \"Person\" (id int primary key, name varchar)"); - executeDdl(grid(0), "CREATE INDEX \"idx\" ON \"Person\" (\"name\")"); + execute(grid(0), "CREATE INDEX \"idx\" ON \"Person\" (\"name\")"); GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { @@ -438,11 +548,11 @@ public void testIndexNameConflictCheckDiscovery() throws Exception { */ @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public void testTableNameConflictCheckSql() throws Exception { - executeDdl(grid(0), "CREATE TABLE \"Person\" (id int primary key, name varchar)"); + execute(grid(0), "CREATE TABLE \"Person\" (id int primary key, name varchar)"); GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl(client(), "CREATE TABLE \"Person\" (id int primary key, name varchar)"); + execute(client(), "CREATE TABLE \"Person\" (id int primary key, name varchar)"); return null; } @@ -453,18 +563,18 @@ public void testTableNameConflictCheckSql() throws Exception { * @throws Exception if failed. */ public void testAffinityKey() throws Exception { - executeDdl("CREATE TABLE \"City\" (\"name\" varchar primary key, \"code\" int) WITH \"affinityKey='name'\""); + execute("CREATE TABLE \"City\" (\"name\" varchar primary key, \"code\" int) WITH \"affinityKey='name'\""); assertAffinityCacheConfiguration("City", "name"); - executeDdl("INSERT INTO \"City\" (\"name\", \"code\") values ('A', 1), ('B', 2), ('C', 3)"); + execute("INSERT INTO \"City\" (\"name\", \"code\") values ('A', 1), ('B', 2), ('C', 3)"); List cityNames = Arrays.asList("A", "B", "C"); List cityCodes = Arrays.asList(1, 2, 3); // We need unique name for this table to avoid conflicts with existing binary metadata. - executeDdl("CREATE TABLE \"Person2\" (\"id\" int, \"city\" varchar," + + execute("CREATE TABLE \"Person2\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache,affinityKey='city'\""); @@ -511,26 +621,26 @@ public void testAffinityKey() throws Exception { */ @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public void testAffinityKeyCaseSensitivity() { - executeDdl("CREATE TABLE \"A\" (\"name\" varchar primary key, \"code\" int) WITH \"affinityKey='name'\""); + execute("CREATE TABLE \"A\" (\"name\" varchar primary key, \"code\" int) WITH \"affinityKey='name'\""); assertAffinityCacheConfiguration("A", "name"); - executeDdl("CREATE TABLE \"B\" (name varchar primary key, \"code\" int) WITH \"affinityKey=name\""); + execute("CREATE TABLE \"B\" (name varchar primary key, \"code\" int) WITH \"affinityKey=name\""); assertAffinityCacheConfiguration("B", "NAME"); - executeDdl("CREATE TABLE \"C\" (name varchar primary key, \"code\" int) WITH \"affinityKey=NamE\""); + execute("CREATE TABLE \"C\" (name varchar primary key, \"code\" int) WITH \"affinityKey=NamE\""); assertAffinityCacheConfiguration("C", "NAME"); - executeDdl("CREATE TABLE \"D\" (\"name\" varchar primary key, \"code\" int) WITH \"affinityKey=NAME\""); + execute("CREATE TABLE \"D\" (\"name\" varchar primary key, \"code\" int) WITH \"affinityKey=NAME\""); assertAffinityCacheConfiguration("D", "name"); // Error arises because user has specified case sensitive affinity column name GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("CREATE TABLE \"E\" (name varchar primary key, \"code\" int) WITH \"affinityKey='Name'\""); + execute("CREATE TABLE \"E\" (name varchar primary key, \"code\" int) WITH \"affinityKey='Name'\""); return null; } @@ -540,14 +650,14 @@ public void testAffinityKeyCaseSensitivity() { // columns whose names are equal in ignore case. GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("CREATE TABLE \"E\" (\"name\" varchar, \"Name\" int, val int, primary key(\"name\", " + + execute("CREATE TABLE \"E\" (\"name\" varchar, \"Name\" int, val int, primary key(\"name\", " + "\"Name\")) WITH \"affinityKey=name\""); return null; } }, IgniteSQLException.class, "Ambiguous affinity column name, use single quotes for case sensitivity: name"); - executeDdl("CREATE TABLE \"E\" (\"name\" varchar, \"Name\" int, val int, primary key(\"name\", " + + execute("CREATE TABLE \"E\" (\"name\" varchar, \"Name\" int, val int, primary key(\"name\", " + "\"Name\")) WITH \"affinityKey='Name'\""); assertAffinityCacheConfiguration("E", "Name"); @@ -561,7 +671,7 @@ public void testAffinityKeyNotKeyColumn() { // Error arises because user has specified case sensitive affinity column name GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("CREATE TABLE \"E\" (name varchar primary key, \"code\" int) WITH \"affinityKey=code\""); + execute("CREATE TABLE \"E\" (name varchar primary key, \"code\" int) WITH \"affinityKey=code\""); return null; } @@ -576,7 +686,7 @@ public void testAffinityKeyNotFound() { // Error arises because user has specified case sensitive affinity column name GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("CREATE TABLE \"E\" (name varchar primary key, \"code\" int) WITH \"affinityKey=missing\""); + execute("CREATE TABLE \"E\" (name varchar primary key, \"code\" int) WITH \"affinityKey=missing\""); return null; } @@ -615,7 +725,7 @@ private void assertAffinityCacheConfiguration(String cacheName, String affKeyFie * @param params Engine parameters. */ private void createTableWithParams(final String params) { - executeDdl("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar" + + execute("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar" + ", \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache," + params + '"'); } @@ -629,7 +739,7 @@ private void createTableWithParams(final String params) { public void testCreateTableInNonPublicSchema() throws Exception { GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("CREATE TABLE \"cache_idx\".\"Person\" (\"id\" int, \"city\" varchar," + + execute("CREATE TABLE \"cache_idx\".\"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"template=cache\""); @@ -663,7 +773,7 @@ private void assertCreateTableWithParamsThrows(final String params, String expEr public void testDropTableNotPublicSchema() throws Exception { GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - executeDdl("DROP TABLE \"cache_idx\".\"Person\""); + execute("DROP TABLE \"cache_idx\".\"Person\""); return null; } @@ -675,8 +785,8 @@ public void testDropTableNotPublicSchema() throws Exception { * * @param sql Statement. */ - private void executeDdl(String sql) { - executeDdl(client(), sql); + private void execute(String sql) { + execute(client(), sql); } /** @@ -755,7 +865,7 @@ private IgniteConfiguration commonConfiguration(int idx) throws Exception { * @param node Node. * @param sql Statement. */ - private void executeDdl(Ignite node, String sql) { + private void execute(Ignite node, String sql) { queryProcessor(node).querySqlFieldsNoCache(new SqlFieldsQuery(sql).setSchema("PUBLIC"), true); }