From aa48bab0848e776754638bce07097b16006cd548 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Fri, 21 Apr 2017 19:05:06 +0300 Subject: [PATCH 01/21] IGNITE-5052 CREATE TABLE first steps --- .../cache/query/IgniteQueryErrorCode.java | 6 + .../query/h2/sql/GridSqlCreateTable.java | 130 ++++++++++++++++ .../query/h2/sql/GridSqlQueryParser.java | 147 ++++++++++++++++++ 3 files changed, 283 insertions(+) create mode 100644 modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java index d05c9fd311484..2b3ae02c7c8c6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java @@ -36,6 +36,12 @@ public final class IgniteQueryErrorCode { /** Requested operation is not supported. */ public final static int UNSUPPORTED_OPERATION = 1002; + /** Command param requires value but none is given. */ + public final static int EMPTY_PARAM_VALUE = 1003; + + /** Unknown param specified. */ + public final static int UNKNOWN_PARAM = 1004; + /* 2xxx - analysis errors */ /** Code encountered SQL statement of some type that it did not expect in current analysis context. */ diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java new file mode 100644 index 0000000000000..c71057253bf9b --- /dev/null +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.ignite.internal.processors.query.h2.sql; + +import java.util.LinkedHashMap; +import org.h2.command.Parser; + +/** + * CREATE TABLE statement. + */ +public class GridSqlCreateTable extends GridSqlStatement { + /** Schema name. */ + private String schemaName; + + /** New schema name. */ + private String newSchemaName; + + /** New cache name. */ + private String newCacheName; + + /** Table name. */ + private String tblName; + + /** Cache name upon which new cache configuration for this table must be based. */ + private String tplCacheName; + + /** Columns. */ + private LinkedHashMap cols; + + /** Affinity column name. */ + private String affColName; + + /** Key class name. */ + private String keyCls; + + /** Value class name. */ + private String valCls; + + public String affinityColumnName() { + return affColName; + } + + public void affinityColumnName(String affColName) { + this.affColName = affColName; + } + + public String templateCacheName() { + return tplCacheName; + } + + public void templateCacheName(String tplCacheName) { + this.tplCacheName = tplCacheName; + } + + public LinkedHashMap columns() { + return cols; + } + + public void columns(LinkedHashMap cols) { + this.cols = cols; + } + + public String newCacheName() { + return newCacheName; + } + + public void newCacheName(String newCacheName) { + this.newCacheName = newCacheName; + } + + public String newSchemaName() { + return newSchemaName; + } + + public void newSchemaName(String newSchemaName) { + this.newSchemaName = newSchemaName; + } + + public String schemaName() { + return schemaName; + } + + public void schemaName(String schemaName) { + this.schemaName = schemaName; + } + + public String tableName() { + return tblName; + } + + public void tableName(String tblName) { + this.tblName = tblName; + } + + public String keyClass() { + return keyCls; + } + + public void keyClass(String keyCls) { + this.keyCls = keyCls; + } + + public String valueClass() { + return valCls; + } + + public void valueClass(String valCls) { + this.valCls = valCls; + } + + /** {@inheritDoc} */ + @Override public String getSQL() { + return "CREATE TABLE " + Parser.quoteIdentifier(schemaName); + } +} 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 199a15726701f..a5dee1471d2e1 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 @@ -32,10 +32,14 @@ import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.util.typedef.F; import org.h2.command.Command; import org.h2.command.CommandContainer; import org.h2.command.Prepared; import org.h2.command.ddl.CreateIndex; +import org.h2.command.ddl.CreateTable; +import org.h2.command.ddl.CreateTableData; +import org.h2.command.ddl.DefineCommand; import org.h2.command.ddl.DropIndex; import org.h2.command.ddl.SchemaCommand; import org.h2.command.dml.Delete; @@ -352,6 +356,61 @@ public class GridSqlQueryParser { /** */ private static final Getter SCHEMA_COMMAND_SCHEMA = getter(SchemaCommand.class, "schema"); + /** */ + private static final Getter CREATE_TABLE_DATA = getter(CreateTable.class, "data"); + + /** */ + private static final Getter> CREATE_TABLE_CONSTRAINTS = + getter(CreateTable.class, "constraintCommands"); + + /** */ + private static final Getter CREATE_TABLE_PK = getter(CreateTable.class, + "pkColumns"); + + /** */ + private static final Getter CREATE_TABLE_IF_NOT_EXISTS = getter(CreateTable.class, + "ifNotExists"); + + /** */ + private static final Getter CREATE_TABLE_QUERY = getter(CreateTable.class, "asQuery"); + + /** */ + private static final Getter CREATE_TABLE_ON_COMMIT_DROP = getter(CreateTable.class, + "onCommitDrop"); + + /** */ + private static final Getter CREATE_TABLE_ON_COMMIT_TRUNCATE = getter(CreateTable.class, + "onCommitTruncate"); + + /** */ + private static final Getter CREATE_TABLE_SORTED_INSERT = getter(CreateTable.class, + "sortedInsertMode"); + + /** */ + private static final Getter CREATE_TABLE_COMMENT = getter(CreateTable.class, + "comment"); + + /** */ + private static final String PARAM_NAME_VALUE_SEPARATOR = "="; + + /** */ + private static final String PARAM_TPL_CACHE = "tplCache"; + + /** */ + private static final String PARAM_NEW_SCHEMA = "newSchemaName"; + + /** */ + private static final String PARAM_NEW_CACHE = "newCacheName"; + + /** */ + private static final String PARAM_AFF_COL = "affColumn"; + + /** */ + private static final String PARAM_KEY_CLS = "keyCls"; + + /** */ + private static final String PARAM_VAL_CLS = "valCls"; + /** */ private final IdentityHashMap h2ObjToGridObj = new IdentityHashMap<>(); @@ -776,6 +835,91 @@ private GridSqlCreateIndex parseCreateIndex(CreateIndex createIdx) { return res; } + /** + * Parse {@code CREATE TABLE} statement. + * + * @param createTbl {@code CREATE TABLE} statement. + * @see H2 {@code CREATE TABLE} spec. + */ + private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { + GridSqlCreateTable res = new GridSqlCreateTable(); + + CreateTableData data = CREATE_TABLE_DATA.get(createTbl); + + String schemaName = data.schema.getName(); + + LinkedHashMap cols = new LinkedHashMap<>(data.columns.size()); + + for (Column col : data.columns) + cols.put(col.getName(), new GridSqlColumn(col, null, col.getName())); + + res.columns(cols); + + res.schemaName(schemaName); + + res.tableName(data.tableName); + + List extraParams = data.tableEngineParams; + + for (String p : extraParams) { + String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR); + + if (parts.length > 2) + throw new IgniteSQLException(""); + + String name = parts[0]; + + String val = parts.length > 1 ? parts[1] : null; + + if (F.isEmpty(name)) + throw new IgniteSQLException(""); + + processExtraParam(name, val, res); + } + + return res; + } + + /** + * @param name Param name. + * @param val Param value. + * @param res Table params to update. + */ + private static void processExtraParam(String name, String val, GridSqlCreateTable res) { + assert !F.isEmpty(name); + + switch (name) { + case PARAM_TPL_CACHE: + ensureParamValueNotEmpty(PARAM_TPL_CACHE, val); + + res.templateCacheName(val); + + break; + + case PARAM_AFF_COL: + ensureParamValueNotEmpty(PARAM_AFF_COL, val); + + res.affinityColumnName(val); + + break; + + default: + throw new IgniteSQLException("Unknown CREATE TABLE param [paramName=" + name + ']', + IgniteQueryErrorCode.UNKNOWN_PARAM); + } + } + + /** + * Check that param with mandatory value has it specified. + * @param name Param name. + * @param val Param value to check. + */ + private static void ensureParamValueNotEmpty(String name, String val) { + if (F.isEmpty(val)) + throw new IgniteSQLException("No value has been given for a CREATE TABLE param [paramName=" + name + ']', + IgniteQueryErrorCode.EMPTY_PARAM_VALUE); + } + /** * @param sortOrder Sort order. * @param qry Query. @@ -845,6 +989,9 @@ public final GridSqlStatement parse(Prepared stmt) { if (stmt instanceof DropIndex) return parseDropIndex((DropIndex)stmt); + if (stmt instanceof CreateTable) + return parseCreateTable((CreateTable)stmt); + throw new CacheException("Unsupported SQL statement: " + stmt); } From 7f04ca5811e4680f75996b30a73c7987eec19a25 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Mon, 24 Apr 2017 20:20:22 +0300 Subject: [PATCH 02/21] IGNITE-5052 CREATE TABLE parsing contd --- .../cache/query/IgniteQueryErrorCode.java | 5 +- .../query/h2/sql/GridSqlQueryParser.java | 56 +++++++++++++++++-- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java index 2b3ae02c7c8c6..9ac6b3b56bd90 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java @@ -40,7 +40,10 @@ public final class IgniteQueryErrorCode { public final static int EMPTY_PARAM_VALUE = 1003; /** Unknown param specified. */ - public final static int UNKNOWN_PARAM = 1004; + public final static int UNKNOWN_PARAM_NAME = 1004; + + /** Invalid syntax of param key-value pair. */ + public final static int INVALID_PARAM_SYNTAX = 1004; /* 2xxx - analysis errors */ 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 a5dee1471d2e1..aec89e8655ca2 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 @@ -411,6 +411,10 @@ public class GridSqlQueryParser { /** */ private static final String PARAM_VAL_CLS = "valCls"; + private static final String[] MANDATORY_CREATE_TABLE_PARAMS = { + PARAM_TPL_CACHE + }; + /** */ private final IdentityHashMap h2ObjToGridObj = new IdentityHashMap<>(); @@ -859,24 +863,36 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { res.tableName(data.tableName); - List extraParams = data.tableEngineParams; + List extraParamsStr = data.tableEngineParams; + + Map params = new HashMap<>(); - for (String p : extraParams) { + for (String p : extraParamsStr) { String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR); if (parts.length > 2) - throw new IgniteSQLException(""); + throw new IgniteSQLException("Invalid param syntax: key[=value] expected [paramStr=" + p + ']', + IgniteQueryErrorCode.INVALID_PARAM_SYNTAX); String name = parts[0]; String val = parts.length > 1 ? parts[1] : null; if (F.isEmpty(name)) - throw new IgniteSQLException(""); + throw new IgniteSQLException("Invalid param syntax: no name given [paramStr=" + p + ']', + IgniteQueryErrorCode.INVALID_PARAM_SYNTAX); + + params.put(name, val); + } - processExtraParam(name, val, res); + for (String mandParamName : MANDATORY_CREATE_TABLE_PARAMS) { + if (!params.containsKey(mandParamName)) + throw new IgniteSQLException("Mandatory param is missing [paramName=" + mandParamName + ']'); } + for (Map.Entry e : params.entrySet()) + processExtraParam(e.getKey(), e.getValue(), res); + return res; } @@ -903,9 +919,37 @@ private static void processExtraParam(String name, String val, GridSqlCreateTabl break; + case PARAM_KEY_CLS: + ensureParamValueNotEmpty(PARAM_KEY_CLS, val); + + res.keyClass(val); + + break; + + case PARAM_VAL_CLS: + ensureParamValueNotEmpty(PARAM_VAL_CLS, val); + + res.valueClass(val); + + break; + + case PARAM_NEW_CACHE: + ensureParamValueNotEmpty(PARAM_NEW_CACHE, val); + + res.newCacheName(val); + + break; + + case PARAM_NEW_SCHEMA: + ensureParamValueNotEmpty(PARAM_NEW_SCHEMA, val); + + res.newSchemaName(val); + + break; + default: throw new IgniteSQLException("Unknown CREATE TABLE param [paramName=" + name + ']', - IgniteQueryErrorCode.UNKNOWN_PARAM); + IgniteQueryErrorCode.UNKNOWN_PARAM_NAME); } } From d6cdb6ab208e24c65e2bc5d6ea8c88344b3725d6 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Tue, 25 Apr 2017 18:11:37 +0300 Subject: [PATCH 03/21] IGNITE-5052 CREATE TABLE parsing contd --- .../operation/SchemaCreateTableOperation.java | 52 ++++++ .../query/h2/sql/GridSqlCreateTable.java | 113 +++++++----- .../query/h2/sql/GridSqlQueryParser.java | 82 +++------ .../cache/index/H2DynamicTableSelfTest.java | 166 ++++++++++++++++++ 4 files changed, 308 insertions(+), 105 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java create mode 100644 modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java new file mode 100644 index 0000000000000..a54a3d98e5857 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.ignite.internal.processors.query.schema.operation; + +import java.util.UUID; +import org.apache.ignite.cache.QueryEntity; +import org.apache.ignite.internal.util.tostring.GridToStringInclude; + +/** + * Schema create table operation. + */ +public class SchemaCreateTableOperation extends SchemaAbstractOperation { + /** */ + @GridToStringInclude + private final QueryEntity entity; + + private final String tplCacheName; + + /** Quietly ignore this command if table already exists. */ + private final boolean ifNotExists; + + /** + * Constructor. + * @param opId Operation ID. + * @param space Space. + * @param entity Query entity to create table from. + * @param tplCacheName Cache name to take settings from. + * @param ifNotExists Quietly ignore this command if table already exists. + */ + public SchemaCreateTableOperation(UUID opId, String space, QueryEntity entity, String tplCacheName, + boolean ifNotExists) { + super(opId, space); + this.entity = entity; + this.tplCacheName = tplCacheName; + this.ifNotExists = ifNotExists; + } +} diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java index c71057253bf9b..3f040a594facc 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java @@ -18,46 +18,42 @@ package org.apache.ignite.internal.processors.query.h2.sql; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import org.apache.ignite.cache.QueryEntity; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; +import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; +import org.apache.ignite.internal.util.typedef.F; import org.h2.command.Parser; +import org.h2.table.Column; +import org.h2.value.DataType; +import org.h2.value.Value; /** * CREATE TABLE statement. */ public class GridSqlCreateTable extends GridSqlStatement { - /** Schema name. */ + /** + * Schema name upon which this statement has been issued - not the name of the schema where this new table + * will be created. */ private String schemaName; - /** New schema name. */ - private String newSchemaName; - - /** New cache name. */ - private String newCacheName; - /** Table name. */ private String tblName; /** Cache name upon which new cache configuration for this table must be based. */ private String tplCacheName; + /** Quietly ignore this command if table already exists. */ + private boolean ifNotExists; + /** Columns. */ private LinkedHashMap cols; - /** Affinity column name. */ - private String affColName; - - /** Key class name. */ - private String keyCls; - - /** Value class name. */ - private String valCls; - - public String affinityColumnName() { - return affColName; - } - - public void affinityColumnName(String affColName) { - this.affColName = affColName; - } + /** Primary key columns. */ + private LinkedHashMap pkCols; public String templateCacheName() { return tplCacheName; @@ -75,20 +71,12 @@ public void columns(LinkedHashMap cols) { this.cols = cols; } - public String newCacheName() { - return newCacheName; - } - - public void newCacheName(String newCacheName) { - this.newCacheName = newCacheName; - } - - public String newSchemaName() { - return newSchemaName; + public LinkedHashMap primaryKeyColumns() { + return pkCols; } - public void newSchemaName(String newSchemaName) { - this.newSchemaName = newSchemaName; + public void primaryKeyColumns(LinkedHashMap pkCols) { + this.pkCols = pkCols; } public String schemaName() { @@ -107,24 +95,55 @@ public void tableName(String tblName) { this.tblName = tblName; } - public String keyClass() { - return keyCls; - } - - public void keyClass(String keyCls) { - this.keyCls = keyCls; + public boolean ifNotExists() { + return ifNotExists; } - public String valueClass() { - return valCls; - } - - public void valueClass(String valCls) { - this.valCls = valCls; + public void ifNotExists(boolean ifNotExists) { + this.ifNotExists = ifNotExists; } /** {@inheritDoc} */ @Override public String getSQL() { return "CREATE TABLE " + Parser.quoteIdentifier(schemaName); } + + /** + * Convert this statement to query entity and do Ignite specific sanity checks on the way. + * @return Query entity mimicking this SQL statement. + */ + public QueryEntity toQueryEntity() { + QueryEntity res = new QueryEntity(); + + res.setTableName(tableName()); + + if (columns().containsKey(IgniteH2Indexing.KEY_FIELD_NAME) || + columns().containsKey(IgniteH2Indexing.VAL_FIELD_NAME)) + throw new IgniteSQLException("Direct specification of _KEY and _VAL columns is forbidden", + IgniteQueryErrorCode.PARSING); + + for (Map.Entry e : columns().entrySet()) { + GridSqlColumn gridCol = e.getValue(); + + Column col = gridCol.column(); + + res.addQueryField(e.getKey(), DataType.getTypeClassName(col.getType()), null); + } + + if (F.isEmpty(pkCols)) + throw new IgniteSQLException("No PRIMARY KEY columns specified"); + + int valColsNum = res.getFields().size() - pkCols.size(); + + if (valColsNum == 0) + throw new IgniteSQLException("No cache value related columns found"); + + res.setKeyType(tableName() + "Key"); + + res.setValueType(tableName()); + + res.setKeyFields(pkCols.keySet()); + + return res; + } } 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 cf3846efa60e6..2488985c80c78 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 @@ -22,10 +22,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.cache.CacheException; import org.apache.ignite.IgniteException; import org.apache.ignite.cache.QueryIndex; @@ -386,31 +388,12 @@ public class GridSqlQueryParser { private static final Getter CREATE_TABLE_SORTED_INSERT = getter(CreateTable.class, "sortedInsertMode"); - /** */ - private static final Getter CREATE_TABLE_COMMENT = getter(CreateTable.class, - "comment"); - /** */ private static final String PARAM_NAME_VALUE_SEPARATOR = "="; /** */ private static final String PARAM_TPL_CACHE = "tplCache"; - /** */ - private static final String PARAM_NEW_SCHEMA = "newSchemaName"; - - /** */ - private static final String PARAM_NEW_CACHE = "newCacheName"; - - /** */ - private static final String PARAM_AFF_COL = "affColumn"; - - /** */ - private static final String PARAM_KEY_CLS = "keyCls"; - - /** */ - private static final String PARAM_VAL_CLS = "valCls"; - private static final String[] MANDATORY_CREATE_TABLE_PARAMS = { PARAM_TPL_CACHE }; @@ -854,19 +837,37 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { CreateTableData data = CREATE_TABLE_DATA.get(createTbl); - String schemaName = data.schema.getName(); + Set pkColNames = new HashSet<>(); + + IndexColumn[] pkIdxCols = CREATE_TABLE_PK.get(createTbl); + + for (IndexColumn pkCol : pkIdxCols) + pkColNames.add(pkCol.columnName); LinkedHashMap cols = new LinkedHashMap<>(data.columns.size()); - for (Column col : data.columns) - cols.put(col.getName(), new GridSqlColumn(col, null, col.getName())); + LinkedHashMap pkCols = new LinkedHashMap<>(); + + for (Column col : data.columns) { + if (!col.isNullable()) + throw new IgniteSQLException("Non nullable columns are forbidden", IgniteQueryErrorCode.PARSING); + + GridSqlColumn gridCol = new GridSqlColumn(col, null, col.getName()); + + if (pkColNames.contains(gridCol.columnName())) + pkCols.put(gridCol.columnName(), gridCol); + + cols.put(col.getName(), gridCol); + } res.columns(cols); - res.schemaName(schemaName); + res.primaryKeyColumns(pkCols); res.tableName(data.tableName); + res.ifNotExists(CREATE_TABLE_IF_NOT_EXISTS.get(createTbl)); + List extraParamsStr = data.tableEngineParams; Map params = new HashMap<>(); @@ -916,41 +917,6 @@ private static void processExtraParam(String name, String val, GridSqlCreateTabl break; - case PARAM_AFF_COL: - ensureParamValueNotEmpty(PARAM_AFF_COL, val); - - res.affinityColumnName(val); - - break; - - case PARAM_KEY_CLS: - ensureParamValueNotEmpty(PARAM_KEY_CLS, val); - - res.keyClass(val); - - break; - - case PARAM_VAL_CLS: - ensureParamValueNotEmpty(PARAM_VAL_CLS, val); - - res.valueClass(val); - - break; - - case PARAM_NEW_CACHE: - ensureParamValueNotEmpty(PARAM_NEW_CACHE, val); - - res.newCacheName(val); - - break; - - case PARAM_NEW_SCHEMA: - ensureParamValueNotEmpty(PARAM_NEW_SCHEMA, val); - - res.newSchemaName(val); - - break; - default: throw new IgniteSQLException("Unknown CREATE TABLE param [paramName=" + name + ']', IgniteQueryErrorCode.UNKNOWN_PARAM_NAME); 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 new file mode 100644 index 0000000000000..bf54d8d70d147 --- /dev/null +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.ignite.internal.processors.cache.index; + +import java.util.Arrays; +import java.util.List; +import org.apache.ignite.Ignition; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cache.CacheWriteSynchronizationMode; +import org.apache.ignite.cache.QueryEntity; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.binary.BinaryMarshaller; +import org.apache.ignite.internal.processors.query.GridQueryProcessor; +import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; +import org.apache.ignite.internal.processors.query.h2.sql.GridSqlCreateTable; +import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.h2.engine.Session; +import org.h2.jdbc.JdbcConnection; + +/** + * Zzz + */ +public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { + /** Client node index. */ + private final static int CLIENT = 2; + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + for (IgniteConfiguration cfg : configurations()) + Ignition.start(cfg); + + client().createCache(cacheConfiguration()); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + stopAllGrids(); + + super.afterTestsStopped(); + } + + /** */ + public void testCreateTableLocal() throws Exception { + GridSqlCreateTable stmt = parse("CREATE TABLE IF NOT EXISTS \"cache\".Person (id int PRIMARY KEY, city varchar," + + " name varchar, surname varchar, age int) WITH \"tplCache=cache\""); + + QueryEntity entity = stmt.toQueryEntity(); + } + + /** + * Get configurations to be used in test. + * + * @return Configurations. + * @throws Exception If failed. + */ + private List configurations() throws Exception { + return Arrays.asList( + serverConfiguration(0), + serverConfiguration(1), + clientConfiguration(2), + serverConfiguration(3) + ); + } + + /** + * Create server configuration. + * + * @param idx Index. + * @return Configuration. + * @throws Exception If failed. + */ + private IgniteConfiguration serverConfiguration(int idx) throws Exception { + return commonConfiguration(idx); + } + + /** + * Create client configuration. + * + * @param idx Index. + * @return Configuration. + * @throws Exception If failed. + */ + private IgniteConfiguration clientConfiguration(int idx) throws Exception { + return commonConfiguration(idx).setClientMode(true); + } + + /** + * Create common node configuration. + * + * @param idx Index. + * @return Configuration. + * @throws Exception If failed. + */ + private IgniteConfiguration commonConfiguration(int idx) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(getTestIgniteInstanceName(idx)); + + cfg.setMarshaller(new BinaryMarshaller()); + + return optimize(cfg); + } + + /** + * @return Client node. + */ + private IgniteEx client() { + return grid(CLIENT); + } + + /** + * + */ + private JdbcConnection connection() throws Exception { + GridKernalContext ctx = client().context(); + + GridQueryProcessor qryProcessor = ctx.query(); + + IgniteH2Indexing idx = U.field(qryProcessor, "idx"); + + return (JdbcConnection)idx.connectionForSpace(CACHE_NAME); + } + + /** + * @param sql Sql. + */ + private GridSqlCreateTable parse(String sql) throws Exception { + Session ses = (Session)connection().getSession(); + + return (GridSqlCreateTable)new GridSqlQueryParser(false).parse(ses.prepare(sql)); + } + + /** + * @return Default cache configuration. + */ + private CacheConfiguration cacheConfiguration() { + CacheConfiguration ccfg = new CacheConfiguration<>(CACHE_NAME); + + ccfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); + ccfg.setSqlEscapeAll(true); + ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ccfg.setCacheMode(CacheMode.PARTITIONED); + + return ccfg; + } +} From 0be9b0877031bafda674949b13db6b3492bd8fe8 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Wed, 26 Apr 2017 11:14:29 +0300 Subject: [PATCH 04/21] IGNITE-5052 Dynamic local CREATE TABLE --- .../configuration/CacheConfiguration.java | 5 +- .../processors/query/GridQueryProcessor.java | 81 ++++++++++++++++--- .../operation/SchemaCreateTableOperation.java | 30 ++++++- .../query/h2/sql/GridSqlCreateTable.java | 10 +-- .../query/h2/sql/GridSqlQueryParser.java | 29 ++++--- .../cache/index/H2DynamicTableSelfTest.java | 23 +++++- 6 files changed, 143 insertions(+), 35 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java index 8a3874fb835ce..94db0552091ca 100644 --- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java @@ -1825,9 +1825,12 @@ public CacheConfiguration setPartitionLossPolicy(PartitionLossPolicy partL * @return {@code this} for chaining. */ public CacheConfiguration setQueryEntities(Collection qryEntities) { - if (this.qryEntities == null) + if (this.qryEntities == null) { this.qryEntities = new ArrayList<>(qryEntities); + return this; + } + for (QueryEntity entity : qryEntities) { boolean found = false; 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 448639b4d0483..7e263d1999497 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 @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.query; +import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteException; @@ -36,18 +37,8 @@ import org.apache.ignite.internal.NodeStoppingException; import org.apache.ignite.internal.processors.GridProcessorAdapter; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.CacheObjectContext; -import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor; -import org.apache.ignite.internal.processors.cache.GridCacheAdapter; -import org.apache.ignite.internal.processors.cache.GridCacheContext; -import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; -import org.apache.ignite.internal.processors.cache.KeyCacheObject; -import org.apache.ignite.internal.processors.cache.QueryCursorImpl; -import org.apache.ignite.internal.processors.cache.query.CacheQueryFuture; -import org.apache.ignite.internal.processors.cache.query.CacheQueryType; -import org.apache.ignite.internal.processors.cache.query.GridCacheQueryType; -import org.apache.ignite.internal.processors.cache.query.QueryCursorEx; +import org.apache.ignite.internal.processors.cache.*; +import org.apache.ignite.internal.processors.cache.query.*; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitor; import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitorImpl; @@ -62,6 +53,7 @@ import org.apache.ignite.internal.processors.query.schema.message.SchemaOperationStatusMessage; import org.apache.ignite.internal.processors.query.schema.message.SchemaProposeDiscoveryMessage; import org.apache.ignite.internal.processors.query.schema.operation.SchemaAbstractOperation; +import org.apache.ignite.internal.processors.query.schema.operation.SchemaCreateTableOperation; import org.apache.ignite.internal.processors.query.schema.operation.SchemaIndexCreateOperation; import org.apache.ignite.internal.processors.query.schema.operation.SchemaIndexDropOperation; import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; @@ -1250,6 +1242,11 @@ else if (op instanceof SchemaIndexDropOperation) { idx.dynamicIndexDrop(space, op0.indexName(), op0.ifExists()); } + else if (op instanceof SchemaCreateTableOperation) { + SchemaCreateTableOperation op0 = (SchemaCreateTableOperation) op; + + dynamicTableCreate(op0.entity(), op0.templateCacheName(), op0.ifNotExists()); + } else throw new SchemaOperationException("Unsupported operation: " + op); } @@ -1261,6 +1258,66 @@ else if (op instanceof SchemaIndexDropOperation) { } } + /** + * Create cache and table from given query entity. + * + * @param entity Entity to create table from. + * @param tplCacheName Cache name to take settings from. + * @param ifNotExists Quietly ignore this command if table already exists. + * @throws IgniteCheckedException If failed. + */ + @SuppressWarnings("unchecked") + private void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) + throws IgniteCheckedException { + IgniteInternalCache tplCache = ctx.cache().cache(tplCacheName); + + if (tplCache == null) + throw new IgniteSQLException("", IgniteQueryErrorCode.CACHE_NOT_FOUND); + + CacheConfiguration tplCfg = tplCache.configuration(); + + CacheConfiguration newCfg = new CacheConfiguration<>(tplCfg); + + newCfg.setName(entity.getTableName()); + + // setQueryEntities actually and sadly does Collection.add, so we have to clear first + newCfg.getQueryEntities().clear(); + + newCfg.setQueryEntities(Collections.singleton(entity)); + + // We want to preserve user specified names as they are + newCfg.setSqlEscapeAll(true); + + IgniteCache res = ctx.grid().getOrCreateCache(newCfg); + + // Instead of interpreting error message, let's just check that configuration of new cache matches + // what we've just tried to create. + if (!ifNotExists) { + boolean chkRes; + + CacheConfiguration resCfg = res.getConfiguration(CacheConfiguration.class); + + if (resCfg.getQueryEntities().size() != 1) + chkRes = false; + else { + QueryEntity resEntity = resCfg.getQueryEntities().iterator().next(); + + chkRes = + F.eq(resEntity.getTableName(), entity.getTableName()) && + F.eq(resEntity.getFields(), entity.getFields()) && + F.eq(resEntity.getKeyType(), entity.getKeyType()) && + F.eq(resEntity.getFields(), entity.getFields()) && + F.eq(resEntity.getKeyFields(), entity.getKeyFields()) && + F.isEmpty(resEntity.getIndexes()) && + F.isEmpty(resEntity.getAliases()); + } + + if (!chkRes) + throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', + IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); + } + } + /** * Register cache in indexing SPI. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java index a54a3d98e5857..cc598239a4d7d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java @@ -20,15 +20,17 @@ import java.util.UUID; import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.internal.util.tostring.GridToStringInclude; +import org.apache.ignite.internal.util.typedef.internal.S; /** * Schema create table operation. */ public class SchemaCreateTableOperation extends SchemaAbstractOperation { - /** */ + /** Query entity to create table from. */ @GridToStringInclude private final QueryEntity entity; + /** Cache name to take settings from. */ private final String tplCacheName; /** Quietly ignore this command if table already exists. */ @@ -49,4 +51,30 @@ public SchemaCreateTableOperation(UUID opId, String space, QueryEntity entity, S this.tplCacheName = tplCacheName; this.ifNotExists = ifNotExists; } + + /** + * @return Query entity to create table from. + */ + public QueryEntity entity() { + return entity; + } + + /** + * @return tplCacheName Cache name to take settings from. + */ + public String templateCacheName() { + return tplCacheName; + } + + /** + * @return Quietly ignore this command if table already exists. + */ + public boolean ifNotExists() { + return ifNotExists; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(SchemaCreateTableOperation.class, this, "parent", super.toString()); + } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java index 3f040a594facc..a6bfc949aec9e 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java @@ -53,7 +53,7 @@ public class GridSqlCreateTable extends GridSqlStatement { private LinkedHashMap cols; /** Primary key columns. */ - private LinkedHashMap pkCols; + private LinkedHashSet pkCols; public String templateCacheName() { return tplCacheName; @@ -71,11 +71,11 @@ public void columns(LinkedHashMap cols) { this.cols = cols; } - public LinkedHashMap primaryKeyColumns() { + public LinkedHashSet primaryKeyColumns() { return pkCols; } - public void primaryKeyColumns(LinkedHashMap pkCols) { + public void primaryKeyColumns(LinkedHashSet pkCols) { this.pkCols = pkCols; } @@ -105,7 +105,7 @@ public void ifNotExists(boolean ifNotExists) { /** {@inheritDoc} */ @Override public String getSQL() { - return "CREATE TABLE " + Parser.quoteIdentifier(schemaName); + return "CREATE TABLE " + Parser.quoteIdentifier(tblName); } /** @@ -142,7 +142,7 @@ public QueryEntity toQueryEntity() { res.setValueType(tableName()); - res.setKeyFields(pkCols.keySet()); + res.setKeyFields(pkCols); return res; } 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 2488985c80c78..3ba0669231515 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 @@ -22,12 +22,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.IdentityHashMap; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import javax.cache.CacheException; import org.apache.ignite.IgniteException; import org.apache.ignite.cache.QueryIndex; @@ -835,31 +834,35 @@ private GridSqlCreateIndex parseCreateIndex(CreateIndex createIdx) { private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { GridSqlCreateTable res = new GridSqlCreateTable(); - CreateTableData data = CREATE_TABLE_DATA.get(createTbl); - - Set pkColNames = new HashSet<>(); + Schema schema = SCHEMA_COMMAND_SCHEMA.get(createTbl); - IndexColumn[] pkIdxCols = CREATE_TABLE_PK.get(createTbl); + res.schemaName(schema.getName()); - for (IndexColumn pkCol : pkIdxCols) - pkColNames.add(pkCol.columnName); + CreateTableData data = CREATE_TABLE_DATA.get(createTbl); LinkedHashMap cols = new LinkedHashMap<>(data.columns.size()); - LinkedHashMap pkCols = new LinkedHashMap<>(); - for (Column col : data.columns) { if (!col.isNullable()) throw new IgniteSQLException("Non nullable columns are forbidden", IgniteQueryErrorCode.PARSING); GridSqlColumn gridCol = new GridSqlColumn(col, null, col.getName()); - if (pkColNames.contains(gridCol.columnName())) - pkCols.put(gridCol.columnName(), gridCol); - cols.put(col.getName(), gridCol); } + IndexColumn[] pkIdxCols = CREATE_TABLE_PK.get(createTbl); + + LinkedHashSet pkCols = new LinkedHashSet<>(); + + for (IndexColumn pkIdxCol : pkIdxCols) { + GridSqlColumn gridCol = cols.get(pkIdxCol.columnName); + + assert gridCol != null; + + pkCols.add(gridCol.columnName()); + } + res.columns(cols); res.primaryKeyColumns(pkCols); 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 bf54d8d70d147..38f64c48e61fb 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 @@ -19,6 +19,9 @@ import java.util.Arrays; import java.util.List; +import java.util.UUID; + +import org.apache.ignite.IgniteCache; import org.apache.ignite.Ignition; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; @@ -29,10 +32,12 @@ import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.binary.BinaryMarshaller; +import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.query.GridQueryProcessor; import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlCreateTable; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser; +import org.apache.ignite.internal.processors.query.schema.operation.SchemaCreateTableOperation; import org.apache.ignite.internal.util.typedef.internal.U; import org.h2.engine.Session; import org.h2.jdbc.JdbcConnection; @@ -51,7 +56,7 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { for (IgniteConfiguration cfg : configurations()) Ignition.start(cfg); - client().createCache(cacheConfiguration()); + client().getOrCreateCache(cacheConfiguration()); } /** {@inheritDoc} */ @@ -63,10 +68,15 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { /** */ public void testCreateTableLocal() throws Exception { - GridSqlCreateTable stmt = parse("CREATE TABLE IF NOT EXISTS \"cache\".Person (id int PRIMARY KEY, city varchar," + - " name varchar, surname varchar, age int) WITH \"tplCache=cache\""); + GridSqlCreateTable stmt = parse("CREATE TABLE IF NOT EXISTS Person (id int, city varchar," + + " name varchar, surname varchar, age int, PRIMARY KEY (id, city)) WITH \"tplCache=cache\""); QueryEntity entity = stmt.toQueryEntity(); + + SchemaCreateTableOperation op = new SchemaCreateTableOperation(UUID.randomUUID(), CACHE_NAME, entity, + stmt.templateCacheName(), stmt.ifNotExists()); + + queryProcessor(client()).processIndexOperationLocal(op, null, cache().context().dynamicDeploymentId(), null); } /** @@ -128,6 +138,13 @@ private IgniteEx client() { return grid(CLIENT); } + /** + * @return Client node. + */ + private IgniteInternalCache cache() { + return client().cachex(CACHE_NAME); + } + /** * */ From 6569d53e91ef698c7955939cbf3681ebaf68a6c2 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Wed, 26 Apr 2017 21:55:23 +0300 Subject: [PATCH 05/21] IGNITE-5052 CREATE/DROP TABLE + few tests --- .../processors/query/GridQueryProcessor.java | 41 +++++-- .../operation/SchemaCreateTableOperation.java | 80 ------------ .../query/h2/ddl/DdlStatementsProcessor.java | 69 ++++++++++- .../query/h2/sql/GridSqlCreateTable.java | 39 ------ .../query/h2/sql/GridSqlDropTable.java | 78 ++++++++++++ .../query/h2/sql/GridSqlQueryParser.java | 30 +++++ .../cache/index/H2DynamicTableSelfTest.java | 116 ++++++++++++++++-- 7 files changed, 313 insertions(+), 140 deletions(-) delete mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java create mode 100644 modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java 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 7e263d1999497..592793c1be2c8 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 @@ -53,7 +53,6 @@ import org.apache.ignite.internal.processors.query.schema.message.SchemaOperationStatusMessage; import org.apache.ignite.internal.processors.query.schema.message.SchemaProposeDiscoveryMessage; import org.apache.ignite.internal.processors.query.schema.operation.SchemaAbstractOperation; -import org.apache.ignite.internal.processors.query.schema.operation.SchemaCreateTableOperation; import org.apache.ignite.internal.processors.query.schema.operation.SchemaIndexCreateOperation; import org.apache.ignite.internal.processors.query.schema.operation.SchemaIndexDropOperation; import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; @@ -1242,11 +1241,6 @@ else if (op instanceof SchemaIndexDropOperation) { idx.dynamicIndexDrop(space, op0.indexName(), op0.ifExists()); } - else if (op instanceof SchemaCreateTableOperation) { - SchemaCreateTableOperation op0 = (SchemaCreateTableOperation) op; - - dynamicTableCreate(op0.entity(), op0.templateCacheName(), op0.ifNotExists()); - } else throw new SchemaOperationException("Unsupported operation: " + op); } @@ -1267,7 +1261,7 @@ else if (op instanceof SchemaCreateTableOperation) { * @throws IgniteCheckedException If failed. */ @SuppressWarnings("unchecked") - private void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) + public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) throws IgniteCheckedException { IgniteInternalCache tplCache = ctx.cache().cache(tplCacheName); @@ -1318,6 +1312,39 @@ private void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean } } + /** + * Drop table by destroying its cache if it's an 1:1 per cache table. + * + * @param schemaName Schema name. + * @param tblName Table name. + * @param ifExists Quietly ignore this command if table does not exist. + * @throws IgniteCheckedException If failed. + */ + @SuppressWarnings("unchecked") + public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) { + String spaceName = idx.space(schemaName); + + QueryTypeDescriptorImpl type = type(spaceName, tblName); + + if (type == null || !F.eq(schemaName, spaceName)) { + if (!ifExists) + throw new IgniteSQLException("Table not found [schemaName=" + schemaName + + ",tblName=" + tblName +']', IgniteQueryErrorCode.TABLE_NOT_FOUND); + + return; + } + + if (!F.eq(schemaName, tblName)) + throw new IgniteSQLException("Only dynamically created table can be dropped [schemaName=" + schemaName + + ",tblName=" + tblName +']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + IgniteCache cache = ctx.grid().cache(spaceName); + + assert cache != null; + + cache.destroy(); + } + /** * Register cache in indexing SPI. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java deleted file mode 100644 index cc598239a4d7d..0000000000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/operation/SchemaCreateTableOperation.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.apache.ignite.internal.processors.query.schema.operation; - -import java.util.UUID; -import org.apache.ignite.cache.QueryEntity; -import org.apache.ignite.internal.util.tostring.GridToStringInclude; -import org.apache.ignite.internal.util.typedef.internal.S; - -/** - * Schema create table operation. - */ -public class SchemaCreateTableOperation extends SchemaAbstractOperation { - /** Query entity to create table from. */ - @GridToStringInclude - private final QueryEntity entity; - - /** Cache name to take settings from. */ - private final String tplCacheName; - - /** Quietly ignore this command if table already exists. */ - private final boolean ifNotExists; - - /** - * Constructor. - * @param opId Operation ID. - * @param space Space. - * @param entity Query entity to create table from. - * @param tplCacheName Cache name to take settings from. - * @param ifNotExists Quietly ignore this command if table already exists. - */ - public SchemaCreateTableOperation(UUID opId, String space, QueryEntity entity, String tplCacheName, - boolean ifNotExists) { - super(opId, space); - this.entity = entity; - this.tplCacheName = tplCacheName; - this.ifNotExists = ifNotExists; - } - - /** - * @return Query entity to create table from. - */ - public QueryEntity entity() { - return entity; - } - - /** - * @return tplCacheName Cache name to take settings from. - */ - public String templateCacheName() { - return tplCacheName; - } - - /** - * @return Quietly ignore this command if table already exists. - */ - public boolean ifNotExists() { - return ifNotExists; - } - - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(SchemaCreateTableOperation.class, this, "parent", super.toString()); - } -} diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index 949ea6afe1561..a333e40ee0fdf 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.cache.QueryIndex; import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.internal.GridKernalContext; @@ -34,15 +35,23 @@ import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table; +import org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlCreateIndex; +import org.apache.ignite.internal.processors.query.h2.sql.GridSqlCreateTable; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlDropIndex; +import org.apache.ignite.internal.processors.query.h2.sql.GridSqlDropTable; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlStatement; import org.apache.ignite.internal.processors.query.schema.SchemaOperationException; +import org.apache.ignite.internal.util.typedef.F; import org.h2.command.Prepared; import org.h2.command.ddl.CreateIndex; +import org.h2.command.ddl.CreateTable; import org.h2.command.ddl.DropIndex; +import org.h2.command.ddl.DropTable; import org.h2.jdbc.JdbcPreparedStatement; +import org.h2.table.Column; +import org.h2.value.DataType; import static org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing.UPDATE_RESULT_META; @@ -128,11 +137,27 @@ else if (gridStmt instanceof GridSqlDropIndex) { fut = ctx.query().dynamicIndexDrop(spaceName, dropIdx.name(), dropIdx.ifExists()); } + else if (gridStmt instanceof GridSqlCreateTable) { + GridSqlCreateTable createTbl = (GridSqlCreateTable)gridStmt; + + ctx.query().dynamicTableCreate(toQueryEntity(createTbl), createTbl.templateCacheName(), + createTbl.ifNotExists()); + + fut = null; + } + else if (gridStmt instanceof GridSqlDropTable) { + GridSqlDropTable dropTbl = (GridSqlDropTable)gridStmt; + + ctx.query().dynamicTableDrop(dropTbl.schemaName(), dropTbl.tableName(), dropTbl.ifExists()); + + fut = null; + } else throw new IgniteSQLException("Unsupported DDL operation: " + sql, IgniteQueryErrorCode.UNSUPPORTED_OPERATION); - fut.get(); + if (fut != null) + fut.get(); QueryCursorImpl> resCur = (QueryCursorImpl>)new QueryCursorImpl(Collections.singletonList (Collections.singletonList(0L)), null, false); @@ -201,11 +226,51 @@ private IgniteSQLException convert(SchemaOperationException e) { return new IgniteSQLException(e.getMessage(), sqlCode); } + /** + * Convert this statement to query entity and do Ignite specific sanity checks on the way. + * @return Query entity mimicking this SQL statement. + */ + private static QueryEntity toQueryEntity(GridSqlCreateTable createTbl) { + QueryEntity res = new QueryEntity(); + + res.setTableName(createTbl.tableName()); + + if (createTbl.columns().containsKey(IgniteH2Indexing.KEY_FIELD_NAME) || + createTbl.columns().containsKey(IgniteH2Indexing.VAL_FIELD_NAME)) + throw new IgniteSQLException("Direct specification of _KEY and _VAL columns is forbidden", + IgniteQueryErrorCode.UNEXPECTED_OPERATION); + + for (Map.Entry e : createTbl.columns().entrySet()) { + GridSqlColumn gridCol = e.getValue(); + + Column col = gridCol.column(); + + res.addQueryField(e.getKey(), DataType.getTypeClassName(col.getType()), null); + } + + if (F.isEmpty(createTbl.primaryKeyColumns())) + throw new IgniteSQLException("No PRIMARY KEY columns specified"); + + int valColsNum = res.getFields().size() - createTbl.primaryKeyColumns().size(); + + if (valColsNum == 0) + throw new IgniteSQLException("No cache value related columns found"); + + res.setKeyType(createTbl.tableName() + "Key"); + + res.setValueType(createTbl.tableName()); + + res.setKeyFields(createTbl.primaryKeyColumns()); + + return res; + } + /** * @param cmd Statement. * @return Whether {@code cmd} is a DDL statement we're able to handle. */ public static boolean isDdlStatement(Prepared cmd) { - return cmd instanceof CreateIndex || cmd instanceof DropIndex; + return cmd instanceof CreateIndex || cmd instanceof DropIndex || cmd instanceof CreateTable || + cmd instanceof DropTable; } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java index a6bfc949aec9e..75b76beb3af45 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java @@ -107,43 +107,4 @@ public void ifNotExists(boolean ifNotExists) { @Override public String getSQL() { return "CREATE TABLE " + Parser.quoteIdentifier(tblName); } - - /** - * Convert this statement to query entity and do Ignite specific sanity checks on the way. - * @return Query entity mimicking this SQL statement. - */ - public QueryEntity toQueryEntity() { - QueryEntity res = new QueryEntity(); - - res.setTableName(tableName()); - - if (columns().containsKey(IgniteH2Indexing.KEY_FIELD_NAME) || - columns().containsKey(IgniteH2Indexing.VAL_FIELD_NAME)) - throw new IgniteSQLException("Direct specification of _KEY and _VAL columns is forbidden", - IgniteQueryErrorCode.PARSING); - - for (Map.Entry e : columns().entrySet()) { - GridSqlColumn gridCol = e.getValue(); - - Column col = gridCol.column(); - - res.addQueryField(e.getKey(), DataType.getTypeClassName(col.getType()), null); - } - - if (F.isEmpty(pkCols)) - throw new IgniteSQLException("No PRIMARY KEY columns specified"); - - int valColsNum = res.getFields().size() - pkCols.size(); - - if (valColsNum == 0) - throw new IgniteSQLException("No cache value related columns found"); - - res.setKeyType(tableName() + "Key"); - - res.setValueType(tableName()); - - res.setKeyFields(pkCols); - - return res; - } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java new file mode 100644 index 0000000000000..cb3fe740c827a --- /dev/null +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.ignite.internal.processors.query.h2.sql; + +/** + * CREATE TABLE statement. + */ +public class GridSqlDropTable extends GridSqlStatement { + /** Schema name. */ + private String schemaName; + + /** Table name. */ + private String tblName; + + /** Quietly ignore this command if table does not exist. */ + private boolean ifExists; + + /** + * @return Schema name. + */ + public String schemaName() { + return schemaName; + } + + /** + * @param schemaName Schema name. + */ + public void schemaName(String schemaName) { + this.schemaName = schemaName; + } + + /** + * @return Table name. + */ + public String tableName() { + return tblName; + } + + /** + * @param tblName Table name. + */ + public void tableName(String tblName) { + this.tblName = tblName; + } + + /** + * @return Quietly ignore this command if table does not exist. + */ + public boolean ifExists() { + return ifExists; + } + + /** + * @param ifExists Quietly ignore this command if table does not exist. + */ + public void ifExists(boolean ifExists) { + this.ifExists = ifExists; + } + + @Override public String getSQL() { + return null; + } +} 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 3ba0669231515..f7ec17b9a5c72 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 @@ -42,6 +42,7 @@ import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.DefineCommand; import org.h2.command.ddl.DropIndex; +import org.h2.command.ddl.DropTable; import org.h2.command.ddl.SchemaCommand; import org.h2.command.dml.Delete; import org.h2.command.dml.Explain; @@ -387,6 +388,12 @@ public class GridSqlQueryParser { private static final Getter CREATE_TABLE_SORTED_INSERT = getter(CreateTable.class, "sortedInsertMode"); + /** */ + private static final Getter DROP_TABLE_IF_EXISTS = getter(DropTable.class, "ifExists"); + + /** */ + private static final Getter DROP_TABLE_NAME = getter(DropTable.class, "tableName"); + /** */ private static final String PARAM_NAME_VALUE_SEPARATOR = "="; @@ -904,6 +911,26 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { return res; } + /** + * Parse {@code DROP TABLE} statement. + * + * @param dropTbl {@code DROP TABLE} statement. + * @see H2 {@code DROP TABLE} spec. + */ + private GridSqlDropTable parseDropTable(DropTable dropTbl) { + GridSqlDropTable res = new GridSqlDropTable(); + + Schema schema = SCHEMA_COMMAND_SCHEMA.get(dropTbl); + + res.schemaName(schema.getName()); + + res.ifExists(DROP_TABLE_IF_EXISTS.get(dropTbl)); + + res.tableName(DROP_TABLE_NAME.get(dropTbl)); + + return res; + } + /** * @param name Param name. * @param val Param value. @@ -1009,6 +1036,9 @@ public final GridSqlStatement parse(Prepared stmt) { if (stmt instanceof CreateTable) return parseCreateTable((CreateTable)stmt); + if (stmt instanceof DropTable) + return parseDropTable((DropTable) stmt); + throw new CacheException("Unsupported SQL statement: " + stmt); } 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 38f64c48e61fb..871456f78b24a 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 @@ -17,9 +17,10 @@ package org.apache.ignite.internal.processors.cache.index; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; -import java.util.UUID; import org.apache.ignite.IgniteCache; import org.apache.ignite.Ignition; @@ -27,17 +28,20 @@ import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cache.CacheWriteSynchronizationMode; import org.apache.ignite.cache.QueryEntity; +import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.binary.BinaryMarshaller; -import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.query.GridQueryProcessor; +import org.apache.ignite.internal.processors.query.GridQueryProperty; +import org.apache.ignite.internal.processors.query.QueryTypeDescriptorImpl; import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; +import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlCreateTable; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser; -import org.apache.ignite.internal.processors.query.schema.operation.SchemaCreateTableOperation; +import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.h2.engine.Session; import org.h2.jdbc.JdbcConnection; @@ -66,17 +70,99 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { super.afterTestsStopped(); } + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + client().destroyCache("Person"); + + super.afterTest(); + } + + /** */ + public void testCreateTable() throws Exception { + cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + + "\"tplCache=cache\"")); + + for (int i = 0; i < 4; i++) { + IgniteEx node = grid(i); + + assertNotNull(node.cache("Person")); + + QueryTypeDescriptorImpl desc = typeExisting(node, "Person", "Person"); + + assertEquals(Object.class, desc.keyClass()); + + assertEquals("PersonKey", desc.keyTypeName()); + + assertEquals(Object.class, desc.valueClass()); + + assertEquals("Person", desc.valueTypeName()); + + assertEquals( + F.asList("id", "city", "name", "surname", "age"), + new ArrayList<>(desc.fields().keySet()) + ); + + assertProperty(desc, "id", Integer.class, true); + + assertProperty(desc, "city", String.class, true); + + assertProperty(desc, "name", String.class, false); + + assertProperty(desc, "surname", String.class, false); + + assertProperty(desc, "age", Integer.class, false); + + GridH2Table tbl = ((IgniteH2Indexing)node.context().query().getIndexing()).dataTable("Person", "Person"); + + assertNotNull(tbl); + } + } + + /** */ + public void testCreateTableIfNotExists() throws Exception { + cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + + "\"tplCache=cache\"")); + + cache().query(new SqlFieldsQuery("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + + "\"tplCache=cache\"")); + } + /** */ - public void testCreateTableLocal() throws Exception { - GridSqlCreateTable stmt = parse("CREATE TABLE IF NOT EXISTS Person (id int, city varchar," + - " name varchar, surname varchar, age int, PRIMARY KEY (id, city)) WITH \"tplCache=cache\""); + public void testDropTable() throws Exception { + cache().query(new SqlFieldsQuery("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + + "\"tplCache=cache\"")); + + cache().query(new SqlFieldsQuery("DROP TABLE \"Person\".\"Person\"")); - QueryEntity entity = stmt.toQueryEntity(); + for (int i = 0; i < 4; i++) { + IgniteEx node = grid(i); - SchemaCreateTableOperation op = new SchemaCreateTableOperation(UUID.randomUUID(), CACHE_NAME, entity, - stmt.templateCacheName(), stmt.ifNotExists()); + assertNull(node.cache("Person")); - queryProcessor(client()).processIndexOperationLocal(op, null, cache().context().dynamicDeploymentId(), null); + QueryTypeDescriptorImpl desc = type(node, "Person", "Person"); + + assertNull(desc); + } + } + + /** */ + public void testDropTableIfExists() throws Exception { + cache().query(new SqlFieldsQuery("DROP TABLE IF EXISTS \"cache\".\"City\"")); + } + + /** */ + private void assertProperty(QueryTypeDescriptorImpl desc, String name, Class type, boolean isKey) { + GridQueryProperty p = desc.property(name); + + assertNotNull(name, p); + + assertEquals(type, p.type()); + + assertEquals(isKey, p.key()); } /** @@ -141,8 +227,8 @@ private IgniteEx client() { /** * @return Client node. */ - private IgniteInternalCache cache() { - return client().cachex(CACHE_NAME); + private IgniteCache cache() { + return client().cache(CACHE_NAME); } /** @@ -178,6 +264,12 @@ private CacheConfiguration cacheConfiguration() { ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); ccfg.setCacheMode(CacheMode.PARTITIONED); + ccfg.setQueryEntities(Collections.singletonList( + new QueryEntity() + .setKeyType(Integer.class.getName()) + .setValueType(Integer.class.getName()) + )); + return ccfg; } } From a7e409b5cea3513e9dcdc242fbde057a99ad84a4 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Thu, 27 Apr 2017 21:01:17 +0300 Subject: [PATCH 06/21] IGNITE-5052 GridSqlCreateTable.toSql --- .../query/h2/sql/GridSqlCreateTable.java | 98 +++++++++++++++++-- .../query/h2/sql/GridSqlQueryParser.java | 10 +- .../query/h2/sql/GridQueryParsingTest.java | 7 ++ 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java index 75b76beb3af45..aa8c725ab62c4 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java @@ -19,17 +19,11 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.Map; -import org.apache.ignite.cache.QueryEntity; -import org.apache.ignite.internal.GridKernalContext; -import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; -import org.apache.ignite.internal.processors.query.IgniteSQLException; -import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; +import java.util.List; +import org.apache.ignite.internal.util.GridStringBuilder; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.SB; import org.h2.command.Parser; -import org.h2.table.Column; -import org.h2.value.DataType; -import org.h2.value.Value; /** * CREATE TABLE statement. @@ -55,6 +49,9 @@ public class GridSqlCreateTable extends GridSqlStatement { /** Primary key columns. */ private LinkedHashSet pkCols; + /** Extra WITH-params. */ + private List params; + public String templateCacheName() { return tplCacheName; } @@ -103,8 +100,89 @@ public void ifNotExists(boolean ifNotExists) { this.ifNotExists = ifNotExists; } + public List params() { + return params; + } + + public void params(List params) { + this.params = params; + } + /** {@inheritDoc} */ @Override public String getSQL() { - return "CREATE TABLE " + Parser.quoteIdentifier(tblName); + GridStringBuilder b = new SB("CREATE TABLE ") + .a(ifNotExists ? "IF NOT EXISTS " : "") + .a("\n") + .a(Parser.quoteIdentifier(schemaName)) + .a('.') + .a(Parser.quoteIdentifier(tblName)) + .a("\n("); + + boolean singleColPk = false; + + boolean first = true; + + for (GridSqlColumn col : cols.values()) { + if (!first) + b.a(",\n"); + else + first = false; + + if (col.column().isPrimaryKey()) { + // Only one column may be marked PRIMARY KEY - multi-col PK is defined separately + assert !singleColPk; + + singleColPk = true; + } + + b.a('\t') + .a(col.getSQL()) + .a(' ') + .a(col.resultType().sql()) + .a(col.column().isPrimaryKey() ? " PRIMARY KEY" : ""); + } + + first = true; + + if (!singleColPk && !F.isEmpty(pkCols)) { + b.a(",\n") + .a('\t') + .a("PRIMARY KEY (\n"); + + for (String col : pkCols) { + GridSqlColumn pkCol = cols.get(col); + + assert pkCol != null; + + if (!first) + b.a(",\n"); + else + first = false; + + b.a("\t\t") + .a(pkCol.getSQL()); + } + + b.a("\n\t)"); + } + + b.a("\n)"); + + if (!F.isEmpty(params)) { + b.a("\nWITH "); + + first = true; + + for (String p : params) { + if (!first) + b.a(','); + else + first = false; + + b.a(Parser.quoteIdentifier(p)); + } + } + + return b.toString(); } } 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 f7ec17b9a5c72..bd3fb1c002883 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 @@ -33,7 +33,9 @@ import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.util.GridStringBuilder; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.SB; import org.h2.command.Command; import org.h2.command.CommandContainer; import org.h2.command.Prepared; @@ -855,6 +857,8 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { GridSqlColumn gridCol = new GridSqlColumn(col, null, col.getName()); + gridCol.resultType(GridSqlType.fromColumn(col)); + cols.put(col.getName(), gridCol); } @@ -878,11 +882,13 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { res.ifNotExists(CREATE_TABLE_IF_NOT_EXISTS.get(createTbl)); - List extraParamsStr = data.tableEngineParams; + List extraParams = data.tableEngineParams; + + res.params(extraParams); Map params = new HashMap<>(); - for (String p : extraParamsStr) { + for (String p : extraParams) { String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR); if (parts.length > 2) 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 9782f28c9ad53..7f507779bfa9a 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 @@ -544,6 +544,13 @@ public void testParseDropIndex() throws Exception { assertParseThrows("drop index if exists schema2.", DbException.class, null); } + /** */ + public void testParseCreateTable() throws Exception { + checkQuery("CREATE TABLE IF NOT EXISTS sch1.\"Person\" (\"id\" integer, \"city\" varchar," + + " \"name\" varchar, \"surname\" varchar, \"age\" integer, PRIMARY KEY (\"id\", \"city\")) WITH " + + "\"tplCache=cache\""); + } + /** * @param sql Statement. * @param exCls Exception class. From b740701d61f7728c78b117bb5edbc60f0cba46e9 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Fri, 28 Apr 2017 14:51:51 +0300 Subject: [PATCH 07/21] Post merge fix --- .../processors/query/h2/ddl/DdlStatementsProcessor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index a333e40ee0fdf..64a6c510d53dc 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -33,6 +33,7 @@ import org.apache.ignite.internal.processors.query.GridQueryProperty; import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.processors.query.QueryUtils; import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn; @@ -235,8 +236,8 @@ private static QueryEntity toQueryEntity(GridSqlCreateTable createTbl) { res.setTableName(createTbl.tableName()); - if (createTbl.columns().containsKey(IgniteH2Indexing.KEY_FIELD_NAME) || - createTbl.columns().containsKey(IgniteH2Indexing.VAL_FIELD_NAME)) + if (createTbl.columns().containsKey(QueryUtils.KEY_FIELD_NAME) || + createTbl.columns().containsKey(QueryUtils.VAL_FIELD_NAME)) throw new IgniteSQLException("Direct specification of _KEY and _VAL columns is forbidden", IgniteQueryErrorCode.UNEXPECTED_OPERATION); From dc5f68b9224adcaf1bdde2a6e2606d33a5549993 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Wed, 10 May 2017 22:03:01 +0300 Subject: [PATCH 08/21] IGNITE-5052 Review fixes --- .../processors/cache/GridCacheProcessor.java | 19 +++-- .../cache/query/IgniteQueryErrorCode.java | 12 +-- .../processors/query/GridQueryIndexing.java | 21 +++++ .../processors/query/GridQueryProcessor.java | 76 +---------------- .../processors/query/h2/IgniteH2Indexing.java | 84 +++++++++++++++++++ .../query/h2/sql/GridSqlQueryParser.java | 8 +- .../cache/index/H2DynamicTableSelfTest.java | 40 ++++----- 7 files changed, 147 insertions(+), 113 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index 87aaee0472d42..b3ff638931e68 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -2072,8 +2072,17 @@ public void completeStartFuture(DynamicCacheChangeRequest req) { assert fut == null || fut.deploymentId != null || req.globalStateChange() || req.resetLostPartitions(); if (fut != null && F.eq(fut.deploymentId(), req.deploymentId()) && - F.eq(req.initiatingNodeId(), ctx.localNodeId())) + F.eq(req.initiatingNodeId(), ctx.localNodeId())) { + /* + GridCacheContext cctx = ctx.cache().context().cacheContext(CU.cacheId(req.cacheName())); + + assert cctx != null; + + fut.onDone(cctx.dynamicDeploymentId()); + */ + fut.onDone(); + } } /** @@ -2563,7 +2572,7 @@ else if (dfltCacheCfg == null) * @return Future that will be completed when cache is deployed. */ @SuppressWarnings("IfMayBeConditional") - public IgniteInternalFuture dynamicStartCache( + public IgniteInternalFuture dynamicStartCache( @Nullable CacheConfiguration ccfg, String cacheName, @Nullable NearCacheConfiguration nearCfg, @@ -2593,7 +2602,7 @@ public IgniteInternalFuture dynamicStartCache( * @return Future that will be completed when cache is deployed. */ @SuppressWarnings("IfMayBeConditional") - public IgniteInternalFuture dynamicStartCache( + public IgniteInternalFuture dynamicStartCache( @Nullable CacheConfiguration ccfg, String cacheName, @Nullable NearCacheConfiguration nearCfg, @@ -4170,7 +4179,7 @@ public T clone(final T obj) throws IgniteCheckedException { * */ @SuppressWarnings("ExternalizableWithoutPublicNoArgConstructor") - private class DynamicCacheStartFuture extends GridFutureAdapter { + private class DynamicCacheStartFuture extends GridFutureAdapter { /** Start ID. */ @GridToStringInclude private IgniteUuid deploymentId; @@ -4208,7 +4217,7 @@ public DynamicCacheChangeRequest request() { } /** {@inheritDoc} */ - @Override public boolean onDone(@Nullable Object res, @Nullable Throwable err) { + @Override public boolean onDone(@Nullable IgniteUuid res, @Nullable Throwable err) { // Make sure to remove future before completion. pendingFuts.remove(req.requestId(), this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java index 9ac6b3b56bd90..99210fa2a70b4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java @@ -36,15 +36,6 @@ public final class IgniteQueryErrorCode { /** Requested operation is not supported. */ public final static int UNSUPPORTED_OPERATION = 1002; - /** Command param requires value but none is given. */ - public final static int EMPTY_PARAM_VALUE = 1003; - - /** Unknown param specified. */ - public final static int UNKNOWN_PARAM_NAME = 1004; - - /** Invalid syntax of param key-value pair. */ - public final static int INVALID_PARAM_SYNTAX = 1004; - /* 2xxx - analysis errors */ /** Code encountered SQL statement of some type that it did not expect in current analysis context. */ @@ -105,6 +96,9 @@ public final class IgniteQueryErrorCode { /** Cache not found. */ public final static int CACHE_NOT_FOUND = 4006; + /** Cache already contains query entities. */ + public final static int QUERY_ENTITIES_PRESENT = 4007; + /** */ private IgniteQueryErrorCode() { // No-op. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index 0afba59b82441..5f6593c53c50b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -24,6 +24,7 @@ import javax.cache.Cache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; +import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.cache.query.SqlQuery; @@ -122,6 +123,26 @@ public long streamUpdateQuery(final String spaceName, final String qry, public QueryCursor> queryLocalSql(GridCacheContext cctx, SqlQuery qry, IndexingQueryFilter filter, boolean keepBinary) throws IgniteCheckedException; + /** + * Create cache and table from given query entity. + * + * @param entity Entity to create table from. + * @param tplCacheName Cache name to take settings from. + * @param ifNotExists Quietly ignore this command if table already exists. + * @throws IgniteCheckedException If failed. + */ + public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) + throws IgniteCheckedException; + + /** + * Drop table by destroying its cache if it's an 1:1 per cache table. + * + * @param schemaName Schema name. + * @param tblName Table name. + * @param ifExists Quietly ignore this command if table does not exist. + */ + public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists); + /** * Executes text query. * 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 592793c1be2c8..1e72255ce196b 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 @@ -17,7 +17,6 @@ package org.apache.ignite.internal.processors.query; -import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteException; @@ -1262,54 +1261,8 @@ else if (op instanceof SchemaIndexDropOperation) { */ @SuppressWarnings("unchecked") public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) - throws IgniteCheckedException { - IgniteInternalCache tplCache = ctx.cache().cache(tplCacheName); - - if (tplCache == null) - throw new IgniteSQLException("", IgniteQueryErrorCode.CACHE_NOT_FOUND); - - CacheConfiguration tplCfg = tplCache.configuration(); - - CacheConfiguration newCfg = new CacheConfiguration<>(tplCfg); - - newCfg.setName(entity.getTableName()); - - // setQueryEntities actually and sadly does Collection.add, so we have to clear first - newCfg.getQueryEntities().clear(); - - newCfg.setQueryEntities(Collections.singleton(entity)); - - // We want to preserve user specified names as they are - newCfg.setSqlEscapeAll(true); - - IgniteCache res = ctx.grid().getOrCreateCache(newCfg); - - // Instead of interpreting error message, let's just check that configuration of new cache matches - // what we've just tried to create. - if (!ifNotExists) { - boolean chkRes; - - CacheConfiguration resCfg = res.getConfiguration(CacheConfiguration.class); - - if (resCfg.getQueryEntities().size() != 1) - chkRes = false; - else { - QueryEntity resEntity = resCfg.getQueryEntities().iterator().next(); - - chkRes = - F.eq(resEntity.getTableName(), entity.getTableName()) && - F.eq(resEntity.getFields(), entity.getFields()) && - F.eq(resEntity.getKeyType(), entity.getKeyType()) && - F.eq(resEntity.getFields(), entity.getFields()) && - F.eq(resEntity.getKeyFields(), entity.getKeyFields()) && - F.isEmpty(resEntity.getIndexes()) && - F.isEmpty(resEntity.getAliases()); - } - - if (!chkRes) - throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', - IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); - } + throws IgniteCheckedException { + getIndexing().dynamicTableCreate(entity, tplCacheName, ifNotExists); } /** @@ -1318,31 +1271,10 @@ public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean * @param schemaName Schema name. * @param tblName Table name. * @param ifExists Quietly ignore this command if table does not exist. - * @throws IgniteCheckedException If failed. */ @SuppressWarnings("unchecked") public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) { - String spaceName = idx.space(schemaName); - - QueryTypeDescriptorImpl type = type(spaceName, tblName); - - if (type == null || !F.eq(schemaName, spaceName)) { - if (!ifExists) - throw new IgniteSQLException("Table not found [schemaName=" + schemaName + - ",tblName=" + tblName +']', IgniteQueryErrorCode.TABLE_NOT_FOUND); - - return; - } - - if (!F.eq(schemaName, tblName)) - throw new IgniteSQLException("Only dynamically created table can be dropped [schemaName=" + schemaName + - ",tblName=" + tblName +']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); - - IgniteCache cache = ctx.grid().cache(spaceName); - - assert cache != null; - - cache.destroy(); + getIndexing().dynamicTableDrop(schemaName, tblName, ifExists); } /** @@ -2141,7 +2073,7 @@ public Collection types(@Nullable String space) { * @param tblName Table name. * @return Type (if any). */ - @Nullable private QueryTypeDescriptorImpl type(@Nullable String space, String tblName) { + @Nullable public QueryTypeDescriptorImpl type(@Nullable String space, String tblName) { for (QueryTypeDescriptorImpl type : types.values()) { if (F.eq(space, type.space()) && F.eq(tblName, type.tableName())) return type; diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index d62d7d8199cd0..9711a779dd091 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -55,10 +55,12 @@ import java.util.concurrent.atomic.AtomicLong; import javax.cache.Cache; import javax.cache.CacheException; +import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.cache.query.QueryCancelledException; import org.apache.ignite.cache.query.QueryCursor; @@ -79,6 +81,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheAffinityManager; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; +import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException; @@ -101,6 +104,7 @@ import org.apache.ignite.internal.processors.query.GridRunningQueryInfo; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.QueryIndexDescriptorImpl; +import org.apache.ignite.internal.processors.query.QueryTypeDescriptorImpl; import org.apache.ignite.internal.processors.query.h2.ddl.DdlStatementsProcessor; import org.apache.ignite.internal.processors.query.h2.opt.DistributedJoinMode; import org.apache.ignite.internal.processors.query.h2.database.H2PkHashIndex; @@ -856,6 +860,86 @@ private void addInitialUserIndex(String spaceName, TableDescriptor desc, GridH2I executeSql(spaceName, sql); } + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) + throws IgniteCheckedException { + IgniteInternalCache tplCache = ctx.cache().cache(tplCacheName); + + if (tplCache == null) + throw new IgniteSQLException("", IgniteQueryErrorCode.CACHE_NOT_FOUND); + + CacheConfiguration tplCfg = tplCache.configuration(); + + if (!F.isEmpty(tplCfg.getQueryEntities())) + throw new IgniteSQLException("Template cache already contains query entities which it should not " + + "[cacheName=" + tplCacheName + ']', IgniteQueryErrorCode.QUERY_ENTITIES_PRESENT); + + CacheConfiguration newCfg = new CacheConfiguration<>(tplCfg); + + newCfg.setName(entity.getTableName()); + + newCfg.setQueryEntities(Collections.singleton(entity)); + + // We want to preserve user specified names as they are + newCfg.setSqlEscapeAll(true); + + IgniteCache res = ctx.grid().getOrCreateCache(newCfg); + + // Instead of interpreting error message, let's just check that configuration of new cache matches + // what we've just tried to create. + if (!ifNotExists) { + boolean chkRes; + + CacheConfiguration resCfg = res.getConfiguration(CacheConfiguration.class); + + if (resCfg.getQueryEntities().size() != 1) + chkRes = false; + else { + QueryEntity resEntity = resCfg.getQueryEntities().iterator().next(); + + chkRes = + F.eq(resEntity.getTableName(), entity.getTableName()) && + F.eq(resEntity.getFields(), entity.getFields()) && + F.eq(resEntity.getKeyType(), entity.getKeyType()) && + F.eq(resEntity.getFields(), entity.getFields()) && + F.eq(resEntity.getKeyFields(), entity.getKeyFields()) && + F.isEmpty(resEntity.getIndexes()) && + F.isEmpty(resEntity.getAliases()); + } + + if (!chkRes) + throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', + IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); + } + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) { + String spaceName = space(schemaName); + + QueryTypeDescriptorImpl type = ctx.query().type(spaceName, tblName); + + if (type == null || !F.eq(schemaName, spaceName)) { + if (!ifExists) + throw new IgniteSQLException("Table not found [schemaName=" + schemaName + + ",tblName=" + tblName +']', IgniteQueryErrorCode.TABLE_NOT_FOUND); + + return; + } + + if (!F.eq(schemaName, tblName)) + throw new IgniteSQLException("Only dynamically created table can be dropped [schemaName=" + schemaName + + ",tblName=" + tblName +']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + IgniteCache cache = ctx.grid().cache(spaceName); + + assert cache != null; + + cache.destroy(); + } + /** * Execute DDL command. * 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 bd3fb1c002883..3fc7fcd59f962 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 @@ -893,7 +893,7 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { if (parts.length > 2) throw new IgniteSQLException("Invalid param syntax: key[=value] expected [paramStr=" + p + ']', - IgniteQueryErrorCode.INVALID_PARAM_SYNTAX); + IgniteQueryErrorCode.PARSING); String name = parts[0]; @@ -901,7 +901,7 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { if (F.isEmpty(name)) throw new IgniteSQLException("Invalid param syntax: no name given [paramStr=" + p + ']', - IgniteQueryErrorCode.INVALID_PARAM_SYNTAX); + IgniteQueryErrorCode.PARSING); params.put(name, val); } @@ -955,7 +955,7 @@ private static void processExtraParam(String name, String val, GridSqlCreateTabl default: throw new IgniteSQLException("Unknown CREATE TABLE param [paramName=" + name + ']', - IgniteQueryErrorCode.UNKNOWN_PARAM_NAME); + IgniteQueryErrorCode.PARSING); } } @@ -967,7 +967,7 @@ private static void processExtraParam(String name, String val, GridSqlCreateTabl private static void ensureParamValueNotEmpty(String name, String val) { if (F.isEmpty(val)) throw new IgniteSQLException("No value has been given for a CREATE TABLE param [paramName=" + name + ']', - IgniteQueryErrorCode.EMPTY_PARAM_VALUE); + IgniteQueryErrorCode.PARSING); } /** 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 871456f78b24a..18ee540cd6b97 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,9 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { /** Client node index. */ private final static int CLIENT = 2; + /** */ + private final static String INDEXED_CACHE_NAME = CACHE_NAME + "_idx"; + /** {@inheritDoc} */ @Override protected void beforeTestsStarted() throws Exception { super.beforeTestsStarted(); @@ -60,6 +63,8 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { for (IgniteConfiguration cfg : configurations()) Ignition.start(cfg); + client().getOrCreateCache(cacheConfigurationForIndexing()); + client().getOrCreateCache(cacheConfiguration()); } @@ -228,29 +233,7 @@ private IgniteEx client() { * @return Client node. */ private IgniteCache cache() { - return client().cache(CACHE_NAME); - } - - /** - * - */ - private JdbcConnection connection() throws Exception { - GridKernalContext ctx = client().context(); - - GridQueryProcessor qryProcessor = ctx.query(); - - IgniteH2Indexing idx = U.field(qryProcessor, "idx"); - - return (JdbcConnection)idx.connectionForSpace(CACHE_NAME); - } - - /** - * @param sql Sql. - */ - private GridSqlCreateTable parse(String sql) throws Exception { - Session ses = (Session)connection().getSession(); - - return (GridSqlCreateTable)new GridSqlQueryParser(false).parse(ses.prepare(sql)); + return client().cache(INDEXED_CACHE_NAME); } /** @@ -264,6 +247,17 @@ private CacheConfiguration cacheConfiguration() { ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); ccfg.setCacheMode(CacheMode.PARTITIONED); + return ccfg; + } + + /** + * @return Cache configuration with query entities - unfortunately, we need this to enable indexing at all. + */ + private CacheConfiguration cacheConfigurationForIndexing() { + CacheConfiguration ccfg = cacheConfiguration(); + + ccfg.setName(INDEXED_CACHE_NAME); + ccfg.setQueryEntities(Collections.singletonList( new QueryEntity() .setKeyType(Integer.class.getName()) From 888eb168685f6e63541ef7c3b096e32cae54fd4d Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Thu, 11 May 2017 14:31:15 +0300 Subject: [PATCH 09/21] IGNITE-5052 Review fixes - contd --- .../org/apache/ignite/internal/IgniteEx.java | 18 ++++++++++ .../apache/ignite/internal/IgniteKernal.java | 33 +++++++++++++++++++ .../processors/cache/GridCacheProcessor.java | 17 ++++------ .../processors/igfs/IgfsIgniteMock.java | 8 +++++ .../junits/multijvm/IgniteProcessProxy.java | 6 ++++ .../processors/query/h2/IgniteH2Indexing.java | 31 +++-------------- 6 files changed, 75 insertions(+), 38 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java index 421d6f911e241..218cd0cc60b00 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java @@ -18,13 +18,17 @@ package org.apache.ignite.internal; import java.util.Collection; +import javax.cache.CacheException; import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteFileSystem; import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.internal.cluster.IgniteClusterEx; import org.apache.ignite.internal.processors.cache.GridCacheUtilityKey; import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.hadoop.Hadoop; +import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgnitePredicate; import org.jetbrains.annotations.Nullable; @@ -59,6 +63,20 @@ public interface IgniteEx extends Ignite { */ public Collection> cachesx(@Nullable IgnitePredicate>... p); + /** + * Gets existing cache with the given name or creates new one with the given configuration. + *

+ * If a cache with the same name already exists, this method will not check that the given + * configuration matches the configuration of existing cache and will return an instance + * of the existing cache. + * + * @param cacheCfg Cache configuration to use. + * @return Tuple [Existing or newly created cache; {@code true} if cache was newly crated, {@code false} otherwise] + * @throws CacheException If error occurs. + */ + public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) + throws CacheException; + /** * Checks if the event type is user-recordable. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index 8ba6a886c8f4e..655361f4c7115 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -162,6 +162,7 @@ import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.SB; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteFuture; import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.lang.IgniteProductVersion; @@ -2816,6 +2817,38 @@ public IgniteInternalCache getCache(String name) { } } + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) { + A.notNull(cacheCfg, "cacheCfg"); + CU.validateCacheName(cacheCfg.getName()); + + guard(); + + try { + checkClusterState(); + + Boolean res = false; + + if (ctx.cache().cache(cacheCfg.getName()) == null) { + res = ctx.cache().dynamicStartCache(cacheCfg, + cacheCfg.getName(), + null, + false, + true, + true).get(); + } + + return new IgniteBiTuple<>((IgniteCache)ctx.cache().publicJCache(cacheCfg.getName()), res); + } + catch (IgniteCheckedException e) { + throw CU.convertToCacheException(e); + } + finally { + unguard(); + } + } + /** {@inheritDoc} */ @Override public Collection getOrCreateCaches(Collection cacheCfgs) { A.notNull(cacheCfgs, "cacheCfgs"); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index b3ff638931e68..2afffda0d77ea 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -2073,15 +2073,10 @@ public void completeStartFuture(DynamicCacheChangeRequest req) { if (fut != null && F.eq(fut.deploymentId(), req.deploymentId()) && F.eq(req.initiatingNodeId(), ctx.localNodeId())) { - /* - GridCacheContext cctx = ctx.cache().context().cacheContext(CU.cacheId(req.cacheName())); - assert cctx != null; - - fut.onDone(cctx.dynamicDeploymentId()); - */ + GridCacheContext cctx = ctx.cache().context().cacheContext(CU.cacheId(req.cacheName())); - fut.onDone(); + fut.onDone(cctx != null ? F.eq(cctx.dynamicDeploymentId(), req.deploymentId()) : null); } } @@ -2572,7 +2567,7 @@ else if (dfltCacheCfg == null) * @return Future that will be completed when cache is deployed. */ @SuppressWarnings("IfMayBeConditional") - public IgniteInternalFuture dynamicStartCache( + public IgniteInternalFuture dynamicStartCache( @Nullable CacheConfiguration ccfg, String cacheName, @Nullable NearCacheConfiguration nearCfg, @@ -2602,7 +2597,7 @@ public IgniteInternalFuture dynamicStartCache( * @return Future that will be completed when cache is deployed. */ @SuppressWarnings("IfMayBeConditional") - public IgniteInternalFuture dynamicStartCache( + public IgniteInternalFuture dynamicStartCache( @Nullable CacheConfiguration ccfg, String cacheName, @Nullable NearCacheConfiguration nearCfg, @@ -4179,7 +4174,7 @@ public T clone(final T obj) throws IgniteCheckedException { * */ @SuppressWarnings("ExternalizableWithoutPublicNoArgConstructor") - private class DynamicCacheStartFuture extends GridFutureAdapter { + private class DynamicCacheStartFuture extends GridFutureAdapter { /** Start ID. */ @GridToStringInclude private IgniteUuid deploymentId; @@ -4217,7 +4212,7 @@ public DynamicCacheChangeRequest request() { } /** {@inheritDoc} */ - @Override public boolean onDone(@Nullable IgniteUuid res, @Nullable Throwable err) { + @Override public boolean onDone(@Nullable Boolean res, @Nullable Throwable err) { // Make sure to remove future before completion. pendingFuts.remove(req.requestId(), this); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java index ecba1bf1dc6ce..a8314bdb6c72f 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java @@ -53,6 +53,7 @@ import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.hadoop.Hadoop; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.plugin.IgnitePlugin; @@ -319,6 +320,13 @@ public IgfsIgniteMock(@Nullable String name, IgniteFileSystem igfs) { return null; } + /** {@inheritDoc} */ + @Override public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) { + throwUnsupported(); + + return null; + } + /** {@inheritDoc} */ @Override public void addCacheConfiguration(CacheConfiguration cacheCfg) { throwUnsupported(); diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java index 26c86dc1642f1..c804bab3728a7 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java @@ -73,6 +73,7 @@ import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteCallable; import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgnitePredicate; @@ -532,6 +533,11 @@ public void kill() throws Exception { throw new UnsupportedOperationException("Operation isn't supported yet."); } + /** {@inheritDoc} */ + @Override public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) { + throw new UnsupportedOperationException("Operation isn't supported yet."); + } + /** {@inheritDoc} */ @Override public void destroyCache(String cacheName) { throw new UnsupportedOperationException("Operation isn't supported yet."); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 9711a779dd091..f890e3bc9bc3e 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -884,34 +884,11 @@ private void addInitialUserIndex(String spaceName, TableDescriptor desc, GridH2I // We want to preserve user specified names as they are newCfg.setSqlEscapeAll(true); - IgniteCache res = ctx.grid().getOrCreateCache(newCfg); + IgniteBiTuple, Boolean> res = ctx.grid().getOrCreateCache0(newCfg); - // Instead of interpreting error message, let's just check that configuration of new cache matches - // what we've just tried to create. - if (!ifNotExists) { - boolean chkRes; - - CacheConfiguration resCfg = res.getConfiguration(CacheConfiguration.class); - - if (resCfg.getQueryEntities().size() != 1) - chkRes = false; - else { - QueryEntity resEntity = resCfg.getQueryEntities().iterator().next(); - - chkRes = - F.eq(resEntity.getTableName(), entity.getTableName()) && - F.eq(resEntity.getFields(), entity.getFields()) && - F.eq(resEntity.getKeyType(), entity.getKeyType()) && - F.eq(resEntity.getFields(), entity.getFields()) && - F.eq(resEntity.getKeyFields(), entity.getKeyFields()) && - F.isEmpty(resEntity.getIndexes()) && - F.isEmpty(resEntity.getAliases()); - } - - if (!chkRes) - throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', - IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); - } + if (!ifNotExists && F.eq(res.get2(), false)) + throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', + IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); } /** {@inheritDoc} */ From 41e2f64cad6dfe33c28266281229b86b413e86a2 Mon Sep 17 00:00:00 2001 From: devozerov Date: Tue, 16 May 2017 11:56:40 +0300 Subject: [PATCH 10/21] Minors. --- .../src/main/java/org/apache/ignite/internal/IgniteKernal.java | 3 ++- .../apache/ignite/internal/processors/igfs/IgfsIgniteMock.java | 3 ++- .../testframework/junits/multijvm/IgniteProcessProxy.java | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index d1216bbf462e7..b3892d4123225 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -2819,7 +2819,8 @@ public IgniteInternalCache getCache(String name) { /** {@inheritDoc} */ @SuppressWarnings("unchecked") - @Override public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) { + @Override public IgniteBiTuple, Boolean> getOrCreateCache0( + CacheConfiguration cacheCfg) { A.notNull(cacheCfg, "cacheCfg"); CU.validateCacheName(cacheCfg.getName()); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java index a8314bdb6c72f..18e637def1001 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java @@ -321,7 +321,8 @@ public IgfsIgniteMock(@Nullable String name, IgniteFileSystem igfs) { } /** {@inheritDoc} */ - @Override public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) { + @Override public IgniteBiTuple, Boolean> getOrCreateCache0( + CacheConfiguration cacheCfg) { throwUnsupported(); return null; diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java index c804bab3728a7..a7fbb02c125fd 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java @@ -534,7 +534,8 @@ public void kill() throws Exception { } /** {@inheritDoc} */ - @Override public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) { + @Override public IgniteBiTuple, Boolean> getOrCreateCache0( + CacheConfiguration cacheCfg) { throw new UnsupportedOperationException("Operation isn't supported yet."); } From 588093fd8db6ef8aae8b6e53f289a100dbe26853 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Tue, 16 May 2017 19:16:44 +0300 Subject: [PATCH 11/21] IGNITE-5052 Review fixes. --- .../apache/ignite/internal/IgniteKernal.java | 26 +------- .../processors/cache/GridCacheProcessor.java | 2 +- .../cache/query/IgniteQueryErrorCode.java | 3 - .../processors/query/GridQueryIndexing.java | 20 ------- .../processors/query/GridQueryProcessor.java | 60 +++++++++++++++++-- .../processors/query/h2/IgniteH2Indexing.java | 57 ------------------ .../query/h2/ddl/DdlStatementsProcessor.java | 13 ---- .../query/h2/sql/GridSqlDropTable.java | 11 ++-- .../query/h2/sql/GridSqlQueryParser.java | 34 ++++++----- 9 files changed, 84 insertions(+), 142 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index b3892d4123225..7d1d6f69429bc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -2790,31 +2790,7 @@ public IgniteInternalCache getCache(String name) { /** {@inheritDoc} */ @Override public IgniteCache getOrCreateCache(CacheConfiguration cacheCfg) { - A.notNull(cacheCfg, "cacheCfg"); - CU.validateCacheName(cacheCfg.getName()); - - guard(); - - try { - checkClusterState(); - - if (ctx.cache().cache(cacheCfg.getName()) == null) { - ctx.cache().dynamicStartCache(cacheCfg, - cacheCfg.getName(), - null, - false, - true, - true).get(); - } - - return ctx.cache().publicJCache(cacheCfg.getName()); - } - catch (IgniteCheckedException e) { - throw CU.convertToCacheException(e); - } - finally { - unguard(); - } + return getOrCreateCache0(cacheCfg).get1(); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index 2afffda0d77ea..e5787949c9aee 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -2488,7 +2488,7 @@ public IgniteInternalFuture getOrCreateFromTemplate(String cacheName, boolean * @return Cache configuration. * @throws IgniteCheckedException If failed. */ - private CacheConfiguration createConfigFromTemplate(String cacheName) throws IgniteCheckedException { + public CacheConfiguration createConfigFromTemplate(String cacheName) throws IgniteCheckedException { CacheConfiguration cfgTemplate = null; CacheConfiguration dfltCacheCfg = null; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java index 99210fa2a70b4..d05c9fd311484 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java @@ -96,9 +96,6 @@ public final class IgniteQueryErrorCode { /** Cache not found. */ public final static int CACHE_NOT_FOUND = 4006; - /** Cache already contains query entities. */ - public final static int QUERY_ENTITIES_PRESENT = 4007; - /** */ private IgniteQueryErrorCode() { // No-op. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index 20a4d29c3ba9f..17cc4f9cfa00a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -123,26 +123,6 @@ public QueryCursor> queryLocalSql(GridCacheContext public QueryCursor> queryLocalSqlFields(GridCacheContext cctx, SqlFieldsQuery qry, IndexingQueryFilter filter, GridQueryCancel cancel) throws IgniteCheckedException; - /** - * Create cache and table from given query entity. - * - * @param entity Entity to create table from. - * @param tplCacheName Cache name to take settings from. - * @param ifNotExists Quietly ignore this command if table already exists. - * @throws IgniteCheckedException If failed. - */ - public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) - throws IgniteCheckedException; - - /** - * Drop table by destroying its cache if it's an 1:1 per cache table. - * - * @param schemaName Schema name. - * @param tblName Table name. - * @param ifExists Quietly ignore this command if table does not exist. - */ - public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists); - /** * Executes text query. * 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 bf71d9c0a337c..40305f69e9430 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 @@ -17,6 +17,7 @@ package org.apache.ignite.internal.processors.query; +import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteException; @@ -36,8 +37,20 @@ import org.apache.ignite.internal.NodeStoppingException; import org.apache.ignite.internal.processors.GridProcessorAdapter; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.*; -import org.apache.ignite.internal.processors.cache.query.*; +import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor; +import org.apache.ignite.internal.processors.cache.GridCacheAdapter; +import org.apache.ignite.internal.processors.cache.GridCacheContext; +import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; +import org.apache.ignite.internal.processors.cache.IgniteInternalCache; +import org.apache.ignite.internal.processors.cache.KeyCacheObject; +import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.internal.processors.cache.query.CacheQueryFuture; +import org.apache.ignite.internal.processors.cache.query.CacheQueryType; +import org.apache.ignite.internal.processors.cache.query.GridCacheQueryType; +import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; +import org.apache.ignite.internal.processors.cache.query.QueryCursorEx; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitor; import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitorImpl; @@ -1262,7 +1275,26 @@ else if (op instanceof SchemaIndexDropOperation) { @SuppressWarnings("unchecked") public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) throws IgniteCheckedException { - getIndexing().dynamicTableCreate(entity, tplCacheName, ifNotExists); + CacheConfiguration tplCfg = ctx.cache().createConfigFromTemplate(tplCacheName); + + if (!F.isEmpty(tplCfg.getQueryEntities())) + throw new IgniteSQLException("Template cache already contains query entities which it should not " + + "[cacheName=" + tplCacheName + ']', IgniteQueryErrorCode.UNKNOWN); + + CacheConfiguration newCfg = new CacheConfiguration<>(tplCfg); + + newCfg.setName(entity.getTableName()); + + newCfg.setQueryEntities(Collections.singleton(entity)); + + // We want to preserve user specified names as they are + newCfg.setSqlEscapeAll(true); + + IgniteBiTuple, Boolean> res = ctx.grid().getOrCreateCache0(newCfg); + + if (!ifNotExists && F.eq(res.get2(), false)) + throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', + IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); } /** @@ -1274,7 +1306,27 @@ public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean */ @SuppressWarnings("unchecked") public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) { - getIndexing().dynamicTableDrop(schemaName, tblName, ifExists); + String spaceName = getIndexing().space(schemaName); + + QueryTypeDescriptorImpl type = type(spaceName, tblName); + + if (type == null || !F.eq(schemaName, spaceName)) { + if (!ifExists) + throw new IgniteSQLException("Table not found [schemaName=" + schemaName + + ",tblName=" + tblName +']', IgniteQueryErrorCode.TABLE_NOT_FOUND); + + return; + } + + if (!F.eq(schemaName, tblName)) + throw new IgniteSQLException("Only dynamically created table can be dropped [schemaName=" + schemaName + + ",tblName=" + tblName +']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + IgniteCache cache = ctx.grid().cache(spaceName); + + assert cache != null; + + cache.destroy(); } /** diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 604661e7f96ec..56f77d52da7a0 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -858,63 +858,6 @@ private void addInitialUserIndex(String spaceName, TableDescriptor desc, GridH2I executeSql(spaceName, sql); } - /** {@inheritDoc} */ - @SuppressWarnings("unchecked") - @Override public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) - throws IgniteCheckedException { - IgniteInternalCache tplCache = ctx.cache().cache(tplCacheName); - - if (tplCache == null) - throw new IgniteSQLException("", IgniteQueryErrorCode.CACHE_NOT_FOUND); - - CacheConfiguration tplCfg = tplCache.configuration(); - - if (!F.isEmpty(tplCfg.getQueryEntities())) - throw new IgniteSQLException("Template cache already contains query entities which it should not " + - "[cacheName=" + tplCacheName + ']', IgniteQueryErrorCode.QUERY_ENTITIES_PRESENT); - - CacheConfiguration newCfg = new CacheConfiguration<>(tplCfg); - - newCfg.setName(entity.getTableName()); - - newCfg.setQueryEntities(Collections.singleton(entity)); - - // We want to preserve user specified names as they are - newCfg.setSqlEscapeAll(true); - - IgniteBiTuple, Boolean> res = ctx.grid().getOrCreateCache0(newCfg); - - if (!ifNotExists && F.eq(res.get2(), false)) - throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', - IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); - } - - /** {@inheritDoc} */ - @SuppressWarnings("unchecked") - @Override public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) { - String spaceName = space(schemaName); - - QueryTypeDescriptorImpl type = ctx.query().type(spaceName, tblName); - - if (type == null || !F.eq(schemaName, spaceName)) { - if (!ifExists) - throw new IgniteSQLException("Table not found [schemaName=" + schemaName + - ",tblName=" + tblName +']', IgniteQueryErrorCode.TABLE_NOT_FOUND); - - return; - } - - if (!F.eq(schemaName, tblName)) - throw new IgniteSQLException("Only dynamically created table can be dropped [schemaName=" + schemaName + - ",tblName=" + tblName +']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); - - IgniteCache cache = ctx.grid().cache(spaceName); - - assert cache != null; - - cache.destroy(); - } - /** * Execute DDL command. * diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index 64a6c510d53dc..e4d1b1f0dce7b 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -236,11 +236,6 @@ private static QueryEntity toQueryEntity(GridSqlCreateTable createTbl) { res.setTableName(createTbl.tableName()); - if (createTbl.columns().containsKey(QueryUtils.KEY_FIELD_NAME) || - createTbl.columns().containsKey(QueryUtils.VAL_FIELD_NAME)) - throw new IgniteSQLException("Direct specification of _KEY and _VAL columns is forbidden", - IgniteQueryErrorCode.UNEXPECTED_OPERATION); - for (Map.Entry e : createTbl.columns().entrySet()) { GridSqlColumn gridCol = e.getValue(); @@ -249,14 +244,6 @@ private static QueryEntity toQueryEntity(GridSqlCreateTable createTbl) { res.addQueryField(e.getKey(), DataType.getTypeClassName(col.getType()), null); } - if (F.isEmpty(createTbl.primaryKeyColumns())) - throw new IgniteSQLException("No PRIMARY KEY columns specified"); - - int valColsNum = res.getFields().size() - createTbl.primaryKeyColumns().size(); - - if (valColsNum == 0) - throw new IgniteSQLException("No cache value related columns found"); - res.setKeyType(createTbl.tableName() + "Key"); res.setValueType(createTbl.tableName()); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java index cb3fe740c827a..4782b2ba00e9e 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java @@ -18,7 +18,7 @@ package org.apache.ignite.internal.processors.query.h2.sql; /** - * CREATE TABLE statement. + * DROP TABLE statement. */ public class GridSqlDropTable extends GridSqlStatement { /** Schema name. */ @@ -27,7 +27,7 @@ public class GridSqlDropTable extends GridSqlStatement { /** Table name. */ private String tblName; - /** Quietly ignore this command if table does not exist. */ + /** Quietly ignore this command if table already exists. */ private boolean ifExists; /** @@ -59,19 +59,20 @@ public void tableName(String tblName) { } /** - * @return Quietly ignore this command if table does not exist. + * @return Quietly ignore this command if table already exists. */ public boolean ifExists() { return ifExists; } /** - * @param ifExists Quietly ignore this command if table does not exist. + * @param ifExists Quietly ignore this command if table already exists. */ public void ifExists(boolean ifExists) { this.ifExists = ifExists; } - + + /** {@inheritDoc} */ @Override public String getSQL() { return null; } 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 3fc7fcd59f962..b26118a0892ac 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 @@ -33,9 +33,8 @@ import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; import org.apache.ignite.internal.processors.query.IgniteSQLException; -import org.apache.ignite.internal.util.GridStringBuilder; +import org.apache.ignite.internal.processors.query.QueryUtils; import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.internal.util.typedef.internal.SB; import org.h2.command.Command; import org.h2.command.CommandContainer; import org.h2.command.Prepared; @@ -378,18 +377,6 @@ public class GridSqlQueryParser { /** */ private static final Getter CREATE_TABLE_QUERY = getter(CreateTable.class, "asQuery"); - /** */ - private static final Getter CREATE_TABLE_ON_COMMIT_DROP = getter(CreateTable.class, - "onCommitDrop"); - - /** */ - private static final Getter CREATE_TABLE_ON_COMMIT_TRUNCATE = getter(CreateTable.class, - "onCommitTruncate"); - - /** */ - private static final Getter CREATE_TABLE_SORTED_INSERT = getter(CreateTable.class, - "sortedInsertMode"); - /** */ private static final Getter DROP_TABLE_IF_EXISTS = getter(DropTable.class, "ifExists"); @@ -843,6 +830,12 @@ private GridSqlCreateIndex parseCreateIndex(CreateIndex createIdx) { private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { GridSqlCreateTable res = new GridSqlCreateTable(); + Query qry = CREATE_TABLE_QUERY.get(createTbl); + + if (qry != null) + throw new IgniteSQLException("CREATE TABLE ... AS ... syntax is not supported", + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + Schema schema = SCHEMA_COMMAND_SCHEMA.get(createTbl); res.schemaName(schema.getName()); @@ -862,6 +855,11 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { cols.put(col.getName(), gridCol); } + if (cols.containsKey(QueryUtils.KEY_FIELD_NAME) || + cols.containsKey(QueryUtils.VAL_FIELD_NAME)) + throw new IgniteSQLException("Direct specification of _KEY and _VAL columns is forbidden", + IgniteQueryErrorCode.PARSING); + IndexColumn[] pkIdxCols = CREATE_TABLE_PK.get(createTbl); LinkedHashSet pkCols = new LinkedHashSet<>(); @@ -874,6 +872,14 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { pkCols.add(gridCol.columnName()); } + if (F.isEmpty(pkCols)) + throw new IgniteSQLException("No PRIMARY KEY columns specified"); + + int valColsNum = cols.size() - pkCols.size(); + + if (valColsNum == 0) + throw new IgniteSQLException("No cache value related columns found"); + res.columns(cols); res.primaryKeyColumns(pkCols); From eef106ff955cd24884d60536bcc97797ec613b6c Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Wed, 17 May 2017 19:09:55 +0300 Subject: [PATCH 12/21] IGNITE-5052 Review fixes. --- .../org/apache/ignite/internal/IgniteEx.java | 16 ++++++- .../apache/ignite/internal/IgniteKernal.java | 16 +++++-- .../cache/CacheAffinitySharedManager.java | 2 + .../cache/DynamicCacheChangeRequest.java | 17 +++++++ .../cache/DynamicCacheDescriptor.java | 17 +++++++ .../GridCachePartitionExchangeManager.java | 4 +- .../processors/cache/GridCacheProcessor.java | 46 +++++++++++++++---- .../GridDhtPartitionsExchangeFuture.java | 2 +- .../DataStructuresProcessor.java | 1 + .../processors/query/GridQueryIndexing.java | 9 ++++ .../processors/query/GridQueryProcessor.java | 4 +- .../processors/igfs/IgfsIgniteMock.java | 10 +++- .../junits/multijvm/IgniteProcessProxy.java | 8 +++- .../processors/query/h2/IgniteH2Indexing.java | 11 +++++ 14 files changed, 140 insertions(+), 23 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java index 218cd0cc60b00..775f49341d133 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java @@ -71,11 +71,23 @@ public interface IgniteEx extends Ignite { * of the existing cache. * * @param cacheCfg Cache configuration to use. + * @param sql {@code true} if this call is triggered by SQL command {@code CREATE TABLE}, {@code false} otherwise. * @return Tuple [Existing or newly created cache; {@code true} if cache was newly crated, {@code false} otherwise] * @throws CacheException If error occurs. */ - public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) - throws CacheException; + public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg, + boolean sql) throws CacheException; + + /** + * Stops dynamically started cache. + * + * @param cacheName Cache name to stop. + * @param sql {@code true} if only cache created with SQL command {@code CREATE TABLE} should be affected, + * {@code false} otherwise. + * @return {@code true} if cache has been stopped as the result of this call, {@code false} otherwise. + * @throws CacheException If error occurs. + */ + public boolean destroyCache0(String cacheName, boolean sql) throws CacheException; /** * Checks if the event type is user-recordable. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index 7d1d6f69429bc..8cff9dafa831d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -46,6 +46,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import javax.cache.CacheException; import javax.management.JMException; import javax.management.ObjectName; import org.apache.ignite.IgniteAtomicLong; @@ -2790,13 +2791,13 @@ public IgniteInternalCache getCache(String name) { /** {@inheritDoc} */ @Override public IgniteCache getOrCreateCache(CacheConfiguration cacheCfg) { - return getOrCreateCache0(cacheCfg).get1(); + return getOrCreateCache0(cacheCfg, false).get1(); } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public IgniteBiTuple, Boolean> getOrCreateCache0( - CacheConfiguration cacheCfg) { + CacheConfiguration cacheCfg, boolean sql) { A.notNull(cacheCfg, "cacheCfg"); CU.validateCacheName(cacheCfg.getName()); @@ -3016,12 +3017,17 @@ private void checkNearCacheStarted(IgniteCacheProxy cache) throws IgniteCh /** {@inheritDoc} */ @Override public void destroyCache(String cacheName) { + destroyCache0(cacheName, false); + } + + /** {@inheritDoc} */ + @Override public boolean destroyCache0(String cacheName, boolean sql) throws CacheException { CU.validateCacheName(cacheName); - IgniteInternalFuture stopFut = destroyCacheAsync(cacheName, true); + IgniteInternalFuture stopFut = destroyCacheAsync(cacheName, true); try { - stopFut.get(); + return stopFut.get(); } catch (IgniteCheckedException e) { throw CU.convertToCacheException(e); @@ -3047,7 +3053,7 @@ private void checkNearCacheStarted(IgniteCacheProxy cache) throws IgniteCh * @param checkThreadTx If {@code true} checks that current thread does not have active transactions. * @return Ignite future. */ - public IgniteInternalFuture destroyCacheAsync(String cacheName, boolean checkThreadTx) { + public IgniteInternalFuture destroyCacheAsync(String cacheName, boolean checkThreadTx) { CU.validateCacheName(cacheName); guard(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java index 09582082dffcc..6c7ff1468b9aa 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java @@ -349,6 +349,8 @@ else if (req.start() && !req.clientStartOnly()) { req.deploymentId(), req.schema()); + desc.sql(req.sql()); + DynamicCacheDescriptor old = registeredCaches.put(cacheId, desc); assert old == null : old; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java index 9d2563d270ac8..8f81b8c8e2479 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java @@ -70,6 +70,9 @@ public class DynamicCacheChangeRequest implements Serializable { /** Close flag. */ private boolean close; + /** SQL flag - whether the change is triggered by an SQL command such as {@code CREATE TABLE}. */ + private boolean sql; + /** Fail if exists flag. */ private boolean failIfExists; @@ -344,6 +347,20 @@ public void close(boolean close) { this.close = close; } + /** + * @return SQL flag. + */ + public boolean sql() { + return sql; + } + + /** + * @param sql New SQL flag. + */ + public void sql(boolean sql) { + this.sql = sql; + } + /** * @param nodeId ID of node provided cache configuration in discovery data. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheDescriptor.java index 09b4c3a52dc41..6152de0ff2060 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheDescriptor.java @@ -55,6 +55,9 @@ public class DynamicCacheDescriptor { /** Started flag. */ private boolean started; + /** SQL flag - whether the change is triggered by an SQL command such as {@code CREATE TABLE}. */ + private boolean sql; + /** Cache type. */ private CacheType cacheType; @@ -208,6 +211,20 @@ public void staticallyConfigured(boolean staticCfg) { this.staticCfg = staticCfg; } + /** + * @return SQL flag. + */ + public boolean sql() { + return sql; + } + + /** + * @param sql New SQL flag. + */ + public void sql(boolean sql) { + this.sql = sql; + } + /** * @return {@code True} if started flag was flipped by this call. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java index 4775ea1255099..b57844c06fcf1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java @@ -248,11 +248,11 @@ public class GridCachePartitionExchangeManager extends GridCacheSharedMana fut = affinityReadyFuture(req.cacheFutureTopologyVersion()); if (fut == null || fut.isDone()) - cctx.cache().completeStartFuture(req); + cctx.cache().completeStartFuture(req, false); else { fut.listen(new CI1>() { @Override public void apply(IgniteInternalFuture fut) { - cctx.cache().completeStartFuture(req); + cctx.cache().completeStartFuture(req, false); } }); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index e5787949c9aee..0d3f81d27cb4a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -119,6 +119,7 @@ import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.X; +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.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; @@ -2065,19 +2066,15 @@ else if (req.close() && req.initiatingNodeId().equals(ctx.localNodeId())) { /** * @param req Request to complete future for. */ - public void completeStartFuture(DynamicCacheChangeRequest req) { + public void completeStartFuture(DynamicCacheChangeRequest req, boolean success) { DynamicCacheStartFuture fut = (DynamicCacheStartFuture)pendingFuts.get(req.requestId()); assert req.deploymentId() != null || req.globalStateChange() || req.resetLostPartitions(); assert fut == null || fut.deploymentId != null || req.globalStateChange() || req.resetLostPartitions(); if (fut != null && F.eq(fut.deploymentId(), req.deploymentId()) && - F.eq(req.initiatingNodeId(), ctx.localNodeId())) { - - GridCacheContext cctx = ctx.cache().context().cacheContext(CU.cacheId(req.cacheName())); - - fut.onDone(cctx != null ? F.eq(cctx.dynamicDeploymentId(), req.deploymentId()) : null); - } + F.eq(req.initiatingNodeId(), ctx.localNodeId())) + fut.onDone(success); } /** @@ -2372,6 +2369,8 @@ private void onDiscoDataReceived(UUID joiningNodeId, UUID rmtNodeId, DynamicCach req.deploymentId(), req.schema()); + desc.sql(req.sql()); + // Received statically configured cache. if (req.initiatingNodeId() == null) desc.staticallyConfigured(true); @@ -2579,11 +2578,33 @@ public IgniteInternalFuture dynamicStartCache( cacheName, nearCfg, CacheType.USER, + false, failIfExists, failIfNotStarted, checkThreadTx); } + /** + * Dynamically starts cache as a result of SQL {@code CREATE TABLE} command. + * + * @param ccfg Cache configuration. + */ + @SuppressWarnings("IfMayBeConditional") + public IgniteInternalFuture dynamicStartSqlCache( + CacheConfiguration ccfg + ) { + A.notNull(ccfg, "ccfg"); + + return dynamicStartCache(ccfg, + ccfg.getName(), + ccfg.getNearConfiguration(), + CacheType.USER, + true, + false, + true, + true); + } + /** * Dynamically starts cache. * @@ -2591,6 +2612,7 @@ public IgniteInternalFuture dynamicStartCache( * @param cacheName Cache name. * @param nearCfg Near cache configuration. * @param cacheType Cache type. + * @param sql If the cache needs to be created as the resukt of SQL {@code CREATE TABLE} command. * @param failIfExists Fail if exists flag. * @param failIfNotStarted If {@code true} fails if cache is not started. * @param checkThreadTx If {@code true} checks that current thread does not have active transactions. @@ -2602,6 +2624,7 @@ public IgniteInternalFuture dynamicStartCache( String cacheName, @Nullable NearCacheConfiguration nearCfg, CacheType cacheType, + boolean sql, boolean failIfExists, boolean failIfNotStarted, boolean checkThreadTx @@ -2620,8 +2643,11 @@ public IgniteInternalFuture dynamicStartCache( failIfExists, failIfNotStarted); - if (req != null) + if (req != null) { + req.sql(sql); + return F.first(initiateCacheChanges(F.asList(req), failIfExists)); + } else return new GridFinishedFuture<>(); } @@ -2701,7 +2727,7 @@ private IgniteInternalFuture dynamicStartCaches( * @param checkThreadTx If {@code true} checks that current thread does not have active transactions. * @return Future that will be completed when cache is destroyed. */ - public IgniteInternalFuture dynamicDestroyCache(String cacheName, boolean checkThreadTx) { + public IgniteInternalFuture dynamicDestroyCache(String cacheName, boolean checkThreadTx) { assert cacheName != null; if (checkThreadTx) @@ -3105,6 +3131,8 @@ private boolean onCacheChangeRequested( DynamicCacheDescriptor startDesc = new DynamicCacheDescriptor(ctx, ccfg, req.cacheType(), false, req.deploymentId(), req.schema()); + startDesc.sql(req.sql()); + if (newTopVer == null) { newTopVer = new AffinityTopologyVersion(topVer.topologyVersion(), topVer.minorTopologyVersion() + 1); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java index 654d3066547b2..6d80dcdf25e95 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java @@ -1209,7 +1209,7 @@ private void sendPartitions(ClusterNode oldestNode) { if (!F.isEmpty(reqs) && err == null) { for (DynamicCacheChangeRequest req : reqs) - cctx.cache().completeStartFuture(req); + cctx.cache().completeStartFuture(req, true); } if (exchangeOnChangeGlobalState && err == null) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java index eb0981bbbaf2d..df9d2699d9902 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java @@ -998,6 +998,7 @@ private String compatibleConfiguration(CollectionConfiguration cfg) throws Ignit null, CacheType.INTERNAL, false, + false, true, true).get(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index 17cc4f9cfa00a..695298325d5a2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -286,6 +286,15 @@ public void rebuildIndexesFromHash(String spaceName, */ public String space(String schemaName); + /** + * Get space name by database schema and table name. + * + * @param schemaName Schema name. Could not be null. Could be empty. + * @param tblName Table name, non-empty. + * @return Space name. Could be null. + */ + public String space(String schemaName, String tblName); + /** * Collect queries that already running more than specified duration. * 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 40305f69e9430..d5e8bc0928e17 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 @@ -1290,7 +1290,7 @@ public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean // We want to preserve user specified names as they are newCfg.setSqlEscapeAll(true); - IgniteBiTuple, Boolean> res = ctx.grid().getOrCreateCache0(newCfg); + IgniteBiTuple, Boolean> res = ctx.grid().getOrCreateCache0(newCfg, true); if (!ifNotExists && F.eq(res.get2(), false)) throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', @@ -1306,7 +1306,7 @@ public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean */ @SuppressWarnings("unchecked") public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) { - String spaceName = getIndexing().space(schemaName); + String spaceName = getIndexing().space(schemaName, tblName); QueryTypeDescriptorImpl type = type(spaceName, tblName); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java index 18e637def1001..a6201b0b99c13 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java @@ -63,6 +63,7 @@ import java.util.Collection; import java.util.Collections; import java.util.concurrent.ExecutorService; +import javax.cache.CacheException; /** * Mocked Ignite implementation for IGFS tests. @@ -322,12 +323,19 @@ public IgfsIgniteMock(@Nullable String name, IgniteFileSystem igfs) { /** {@inheritDoc} */ @Override public IgniteBiTuple, Boolean> getOrCreateCache0( - CacheConfiguration cacheCfg) { + CacheConfiguration cacheCfg, boolean sql) { throwUnsupported(); return null; } + /** {@inheritDoc} */ + @Override public boolean destroyCache0(String cacheName, boolean sql) throws CacheException { + throwUnsupported(); + + return false; + } + /** {@inheritDoc} */ @Override public void addCacheConfiguration(CacheConfiguration cacheCfg) { throwUnsupported(); diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java index a7fbb02c125fd..7508430157e58 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java @@ -25,6 +25,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; +import javax.cache.CacheException; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteAtomicLong; import org.apache.ignite.IgniteAtomicReference; @@ -535,7 +536,7 @@ public void kill() throws Exception { /** {@inheritDoc} */ @Override public IgniteBiTuple, Boolean> getOrCreateCache0( - CacheConfiguration cacheCfg) { + CacheConfiguration cacheCfg, boolean sql) { throw new UnsupportedOperationException("Operation isn't supported yet."); } @@ -544,6 +545,11 @@ public void kill() throws Exception { throw new UnsupportedOperationException("Operation isn't supported yet."); } + /** {@inheritDoc} */ + @Override public boolean destroyCache0(String cacheName, boolean sql) throws CacheException { + throw new UnsupportedOperationException("Operation isn't supported yet."); + } + /** {@inheritDoc} */ @Override public void destroyCaches(Collection cacheNames) { throw new UnsupportedOperationException("Operation isn't supported yet."); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 56f77d52da7a0..627af068fcd1d 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -2122,6 +2122,17 @@ private void cleanupStatementCache() { return schema.spaceName; } + /** {@inheritDoc} */ + @Override public String space(String schemaName, String tblName) { + GridH2Table tbl = dataTable(schemaName, tblName); + + if (tbl == null) + throw new IgniteSQLException("Table not found [schemaName=" + schemaName + ",tblName=" + tblName + ']', + IgniteQueryErrorCode.TABLE_NOT_FOUND); + + return tbl.spaceName(); + } + /** * Rebuild indexes from hash index. * From 813dd688fa726567c45db4a4b56f5774d6859bd7 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Thu, 18 May 2017 17:05:54 +0300 Subject: [PATCH 13/21] IGNITE-5052 Post merge and review fixes. --- .../org/apache/ignite/internal/IgniteEx.java | 8 +- .../apache/ignite/internal/IgniteKernal.java | 8 +- .../cache/CacheAffinitySharedManager.java | 2 - .../processors/cache/ClusterCachesInfo.java | 8 +- .../cache/DynamicCacheChangeRequest.java | 17 --- .../cache/DynamicCacheDescriptor.java | 37 ------ .../processors/cache/ExchangeActions.java | 2 +- .../processors/cache/GridCacheProcessor.java | 9 +- .../processors/query/GridQueryProcessor.java | 29 +---- .../processors/igfs/IgfsIgniteMock.java | 4 +- .../junits/multijvm/IgniteProcessProxy.java | 4 +- .../query/h2/sql/GridSqlCreateTable.java | 121 +++++++----------- .../query/h2/sql/GridSqlDropTable.java | 6 +- .../cache/index/H2DynamicTableSelfTest.java | 40 ++++-- .../query/h2/sql/GridQueryParsingTest.java | 104 ++++++++++++++- 15 files changed, 205 insertions(+), 194 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java index 775f49341d133..7f9f7d069388e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java @@ -71,23 +71,19 @@ public interface IgniteEx extends Ignite { * of the existing cache. * * @param cacheCfg Cache configuration to use. - * @param sql {@code true} if this call is triggered by SQL command {@code CREATE TABLE}, {@code false} otherwise. * @return Tuple [Existing or newly created cache; {@code true} if cache was newly crated, {@code false} otherwise] * @throws CacheException If error occurs. */ - public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg, - boolean sql) throws CacheException; + public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) throws CacheException; /** * Stops dynamically started cache. * * @param cacheName Cache name to stop. - * @param sql {@code true} if only cache created with SQL command {@code CREATE TABLE} should be affected, - * {@code false} otherwise. * @return {@code true} if cache has been stopped as the result of this call, {@code false} otherwise. * @throws CacheException If error occurs. */ - public boolean destroyCache0(String cacheName, boolean sql) throws CacheException; + public boolean destroyCache0(String cacheName) throws CacheException; /** * Checks if the event type is user-recordable. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index 8cff9dafa831d..c75e040127aa3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -2791,13 +2791,13 @@ public IgniteInternalCache getCache(String name) { /** {@inheritDoc} */ @Override public IgniteCache getOrCreateCache(CacheConfiguration cacheCfg) { - return getOrCreateCache0(cacheCfg, false).get1(); + return getOrCreateCache0(cacheCfg).get1(); } /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public IgniteBiTuple, Boolean> getOrCreateCache0( - CacheConfiguration cacheCfg, boolean sql) { + CacheConfiguration cacheCfg) { A.notNull(cacheCfg, "cacheCfg"); CU.validateCacheName(cacheCfg.getName()); @@ -3017,11 +3017,11 @@ private void checkNearCacheStarted(IgniteCacheProxy cache) throws IgniteCh /** {@inheritDoc} */ @Override public void destroyCache(String cacheName) { - destroyCache0(cacheName, false); + destroyCache0(cacheName); } /** {@inheritDoc} */ - @Override public boolean destroyCache0(String cacheName, boolean sql) throws CacheException { + @Override public boolean destroyCache0(String cacheName) throws CacheException { CU.validateCacheName(cacheName); IgniteInternalFuture stopFut = destroyCacheAsync(cacheName, true); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java index fa863680b53a2..50d3092a3d0d4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java @@ -342,8 +342,6 @@ private void updateCachesInfo(ExchangeActions exchActions) { req.deploymentId(), req.schema()); - desc.sql(req.sql()); - DynamicCacheDescriptor old = registeredCaches.put(cacheId, desc); assert old == null : old; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java index 28ec600f6619c..19a4be977f284 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java @@ -272,7 +272,7 @@ boolean onCacheChangeRequested(DynamicCacheChangeBatch batch, AffinityTopologyVe if (req.start()) { if (desc == null) { if (req.clientStartOnly()) { - ctx.cache().completeCacheStartFuture(req, new IgniteCheckedException("Failed to start " + + ctx.cache().completeCacheStartFuture(req, false, new IgniteCheckedException("Failed to start " + "client cache (a cache with the given name is not started): " + req.cacheName())); } else { @@ -327,7 +327,7 @@ boolean onCacheChangeRequested(DynamicCacheChangeBatch batch, AffinityTopologyVe } else { if (req.failIfExists()) { - ctx.cache().completeCacheStartFuture(req, + ctx.cache().completeCacheStartFuture(req, false, new CacheExistsException("Failed to start cache " + "(a cache with the same name is already started): " + req.cacheName())); } @@ -418,11 +418,11 @@ else if (req.close()) { ctx.cache().context().exchange().affinityReadyFuture(waitTopVer) : null; if (fut == null || fut.isDone()) - ctx.cache().completeCacheStartFuture(req, null); + ctx.cache().completeCacheStartFuture(req, false, null); else { fut.listen(new IgniteInClosure>() { @Override public void apply(IgniteInternalFuture fut) { - ctx.cache().completeCacheStartFuture(req, null); + ctx.cache().completeCacheStartFuture(req, false, null); } }); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java index 5ffbcc1da4c2c..f8c2c7df763fd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java @@ -70,9 +70,6 @@ public class DynamicCacheChangeRequest implements Serializable { /** Close flag. */ private boolean close; - /** SQL flag - whether the change is triggered by an SQL command such as {@code CREATE TABLE}. */ - private boolean sql; - /** Fail if exists flag. */ private boolean failIfExists; @@ -383,20 +380,6 @@ public void close(boolean close) { this.close = close; } - /** - * @return SQL flag. - */ - public boolean sql() { - return sql; - } - - /** - * @param sql New SQL flag. - */ - public void sql(boolean sql) { - this.sql = sql; - } - /** * @param nodeId ID of node provided cache configuration in discovery data. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheDescriptor.java index 07c8d2b322deb..40d3706830000 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheDescriptor.java @@ -48,9 +48,6 @@ public class DynamicCacheDescriptor { /** Statically configured flag. */ private final boolean staticCfg; - /** SQL flag - whether the change is triggered by an SQL command such as {@code CREATE TABLE}. */ - private boolean sql; - /** Cache type. */ private CacheType cacheType; @@ -181,40 +178,6 @@ public String cacheName() { return cacheCfg.getName(); } - /** - * @return SQL flag. - */ - public boolean sql() { - return sql; - } - - /** - * @param sql New SQL flag. - */ - public void sql(boolean sql) { - this.sql = sql; - } - - /** - * @return {@code True} if started flag was flipped by this call. - */ - public boolean onStart() { - if (!started) { - started = true; - - return true; - } - - return false; - } - - /** - * @return Started flag. - */ - public boolean started() { - return started; - } - /** * @return Cache configuration. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ExchangeActions.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ExchangeActions.java index eac11205c8f60..5ac51eaa7d58a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ExchangeActions.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ExchangeActions.java @@ -132,7 +132,7 @@ public void completeRequestFutures(GridCacheSharedContext ctx) { private void completeRequestFutures(Map map, GridCacheSharedContext ctx) { if (map != null) { for (ActionData req : map.values()) - ctx.cache().completeCacheStartFuture(req.req, null); + ctx.cache().completeCacheStartFuture(req.req, true, null); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index ba0667f8364b8..f545ef3c1f495 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -2257,11 +2257,8 @@ public IgniteInternalFuture dynamicStartCache( failIfExists, failIfNotStarted); - if (req != null) { - req.sql(sql); - + if (req != null) return F.first(initiateCacheChanges(F.asList(req), failIfExists)); - } else return new GridFinishedFuture<>(); } @@ -2543,7 +2540,7 @@ private Collection initiateCacheChanges( if (desc == null) // No-op. - fut.onDone(); + fut.onDone(false); else { assert desc.cacheConfiguration() != null : desc; @@ -3478,7 +3475,7 @@ public T clone(final T obj) throws IgniteCheckedException { * */ @SuppressWarnings("ExternalizableWithoutPublicNoArgConstructor") - private class DynamicCacheStartFuture extends GridFutureAdapter { + private class DynamicCacheStartFuture extends GridFutureAdapter { /** Cache name. */ private String cacheName; 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 d5e8bc0928e17..78b302f083b08 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 @@ -43,7 +43,6 @@ import org.apache.ignite.internal.processors.cache.GridCacheAdapter; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; -import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; import org.apache.ignite.internal.processors.cache.query.CacheQueryFuture; @@ -1290,9 +1289,9 @@ public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean // We want to preserve user specified names as they are newCfg.setSqlEscapeAll(true); - IgniteBiTuple, Boolean> res = ctx.grid().getOrCreateCache0(newCfg, true); + boolean res = ctx.grid().getOrCreateCache0(newCfg).get2(); - if (!ifNotExists && F.eq(res.get2(), false)) + if (!res && !ifNotExists) throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); } @@ -1306,27 +1305,11 @@ public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean */ @SuppressWarnings("unchecked") public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) { - String spaceName = getIndexing().space(schemaName, tblName); + boolean res = ctx.grid().destroyCache0(tblName); - QueryTypeDescriptorImpl type = type(spaceName, tblName); - - if (type == null || !F.eq(schemaName, spaceName)) { - if (!ifExists) - throw new IgniteSQLException("Table not found [schemaName=" + schemaName + - ",tblName=" + tblName +']', IgniteQueryErrorCode.TABLE_NOT_FOUND); - - return; - } - - if (!F.eq(schemaName, tblName)) - throw new IgniteSQLException("Only dynamically created table can be dropped [schemaName=" + schemaName + - ",tblName=" + tblName +']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); - - IgniteCache cache = ctx.grid().cache(spaceName); - - assert cache != null; - - cache.destroy(); + if (!res && !ifExists) + throw new IgniteSQLException("Table not found [schemaName=" + schemaName + + ",tblName=" + tblName +']', IgniteQueryErrorCode.TABLE_NOT_FOUND); } /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java index a6201b0b99c13..cc058b15b7565 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsIgniteMock.java @@ -323,14 +323,14 @@ public IgfsIgniteMock(@Nullable String name, IgniteFileSystem igfs) { /** {@inheritDoc} */ @Override public IgniteBiTuple, Boolean> getOrCreateCache0( - CacheConfiguration cacheCfg, boolean sql) { + CacheConfiguration cacheCfg) { throwUnsupported(); return null; } /** {@inheritDoc} */ - @Override public boolean destroyCache0(String cacheName, boolean sql) throws CacheException { + @Override public boolean destroyCache0(String cacheName) throws CacheException { throwUnsupported(); return false; diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java index 7508430157e58..34ca22f4aaa33 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java @@ -536,7 +536,7 @@ public void kill() throws Exception { /** {@inheritDoc} */ @Override public IgniteBiTuple, Boolean> getOrCreateCache0( - CacheConfiguration cacheCfg, boolean sql) { + CacheConfiguration cacheCfg) { throw new UnsupportedOperationException("Operation isn't supported yet."); } @@ -546,7 +546,7 @@ public void kill() throws Exception { } /** {@inheritDoc} */ - @Override public boolean destroyCache0(String cacheName, boolean sql) throws CacheException { + @Override public boolean destroyCache0(String cacheName) throws CacheException { throw new UnsupportedOperationException("Operation isn't supported yet."); } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java index aa8c725ab62c4..52c9cc91e2f40 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlCreateTable.java @@ -20,10 +20,6 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; -import org.apache.ignite.internal.util.GridStringBuilder; -import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.internal.util.typedef.internal.SB; -import org.h2.command.Parser; /** * CREATE TABLE statement. @@ -52,137 +48,106 @@ public class GridSqlCreateTable extends GridSqlStatement { /** Extra WITH-params. */ private List params; + /** + * @return Cache name upon which new cache configuration for this table must be based. + */ public String templateCacheName() { return tplCacheName; } + /** + * @param tplCacheName Cache name upon which new cache configuration for this table must be based. + */ public void templateCacheName(String tplCacheName) { this.tplCacheName = tplCacheName; } + /** + * @return Columns. + */ public LinkedHashMap columns() { return cols; } + /** + * @param cols Columns. + */ public void columns(LinkedHashMap cols) { this.cols = cols; } + /** + * @return Primary key columns. + */ public LinkedHashSet primaryKeyColumns() { return pkCols; } + /** + * @param pkCols Primary key columns. + */ public void primaryKeyColumns(LinkedHashSet pkCols) { this.pkCols = pkCols; } + /** + * @return Schema name upon which this statement has been issued. + */ public String schemaName() { return schemaName; } + /** + * @param schemaName Schema name upon which this statement has been issued. + */ public void schemaName(String schemaName) { this.schemaName = schemaName; } + /** + * @return Table name. + */ public String tableName() { return tblName; } + /** + * @param tblName Table name. + */ public void tableName(String tblName) { this.tblName = tblName; } + /** + * @return Quietly ignore this command if table already exists. + */ public boolean ifNotExists() { return ifNotExists; } + /** + * @param ifNotExists Quietly ignore this command if table already exists. + */ public void ifNotExists(boolean ifNotExists) { this.ifNotExists = ifNotExists; } + /** + * @return Extra WITH-params. + */ public List params() { return params; } + /** + * @param params Extra WITH-params. + */ public void params(List params) { this.params = params; } /** {@inheritDoc} */ @Override public String getSQL() { - GridStringBuilder b = new SB("CREATE TABLE ") - .a(ifNotExists ? "IF NOT EXISTS " : "") - .a("\n") - .a(Parser.quoteIdentifier(schemaName)) - .a('.') - .a(Parser.quoteIdentifier(tblName)) - .a("\n("); - - boolean singleColPk = false; - - boolean first = true; - - for (GridSqlColumn col : cols.values()) { - if (!first) - b.a(",\n"); - else - first = false; - - if (col.column().isPrimaryKey()) { - // Only one column may be marked PRIMARY KEY - multi-col PK is defined separately - assert !singleColPk; - - singleColPk = true; - } - - b.a('\t') - .a(col.getSQL()) - .a(' ') - .a(col.resultType().sql()) - .a(col.column().isPrimaryKey() ? " PRIMARY KEY" : ""); - } - - first = true; - - if (!singleColPk && !F.isEmpty(pkCols)) { - b.a(",\n") - .a('\t') - .a("PRIMARY KEY (\n"); - - for (String col : pkCols) { - GridSqlColumn pkCol = cols.get(col); - - assert pkCol != null; - - if (!first) - b.a(",\n"); - else - first = false; - - b.a("\t\t") - .a(pkCol.getSQL()); - } - - b.a("\n\t)"); - } - - b.a("\n)"); - - if (!F.isEmpty(params)) { - b.a("\nWITH "); - - first = true; - - for (String p : params) { - if (!first) - b.a(','); - else - first = false; - - b.a(Parser.quoteIdentifier(p)); - } - } - - return b.toString(); + return null; } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java index 4782b2ba00e9e..34cb6fef99fa5 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlDropTable.java @@ -27,7 +27,7 @@ public class GridSqlDropTable extends GridSqlStatement { /** Table name. */ private String tblName; - /** Quietly ignore this command if table already exists. */ + /** Quietly ignore this command if table does not exist. */ private boolean ifExists; /** @@ -59,14 +59,14 @@ public void tableName(String tblName) { } /** - * @return Quietly ignore this command if table already exists. + * @return Quietly ignore this command if table does not exist. */ public boolean ifExists() { return ifExists; } /** - * @param ifExists Quietly ignore this command if table already exists. + * @param ifExists Quietly ignore this command if table does not exist. */ public void ifExists(boolean ifExists) { this.ifExists = ifExists; 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 18ee540cd6b97..ef13cf2823651 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 @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.Callable; import org.apache.ignite.IgniteCache; import org.apache.ignite.Ignition; @@ -31,23 +32,18 @@ import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; -import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.binary.BinaryMarshaller; -import org.apache.ignite.internal.processors.query.GridQueryProcessor; import org.apache.ignite.internal.processors.query.GridQueryProperty; +import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.QueryTypeDescriptorImpl; import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table; -import org.apache.ignite.internal.processors.query.h2.sql.GridSqlCreateTable; -import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser; import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.h2.engine.Session; -import org.h2.jdbc.JdbcConnection; +import org.apache.ignite.testframework.GridTestUtils; /** - * Zzz + * Tests for CREATE/DROP TABLE. */ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { /** Client node index. */ @@ -135,6 +131,23 @@ public void testCreateTableIfNotExists() throws Exception { "\"tplCache=cache\"")); } + /** */ + public void testCreateExistingTable() throws Exception { + cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + + "\"tplCache=cache\"")); + + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar" + + ", \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + + "\"tplCache=cache\"")); + + return null; + } + }, IgniteSQLException.class, "Table already exists [tblName=Person]"); + } + /** */ public void testDropTable() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + @@ -159,6 +172,17 @@ public void testDropTableIfExists() throws Exception { cache().query(new SqlFieldsQuery("DROP TABLE IF EXISTS \"cache\".\"City\"")); } + /** */ + public void testDropMissingTable() throws Exception { + GridTestUtils.assertThrows(null, new Callable() { + @Override public Object call() throws Exception { + cache().query(new SqlFieldsQuery("DROP TABLE \"cache\".\"City\"")); + + return null; + } + }, IgniteSQLException.class, "Table not found [schemaName=cache,tblName=City]"); + } + /** */ private void assertProperty(QueryTypeDescriptorImpl desc, String name, Class type, boolean isKey) { GridQueryProperty p = desc.property(name); 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 b50750f655389..d425062551a9d 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 @@ -40,14 +40,18 @@ import org.apache.ignite.internal.processors.query.GridQueryProcessor; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; +import org.apache.ignite.internal.util.GridStringBuilder; import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.SB; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.h2.command.Parser; import org.h2.command.Prepared; +import org.h2.command.ddl.CreateTable; import org.h2.engine.Session; import org.h2.jdbc.JdbcConnection; import org.h2.message.DbException; @@ -547,7 +551,7 @@ public void testParseDropIndex() throws Exception { /** */ public void testParseCreateTable() throws Exception { - checkQuery("CREATE TABLE IF NOT EXISTS sch1.\"Person\" (\"id\" integer, \"city\" varchar," + + checkCreateTable("CREATE TABLE IF NOT EXISTS sch1.\"Person\" (\"id\" integer, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" integer, PRIMARY KEY (\"id\", \"city\")) WITH " + "\"tplCache=cache\""); } @@ -729,6 +733,87 @@ private static String normalizeSql(String sql) { .trim(); } + /** + * @param createTbl {@code CREATE TABLE} command. + * @return Corresponding SQL. + */ + private static String createTableToSql(GridSqlCreateTable createTbl) { + GridStringBuilder b = new SB("CREATE TABLE ") + .a(createTbl.ifNotExists() ? "IF NOT EXISTS " : "") + .a("\n") + .a(Parser.quoteIdentifier(createTbl.schemaName())) + .a('.') + .a(Parser.quoteIdentifier(createTbl.tableName())) + .a("\n("); + + boolean singleColPk = false; + + boolean first = true; + + for (GridSqlColumn col : createTbl.columns().values()) { + if (!first) + b.a(",\n"); + else + first = false; + + if (col.column().isPrimaryKey()) { + // Only one column may be marked PRIMARY KEY - multi-col PK is defined separately + assert !singleColPk; + + singleColPk = true; + } + + b.a('\t') + .a(col.getSQL()) + .a(' ') + .a(col.resultType().sql()) + .a(col.column().isPrimaryKey() ? " PRIMARY KEY" : ""); + } + + first = true; + + if (!singleColPk && !F.isEmpty(createTbl.primaryKeyColumns())) { + b.a(",\n") + .a('\t') + .a("PRIMARY KEY (\n"); + + for (String col : createTbl.primaryKeyColumns()) { + GridSqlColumn pkCol = createTbl.columns().get(col); + + assert pkCol != null; + + if (!first) + b.a(",\n"); + else + first = false; + + b.a("\t\t") + .a(pkCol.getSQL()); + } + + b.a("\n\t)"); + } + + b.a("\n)"); + + if (!F.isEmpty(createTbl.params())) { + b.a("\nWITH "); + + first = true; + + for (String p : createTbl.params()) { + if (!first) + b.a(','); + else + first = false; + + b.a(Parser.quoteIdentifier(p)); + } + } + + return b.toString(); + } + /** * @param qry Query. */ @@ -744,6 +829,23 @@ private void checkQuery(String qry) throws Exception { assertSqlEquals(U.firstNotNull(prepared.getPlanSQL(), prepared.getSQL()), res); } + /** + * @param qry Query. + */ + private void checkCreateTable(String qry) throws Exception { + Prepared prepared = parse(qry); + + assertTrue(prepared instanceof CreateTable); + + GridSqlStatement gridStmt = new GridSqlQueryParser(false).parse(prepared); + + String res = createTableToSql((GridSqlCreateTable)gridStmt); + + System.out.println(normalizeSql(res)); + + assertSqlEquals(U.firstNotNull(prepared.getPlanSQL(), prepared.getSQL()), res); + } + @QuerySqlFunction public static int cool1() { return 1; From e3f05f2e5be2e1bd616270711717275fb49b59f1 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Thu, 18 May 2017 20:40:18 +0300 Subject: [PATCH 14/21] IGNITE-5052 CREATE TABLE tests. --- .../query/h2/sql/GridSqlQueryParser.java | 24 +-- .../query/h2/sql/GridQueryParsingTest.java | 148 +++++++++++++++++- 2 files changed, 157 insertions(+), 15 deletions(-) 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 b26118a0892ac..de154e3b73900 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 @@ -894,22 +894,24 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { Map params = new HashMap<>(); - for (String p : extraParams) { - String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR); + if (!F.isEmpty(extraParams)) { + for (String p : extraParams) { + String[] parts = p.split(PARAM_NAME_VALUE_SEPARATOR); - if (parts.length > 2) - throw new IgniteSQLException("Invalid param syntax: key[=value] expected [paramStr=" + p + ']', - IgniteQueryErrorCode.PARSING); + if (parts.length > 2) + throw new IgniteSQLException("Invalid param syntax: key[=value] expected [paramStr=" + p + ']', + IgniteQueryErrorCode.PARSING); - String name = parts[0]; + String name = parts[0]; - String val = parts.length > 1 ? parts[1] : null; + String val = parts.length > 1 ? parts[1] : null; - if (F.isEmpty(name)) - throw new IgniteSQLException("Invalid param syntax: no name given [paramStr=" + p + ']', - IgniteQueryErrorCode.PARSING); + if (F.isEmpty(name)) + throw new IgniteSQLException("Invalid param syntax: no name given [paramStr=" + p + ']', + IgniteQueryErrorCode.PARSING); - params.put(name, val); + params.put(name, val); + } } for (String mandParamName : MANDATORY_CREATE_TABLE_PARAMS) { 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 d425062551a9d..2cdfb4b500278 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 @@ -22,8 +22,11 @@ import java.sql.Date; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; import java.util.concurrent.Callable; import org.apache.ignite.Ignite; @@ -55,6 +58,8 @@ import org.h2.engine.Session; import org.h2.jdbc.JdbcConnection; import org.h2.message.DbException; +import org.h2.table.Column; +import org.h2.value.Value; import org.jetbrains.annotations.NotNull; import static org.apache.ignite.cache.CacheRebalanceMode.SYNC; @@ -536,7 +541,7 @@ public void testParseCreateIndex() throws Exception { * */ public void testParseDropIndex() throws Exception { - // Schema that is not set defaults to default schema of connection which is empty string + // Schema that is not set defaults to default schema of connection which is sch1 assertDropIndexEquals(buildDropIndex("idx", "sch1", false), "drop index idx"); assertDropIndexEquals(buildDropIndex("idx", "sch1", true), "drop index if exists idx"); assertDropIndexEquals(buildDropIndex("idx", "sch1", true), "drop index if exists sch1.idx"); @@ -549,11 +554,40 @@ public void testParseDropIndex() throws Exception { assertParseThrows("drop index if exists schema2.", DbException.class, null); } + /** + * + */ + public void testParseDropTable() throws Exception { + // Schema that is not set defaults to default schema of connection which is sch1 + assertDropTableEquals(buildDropTable("sch1", "tbl", false), "drop table tbl"); + assertDropTableEquals(buildDropTable("sch1", "tbl", true), "drop table if exists tbl"); + assertDropTableEquals(buildDropTable("sch1", "tbl", true), "drop table if exists sch1.tbl"); + assertDropTableEquals(buildDropTable("sch1", "tbl", false), "drop table sch1.tbl"); + + // Message is null as long as it may differ from system to system, so we just check for exceptions + assertParseThrows("drop table schema2.", DbException.class, null); + assertParseThrows("drop table", DbException.class, null); + assertParseThrows("drop table if exists", DbException.class, null); + assertParseThrows("drop table if exists schema2.", DbException.class, null); + } + /** */ public void testParseCreateTable() throws Exception { - checkCreateTable("CREATE TABLE IF NOT EXISTS sch1.\"Person\" (\"id\" integer, \"city\" varchar," + - " \"name\" varchar, \"surname\" varchar, \"age\" integer, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"tplCache=cache\""); + assertCreateTableEquals( + buildCreateTable("sch1", "Person", "cache", F.asList("id", "city"), + true, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), + c("surname", Value.STRING), c("age", Value.INT)), + "CREATE TABLE IF NOT EXISTS sch1.\"Person\" (\"id\" integer, \"city\" varchar," + + " \"name\" varchar, \"surname\" varchar, \"age\" integer, PRIMARY KEY (\"id\", \"city\")) WITH " + + "\"tplCache=cache\""); + + assertCreateTableEquals( + buildCreateTable("sch1", "Person", "cache", F.asList("id"), + false, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), + c("surname", Value.STRING), c("age", Value.INT)), + "CREATE TABLE sch1.\"Person\" (\"id\" integer PRIMARY KEY, \"city\" varchar," + + " \"name\" varchar, \"surname\" varchar, \"age\" integer) WITH " + + "\"tplCache=cache\""); } /** @@ -620,6 +654,112 @@ private static GridSqlDropIndex buildDropIndex(String name, String schema, boole return res; } + /** + * Parse SQL and compare it to expected instance of DROP TABLE. + */ + private void assertCreateTableEquals(GridSqlCreateTable exp, String sql) throws Exception { + Prepared prepared = parse(sql); + + GridSqlStatement stmt = new GridSqlQueryParser(false).parse(prepared); + + assertTrue(stmt instanceof GridSqlCreateTable); + + assertCreateTableEquals(exp, (GridSqlCreateTable) stmt); + } + + /** + * Test two instances of {@link GridSqlDropTable} for equality. + */ + private static void assertCreateTableEquals(GridSqlCreateTable exp, GridSqlCreateTable actual) { + assertEqualsIgnoreCase(exp.schemaName(), actual.schemaName()); + assertEqualsIgnoreCase(exp.tableName(), actual.tableName()); + assertEquals(exp.templateCacheName(), actual.templateCacheName()); + assertEquals(exp.primaryKeyColumns(), actual.primaryKeyColumns()); + assertEquals(new ArrayList<>(exp.columns().keySet()), new ArrayList<>(actual.columns().keySet())); + + for (Map.Entry col : exp.columns().entrySet()) { + GridSqlColumn val = actual.columns().get(col.getKey()); + + assertNotNull(val); + + assertEquals(col.getValue().columnName(), val.columnName()); + assertEquals(col.getValue().column().getType(), val.column().getType()); + } + + assertEquals(exp.ifNotExists(), actual.ifNotExists()); + } + + /** + * + */ + private static GridSqlCreateTable buildCreateTable(String schema, String tbl, String tplCacheName, + Collection pkColNames, boolean ifNotExists, GridSqlColumn... cols) { + GridSqlCreateTable res = new GridSqlCreateTable(); + + res.schemaName(schema); + + res.tableName(tbl); + + res.templateCacheName(tplCacheName); + + res.primaryKeyColumns(new LinkedHashSet<>(pkColNames)); + + LinkedHashMap m = new LinkedHashMap<>(); + + for (GridSqlColumn col : cols) + m.put(col.columnName(), col); + + res.columns(m); + + res.ifNotExists(ifNotExists); + + return res; + } + + /** + * @param name Column name. + * @param type Column data type. + * @return {@link GridSqlColumn} with given name and type. + */ + private static GridSqlColumn c(String name, int type) { + return new GridSqlColumn(new Column(name, type), null, name); + } + + /** + * Parse SQL and compare it to expected instance of DROP TABLE. + */ + private void assertDropTableEquals(GridSqlDropTable exp, String sql) throws Exception { + Prepared prepared = parse(sql); + + GridSqlStatement stmt = new GridSqlQueryParser(false).parse(prepared); + + assertTrue(stmt instanceof GridSqlDropTable); + + assertDropTableEquals(exp, (GridSqlDropTable) stmt); + } + + /** + * Test two instances of {@link GridSqlDropTable} for equality. + */ + private static void assertDropTableEquals(GridSqlDropTable exp, GridSqlDropTable actual) { + assertEqualsIgnoreCase(exp.schemaName(), actual.schemaName()); + assertEqualsIgnoreCase(exp.tableName(), actual.tableName()); + assertEquals(exp.ifExists(), actual.ifExists()); + } + + /** + * + */ + private static GridSqlDropTable buildDropTable(String schema, String tbl, boolean ifExists) { + GridSqlDropTable res = new GridSqlDropTable(); + + res.schemaName(schema); + res.tableName(tbl); + res.ifExists(ifExists); + + return res; + } + /** * Test two instances of {@link GridSqlCreateIndex} for equality. */ From a905de9bbecac0284a655884e4f573c9b54382ae Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Thu, 18 May 2017 20:56:36 +0300 Subject: [PATCH 15/21] IGNITE-5052 CREATE TABLE tests. --- .../query/h2/sql/GridSqlQueryParser.java | 10 +++++----- .../query/h2/sql/GridQueryParsingTest.java | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) 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 de154e3b73900..52a135a4ea8fa 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 @@ -855,13 +855,16 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { cols.put(col.getName(), gridCol); } - if (cols.containsKey(QueryUtils.KEY_FIELD_NAME) || - cols.containsKey(QueryUtils.VAL_FIELD_NAME)) + if (cols.containsKey(QueryUtils.KEY_FIELD_NAME.toUpperCase()) || + cols.containsKey(QueryUtils.VAL_FIELD_NAME.toUpperCase())) throw new IgniteSQLException("Direct specification of _KEY and _VAL columns is forbidden", IgniteQueryErrorCode.PARSING); IndexColumn[] pkIdxCols = CREATE_TABLE_PK.get(createTbl); + if (F.isEmpty(pkIdxCols)) + throw new IgniteSQLException("No PRIMARY KEY columns specified"); + LinkedHashSet pkCols = new LinkedHashSet<>(); for (IndexColumn pkIdxCol : pkIdxCols) { @@ -872,9 +875,6 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { pkCols.add(gridCol.columnName()); } - if (F.isEmpty(pkCols)) - throw new IgniteSQLException("No PRIMARY KEY columns specified"); - int valColsNum = cols.size() - pkCols.size(); if (valColsNum == 0) 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 2cdfb4b500278..e68479f03a99e 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 @@ -588,6 +588,24 @@ false, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), "CREATE TABLE sch1.\"Person\" (\"id\" integer PRIMARY KEY, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" integer) WITH " + "\"tplCache=cache\""); + + assertParseThrows("create table Person (id int)", + IgniteSQLException.class, "No PRIMARY KEY columns specified"); + + assertParseThrows("create table Person (id int) AS SELECT 2 * 2", + IgniteSQLException.class, "CREATE TABLE ... AS ... syntax is not supported"); + + 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=tplCache]"); + + assertParseThrows("create table Person (id int primary key, age int not null) WITH \"tplCache=cache\"", + IgniteSQLException.class, "Non nullable columns are forbidden"); + + assertParseThrows("create table Int (_key int primary key, _val int) WITH \"tplCache=cache\"", + IgniteSQLException.class, "Direct specification of _KEY and _VAL columns is forbidden"); } /** From 53c2f28aa5f0961035e7454b83b0dc3e0aa239a1 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Fri, 19 May 2017 15:18:25 +0300 Subject: [PATCH 16/21] IGNITE-5052 Removed odd stuff --- .../processors/cache/GridCacheProcessor.java | 25 ------------------- .../DataStructuresProcessor.java | 1 - 2 files changed, 26 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index f545ef3c1f495..ee29bac8d74eb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -119,7 +119,6 @@ import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.util.typedef.X; -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.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; @@ -2192,33 +2191,11 @@ public IgniteInternalFuture dynamicStartCache( cacheName, nearCfg, CacheType.USER, - false, failIfExists, failIfNotStarted, checkThreadTx); } - /** - * Dynamically starts cache as a result of SQL {@code CREATE TABLE} command. - * - * @param ccfg Cache configuration. - */ - @SuppressWarnings("IfMayBeConditional") - public IgniteInternalFuture dynamicStartSqlCache( - CacheConfiguration ccfg - ) { - A.notNull(ccfg, "ccfg"); - - return dynamicStartCache(ccfg, - ccfg.getName(), - ccfg.getNearConfiguration(), - CacheType.USER, - true, - false, - true, - true); - } - /** * Dynamically starts cache. * @@ -2226,7 +2203,6 @@ public IgniteInternalFuture dynamicStartSqlCache( * @param cacheName Cache name. * @param nearCfg Near cache configuration. * @param cacheType Cache type. - * @param sql If the cache needs to be created as the resukt of SQL {@code CREATE TABLE} command. * @param failIfExists Fail if exists flag. * @param failIfNotStarted If {@code true} fails if cache is not started. * @param checkThreadTx If {@code true} checks that current thread does not have active transactions. @@ -2238,7 +2214,6 @@ public IgniteInternalFuture dynamicStartCache( String cacheName, @Nullable NearCacheConfiguration nearCfg, CacheType cacheType, - boolean sql, boolean failIfExists, boolean failIfNotStarted, boolean checkThreadTx diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java index df9d2699d9902..eb0981bbbaf2d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastructures/DataStructuresProcessor.java @@ -998,7 +998,6 @@ private String compatibleConfiguration(CollectionConfiguration cfg) throws Ignit null, CacheType.INTERNAL, false, - false, true, true).get(); } From 307bee450848f1e85e5e223ba4022d4a4bf00b30 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Fri, 19 May 2017 18:21:50 +0300 Subject: [PATCH 17/21] IGNITE-5052 Additional checks for unsupported stuff in CREATE TABLE --- .../query/h2/sql/GridSqlQueryParser.java | 59 ++++++++++++++++++- .../query/h2/sql/GridQueryParsingTest.java | 17 +++++- 2 files changed, 73 insertions(+), 3 deletions(-) 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 52a135a4ea8fa..b467fad0c4fff 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 @@ -38,6 +38,7 @@ import org.h2.command.Command; import org.h2.command.CommandContainer; import org.h2.command.Prepared; +import org.h2.command.ddl.AlterTableAddConstraint; import org.h2.command.ddl.CreateIndex; import org.h2.command.ddl.CreateTable; import org.h2.command.ddl.CreateTableData; @@ -53,6 +54,7 @@ import org.h2.command.dml.Select; import org.h2.command.dml.SelectUnion; import org.h2.command.dml.Update; +import org.h2.engine.Constants; import org.h2.engine.FunctionAlias; import org.h2.expression.Aggregate; import org.h2.expression.Alias; @@ -383,6 +385,12 @@ public class GridSqlQueryParser { /** */ private static final Getter DROP_TABLE_NAME = getter(DropTable.class, "tableName"); + /** */ + private static final Getter COLUMN_IS_COMPUTED = getter(Column.class, "isComputed"); + + /** */ + private static final Getter COLUMN_CHECK_CONSTRAINT = getter(Column.class, "checkConstraint"); + /** */ private static final String PARAM_NAME_VALUE_SEPARATOR = "="; @@ -836,6 +844,28 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { throw new IgniteSQLException("CREATE TABLE ... AS ... syntax is not supported", IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + List constraints = CREATE_TABLE_CONSTRAINTS.get(createTbl); + + if (constraints.size() == 0) + throw new IgniteSQLException("No PRIMARY KEY defined for CREATE TABLE", + IgniteQueryErrorCode.PARSING); + + if (constraints.size() > 1) + throw new IgniteSQLException("Too many constraints - only PRIMARY KEY is supported for CREATE TABLE", + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + DefineCommand constraint = constraints.get(0); + + if (!(constraint instanceof AlterTableAddConstraint)) + throw new IgniteSQLException("Unsupported type of constraint for CREATE TABLE - only PRIMARY KEY " + + "is supported", IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + AlterTableAddConstraint alterTbl = (AlterTableAddConstraint)constraint; + + if (alterTbl.getType() != Command.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY) + throw new IgniteSQLException("Unsupported type of constraint for CREATE TABLE - only PRIMARY KEY " + + "is supported", IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + Schema schema = SCHEMA_COMMAND_SCHEMA.get(createTbl); res.schemaName(schema.getName()); @@ -845,8 +875,33 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { LinkedHashMap cols = new LinkedHashMap<>(data.columns.size()); for (Column col : data.columns) { + if (col.isAutoIncrement()) + throw new IgniteSQLException("AUTO_INCREMENT columns are not supported [colName=" + col.getName() + ']', + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + if (!col.isNullable()) - throw new IgniteSQLException("Non nullable columns are forbidden", IgniteQueryErrorCode.PARSING); + throw new IgniteSQLException("Non nullable columns are forbidden [colName=" + col.getName() + ']', + IgniteQueryErrorCode.PARSING); + + if (COLUMN_IS_COMPUTED.get(col)) + throw new IgniteSQLException("Computed columns are not supported [colName=" + col.getName() + ']', + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + if (col.getDefaultExpression() != null) + throw new IgniteSQLException("DEFAULT expressions are not supported [colName=" + col.getName() + ']', + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + if (col.getSequence() != null) + throw new IgniteSQLException("SEQUENCE columns are not supported [colName=" + col.getName() + ']', + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + if (col.getSelectivity() != Constants.SELECTIVITY_DEFAULT) + throw new IgniteSQLException("SELECTIVITY column attr is not supported [colName=" + col.getName() + ']', + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + + if (COLUMN_CHECK_CONSTRAINT.get(col) != null) + throw new IgniteSQLException("Column CHECK constraints are not supported [colName=" + col.getName() + + ']', IgniteQueryErrorCode.UNSUPPORTED_OPERATION); GridSqlColumn gridCol = new GridSqlColumn(col, null, col.getName()); @@ -863,7 +918,7 @@ private GridSqlCreateTable parseCreateTable(CreateTable createTbl) { IndexColumn[] pkIdxCols = CREATE_TABLE_PK.get(createTbl); if (F.isEmpty(pkIdxCols)) - throw new IgniteSQLException("No PRIMARY KEY columns specified"); + throw new AssertionError("No PRIMARY KEY columns specified"); LinkedHashSet pkCols = new LinkedHashSet<>(); 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 e68479f03a99e..33f2db2b76ad2 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 @@ -590,7 +590,7 @@ false, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), "\"tplCache=cache\""); assertParseThrows("create table Person (id int)", - IgniteSQLException.class, "No PRIMARY KEY columns specified"); + IgniteSQLException.class, "No PRIMARY KEY defined for CREATE TABLE"); assertParseThrows("create table Person (id int) AS SELECT 2 * 2", IgniteSQLException.class, "CREATE TABLE ... AS ... syntax is not supported"); @@ -604,6 +604,21 @@ false, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), assertParseThrows("create table Person (id int primary key, age int not null) WITH \"tplCache=cache\"", IgniteSQLException.class, "Non nullable columns are forbidden"); + assertParseThrows("create table Person (id int primary key, age int unique) WITH \"tplCache=cache\"", + IgniteSQLException.class, "Too many constraints - only PRIMARY KEY is supported for CREATE TABLE"); + + assertParseThrows("create table Person (id int auto_increment primary key, age int) WITH \"tplCache=cache\"", + IgniteSQLException.class, "AUTO_INCREMENT columns are not supported"); + + assertParseThrows("create table Person (id int primary key check id > 0, age int) WITH \"tplCache=cache\"", + IgniteSQLException.class, "Column CHECK constraints are is not supported [colName=ID]"); + + assertParseThrows("create table Person (id int as age * 2 primary key, age int) WITH \"tplCache=cache\"", + IgniteSQLException.class, "Computed columns are not supported [colName=ID]"); + + assertParseThrows("create table Person (id int primary key, age int default 5) WITH \"tplCache=cache\"", + IgniteSQLException.class, "DEFAULT expressions are not supported [colName=AGE]"); + assertParseThrows("create table Int (_key int primary key, _val int) WITH \"tplCache=cache\"", IgniteSQLException.class, "Direct specification of _KEY and _VAL columns is forbidden"); } From 84d089568a1424f03a7afd40de6bf0483d74ea48 Mon Sep 17 00:00:00 2001 From: devozerov Date: Mon, 22 May 2017 13:51:22 +0300 Subject: [PATCH 18/21] Minors. --- .../java/org/apache/ignite/internal/IgniteEx.java | 3 ++- .../cache/CacheAffinitySharedManager.java | 2 +- .../processors/cache/ClusterCachesInfo.java | 2 +- .../processors/query/GridQueryIndexing.java | 9 --------- .../processors/query/h2/IgniteH2Indexing.java | 15 --------------- .../query/h2/ddl/DdlStatementsProcessor.java | 2 -- 6 files changed, 4 insertions(+), 29 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java index 7f9f7d069388e..8c270272fbd17 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteEx.java @@ -74,7 +74,8 @@ public interface IgniteEx extends Ignite { * @return Tuple [Existing or newly created cache; {@code true} if cache was newly crated, {@code false} otherwise] * @throws CacheException If error occurs. */ - public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) throws CacheException; + public IgniteBiTuple, Boolean> getOrCreateCache0(CacheConfiguration cacheCfg) + throws CacheException; /** * Stops dynamically started cache. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java index 50d3092a3d0d4..cec42a80c3dd4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheAffinitySharedManager.java @@ -342,7 +342,7 @@ private void updateCachesInfo(ExchangeActions exchActions) { req.deploymentId(), req.schema()); - DynamicCacheDescriptor old = registeredCaches.put(cacheId, desc); + DynamicCacheDescriptor old = registeredCaches.put(cacheId, desc); assert old == null : old; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java index 745bf92f62d15..ab5cf37c438b6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java @@ -420,7 +420,7 @@ else if (req.close()) { if (!F.isEmpty(reqsToComplete)) { ctx.closure().callLocalSafe(new Callable() { @Override public Void call() throws Exception { - for (T2 t :reqsToComplete) { + for (T2 t : reqsToComplete) { final DynamicCacheChangeRequest req = t.get1(); AffinityTopologyVersion waitTopVer = t.get2(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index 695298325d5a2..17cc4f9cfa00a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -286,15 +286,6 @@ public void rebuildIndexesFromHash(String spaceName, */ public String space(String schemaName); - /** - * Get space name by database schema and table name. - * - * @param schemaName Schema name. Could not be null. Could be empty. - * @param tblName Table name, non-empty. - * @return Space name. Could be null. - */ - public String space(String schemaName, String tblName); - /** * Collect queries that already running more than specified duration. * diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 418ba3a954be8..0874ddcf14516 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -56,12 +56,10 @@ import java.util.concurrent.atomic.AtomicLong; import javax.cache.Cache; import javax.cache.CacheException; -import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; -import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.cache.query.QueryCancelledException; import org.apache.ignite.cache.query.QueryCursor; @@ -82,7 +80,6 @@ import org.apache.ignite.internal.processors.cache.GridCacheAffinityManager; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; -import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException; @@ -106,7 +103,6 @@ import org.apache.ignite.internal.processors.query.GridRunningQueryInfo; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.QueryIndexDescriptorImpl; -import org.apache.ignite.internal.processors.query.QueryTypeDescriptorImpl; import org.apache.ignite.internal.processors.query.h2.ddl.DdlStatementsProcessor; import org.apache.ignite.internal.processors.query.h2.opt.DistributedJoinMode; import org.apache.ignite.internal.processors.query.h2.database.H2PkHashIndex; @@ -2122,17 +2118,6 @@ private void cleanupStatementCache() { return schema.spaceName; } - /** {@inheritDoc} */ - @Override public String space(String schemaName, String tblName) { - GridH2Table tbl = dataTable(schemaName, tblName); - - if (tbl == null) - throw new IgniteSQLException("Table not found [schemaName=" + schemaName + ",tblName=" + tblName + ']', - IgniteQueryErrorCode.TABLE_NOT_FOUND); - - return tbl.spaceName(); - } - /** * Rebuild indexes from hash index. * diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index e4d1b1f0dce7b..eedf752dcc98c 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -33,7 +33,6 @@ import org.apache.ignite.internal.processors.query.GridQueryProperty; import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; import org.apache.ignite.internal.processors.query.IgniteSQLException; -import org.apache.ignite.internal.processors.query.QueryUtils; import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing; import org.apache.ignite.internal.processors.query.h2.opt.GridH2Table; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn; @@ -44,7 +43,6 @@ import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser; import org.apache.ignite.internal.processors.query.h2.sql.GridSqlStatement; import org.apache.ignite.internal.processors.query.schema.SchemaOperationException; -import org.apache.ignite.internal.util.typedef.F; import org.h2.command.Prepared; import org.h2.command.ddl.CreateIndex; import org.h2.command.ddl.CreateTable; From 32abecbb5fd2cc95083870183e27c93b1b5ee3ab Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Mon, 22 May 2017 20:00:16 +0300 Subject: [PATCH 19/21] IGNITE-5052 Review fixes. --- .../processors/cache/GridCacheProcessor.java | 27 +++++++++++++---- .../processors/query/GridQueryProcessor.java | 29 ++++++++++--------- .../processors/query/h2/IgniteH2Indexing.java | 1 - .../query/h2/ddl/DdlStatementsProcessor.java | 4 +-- .../query/h2/sql/GridSqlQueryParser.java | 9 +++--- .../cache/index/H2DynamicTableSelfTest.java | 24 +++++++-------- .../query/h2/sql/GridQueryParsingTest.java | 22 +++++++------- .../IgniteCacheQuerySelfTestSuite.java | 2 ++ 8 files changed, 69 insertions(+), 49 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index ee29bac8d74eb..3301370842b64 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -2063,7 +2063,7 @@ private boolean startAllCachesOnClientStart() { */ public IgniteInternalFuture createFromTemplate(String cacheName) { try { - CacheConfiguration cfg = createConfigFromTemplate(cacheName); + CacheConfiguration cfg = getOrCreateConfigFromTemplate(cacheName); return dynamicStartCache(cfg, cacheName, null, true, true, true); } @@ -2086,7 +2086,7 @@ public IgniteInternalFuture getOrCreateFromTemplate(String cacheName, boolean if (publicJCache(cacheName, false, checkThreadTx) != null) // Cache with given name already started. return new GridFinishedFuture<>(); - CacheConfiguration cfg = createConfigFromTemplate(cacheName); + CacheConfiguration cfg = getOrCreateConfigFromTemplate(cacheName); return dynamicStartCache(cfg, cacheName, null, false, true, checkThreadTx); } @@ -2097,10 +2097,10 @@ public IgniteInternalFuture getOrCreateFromTemplate(String cacheName, boolean /** * @param cacheName Cache name. - * @return Cache configuration. + * @return Cache configuration, or {@code null} if no template with matching name found. * @throws IgniteCheckedException If failed. */ - public CacheConfiguration createConfigFromTemplate(String cacheName) throws IgniteCheckedException { + public CacheConfiguration getConfigFromTemplate(String cacheName) throws IgniteCheckedException { CacheConfiguration cfgTemplate = null; CacheConfiguration dfltCacheCfg = null; @@ -2158,7 +2158,10 @@ else if (dfltCacheCfg == null) if (cfgTemplate == null) cfgTemplate = dfltCacheCfg; - cfgTemplate = cfgTemplate == null ? new CacheConfiguration() : cloneCheckSerializable(cfgTemplate); + if (cfgTemplate == null) + return null; + + cfgTemplate = cloneCheckSerializable(cfgTemplate); CacheConfiguration cfg = new CacheConfiguration(cfgTemplate); @@ -2167,6 +2170,20 @@ else if (dfltCacheCfg == null) return cfg; } + /** + * @param cacheName Cache name. + * @return Cache configuration. + * @throws IgniteCheckedException If failed. + */ + private CacheConfiguration getOrCreateConfigFromTemplate(String cacheName) throws IgniteCheckedException { + CacheConfiguration cfg = getConfigFromTemplate(cacheName); + + if (cfg != null) + return cfg; + else + return new CacheConfiguration(cacheName); + } + /** * Dynamically starts cache. * 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 78b302f083b08..d449dc9c42128 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 @@ -17,7 +17,6 @@ package org.apache.ignite.internal.processors.query; -import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteException; @@ -48,7 +47,6 @@ import org.apache.ignite.internal.processors.cache.query.CacheQueryFuture; import org.apache.ignite.internal.processors.cache.query.CacheQueryType; import org.apache.ignite.internal.processors.cache.query.GridCacheQueryType; -import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; import org.apache.ignite.internal.processors.cache.query.QueryCursorEx; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitor; @@ -1266,21 +1264,25 @@ else if (op instanceof SchemaIndexDropOperation) { /** * Create cache and table from given query entity. * + * @param schemaName Schema name to create table in. * @param entity Entity to create table from. - * @param tplCacheName Cache name to take settings from. + * @param templateCacheName Cache name to take settings from. * @param ifNotExists Quietly ignore this command if table already exists. * @throws IgniteCheckedException If failed. */ @SuppressWarnings("unchecked") - public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean ifNotExists) + public void dynamicTableCreate(String schemaName, QueryEntity entity, String templateCacheName, boolean ifNotExists) throws IgniteCheckedException { - CacheConfiguration tplCfg = ctx.cache().createConfigFromTemplate(tplCacheName); + CacheConfiguration templateCfg = ctx.cache().getConfigFromTemplate(templateCacheName); - if (!F.isEmpty(tplCfg.getQueryEntities())) - throw new IgniteSQLException("Template cache already contains query entities which it should not " + - "[cacheName=" + tplCacheName + ']', IgniteQueryErrorCode.UNKNOWN); + if (templateCfg == null) + throw new SchemaOperationException(SchemaOperationException.CODE_CACHE_NOT_FOUND, templateCacheName); - CacheConfiguration newCfg = new CacheConfiguration<>(tplCfg); + 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); newCfg.setName(entity.getTableName()); @@ -1292,8 +1294,7 @@ public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean boolean res = ctx.grid().getOrCreateCache0(newCfg).get2(); if (!res && !ifNotExists) - throw new IgniteSQLException("Table already exists [tblName=" + entity.getTableName() + ']', - IgniteQueryErrorCode.TABLE_ALREADY_EXISTS); + throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_EXISTS, entity.getTableName()); } /** @@ -1302,14 +1303,14 @@ public void dynamicTableCreate(QueryEntity entity, String tplCacheName, boolean * @param schemaName Schema name. * @param tblName Table name. * @param ifExists Quietly ignore this command if table does not exist. + * @throws SchemaOperationException if {@code ifExists} is {@code false} and cache was not found. */ @SuppressWarnings("unchecked") - public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) { + public void dynamicTableDrop(String schemaName, String tblName, boolean ifExists) throws SchemaOperationException { boolean res = ctx.grid().destroyCache0(tblName); if (!res && !ifExists) - throw new IgniteSQLException("Table not found [schemaName=" + schemaName + - ",tblName=" + tblName +']', IgniteQueryErrorCode.TABLE_NOT_FOUND); + throw new SchemaOperationException(SchemaOperationException.CODE_TABLE_NOT_FOUND, tblName); } /** diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 0874ddcf14516..5ffc348757e2b 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1632,7 +1632,6 @@ public static Session session(Connection c) { } } - prepared = GridSqlQueryParser.prepared(stmt); if (qry instanceof JdbcSqlFieldsQuery && ((JdbcSqlFieldsQuery) qry).isQuery() != prepared.isQuery()) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index eedf752dcc98c..7f72f4717b5bc 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -139,8 +139,8 @@ else if (gridStmt instanceof GridSqlDropIndex) { else if (gridStmt instanceof GridSqlCreateTable) { GridSqlCreateTable createTbl = (GridSqlCreateTable)gridStmt; - ctx.query().dynamicTableCreate(toQueryEntity(createTbl), createTbl.templateCacheName(), - createTbl.ifNotExists()); + ctx.query().dynamicTableCreate(createTbl.schemaName(), toQueryEntity(createTbl), + createTbl.templateCacheName(), createTbl.ifNotExists()); fut = null; } 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 b467fad0c4fff..475dff28745e9 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 @@ -395,10 +395,11 @@ public class GridSqlQueryParser { private static final String PARAM_NAME_VALUE_SEPARATOR = "="; /** */ - private static final String PARAM_TPL_CACHE = "tplCache"; + 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_TPL_CACHE + PARAM_CACHE_TEMPLATE }; /** */ @@ -1009,8 +1010,8 @@ private static void processExtraParam(String name, String val, GridSqlCreateTabl assert !F.isEmpty(name); switch (name) { - case PARAM_TPL_CACHE: - ensureParamValueNotEmpty(PARAM_TPL_CACHE, val); + case PARAM_CACHE_TEMPLATE: + ensureParamValueNotEmpty(PARAM_CACHE_TEMPLATE, val); res.templateCacheName(val); 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 ef13cf2823651..90cb65e2bfd66 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 @@ -61,7 +61,7 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { client().getOrCreateCache(cacheConfigurationForIndexing()); - client().getOrCreateCache(cacheConfiguration()); + client().addCacheConfiguration(cacheConfiguration()); } /** {@inheritDoc} */ @@ -82,7 +82,7 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { public void testCreateTable() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"tplCache=cache\"")); + "\"cacheTemplate=cache\"")); for (int i = 0; i < 4; i++) { IgniteEx node = grid(i); @@ -124,35 +124,35 @@ public void testCreateTable() throws Exception { public void testCreateTableIfNotExists() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"tplCache=cache\"")); + "\"cacheTemplate=cache\"")); cache().query(new SqlFieldsQuery("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"tplCache=cache\"")); + "\"cacheTemplate=cache\"")); } /** */ public void testCreateExistingTable() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"tplCache=cache\"")); + "\"cacheTemplate=cache\"")); GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar" + ", \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"tplCache=cache\"")); + "\"cacheTemplate=cache\"")); return null; } - }, IgniteSQLException.class, "Table already exists [tblName=Person]"); + }, IgniteSQLException.class, "Table already exists: Person"); } /** */ public void testDropTable() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"tplCache=cache\"")); + "\"cacheTemplate=cache\"")); cache().query(new SqlFieldsQuery("DROP TABLE \"Person\".\"Person\"")); @@ -169,18 +169,18 @@ public void testDropTable() throws Exception { /** */ public void testDropTableIfExists() throws Exception { - cache().query(new SqlFieldsQuery("DROP TABLE IF EXISTS \"cache\".\"City\"")); + cache().query(new SqlFieldsQuery("DROP TABLE IF EXISTS \"cache_idx\".\"City\"")); } /** */ public void testDropMissingTable() throws Exception { GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { - cache().query(new SqlFieldsQuery("DROP TABLE \"cache\".\"City\"")); + cache().query(new SqlFieldsQuery("DROP TABLE \"cache_idx\".\"City\"")); return null; } - }, IgniteSQLException.class, "Table not found [schemaName=cache,tblName=City]"); + }, IgniteSQLException.class, "Table doesn't exist: City"); } /** */ @@ -254,7 +254,7 @@ private IgniteEx client() { } /** - * @return Client node. + * @return Cache to issue queries upon. */ private IgniteCache cache() { return client().cache(INDEXED_CACHE_NAME); 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 33f2db2b76ad2..e372584222c46 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 @@ -579,7 +579,7 @@ true, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), c("surname", Value.STRING), c("age", Value.INT)), "CREATE TABLE IF NOT EXISTS sch1.\"Person\" (\"id\" integer, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" integer, PRIMARY KEY (\"id\", \"city\")) WITH " + - "\"tplCache=cache\""); + "\"cacheTemplate=cache\""); assertCreateTableEquals( buildCreateTable("sch1", "Person", "cache", F.asList("id"), @@ -587,7 +587,7 @@ false, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), c("surname", Value.STRING), c("age", Value.INT)), "CREATE TABLE sch1.\"Person\" (\"id\" integer PRIMARY KEY, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" integer) WITH " + - "\"tplCache=cache\""); + "\"cacheTemplate=cache\""); assertParseThrows("create table Person (id int)", IgniteSQLException.class, "No PRIMARY KEY defined for CREATE TABLE"); @@ -599,27 +599,27 @@ false, c("id", Value.INT), c("city", Value.STRING), c("name", Value.STRING), 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=tplCache]"); + IgniteSQLException.class, "Mandatory param is missing [paramName=cacheTemplate]"); - assertParseThrows("create table Person (id int primary key, age int not null) WITH \"tplCache=cache\"", + assertParseThrows("create table Person (id int primary key, age int not null) WITH \"cacheTemplate=cache\"", IgniteSQLException.class, "Non nullable columns are forbidden"); - assertParseThrows("create table Person (id int primary key, age int unique) WITH \"tplCache=cache\"", + assertParseThrows("create table Person (id int primary key, age int unique) WITH \"cacheTemplate=cache\"", IgniteSQLException.class, "Too many constraints - only PRIMARY KEY is supported for CREATE TABLE"); - assertParseThrows("create table Person (id int auto_increment primary key, age int) WITH \"tplCache=cache\"", + assertParseThrows("create table Person (id int auto_increment primary key, age int) WITH \"cacheTemplate=cache\"", IgniteSQLException.class, "AUTO_INCREMENT columns are not supported"); - assertParseThrows("create table Person (id int primary key check id > 0, age int) WITH \"tplCache=cache\"", - IgniteSQLException.class, "Column CHECK constraints are is not supported [colName=ID]"); + assertParseThrows("create table Person (id int primary key check id > 0, age int) WITH \"cacheTemplate=cache\"", + IgniteSQLException.class, "Column CHECK constraints are not supported [colName=ID]"); - assertParseThrows("create table Person (id int as age * 2 primary key, age int) WITH \"tplCache=cache\"", + assertParseThrows("create table Person (id int as age * 2 primary key, age int) WITH \"cacheTemplate=cache\"", IgniteSQLException.class, "Computed columns are not supported [colName=ID]"); - assertParseThrows("create table Person (id int primary key, age int default 5) WITH \"tplCache=cache\"", + assertParseThrows("create table Person (id int primary key, age int default 5) WITH \"cacheTemplate=cache\"", IgniteSQLException.class, "DEFAULT expressions are not supported [colName=AGE]"); - assertParseThrows("create table Int (_key int primary key, _val int) WITH \"tplCache=cache\"", + assertParseThrows("create table Int (_key int primary key, _val int) WITH \"cacheTemplate=cache\"", IgniteSQLException.class, "Direct specification of _KEY and _VAL columns is forbidden"); } diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java index 6370cd0a051f6..14fb6cef026f0 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java @@ -96,6 +96,7 @@ import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerNodeFIlterBasicSelfTest; import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerNodeFilterCoordinatorBasicSelfTest; import org.apache.ignite.internal.processors.cache.index.DynamicIndexServerBasicSelfTest; +import org.apache.ignite.internal.processors.cache.index.H2DynamicTableSelfTest; import org.apache.ignite.internal.processors.cache.index.QueryEntityValidationSelfTest; import org.apache.ignite.internal.processors.cache.index.SchemaExchangeSelfTest; import org.apache.ignite.internal.processors.cache.local.IgniteCacheLocalAtomicQuerySelfTest; @@ -227,6 +228,7 @@ public static TestSuite suite() throws Exception { suite.addTestSuite(H2DynamicIndexAtomicReplicatedSelfTest.class); suite.addTestSuite(H2DynamicIndexAtomicPartitionedSelfTest.class); suite.addTestSuite(H2DynamicIndexAtomicPartitionedNearSelfTest.class); + suite.addTestSuite(H2DynamicTableSelfTest.class); // Fields queries. suite.addTestSuite(SqlFieldsQuerySelfTest.class); From 49a14d1f6c75a449e41fd007b60dc71ca2a6c302 Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Tue, 23 May 2017 13:49:52 +0300 Subject: [PATCH 20/21] IGNITE-5052 Javadocs fixed. --- .../cache/index/H2DynamicTableSelfTest.java | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 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 90cb65e2bfd66..b072fdbb91bf0 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 @@ -78,7 +78,10 @@ public class H2DynamicTableSelfTest extends AbstractSchemaSelfTest { super.afterTest(); } - /** */ + /** + * Test that {@code CREATE TABLE} actually creates new cache, H2 table and type descriptor on all nodes. + * @throws Exception if failed. + */ public void testCreateTable() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + @@ -120,7 +123,11 @@ public void testCreateTable() throws Exception { } } - /** */ + /** + * Test that attempting to {@code CREATE TABLE} that already exists does not yield an error if the statement + * contains {@code IF NOT EXISTS} clause. + * @throws Exception if failed. + */ public void testCreateTableIfNotExists() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + @@ -131,7 +138,10 @@ public void testCreateTableIfNotExists() throws Exception { "\"cacheTemplate=cache\"")); } - /** */ + /** + * Test that attempting to {@code CREATE TABLE} that already exists yields an error. + * @throws Exception if failed. + */ public void testCreateExistingTable() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + @@ -148,7 +158,10 @@ public void testCreateExistingTable() throws Exception { }, IgniteSQLException.class, "Table already exists: Person"); } - /** */ + /** + * Test that {@code DROP TABLE} actually removes specified cache and type descriptor on all nodes. + * @throws Exception if failed. + */ public void testDropTable() throws Exception { cache().query(new SqlFieldsQuery("CREATE TABLE IF NOT EXISTS \"Person\" (\"id\" int, \"city\" varchar," + " \"name\" varchar, \"surname\" varchar, \"age\" int, PRIMARY KEY (\"id\", \"city\")) WITH " + @@ -167,12 +180,19 @@ public void testDropTable() throws Exception { } } - /** */ - public void testDropTableIfExists() throws Exception { + /** + * Test that attempting to {@code DROP TABLE} that does not exist does not yield an error if the statement contains + * {@code IF EXISTS} clause. + * @throws Exception if failed. + */ + public void testDropMissingTableIfExists() throws Exception { cache().query(new SqlFieldsQuery("DROP TABLE IF EXISTS \"cache_idx\".\"City\"")); } - /** */ + /** + * Test that attempting to {@code DROP TABLE} that does not exist yields an error. + * @throws Exception if failed. + */ public void testDropMissingTable() throws Exception { GridTestUtils.assertThrows(null, new Callable() { @Override public Object call() throws Exception { @@ -183,7 +203,14 @@ public void testDropMissingTable() throws Exception { }, IgniteSQLException.class, "Table doesn't exist: City"); } - /** */ + /** + * Check that a property in given descriptor is present and has parameters as expected. + * @param desc Descriptor. + * @param name Property name. + * @param type Expected property type. + * @param isKey {@code true} if the property is expected to belong to key, {@code false} is it's expected to belong + * to value. + */ private void assertProperty(QueryTypeDescriptorImpl desc, String name, Class type, boolean isKey) { GridQueryProperty p = desc.property(name); From 06af28382b2b6203b6ddc9c94cb27507d5742faa Mon Sep 17 00:00:00 2001 From: Alexander Paschenko Date: Wed, 24 May 2017 15:14:55 +0300 Subject: [PATCH 21/21] IGNITE-5052 Preserve existing protocol for getorcreate and destcache REST commands despite changes in GridCacheProcessor --- .../rest/handlers/cache/GridCacheCommandHandler.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java index 18cd6afc6c044..080d639e0a2a0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/cache/GridCacheCommandHandler.java @@ -383,7 +383,9 @@ private static IgniteInternalCache cache(Ignite ignite, new CX1, GridRestResponse>() { @Override public GridRestResponse applyx(IgniteInternalFuture f) throws IgniteCheckedException { - return new GridRestResponse(f.get()); + f.get(); + + return new GridRestResponse(null); } }); @@ -396,7 +398,9 @@ private static IgniteInternalCache cache(Ignite ignite, new CX1, GridRestResponse>() { @Override public GridRestResponse applyx(IgniteInternalFuture f) throws IgniteCheckedException { - return new GridRestResponse(f.get()); + f.get(); + + return new GridRestResponse(null); } });