From e03c7b552ea11e89f47ad4c3a34b076855e77487 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Thu, 1 Jun 2017 13:16:23 +0300 Subject: [PATCH 1/4] IGNITE-5327 PARTITIONED and REPLICATED cache templates --- .../processors/query/GridQueryProcessor.java | 20 ++++++++---- .../cache/index/H2DynamicTableSelfTest.java | 32 ++++++++++++++++++- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index fef7d4c18997a..dbc8c1d74667c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -1284,16 +1284,24 @@ else if (op instanceof SchemaIndexDropOperation) { @SuppressWarnings("unchecked") public void dynamicTableCreate(String schemaName, QueryEntity entity, String templateCacheName, boolean ifNotExists) throws IgniteCheckedException { - CacheConfiguration templateCfg = ctx.cache().getConfigFromTemplate(templateCacheName); + CacheConfiguration newCfg; - if (templateCfg == null) - throw new SchemaOperationException(SchemaOperationException.CODE_CACHE_NOT_FOUND, templateCacheName); + CacheConfiguration templateCfg = ctx.cache().getConfigFromTemplate(templateCacheName); - if (!F.isEmpty(templateCfg.getQueryEntities())) + if (templateCfg == null) { + if ("PARTITIONED".equals(templateCacheName)) + newCfg = new CacheConfiguration<>().setCacheMode(CacheMode.PARTITIONED); + else if ("REPLICATED".equals(templateCacheName)) + newCfg = new CacheConfiguration<>().setCacheMode(CacheMode.REPLICATED); + else + throw new SchemaOperationException(SchemaOperationException.CODE_CACHE_NOT_FOUND, templateCacheName); + } + else if (!F.isEmpty(templateCfg.getQueryEntities())) { throw new SchemaOperationException("Template cache already contains query entities which it should not " + "[cacheName=" + templateCacheName + ']'); - - CacheConfiguration newCfg = new CacheConfiguration<>(templateCfg); + } + else + newCfg = new CacheConfiguration<>(templateCfg); newCfg.setName(entity.getTableName()); newCfg.setQueryEntities(Collections.singleton(entity)); 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 4d74bacc2d4e5..da189b4bcf0de 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 @@ -92,9 +92,36 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { * @throws Exception if failed. */ public void testCreateTable() throws Exception { + doTestCreateTable(CACHE_NAME, null); + } + + /** + * Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code REPLICATED} cache, + * H2 table and type descriptor on all nodes. + * @throws Exception if failed. + */ + public void testCreateTableReplicated() throws Exception { + doTestCreateTable("REPLICATED", CacheMode.REPLICATED); + } + + /** + * Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code PARTITIONED} cache, + * H2 table and type descriptor on all nodes. + * @throws Exception if failed. + */ + public void testCreateTablePartitioned() throws Exception { + doTestCreateTable("PARTITIONED", CacheMode.PARTITIONED); + } + + /** + * + * @param tplCacheName + * @param mode + */ + private void doTestCreateTable(String tplCacheName, CacheMode mode) { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"cacheTemplate=cache\"")); + "\"cacheTemplate=" + tplCacheName + "\"")); for (int i = 0; i < 4; i++) { IgniteEx node = grid(i); @@ -107,6 +134,9 @@ public void testCreateTable() throws Exception { assertTrue(cacheDesc.sql()); + if (mode != null) + assertEquals(mode, cacheDesc.cacheConfiguration().getCacheMode()); + QueryTypeDescriptorImpl desc = typeExisting(node, "Person", "Person"); assertEquals(Object.class, desc.keyClass()); From e48a32451cdae40d543e43376ad65d6647808c73 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Thu, 1 Jun 2017 13:18:43 +0300 Subject: [PATCH 2/4] Added javadoc to a test. --- .../processors/cache/index/H2DynamicTableSelfTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 da189b4bcf0de..fafd538c607f8 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 @@ -114,9 +114,10 @@ public void testCreateTablePartitioned() throws Exception { } /** - * - * @param tplCacheName - * @param mode + * 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. + * @param tplCacheName Template cache name. + * @param mode Expected cache mode, or {@code null} if no check is needed. */ private void doTestCreateTable(String tplCacheName, CacheMode mode) { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + From 6c024e696dd00ccd45e3c07850632c6c57e7186b Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Fri, 2 Jun 2017 12:55:01 +0300 Subject: [PATCH 3/4] IGNITE-5327 Review fixes --- .../processors/query/GridQueryProcessor.java | 11 ++++-- .../query/h2/sql/GridSqlQueryParser.java | 38 ++++++++----------- .../cache/index/H2DynamicTableSelfTest.java | 31 ++++++++++++++- 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index fcd7e7d76b429..6e04b21a0e959 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -71,6 +71,7 @@ import org.apache.ignite.internal.util.lang.GridClosureException; import org.apache.ignite.internal.util.lang.IgniteOutClosureX; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.util.typedef.T3; @@ -1287,21 +1288,25 @@ else if (op instanceof SchemaIndexDropOperation) { * * @param schemaName Schema name to create table in. * @param entity Entity to create table from. - * @param templateCacheName Cache name to take settings from. + * @param templateCacheName Cache name to take settings from, if {@code null}, + * a new {@code PARTITIONED} cache will be created. * @param ifNotExists Quietly ignore this command if table already exists. * @throws IgniteCheckedException If failed. */ @SuppressWarnings("unchecked") public void dynamicTableCreate(String schemaName, QueryEntity entity, String templateCacheName, boolean ifNotExists) throws IgniteCheckedException { + // Use PARTITIONED as template cache name if no actual name is given. + templateCacheName = U.firstNotNull(templateCacheName, CacheMode.PARTITIONED.name()); + CacheConfiguration newCfg; CacheConfiguration templateCfg = ctx.cache().getConfigFromTemplate(templateCacheName); if (templateCfg == null) { - if ("PARTITIONED".equals(templateCacheName)) + if (CacheMode.PARTITIONED.name().equalsIgnoreCase(templateCacheName)) newCfg = new CacheConfiguration<>().setCacheMode(CacheMode.PARTITIONED); - else if ("REPLICATED".equals(templateCacheName)) + else if (CacheMode.REPLICATED.name().equalsIgnoreCase(templateCacheName)) newCfg = new CacheConfiguration<>().setCacheMode(CacheMode.REPLICATED); else throw new SchemaOperationException(SchemaOperationException.CODE_CACHE_NOT_FOUND, templateCacheName); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java index f310e0f133f26..52494e9a5864a 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java @@ -29,6 +29,7 @@ import java.util.Map; import javax.cache.CacheException; import org.apache.ignite.IgniteException; +import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cache.QueryIndex; import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; @@ -397,11 +398,6 @@ public class GridSqlQueryParser { /** */ private static final String PARAM_CACHE_TEMPLATE = "cacheTemplate"; - /** Names of the params that need to be present in WITH clause of CREATE TABLE. */ - private static final String[] MANDATORY_CREATE_TABLE_PARAMS = { - PARAM_CACHE_TEMPLATE - }; - /** */ private final IdentityHashMap h2ObjToGridObj = new IdentityHashMap<>(); @@ -948,31 +944,27 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { res.params(extraParams); - Map params = new HashMap<>(); + if (F.isEmpty(extraParams)) + return res; - if (!F.isEmpty(extraParams)) { - for (String p : extraParams) { - String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR); + Map params = new HashMap<>(); - if (parts.length > 2) - throw new IgniteSQLException("Invalid param syntax: key[=value] expected [paramStr=" + p + ']', - IgniteQueryErrorCode.PARSING); + for (String p : extraParams) { + String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR); - String name = parts[0]; + if (parts.length > 2) + throw new IgniteSQLException("Invalid param syntax: key[=value] expected [paramStr=" + p + ']', + IgniteQueryErrorCode.PARSING); - String val = parts.length > 1 ? parts[1] : null; + String name = parts[0]; - if (F.isEmpty(name)) - throw new IgniteSQLException("Invalid param syntax: no name given [paramStr=" + p + ']', - IgniteQueryErrorCode.PARSING); + String val = parts.length > 1 ? parts[1] : null; - params.put(name, val); - } - } + if (F.isEmpty(name)) + throw new IgniteSQLException("Invalid param syntax: no name given [paramStr=" + p + ']', + IgniteQueryErrorCode.PARSING); - for (String mandParamName : MANDATORY_CREATE_TABLE_PARAMS) { - if (!params.containsKey(mandParamName)) - throw new IgniteSQLException("Mandatory param is missing [paramName=" + mandParamName + ']'); + params.put(name, val); } for (Map.Entry e : params.entrySet()) 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 fafd538c607f8..7b9b897e7754d 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 @@ -113,6 +113,33 @@ public void testCreateTablePartitioned() throws Exception { doTestCreateTable("PARTITIONED", CacheMode.PARTITIONED); } + /** + * Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code REPLICATED} cache, + * H2 table and type descriptor on all nodes. + * @throws Exception if failed. + */ + public void testCreateTableReplicatedCaseInsensitive() throws Exception { + doTestCreateTable("replicated", CacheMode.REPLICATED); + } + + /** + * Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code PARTITIONED} cache, + * H2 table and type descriptor on all nodes. + * @throws Exception if failed. + */ + public void testCreateTablePartitionedCaseInsensitive() throws Exception { + doTestCreateTable("partitioned", CacheMode.PARTITIONED); + } + + /** + * Test that {@code CREATE TABLE} with reserved template cache name actually creates new {@code PARTITIONED} cache, + * H2 table and type descriptor on all nodes, when no cache template name is given. + * @throws Exception if failed. + */ + public void testCreateTableNoTemplate() throws Exception { + doTestCreateTable(null, CacheMode.PARTITIONED); + } + /** * 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. @@ -121,8 +148,8 @@ public void testCreateTablePartitioned() throws Exception { */ private void doTestCreateTable(String tplCacheName, CacheMode mode) { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + - " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"cacheTemplate=" + tplCacheName + "\"")); + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\"))" + + (F.isEmpty(tplCacheName) ? "" : " WITH \"cacheTemplate=" + tplCacheName + "\""))); for (int i = 0; i < 4; i++) { IgniteEx node = grid(i); From 8c26864fa20216fecd6edd586af47dc5c29a20e1 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Fri, 2 Jun 2017 15:01:08 +0300 Subject: [PATCH 4/4] Removed obsolete test check. --- .../internal/processors/query/h2/sql/GridQueryParsingTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java index b66a34369d0b5..aa3d7462e922c 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java @@ -598,9 +598,6 @@ false, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), assertParseThrows("create table Person (id int primary key)", IgniteSQLException.class, "No cache value related columns found"); - assertParseThrows("create table Person (id int primary key, age int null)", - IgniteSQLException.class, "Mandatory param is missing [paramName=cacheTemplate]"); - assertParseThrows("create table Person (id int primary key, age int not null) WITH \"cacheTemplate=cache\"", IgniteSQLException.class, "Non nullable columns are forbidden");