You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2015/12/23 03:56:45 UTC
[07/28] ignite git commit: ignite-1979 Support case insensitive
nonquoted cache names in SQL - Fixes #324.
ignite-1979 Support case insensitive nonquoted cache names in SQL - Fixes #324.
Signed-off-by: S.Vladykin <sv...@gridgain.com>
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/da24df99
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/da24df99
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/da24df99
Branch: refs/heads/ignite-gg-10889
Commit: da24df99525b796a79fdb55997efe1c9bd515a5d
Parents: a0cdb59
Author: vershov <ve...@gridgain.com>
Authored: Tue Dec 22 00:08:37 2015 +0300
Committer: S.Vladykin <sv...@gridgain.com>
Committed: Tue Dec 22 00:08:37 2015 +0300
----------------------------------------------------------------------
.../configuration/CacheConfiguration.java | 44 +++-
.../ignite/internal/util/IgniteUtils.java | 6 +-
.../cache/VisorCacheQueryConfiguration.java | 11 +
.../processors/query/h2/IgniteH2Indexing.java | 118 ++++++---
.../query/h2/sql/GridSqlQuerySplitter.java | 48 ++--
.../query/IgniteSqlSchemaIndexingTest.java | 240 +++++++++++++++++++
.../IgniteCacheQuerySelfTestSuite.java | 2 +
.../commands/cache/VisorCacheCommand.scala | 13 +-
8 files changed, 416 insertions(+), 66 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/da24df99/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
----------------------------------------------------------------------
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 be1240c..d52662e 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
@@ -365,15 +365,18 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
private IgnitePredicate<ClusterNode> nodeFilter;
/** */
- private boolean sqlEscapeAll;
+ private String sqlSchema;
/** */
- private transient Class<?>[] indexedTypes;
+ private boolean sqlEscapeAll;
/** */
private int sqlOnheapRowCacheSize = DFLT_SQL_ONHEAP_ROW_CACHE_SIZE;
/** */
+ private transient Class<?>[] indexedTypes;
+
+ /** */
private boolean snapshotableIdx;
/** Copy on read flag. */
@@ -466,6 +469,7 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
rebalanceTimeout = cc.getRebalanceTimeout();
rebalanceThrottle = cc.getRebalanceThrottle();
snapshotableIdx = cc.isSnapshotableIndex();
+ sqlSchema = cc.getSqlSchema();
sqlEscapeAll = cc.isSqlEscapeAll();
sqlFuncCls = cc.getSqlFunctionClasses();
sqlOnheapRowCacheSize = cc.getSqlOnheapRowCacheSize();
@@ -1770,7 +1774,7 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
}
/**
- * Gets timeout in milliseconds after which long query warning will be printed.
+ * Sets timeout in milliseconds after which long query warning will be printed.
*
* @param longQryWarnTimeout Timeout in milliseconds.
* @return {@code this} for chaining.
@@ -1782,6 +1786,40 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K, V> {
}
/**
+ * Gets custom name of the sql schema. If custom sql schema is not set then {@code null} will be returned and
+ * quoted case sensitive name will be used as sql schema.
+ *
+ * @return Schema name for current cache according to SQL ANSI-99. Could be {@code null}.
+ */
+ @Nullable public String getSqlSchema() {
+ return sqlSchema;
+ }
+
+ /**
+ * Sets sql schema to be used for current cache. This name will correspond to SQL ANSI-99 standard.
+ * Nonquoted identifiers are not case sensitive. Quoted identifiers are case sensitive.
+ * <p/>
+ * Be aware of using the same string in case sensitive and case insensitive manner simultaneously, since
+ * behaviour for such case is not specified.
+ * <p/>
+ * When sqlSchema is not specified, quoted {@code cacheName} is used instead.
+ * <p/>
+ * {@code sqlSchema} could not be an empty string. Has to be {@code "\"\""} instead.
+ *
+ * @param sqlSchema Schema name for current cache according to SQL ANSI-99. Should not be {@code null}.
+ *
+ * @return {@code this} for chaining.
+ */
+ public CacheConfiguration<K, V> setSqlSchema(String sqlSchema) {
+ A.ensure((sqlSchema != null), "Schema could not be null.");
+ A.ensure(!sqlSchema.isEmpty(), "Schema could not be empty.");
+
+ this.sqlSchema = sqlSchema;
+
+ return this;
+ }
+
+ /**
* If {@code true} all the SQL table and field names will be escaped with double quotes like
* ({@code "tableName"."fieldsName"}). This enforces case sensitivity for field names and
* also allows having special characters in table and field names.
http://git-wip-us.apache.org/repos/asf/ignite/blob/da24df99/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index e74b3f0..be4851d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -4243,11 +4243,11 @@ public abstract class IgniteUtils {
/**
* Mask component name to make sure that it is not {@code null}.
*
- * @param cacheName Component name to mask, possibly {@code null}.
+ * @param name Component name to mask, possibly {@code null}.
* @return Component name.
*/
- public static String maskName(@Nullable String cacheName) {
- return cacheName == null ? "default" : cacheName;
+ public static String maskName(@Nullable String name) {
+ return name == null ? "default" : name;
}
/**
http://git-wip-us.apache.org/repos/asf/ignite/blob/da24df99/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheQueryConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheQueryConfiguration.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheQueryConfiguration.java
index cbb97a5..a779db4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheQueryConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/cache/VisorCacheQueryConfiguration.java
@@ -35,6 +35,9 @@ public class VisorCacheQueryConfiguration implements Serializable {
private long longQryWarnTimeout;
/** */
+ private String sqlSchema;
+
+ /** */
private boolean sqlEscapeAll;
/** */
@@ -69,6 +72,7 @@ public class VisorCacheQueryConfiguration implements Serializable {
cfg.sqlFuncClss = compactClasses(ccfg.getSqlFunctionClasses());
cfg.longQryWarnTimeout = ccfg.getLongQueryWarningTimeout();
+ cfg.sqlSchema = ccfg.getSqlSchema();
cfg.sqlEscapeAll = ccfg.isSqlEscapeAll();
cfg.indexedTypes = compactClasses(ccfg.getIndexedTypes());
cfg.sqlOnheapRowCacheSize = ccfg.getSqlOnheapRowCacheSize();
@@ -91,6 +95,13 @@ public class VisorCacheQueryConfiguration implements Serializable {
}
/**
+ * @return Schema name, which is used by SQL engine for SQL statements generation.
+ */
+ public String sqlSchema() {
+ return sqlSchema;
+ }
+
+ /**
* @return {@code true} if SQL engine generate SQL statements with escaped names.
*/
public boolean sqlEscapeAll() {
http://git-wip-us.apache.org/repos/asf/ignite/blob/da24df99/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java
----------------------------------------------------------------------
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 8625be9..dead526 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
@@ -195,6 +195,12 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/** */
private static final Field COMMAND_FIELD;
+ /** */
+ private static final char ESC_CH = '\"';
+
+ /** */
+ private static final String ESC_STR = ESC_CH + "" + ESC_CH;
+
/**
* Command in H2 prepared statement.
*/
@@ -236,6 +242,9 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/** */
private GridReduceQueryExecutor rdcQryExec;
+ /** space name -> schema name */
+ private final Map<String, String> space2schema = new ConcurrentHashMap8<>();
+
/** */
private final ThreadLocal<ConnectionWrapper> connCache = new ThreadLocal<ConnectionWrapper>() {
@Nullable @Override public ConnectionWrapper get() {
@@ -360,7 +369,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
try {
stmt = c.connection().createStatement();
- stmt.executeUpdate("SET SCHEMA \"" + schema + '"');
+ stmt.executeUpdate("SET SCHEMA " + schema);
if (log.isDebugEnabled())
log.debug("Set schema: " + schema);
@@ -386,7 +395,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
* @throws IgniteCheckedException If failed to create db schema.
*/
private void createSchema(String schema) throws IgniteCheckedException {
- executeStatement("INFORMATION_SCHEMA", "CREATE SCHEMA IF NOT EXISTS \"" + schema + '"');
+ executeStatement("INFORMATION_SCHEMA", "CREATE SCHEMA IF NOT EXISTS " + schema);
if (log.isDebugEnabled())
log.debug("Created H2 schema for index database: " + schema);
@@ -399,7 +408,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
* @throws IgniteCheckedException If failed to create db schema.
*/
private void dropSchema(String schema) throws IgniteCheckedException {
- executeStatement("INFORMATION_SCHEMA", "DROP SCHEMA IF EXISTS \"" + schema + '"');
+ executeStatement("INFORMATION_SCHEMA", "DROP SCHEMA IF EXISTS " + schema);
if (log.isDebugEnabled())
log.debug("Dropped H2 schema for index database: " + schema);
@@ -642,7 +651,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
if (log.isDebugEnabled())
log.debug("Removing query index table: " + tbl.fullTableName());
- Connection c = connectionForThread(tbl.schema());
+ Connection c = connectionForThread(tbl.schemaName());
Statement stmt = null;
@@ -767,6 +776,22 @@ public class IgniteH2Indexing implements GridQueryIndexing {
}
/**
+ * Stores rule for constructing schemaName according to cache configuration.
+ *
+ * @param ccfg Cache configuration.
+ * @return Proper schema name according to ANSI-99 standard.
+ */
+ private static String schemaNameFromCacheConf(CacheConfiguration<?,?> ccfg) {
+ if (ccfg.getSqlSchema() == null)
+ return escapeName(ccfg.getName(), true);
+
+ if (ccfg.getSqlSchema().charAt(0) == ESC_CH)
+ return ccfg.getSqlSchema();
+
+ return ccfg.isSqlEscapeAll() ? escapeName(ccfg.getSqlSchema(), true) : ccfg.getSqlSchema().toUpperCase();
+ }
+
+ /**
* Executes sql query.
*
* @param conn Connection,.
@@ -865,9 +890,9 @@ public class IgniteH2Indexing implements GridQueryIndexing {
* @return Result set.
* @throws IgniteCheckedException If failed.
*/
- private ResultSet executeQuery(String space, String qry, @Nullable Collection<Object> params,
- TableDescriptor tbl) throws IgniteCheckedException {
- Connection conn = connectionForThread(tbl.schema());
+ private ResultSet executeQuery(String space, String qry, @Nullable Collection<Object> params, TableDescriptor tbl)
+ throws IgniteCheckedException {
+ Connection conn = connectionForThread(tbl.schemaName());
String sql = generateQuery(qry, tbl);
@@ -1027,7 +1052,8 @@ public class IgniteH2Indexing implements GridQueryIndexing {
}
try {
- twoStepQry = GridSqlQuerySplitter.split((JdbcPreparedStatement)stmt, qry.getArgs(), qry.isCollocated());
+ twoStepQry = GridSqlQuerySplitter.split(
+ (JdbcPreparedStatement)stmt, qry.getArgs(), qry.isCollocated(), this);
meta = meta(stmt.getMetaData());
}
@@ -1174,6 +1200,16 @@ public class IgniteH2Indexing implements GridQueryIndexing {
}
/**
+ * Returns empty string, if {@code nullableString} is empty.
+ *
+ * @param nullableString String for convertion. Could be null.
+ * @return Non null string. Could be empty.
+ */
+ private static String emptyIfNull(String nullableString) {
+ return nullableString == null ? "" : nullableString;
+ }
+
+ /**
* Escapes name to be valid SQL identifier. Currently just replaces '.' and '$' sign with '_'.
*
* @param name Name.
@@ -1181,8 +1217,11 @@ public class IgniteH2Indexing implements GridQueryIndexing {
* @return Escaped name.
*/
private static String escapeName(String name, boolean escapeAll) {
+ if (name == null) // It is possible only for a cache name.
+ return ESC_STR;
+
if (escapeAll)
- return "\"" + name + "\"";
+ return ESC_CH + name + ESC_CH;
SB sb = null;
@@ -1304,24 +1343,32 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/**
* Gets database schema from space.
*
- * @param space Space name.
- * @return Schema name.
+ * @param space Space name. {@code null} would be converted to an empty string.
+ * @return Schema name. Should not be null since we should not fail for an invalid space name.
*/
- public static String schema(@Nullable String space) {
- if (space == null)
- return "";
-
- return space;
+ private String schema(@Nullable String space) {
+ return emptyIfNull(space2schema.get(emptyIfNull(space)));
}
/**
- * @param schema Schema.
- * @return Space name.
+ * Gets space name from database schema.
+ *
+ * @param schemaName Schema name. Could not be null. Could be empty.
+ * @return Space name. Could be null.
*/
- public static String space(String schema) {
- assert schema != null;
+ public String space(String schemaName) {
+ assert schemaName != null;
+
+ Schema schema = schemas.get(schemaName);
+
+ // For the compatibility with conversion from """" to "" inside h2 lib
+ if (schema == null) {
+ assert schemaName.isEmpty() || schemaName.charAt(0) != ESC_CH;
+
+ schema = schemas.get(escapeName(schemaName, true));
+ }
- return "".equals(schema) ? null : schema;
+ return schema.spaceName;
}
/** {@inheritDoc} */
@@ -1427,7 +1474,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
rdcQryExec.start(ctx, this);
}
- // TODO https://issues.apache.org/jira/browse/IGNITE-751
+ // TODO https://issues.apache.org/jira/browse/IGNITE-2139
// registerMBean(gridName, this, GridH2IndexingSpiMBean.class);
}
@@ -1485,7 +1532,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
if (log.isDebugEnabled())
log.debug("Stopping cache query index...");
-// unregisterMBean(); TODO
+// unregisterMBean(); TODO https://issues.apache.org/jira/browse/IGNITE-2139
for (Schema schema : schemas.values()) {
for (TableDescriptor desc : schema.tbls.values()) {
@@ -1501,6 +1548,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
conns.clear();
schemas.clear();
+ space2schema.clear();
try (Connection c = DriverManager.getConnection(dbUrl);
Statement s = c.createStatement()) {
@@ -1516,12 +1564,14 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/** {@inheritDoc} */
@Override public void registerCache(CacheConfiguration<?,?> ccfg) throws IgniteCheckedException {
- String schema = schema(ccfg.getName());
+ String schema = schemaNameFromCacheConf(ccfg);
- if (schemas.putIfAbsent(schema, new Schema(ccfg.getName(),
+ if (schemas.putIfAbsent(schema, new Schema(ccfg.getName(), schema,
ccfg.getOffHeapMaxMemory() >= 0 || ccfg.getMemoryMode() == CacheMemoryMode.OFFHEAP_TIERED ?
new GridUnsafeMemory(0) : null, ccfg)) != null)
- throw new IgniteCheckedException("Cache already registered: " + U.maskName(ccfg.getName()));
+ throw new IgniteCheckedException("Schema for cache already registered: " + U.maskName(ccfg.getName()));
+
+ space2schema.put(emptyIfNull(ccfg.getName()), schema);
createSchema(schema);
@@ -1531,10 +1581,10 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/** {@inheritDoc} */
@Override public void unregisterCache(CacheConfiguration<?, ?> ccfg) {
String schema = schema(ccfg.getName());
-
Schema rmv = schemas.remove(schema);
if (rmv != null) {
+ space2schema.remove(rmv.spaceName);
mapQryExec.onCacheStop(ccfg.getName());
try {
@@ -1855,15 +1905,14 @@ public class IgniteH2Indexing implements GridQueryIndexing {
this.type = type;
this.schema = schema;
- fullTblName = '\"' + IgniteH2Indexing.schema(schema.spaceName) + "\"." +
- escapeName(type.name(), schema.escapeAll());
+ fullTblName = schema.schemaName + "." + escapeName(type.name(), schema.escapeAll());
}
/**
* @return Schema name.
*/
- public String schema() {
- return IgniteH2Indexing.schema(schema.spaceName);
+ public String schemaName() {
+ return schema.schemaName;
}
/**
@@ -2129,6 +2178,9 @@ public class IgniteH2Indexing implements GridQueryIndexing {
private final String spaceName;
/** */
+ private final String schemaName;
+
+ /** */
private final GridUnsafeMemory offheap;
/** */
@@ -2142,11 +2194,13 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/**
* @param spaceName Space name.
+ * @param schemaName Schema name.
* @param offheap Offheap memory.
* @param ccfg Cache configuration.
*/
- private Schema(@Nullable String spaceName, GridUnsafeMemory offheap, CacheConfiguration<?,?> ccfg) {
+ private Schema(@Nullable String spaceName, String schemaName, GridUnsafeMemory offheap, CacheConfiguration<?,?> ccfg) {
this.spaceName = spaceName;
+ this.schemaName = schemaName;
this.offheap = offheap;
this.ccfg = ccfg;
http://git-wip-us.apache.org/repos/asf/ignite/blob/da24df99/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
index 727c2c7..3d9c10a 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java
@@ -138,18 +138,19 @@ public class GridSqlQuerySplitter {
* @param stmt Prepared statement.
* @param params Parameters.
* @param collocated Collocated query.
+ * @param igniteH2Indexing Indexing implementation.
* @return Two step query.
*/
- public static GridCacheTwoStepQuery split(JdbcPreparedStatement stmt, Object[] params, boolean collocated) {
+ public static GridCacheTwoStepQuery split(JdbcPreparedStatement stmt, Object[] params, boolean collocated, IgniteH2Indexing igniteH2Indexing) {
if (params == null)
params = GridCacheSqlQuery.EMPTY_PARAMS;
- Set<String> spaces = new HashSet<>();
+ Set<String> schemas = new HashSet<>();
// Map query will be direct reference to the original query AST.
// Thus all the modifications will be performed on the original AST, so we should be careful when
// nullifying or updating things, have to make sure that we will not need them in the original form later.
- final GridSqlSelect mapQry = wrapUnion(collectAllSpaces(GridSqlQueryParser.parse(stmt), spaces));
+ final GridSqlSelect mapQry = wrapUnion(collectAllSpaces(GridSqlQueryParser.parse(stmt), schemas));
final boolean explain = mapQry.explain();
@@ -258,6 +259,11 @@ public class GridSqlQuerySplitter {
map.parameterIndexes(toIntArray(paramIdxs));
+ Set<String> spaces = new HashSet<>(schemas.size());
+
+ for (String schema : schemas)
+ spaces.add(igniteH2Indexing.space(schema));
+
// Build resulting two step query.
GridCacheTwoStepQuery res = new GridCacheTwoStepQuery(spaces, rdc, rdcQry.simpleQuery()).addMapQuery(map);
@@ -309,25 +315,25 @@ public class GridSqlQuerySplitter {
/**
* @param qry Query.
- * @param spaces Space names.
+ * @param schemas Shemas' names.
* @return Query.
*/
- private static GridSqlQuery collectAllSpaces(GridSqlQuery qry, Set<String> spaces) {
+ private static GridSqlQuery collectAllSpaces(GridSqlQuery qry, Set<String> schemas) {
if (qry instanceof GridSqlUnion) {
GridSqlUnion union = (GridSqlUnion)qry;
- collectAllSpaces(union.left(), spaces);
- collectAllSpaces(union.right(), spaces);
+ collectAllSpaces(union.left(), schemas);
+ collectAllSpaces(union.right(), schemas);
}
else {
GridSqlSelect select = (GridSqlSelect)qry;
- collectAllSpacesInFrom(select.from(), spaces);
+ collectAllSpacesInFrom(select.from(), schemas);
for (GridSqlElement el : select.columns(false))
- collectAllSpacesInSubqueries(el, spaces);
+ collectAllSpacesInSubqueries(el, schemas);
- collectAllSpacesInSubqueries(select.where(), spaces);
+ collectAllSpacesInSubqueries(select.where(), schemas);
}
return qry;
@@ -335,26 +341,26 @@ public class GridSqlQuerySplitter {
/**
* @param from From element.
- * @param spaces Space names.
+ * @param schemas Shemas' names.
*/
- private static void collectAllSpacesInFrom(GridSqlElement from, Set<String> spaces) {
+ private static void collectAllSpacesInFrom(GridSqlElement from, Set<String> schemas) {
assert from != null;
if (from instanceof GridSqlJoin) {
// Left and right.
- collectAllSpacesInFrom(from.child(0), spaces);
- collectAllSpacesInFrom(from.child(1), spaces);
+ collectAllSpacesInFrom(from.child(0), schemas);
+ collectAllSpacesInFrom(from.child(1), schemas);
}
else if (from instanceof GridSqlTable) {
String schema = ((GridSqlTable)from).schema();
if (schema != null)
- spaces.add(IgniteH2Indexing.space(schema));
+ schemas.add(schema);
}
else if (from instanceof GridSqlSubquery)
- collectAllSpaces(((GridSqlSubquery)from).select(), spaces);
+ collectAllSpaces(((GridSqlSubquery)from).select(), schemas);
else if (from instanceof GridSqlAlias)
- collectAllSpacesInFrom(from.child(), spaces);
+ collectAllSpacesInFrom(from.child(), schemas);
else if (!(from instanceof GridSqlFunction))
throw new IllegalStateException(from.getClass().getName() + " : " + from.getSQL());
}
@@ -362,18 +368,18 @@ public class GridSqlQuerySplitter {
/**
* Searches spaces in subqueries in SELECT and WHERE clauses.
* @param el Element.
- * @param spaces Space names.
+ * @param schemas Schemas' names.
*/
- private static void collectAllSpacesInSubqueries(GridSqlElement el, Set<String> spaces) {
+ private static void collectAllSpacesInSubqueries(GridSqlElement el, Set<String> schemas) {
if (el instanceof GridSqlAlias)
el = el.child();
if (el instanceof GridSqlOperation || el instanceof GridSqlFunction) {
for (GridSqlElement child : el)
- collectAllSpacesInSubqueries(child, spaces);
+ collectAllSpacesInSubqueries(child, schemas);
}
else if (el instanceof GridSqlSubquery)
- collectAllSpaces(((GridSqlSubquery)el).select(), spaces);
+ collectAllSpaces(((GridSqlSubquery)el).select(), schemas);
}
/**
http://git-wip-us.apache.org/repos/asf/ignite/blob/da24df99/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSchemaIndexingTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSchemaIndexingTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSchemaIndexingTest.java
new file mode 100644
index 0000000..5c9acb5
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSchemaIndexingTest.java
@@ -0,0 +1,240 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing;
+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;
+
+/**
+ * Tests {@link IgniteH2Indexing} support {@link CacheConfiguration#setSqlSchema(String)} configuration.
+ */
+@SuppressWarnings("unchecked")
+public class IgniteSqlSchemaIndexingTest extends GridCommonAbstractTest {
+ /** */
+ private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration() throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration();
+
+ cfg.setPeerClassLoadingEnabled(false);
+
+ TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+ disco.setIpFinder(ipFinder);
+
+ cfg.setDiscoverySpi(disco);
+
+ return cfg;
+ }
+
+ /**
+ * @param name Cache name.
+ * @param partitioned Partition or replicated cache.
+ * @param idxTypes Indexed types.
+ * @return Cache configuration.
+ */
+ private static CacheConfiguration cacheConfig(String name, boolean partitioned, Class<?>... idxTypes) {
+ return new CacheConfiguration()
+ .setName(name)
+ .setCacheMode(partitioned ? CacheMode.PARTITIONED : CacheMode.REPLICATED)
+ .setAtomicityMode(CacheAtomicityMode.ATOMIC)
+ .setBackups(1)
+ .setIndexedTypes(Integer.class, Fact.class);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ stopAllGrids();
+ }
+
+ /**
+ * Tests collision for case insensitive sqlScheme.
+ *
+ * @throws Exception If failed.
+ */
+ public void testCaseSensitive() throws Exception {
+ //TODO rewrite with dynamic cache creation, and GRID start in #beforeTest after resolve of
+ //https://issues.apache.org/jira/browse/IGNITE-1094
+
+ GridTestUtils.assertThrows(log, new Callable<Object>() {
+ @Override public Object call() throws Exception {
+ final CacheConfiguration cfg = cacheConfig("InSensitiveCache", true, Integer.class, Integer.class)
+ .setSqlSchema("InsensitiveCache");
+ final CacheConfiguration collisionCfg = cacheConfig("InsensitiveCache", true, Integer.class, Integer.class)
+ .setSqlSchema("Insensitivecache");
+ IgniteConfiguration icfg = new IgniteConfiguration()
+ .setLocalHost("127.0.0.1")
+ .setCacheConfiguration(cfg, collisionCfg);
+
+ Ignition.start(icfg);
+
+ return null;
+ }
+ }, IgniteException.class, "Schema for cache already registered");
+ }
+
+ /**
+ * Tests unregistration of previous scheme.
+ *
+ * @throws Exception If failed.
+ */
+ public void testCacheUnregistration() throws Exception {
+ startGridsMultiThreaded(3, true);
+
+ final CacheConfiguration<Integer, Fact> cfg = cacheConfig("Insensitive_Cache", true, Integer.class, Fact.class)
+ .setSqlSchema("Insensitive_Cache");
+ final CacheConfiguration<Integer, Fact> collisionCfg = cacheConfig("InsensitiveCache", true, Integer.class, Fact.class)
+ .setSqlSchema("Insensitive_Cache");
+
+ IgniteCache<Integer, Fact> cache = ignite(0).createCache(cfg);
+
+ SqlFieldsQuery qry = new SqlFieldsQuery("select f.id, f.name " +
+ "from InSENSitive_Cache.Fact f");
+
+ cache.put(1, new Fact(1, "cacheInsensitive"));
+
+ for (List<?> row : cache.query(qry)) {
+ assertEquals(2, row.size());
+ assertEquals(1, row.get(0));
+ assertEquals("cacheInsensitive", row.get(1));
+ }
+
+ ignite(0).destroyCache(cache.getName());
+
+ cache = ignite(0).createCache(collisionCfg); // Previous collision should be removed by now.
+
+ cache.put(1, new Fact(1, "cacheInsensitive"));
+ cache.put(2, new Fact(2, "ThisIsANewCache"));
+ cache.put(3, new Fact(3, "With3RecordsAndAnotherName"));
+
+ assertEquals(3, cache.query(qry).getAll().size());
+
+ ignite(0).destroyCache(cache.getName());
+ }
+
+ /**
+ * Tests escapeAll and sqlSchema apposition.
+ *
+ * @throws Exception If failed.
+ */
+ public void testSchemaEscapeAll() throws Exception {
+ startGridsMultiThreaded(3, true);
+
+ final CacheConfiguration<Integer, Fact> cfg = cacheConfig("simpleSchema", true, Integer.class, Fact.class)
+ .setSqlSchema("SchemaName1")
+ .setSqlEscapeAll(true);
+
+ final CacheConfiguration<Integer, Fact> cfgEsc = cacheConfig("escapedSchema", true, Integer.class, Fact.class)
+ .setSqlSchema("\"SchemaName2\"")
+ .setSqlEscapeAll(true);
+
+ escapeCheckSchemaName(ignite(0).createCache(cfg), log, cfg.getSqlSchema());
+
+ escapeCheckSchemaName(ignite(0).createCache(cfgEsc), log, "SchemaName2");
+
+ ignite(0).destroyCache(cfg.getName());
+ ignite(0).destroyCache(cfgEsc.getName());
+ }
+
+ /**
+ * Executes query with and without escaped schema name.
+ * @param cache cache for querying
+ * @param log logger for assertThrows
+ * @param schemaName - schema name without quotes for testing
+ */
+ private static void escapeCheckSchemaName(final IgniteCache<Integer, Fact> cache, IgniteLogger log, String schemaName) {
+ final SqlFieldsQuery qryWrong = new SqlFieldsQuery("select f.id, f.name " +
+ "from " + schemaName.toUpperCase() + ".Fact f");
+
+ cache.put(1, new Fact(1, "cacheInsensitive"));
+
+ GridTestUtils.assertThrows(log, new Callable<Object>() {
+ @Override public Object call() throws Exception {
+ cache.query(qryWrong);
+ return null;
+ }
+ }, IgniteException.class, "Failed to parse query");
+
+ SqlFieldsQuery qryCorrect = new SqlFieldsQuery("select f.\"id\", f.\"name\" " +
+ "from \""+schemaName+"\".\"Fact\" f");
+
+ for ( List<?> row : cache.query(qryCorrect)) {
+ assertEquals(2, row.size());
+ assertEquals(1, row.get(0));
+ assertEquals("cacheInsensitive", row.get(1));
+ }
+ }
+
+ // TODO add tests with dynamic cache unregistration, after resolve of https://issues.apache.org/jira/browse/IGNITE-1094
+
+ /** Test class as query entity */
+ private static class Fact {
+ /** Primary key. */
+ @QuerySqlField
+ private int id;
+
+ @QuerySqlField
+ private String name;
+
+ /**
+ * Constructs a fact.
+ *
+ * @param id fact ID.
+ * @param name fact name.
+ */
+ Fact(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ /**
+ * Gets fact ID.
+ *
+ * @return fact ID.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Gets fact name.
+ *
+ * @return Fact name.
+ */
+ public String getName() {
+ return name;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/da24df99/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java
----------------------------------------------------------------------
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 fc88c75..7c8d1d7 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
@@ -92,6 +92,7 @@ import org.apache.ignite.internal.processors.cache.reducefields.GridCacheReduceF
import org.apache.ignite.internal.processors.cache.reducefields.GridCacheReduceFieldsQueryLocalSelfTest;
import org.apache.ignite.internal.processors.cache.reducefields.GridCacheReduceFieldsQueryPartitionedSelfTest;
import org.apache.ignite.internal.processors.cache.reducefields.GridCacheReduceFieldsQueryReplicatedSelfTest;
+import org.apache.ignite.internal.processors.query.IgniteSqlSchemaIndexingTest;
import org.apache.ignite.internal.processors.query.IgniteSqlSplitterSelfTest;
import org.apache.ignite.internal.processors.query.h2.sql.BaseH2CompareQueryTest;
import org.apache.ignite.internal.processors.query.h2.sql.GridQueryParsingTest;
@@ -117,6 +118,7 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite {
// Queries tests.
suite.addTestSuite(IgniteSqlSplitterSelfTest.class);
+ suite.addTestSuite(IgniteSqlSchemaIndexingTest.class);
suite.addTestSuite(GridCacheQueryIndexDisabledSelfTest.class);
suite.addTestSuite(IgniteCacheQueryLoadSelfTest.class);
suite.addTestSuite(IgniteCacheLocalQuerySelfTest.class);
http://git-wip-us.apache.org/repos/asf/ignite/blob/da24df99/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala
index 90c2de0..0d8d036 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala
@@ -17,23 +17,21 @@
package org.apache.ignite.visor.commands.cache
+import java.lang.{Boolean => JavaBoolean}
+import java.util.{Collection => JavaCollection, Collections, UUID}
+
import org.apache.ignite._
import org.apache.ignite.cluster.ClusterNode
import org.apache.ignite.internal.util.typedef._
+import org.apache.ignite.internal.visor.cache._
+import org.apache.ignite.internal.visor.util.VisorTaskUtils._
import org.apache.ignite.lang.IgniteBiTuple
import org.apache.ignite.visor.VisorTag
import org.apache.ignite.visor.commands.cache.VisorCacheCommand._
import org.apache.ignite.visor.commands.common.VisorTextTable
import org.apache.ignite.visor.visor._
-
import org.jetbrains.annotations._
-import java.lang.{Boolean => JavaBoolean}
-import java.util.{Collection => JavaCollection, Collections, UUID}
-
-import org.apache.ignite.internal.visor.cache._
-import org.apache.ignite.internal.visor.util.VisorTaskUtils._
-
import scala.collection.JavaConversions._
import scala.language.{implicitConversions, reflectiveCalls}
@@ -890,6 +888,7 @@ object VisorCacheCommand {
cacheT += ("Expiry Policy Factory Class Name", safe(cfg.expiryPolicyFactory()))
cacheT +=("Query Execution Time Threshold", queryCfg.longQueryWarningTimeout())
+ cacheT +=("Query Schema Name", queryCfg.sqlSchema())
cacheT +=("Query Escaped Names", bool2Str(queryCfg.sqlEscapeAll()))
cacheT +=("Query Onheap Cache Size", queryCfg.sqlOnheapRowCacheSize())