You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2018/08/29 16:51:18 UTC
[38/50] [abbrv] ignite git commit: IGNITE-6055: SQL. Add string
length constraint - Fixes #3973.
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
index d73e89d..79780f7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
@@ -76,13 +76,11 @@ import org.apache.ignite.failure.StopNodeFailureHandler;
import org.apache.ignite.failure.StopNodeOrHaltFailureHandler;
import org.apache.ignite.internal.binary.BinaryRawReaderEx;
import org.apache.ignite.internal.binary.BinaryRawWriterEx;
+import org.apache.ignite.internal.processors.odbc.ClientListenerProtocolVersion;
import org.apache.ignite.internal.processors.platform.cache.affinity.PlatformAffinityFunction;
import org.apache.ignite.internal.processors.platform.cache.expiry.PlatformExpiryPolicyFactory;
import org.apache.ignite.internal.processors.platform.events.PlatformLocalEventListener;
import org.apache.ignite.internal.processors.platform.plugin.cache.PlatformCachePluginConfiguration;
-import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.lang.IgniteBiTuple;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.platform.dotnet.PlatformDotNetAffinityFunction;
import org.apache.ignite.platform.dotnet.PlatformDotNetBinaryConfiguration;
@@ -108,6 +106,8 @@ import org.apache.ignite.ssl.SslContextFactory;
import org.apache.ignite.transactions.TransactionConcurrency;
import org.apache.ignite.transactions.TransactionIsolation;
+import static org.apache.ignite.internal.processors.platform.client.ClientConnectionContext.VER_1_2_0;
+
/**
* Configuration utils.
*
@@ -158,9 +158,10 @@ public class PlatformConfigurationUtils {
* Reads cache configuration from a stream.
*
* @param in Stream.
+ * @param ver Client version.
* @return Cache configuration.
*/
- public static CacheConfiguration readCacheConfiguration(BinaryRawReaderEx in) {
+ public static CacheConfiguration readCacheConfiguration(BinaryRawReaderEx in, ClientListenerProtocolVersion ver) {
assert in != null;
CacheConfiguration ccfg = new CacheConfiguration();
@@ -226,7 +227,7 @@ public class PlatformConfigurationUtils {
Collection<QueryEntity> entities = new ArrayList<>(qryEntCnt);
for (int i = 0; i < qryEntCnt; i++)
- entities.add(readQueryEntity(in));
+ entities.add(readQueryEntity(in, ver));
ccfg.setQueryEntities(entities);
}
@@ -483,9 +484,10 @@ public class PlatformConfigurationUtils {
* Reads the query entity.
*
* @param in Stream.
+ * @param ver Client version.
* @return QueryEntity.
*/
- public static QueryEntity readQueryEntity(BinaryRawReader in) {
+ public static QueryEntity readQueryEntity(BinaryRawReader in, ClientListenerProtocolVersion ver) {
QueryEntity res = new QueryEntity();
res.setKeyType(in.readString());
@@ -499,7 +501,8 @@ public class PlatformConfigurationUtils {
Set<String> keyFields = new HashSet<>(cnt);
Set<String> notNullFields = new HashSet<>(cnt);
Map<String, Object> defVals = new HashMap<>(cnt);
- Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = new HashMap<>(cnt);
+ Map<String, Integer> fieldsPrecision = new HashMap<>(cnt);
+ Map<String, Integer> fieldsScale = new HashMap<>(cnt);
if (cnt > 0) {
LinkedHashMap<String, String> fields = new LinkedHashMap<>(cnt);
@@ -519,13 +522,18 @@ public class PlatformConfigurationUtils {
Object defVal = in.readObject();
if (defVal != null)
defVals.put(fieldName, defVal);
+
+ if (ver.compareTo(VER_1_2_0) >= 0) {
+ int precision = in.readInt();
- int precision = in.readInt();
+ if (precision != -1)
+ fieldsPrecision.put(fieldName, precision);
- int scale = in.readInt();
+ int scale = in.readInt();
- if (precision != -1 || scale != -1)
- decimalInfo.put(fieldName, F.t(precision, scale));
+ if (scale != -1)
+ fieldsScale.put(fieldName, scale);
+ }
}
res.setFields(fields);
@@ -539,8 +547,11 @@ public class PlatformConfigurationUtils {
if (!defVals.isEmpty())
res.setDefaultFieldValues(defVals);
- if (!decimalInfo.isEmpty())
- res.setDecimalInfo(decimalInfo);
+ if (!fieldsPrecision.isEmpty())
+ res.setFieldsPrecision(fieldsPrecision);
+
+ if (!fieldsScale.isEmpty())
+ res.setFieldsScale(fieldsScale);
}
// Aliases
@@ -601,9 +612,11 @@ public class PlatformConfigurationUtils {
* Reads Ignite configuration.
* @param in Reader.
* @param cfg Configuration.
+ * @param ver Client version.
*/
@SuppressWarnings("deprecation")
- public static void readIgniteConfiguration(BinaryRawReaderEx in, IgniteConfiguration cfg) {
+ public static void readIgniteConfiguration(BinaryRawReaderEx in, IgniteConfiguration cfg,
+ ClientListenerProtocolVersion ver) {
if (in.readBoolean())
cfg.setClientMode(in.readBoolean());
int[] evtTypes = in.readIntArray();
@@ -683,7 +696,7 @@ public class PlatformConfigurationUtils {
if (in.readBoolean())
cfg.setQueryThreadPoolSize(in.readInt());
- readCacheConfigurations(in, cfg);
+ readCacheConfigurations(in, cfg, ver);
readDiscoveryConfiguration(in, cfg);
if (in.readBoolean()) {
@@ -819,8 +832,10 @@ public class PlatformConfigurationUtils {
*
* @param cfg IgniteConfiguration to update.
* @param in Reader.
+ * @param ver Client version.
*/
- private static void readCacheConfigurations(BinaryRawReaderEx in, IgniteConfiguration cfg) {
+ private static void readCacheConfigurations(BinaryRawReaderEx in, IgniteConfiguration cfg,
+ ClientListenerProtocolVersion ver) {
int len = in.readInt();
if (len == 0)
@@ -829,7 +844,7 @@ public class PlatformConfigurationUtils {
List<CacheConfiguration> caches = new ArrayList<>();
for (int i = 0; i < len; i++)
- caches.add(readCacheConfiguration(in));
+ caches.add(readCacheConfiguration(in, ver));
CacheConfiguration[] oldCaches = cfg.getCacheConfiguration();
CacheConfiguration[] caches0 = caches.toArray(new CacheConfiguration[caches.size()]);
@@ -928,8 +943,10 @@ public class PlatformConfigurationUtils {
*
* @param writer Writer.
* @param ccfg Configuration.
+ * @param ver Client version.
*/
- public static void writeCacheConfiguration(BinaryRawWriter writer, CacheConfiguration ccfg) {
+ public static void writeCacheConfiguration(BinaryRawWriter writer, CacheConfiguration ccfg,
+ ClientListenerProtocolVersion ver) {
assert writer != null;
assert ccfg != null;
@@ -989,7 +1006,7 @@ public class PlatformConfigurationUtils {
writer.writeInt(qryEntities.size());
for (QueryEntity e : qryEntities)
- writeQueryEntity(writer, e);
+ writeQueryEntity(writer, e, ver);
}
else
writer.writeInt(0);
@@ -1046,8 +1063,10 @@ public class PlatformConfigurationUtils {
*
* @param writer Writer.
* @param qryEntity Query entity.
+ * @param ver Client version.
*/
- public static void writeQueryEntity(BinaryRawWriter writer, QueryEntity qryEntity) {
+ public static void writeQueryEntity(BinaryRawWriter writer, QueryEntity qryEntity,
+ ClientListenerProtocolVersion ver) {
assert qryEntity != null;
writer.writeString(qryEntity.getKeyType());
@@ -1063,7 +1082,8 @@ public class PlatformConfigurationUtils {
Set<String> keyFields = qryEntity.getKeyFields();
Set<String> notNullFields = qryEntity.getNotNullFields();
Map<String, Object> defVals = qryEntity.getDefaultFieldValues();
- Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = qryEntity.getDecimalInfo();
+ Map<String, Integer> fieldsPrecision = qryEntity.getFieldsPrecision();
+ Map<String, Integer> fieldsScale = qryEntity.getFieldsScale();
writer.writeInt(fields.size());
@@ -1074,11 +1094,10 @@ public class PlatformConfigurationUtils {
writer.writeBoolean(notNullFields != null && notNullFields.contains(field.getKey()));
writer.writeObject(defVals != null ? defVals.get(field.getKey()) : null);
- IgniteBiTuple<Integer, Integer> precisionAndScale =
- decimalInfo == null ? null : decimalInfo.get(field.getKey());
-
- writer.writeInt(precisionAndScale == null ? -1 : precisionAndScale.get1());
- writer.writeInt(precisionAndScale == null ? -1 : precisionAndScale.get2());
+ if (ver.compareTo(VER_1_2_0) >= 0) {
+ writer.writeInt(fieldsPrecision == null ? -1 : fieldsPrecision.getOrDefault(field.getKey(), -1));
+ writer.writeInt(fieldsScale == null ? -1 : fieldsScale.getOrDefault(field.getKey(), -1));
+ }
}
}
else
@@ -1143,9 +1162,11 @@ public class PlatformConfigurationUtils {
*
* @param w Writer.
* @param cfg Configuration.
+ * @param ver Client version.
*/
@SuppressWarnings("deprecation")
- public static void writeIgniteConfiguration(BinaryRawWriter w, IgniteConfiguration cfg) {
+ public static void writeIgniteConfiguration(BinaryRawWriter w, IgniteConfiguration cfg,
+ ClientListenerProtocolVersion ver) {
assert w != null;
assert cfg != null;
@@ -1218,7 +1239,7 @@ public class PlatformConfigurationUtils {
w.writeInt(cacheCfg.length);
for (CacheConfiguration ccfg : cacheCfg)
- writeCacheConfiguration(w, ccfg);
+ writeCacheConfiguration(w, ccfg, ver);
}
else
w.writeInt(0);
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java
index 9b08d77..f9df499 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryFieldMetadata.java
@@ -51,4 +51,18 @@ public interface GridQueryFieldMetadata extends Externalizable {
* @return Field type name.
*/
public String fieldTypeName();
-}
\ No newline at end of file
+
+ /**
+ * Gets field precision.
+ *
+ * @return Field precision.
+ */
+ public int precision();
+
+ /**
+ * Gets field scale.
+ *
+ * @return Field scale.
+ */
+ public int scale();
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.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 04d1aa9..57eaa4a 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
@@ -2471,8 +2471,17 @@ public class GridQueryProcessor extends GridProcessorAdapter {
for (QueryField col : cols) {
try {
- props.add(new QueryBinaryProperty(ctx, col.name(), null, Class.forName(col.typeName()),
- false, null, !col.isNullable(), null, -1, -1));
+ props.add(new QueryBinaryProperty(
+ ctx,
+ col.name(),
+ null,
+ Class.forName(col.typeName()),
+ false,
+ null,
+ !col.isNullable(),
+ null,
+ col.precision(),
+ col.scale()));
}
catch (ClassNotFoundException e) {
throw new SchemaOperationException("Class not found for new property: " + col.typeName());
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java
index d68a6cb..b74e3df 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryField.java
@@ -70,6 +70,8 @@ public class QueryField implements Serializable {
* @param typeName Class name for this field's values.
* @param nullable Nullable flag.
* @param dfltValue Default value.
+ * @param precision Precision.
+ * @param scale Scale.
*/
public QueryField(String name, String typeName, boolean nullable, Object dfltValue, int precision, int scale) {
this.name = name;
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
index a7710f9..2eaeb1f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryTypeDescriptorImpl.java
@@ -26,7 +26,9 @@ import java.util.List;
import java.util.Map;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.cache.QueryIndexType;
-import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.cache.CacheObject;
+import org.apache.ignite.internal.processors.cache.CacheObjectContext;
+import org.apache.ignite.internal.processors.cache.KeyCacheObject;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.F;
@@ -34,6 +36,13 @@ import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.jetbrains.annotations.Nullable;
+import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.NULL_KEY;
+import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.NULL_VALUE;
+import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.TOO_LONG_KEY;
+import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.TOO_LONG_VALUE;
+import static org.apache.ignite.internal.processors.query.QueryUtils.KEY_FIELD_NAME;
+import static org.apache.ignite.internal.processors.query.QueryUtils.VAL_FIELD_NAME;
+
/**
* Descriptor of type.
*/
@@ -110,13 +119,18 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor {
/** */
private List<GridQueryProperty> propsWithDefaultValue;
+ /** */
+ @Nullable private CacheObjectContext coCtx;
+
/**
* Constructor.
*
* @param cacheName Cache name.
+ * @param coCtx Cache object context.
*/
- public QueryTypeDescriptorImpl(String cacheName) {
+ public QueryTypeDescriptorImpl(String cacheName, @Nullable CacheObjectContext coCtx) {
this.cacheName = cacheName;
+ this.coCtx = coCtx;
}
/**
@@ -368,6 +382,19 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor {
* @throws IgniteCheckedException In case of error.
*/
public void addProperty(GridQueryProperty prop, boolean failOnDuplicate) throws IgniteCheckedException {
+ addProperty(prop, failOnDuplicate, true);
+ }
+
+ /**
+ * Adds property to the type descriptor.
+ *
+ * @param prop Property.
+ * @param failOnDuplicate Fail on duplicate flag.
+ * @param isField {@code True} if {@code prop} if field, {@code False} if prop is "_KEY" or "_VAL".
+ * @throws IgniteCheckedException In case of error.
+ */
+ public void addProperty(GridQueryProperty prop, boolean failOnDuplicate, boolean isField)
+ throws IgniteCheckedException {
String name = prop.name();
if (props.put(name, prop) != null && failOnDuplicate)
@@ -382,6 +409,12 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor {
validateProps.add(prop);
}
+ else if (prop.precision() != -1) {
+ if (validateProps == null)
+ validateProps = new ArrayList<>();
+
+ validateProps.add(prop);
+ }
if (prop.defaultValue() != null) {
if (propsWithDefaultValue == null)
@@ -390,7 +423,8 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor {
propsWithDefaultValue.add(prop);
}
- fields.put(name, prop.type());
+ if (isField)
+ fields.put(name, prop.type());
}
/**
@@ -525,26 +559,35 @@ public class QueryTypeDescriptorImpl implements GridQueryTypeDescriptor {
Object propVal;
- int errCode;
+ boolean isKey = false;
- if (F.eq(prop.name(), keyFieldName)) {
- propVal = key;
+ if (F.eq(prop.name(), keyFieldName) || (keyFieldName == null && F.eq(prop.name(), KEY_FIELD_NAME))) {
+ propVal = key instanceof KeyCacheObject && coCtx != null ?
+ ((KeyCacheObject)key).value(coCtx, true) : key;
- errCode = IgniteQueryErrorCode.NULL_KEY;
+ isKey = true;
}
- else if (F.eq(prop.name(), valFieldName)) {
- propVal = val;
-
- errCode = IgniteQueryErrorCode.NULL_VALUE;
+ else if (F.eq(prop.name(), valFieldName) || (valFieldName == null && F.eq(prop.name(), VAL_FIELD_NAME))) {
+ propVal = val instanceof CacheObject && coCtx != null ?
+ ((CacheObject)val).value(coCtx, true) : val;
}
else {
propVal = prop.value(key, val);
+ }
- errCode = IgniteQueryErrorCode.NULL_VALUE;
+ if (propVal == null && prop.notNull()) {
+ throw new IgniteSQLException("Null value is not allowed for column '" + prop.name() + "'",
+ isKey ? NULL_KEY : NULL_VALUE);
}
- if (propVal == null)
- throw new IgniteSQLException("Null value is not allowed for column '" + prop.name() + "'", errCode);
+ if (prop.precision() != -1 &&
+ propVal != null &&
+ String.class == propVal.getClass() &&
+ ((String)propVal).length() > prop.precision()) {
+ throw new IgniteSQLException("Value for a column '" + prop.name() + "' is too long. " +
+ "Maximum length: " + prop.precision() + ", actual length: " + ((CharSequence)propVal).length(),
+ isKey ? TOO_LONG_KEY : TOO_LONG_VALUE);
+ }
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
index 3f40990..42de312 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/QueryUtils.java
@@ -27,6 +27,7 @@ import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -61,7 +62,6 @@ import org.apache.ignite.internal.util.Jsr310Java8DateTimeApiUtils;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.lang.IgniteBiTuple;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -268,7 +268,8 @@ public class QueryUtils {
normalEntity.setValueFieldName(entity.getValueFieldName());
normalEntity.setNotNullFields(entity.getNotNullFields());
normalEntity.setDefaultFieldValues(entity.getDefaultFieldValues());
- normalEntity.setDecimalInfo(entity.getDecimalInfo());
+ normalEntity.setFieldsPrecision(entity.getFieldsPrecision());
+ normalEntity.setFieldsScale(entity.getFieldsScale());
// Normalize table name.
String normalTblName = entity.getTableName();
@@ -407,7 +408,7 @@ public class QueryUtils {
CacheObjectContext coCtx = binaryEnabled ? ctx.cacheObjects().contextForCache(ccfg) : null;
- QueryTypeDescriptorImpl desc = new QueryTypeDescriptorImpl(cacheName);
+ QueryTypeDescriptorImpl desc = new QueryTypeDescriptorImpl(cacheName, coCtx);
desc.schemaName(schemaName);
@@ -543,10 +544,12 @@ public class QueryUtils {
*/
public static void processBinaryMeta(GridKernalContext ctx, QueryEntity qryEntity, QueryTypeDescriptorImpl d)
throws IgniteCheckedException {
+ LinkedHashMap<String, String> fields = qryEntity.getFields();
Set<String> keyFields = qryEntity.getKeyFields();
Set<String> notNulls = qryEntity.getNotNullFields();
Map<String, Object> dlftVals = qryEntity.getDefaultFieldValues();
- Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = qryEntity.getDecimalInfo();
+ Map<String, Integer> precision = qryEntity.getFieldsPrecision();
+ Map<String, Integer> scale = qryEntity.getFieldsScale();
// We have to distinguish between empty and null keyFields when the key is not of SQL type -
// when a key is not of SQL type, absence of a field in nonnull keyFields tell us that this field
@@ -559,13 +562,13 @@ public class QueryUtils {
if (hasKeyFields && !isKeyClsSqlType) {
//ensure that 'keyFields' is case sensitive subset of 'fields'
for (String keyField : keyFields) {
- if (!qryEntity.getFields().containsKey(keyField))
+ if (!fields.containsKey(keyField))
throw new IgniteCheckedException("QueryEntity 'keyFields' property must be a subset of keys " +
"from 'fields' property (case sensitive): " + keyField);
}
}
- for (Map.Entry<String, String> entry : qryEntity.getFields().entrySet()) {
+ for (Map.Entry<String, String> entry : fields.entrySet()) {
Boolean isKeyField;
if (isKeyClsSqlType) // We don't care about keyFields in this case - it might be null, or empty, or anything
@@ -577,22 +580,73 @@ public class QueryUtils {
Object dfltVal = dlftVals != null ? dlftVals.get(entry.getKey()) : null;
- IgniteBiTuple<Integer, Integer> precisionAndScale =
- decimalInfo != null ? decimalInfo.get(entry.getKey()) : null;
-
QueryBinaryProperty prop = buildBinaryProperty(ctx, entry.getKey(),
U.classForName(entry.getValue(), Object.class, true),
d.aliases(), isKeyField, notNull, dfltVal,
- precisionAndScale != null ? precisionAndScale.get1() : -1,
- precisionAndScale != null ? precisionAndScale.get2() : -1);
+ precision == null ? -1 : precision.getOrDefault(entry.getKey(), -1),
+ scale == null ? -1 : scale.getOrDefault(entry.getKey(), -1));
d.addProperty(prop, false);
}
+ String keyFieldName = qryEntity.getKeyFieldName();
+
+ if (keyFieldName == null)
+ keyFieldName = KEY_FIELD_NAME;
+
+ if (!F.isEmpty(precision) && precision.containsKey(keyFieldName) &&
+ !fields.containsKey(keyFieldName)) {
+ addKeyValueValidationProperty(ctx, qryEntity, d, keyFieldName, true);
+ }
+
+ String valFieldName = qryEntity.getValueFieldName();
+
+ if (valFieldName == null)
+ valFieldName = VAL_FIELD_NAME;
+
+ if (!F.isEmpty(precision) && precision.containsKey(valFieldName) &&
+ !fields.containsKey(valFieldName)) {
+ addKeyValueValidationProperty(ctx, qryEntity, d, valFieldName, false);
+ }
+
processIndexes(qryEntity, d);
}
/**
+ * Add validate property to QueryTypeDescriptor.
+ *
+ * @param ctx Kernel context.
+ * @param qryEntity Query entity.
+ * @param d Descriptor.
+ * @param name Field name.
+ * @throws IgniteCheckedException
+ */
+ private static void addKeyValueValidationProperty(GridKernalContext ctx, QueryEntity qryEntity, QueryTypeDescriptorImpl d,
+ String name, boolean isKey) throws IgniteCheckedException {
+
+ Map<String, Object> dfltVals = qryEntity.getDefaultFieldValues();
+ Map<String, Integer> precision = qryEntity.getFieldsPrecision();
+ Map<String, Integer> scale = qryEntity.getFieldsScale();
+
+ String typeName = isKey ? qryEntity.getKeyType() : qryEntity.getValueType();
+
+ Object dfltVal = dfltVals.get(name);
+
+ QueryBinaryProperty prop = buildBinaryProperty(
+ ctx,
+ name,
+ U.classForName(typeName, Object.class, true),
+ d.aliases(),
+ isKey,
+ true,
+ dfltVal,
+ precision == null ? -1 : precision.getOrDefault(name, -1),
+ scale == null ? -1 : scale.getOrDefault(name, -1));
+
+ d.addProperty(prop, true, false);
+ }
+
+ /**
* Processes declarative metadata for binary object.
*
* @param qryEntity Declared metadata.
@@ -731,11 +785,10 @@ public class QueryUtils {
* @param precision Precision.
* @param scale Scale.
* @return Binary property.
- * @throws IgniteCheckedException On error.
*/
- public static QueryBinaryProperty buildBinaryProperty(GridKernalContext ctx, String pathStr, Class<?> resType,
- Map<String, String> aliases, @Nullable Boolean isKeyField, boolean notNull, Object dlftVal,
- int precision, int scale) throws IgniteCheckedException {
+ public static QueryBinaryProperty buildBinaryProperty(GridKernalContext ctx, String pathStr,
+ Class<?> resType, Map<String, String> aliases, @Nullable Boolean isKeyField, boolean notNull, Object dlftVal,
+ int precision, int scale) {
String[] path = pathStr.split("\\.");
QueryBinaryProperty res = null;
@@ -1215,6 +1268,26 @@ public class QueryUtils {
", queryIdx=" + idx + ']');
}
}
+
+ Map<String, Object> dfltVals = entity.getDefaultFieldValues();
+ Map<String, Integer> precision = entity.getFieldsPrecision();
+
+ if (!F.isEmpty(precision)) {
+ for (String fld : precision.keySet()) {
+ if (!dfltVals.containsKey(fld))
+ continue;
+
+ Object dfltVal = dfltVals.get(fld);
+
+ if (dfltVal == null)
+ continue;
+
+ if (dfltVal.toString().length() > precision.get(fld)) {
+ throw new IgniteSQLException("Default value '" + dfltVal +
+ "' is longer than maximum length " + precision.get(fld));
+ }
+ }
+ }
}
/**
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
index 786d0e0..cb3d8f2 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java
@@ -407,6 +407,24 @@ public final class GridTestUtils {
* Checks whether callable throws exception, which is itself of a specified
* class, or has a cause of the specified class.
*
+ * @param runnable Runnable.
+ * @param cls Expected class.
+ * @return Thrown throwable.
+ */
+ @Nullable public static Throwable assertThrowsWithCause(Runnable runnable, Class<? extends Throwable> cls) {
+ return assertThrowsWithCause(new Callable<Integer>() {
+ @Override public Integer call() throws Exception {
+ runnable.run();
+
+ return 0;
+ }
+ }, cls);
+ }
+
+ /**
+ * Checks whether callable throws exception, which is itself of a specified
+ * class, or has a cause of the specified class.
+ *
* @param call Callable.
* @param cls Expected class.
* @return Thrown throwable.
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java
index 46aa1fc..de4c6c6 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2SqlFieldMetadata.java
@@ -46,6 +46,12 @@ public class H2SqlFieldMetadata implements GridQueryFieldMetadata {
/** Type. */
private String type;
+ /** Precision. */
+ private int precision;
+
+ /** Scale. */
+ private int scale;
+
/**
* Required by {@link Externalizable}.
*/
@@ -58,14 +64,19 @@ public class H2SqlFieldMetadata implements GridQueryFieldMetadata {
* @param typeName Type name.
* @param name Name.
* @param type Type.
+ * @param precision Precision.
+ * @param scale Scale.
*/
- H2SqlFieldMetadata(@Nullable String schemaName, @Nullable String typeName, String name, String type) {
+ H2SqlFieldMetadata(@Nullable String schemaName, @Nullable String typeName, String name, String type,
+ int precision, int scale) {
assert name != null && type != null : schemaName + " | " + typeName + " | " + name + " | " + type;
this.schemaName = schemaName;
this.typeName = typeName;
this.name = name;
this.type = type;
+ this.precision = precision;
+ this.scale = scale;
}
/** {@inheritDoc} */
@@ -89,11 +100,24 @@ public class H2SqlFieldMetadata implements GridQueryFieldMetadata {
}
/** {@inheritDoc} */
+ @Override public int precision() {
+ return precision;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int scale() {
+ return scale;
+ }
+
+ /** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
U.writeString(out, schemaName);
U.writeString(out, typeName);
U.writeString(out, name);
U.writeString(out, type);
+ out.write(precision);
+ out.write(scale);
+
}
/** {@inheritDoc} */
@@ -102,6 +126,8 @@ public class H2SqlFieldMetadata implements GridQueryFieldMetadata {
typeName = U.readString(in);
name = U.readString(in);
type = U.readString(in);
+ precision = in.read();
+ scale = in.read();
}
/** {@inheritDoc} */
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
index e9d9f90..b9d9d8e 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/H2Utils.java
@@ -211,11 +211,13 @@ public class H2Utils {
String typeName = rsMeta.getTableName(i);
String name = rsMeta.getColumnLabel(i);
String type = rsMeta.getColumnClassName(i);
+ int precision = rsMeta.getPrecision(i);
+ int scale = rsMeta.getScale(i);
if (type == null) // Expression always returns NULL.
type = Void.class.getName();
- meta.add(new H2SqlFieldMetadata(schemaName, typeName, name, type));
+ meta.add(new H2SqlFieldMetadata(schemaName, typeName, name, type, precision, scale));
}
return meta;
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/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 5859ecb..6b7eddf 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
@@ -85,6 +85,7 @@ import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata;
import org.apache.ignite.internal.processors.query.GridQueryFieldsResult;
import org.apache.ignite.internal.processors.query.GridQueryFieldsResultAdapter;
import org.apache.ignite.internal.processors.query.GridQueryIndexing;
+import org.apache.ignite.internal.processors.query.GridQueryProperty;
import org.apache.ignite.internal.processors.query.GridQueryRowCacheCleaner;
import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
import org.apache.ignite.internal.processors.query.GridRunningQueryInfo;
@@ -231,7 +232,7 @@ public class IgniteH2Indexing implements GridQueryIndexing {
/** Dummy metadata for update result. */
public static final List<GridQueryFieldMetadata> UPDATE_RESULT_META = Collections.<GridQueryFieldMetadata>
- singletonList(new H2SqlFieldMetadata(null, null, "UPDATED", Long.class.getName()));
+ singletonList(new H2SqlFieldMetadata(null, null, "UPDATED", Long.class.getName(), -1, -1));
/** */
private static final int PREPARED_STMT_CACHE_SIZE = 256;
@@ -2304,8 +2305,16 @@ public class IgniteH2Indexing implements GridQueryIndexing {
assert schema != null;
assert tbl != null;
- String keyType = dbTypeFromClass(tbl.type().keyClass());
- String valTypeStr = dbTypeFromClass(tbl.type().valueClass());
+ GridQueryProperty keyProp = tbl.type().property(KEY_FIELD_NAME);
+ GridQueryProperty valProp = tbl.type().property(VAL_FIELD_NAME);
+
+ String keyType = dbTypeFromClass(tbl.type().keyClass(),
+ keyProp == null ? -1 : keyProp.precision(),
+ keyProp == null ? -1 : keyProp.scale());
+
+ String valTypeStr = dbTypeFromClass(tbl.type().valueClass(),
+ valProp == null ? -1 : valProp.precision(),
+ valProp == null ? -1 : valProp.scale());
SB sql = new SB();
@@ -2317,9 +2326,15 @@ public class IgniteH2Indexing implements GridQueryIndexing {
sql.a(',').a(VAL_FIELD_NAME).a(' ').a(valTypeStr).a(keyValVisibility);
sql.a(',').a(VER_FIELD_NAME).a(" OTHER INVISIBLE");
- for (Map.Entry<String, Class<?>> e : tbl.type().fields().entrySet())
- sql.a(',').a(H2Utils.withQuotes(e.getKey())).a(' ').a(dbTypeFromClass(e.getValue()))
- .a(tbl.type().property(e.getKey()).notNull()? " NOT NULL" : "");
+ for (Map.Entry<String, Class<?>> e : tbl.type().fields().entrySet()) {
+ GridQueryProperty prop = tbl.type().property(e.getKey());
+
+ sql.a(',')
+ .a(H2Utils.withQuotes(e.getKey()))
+ .a(' ')
+ .a(dbTypeFromClass(e.getValue(), prop.precision(), prop.scale()))
+ .a(prop.notNull() ? " NOT NULL" : "");
+ }
sql.a(')');
@@ -2391,10 +2406,17 @@ public class IgniteH2Indexing implements GridQueryIndexing {
* Gets corresponding DB type from java class.
*
* @param cls Java class.
+ * @param precision Field precision.
+ * @param scale Field scale.
* @return DB type name.
*/
- private String dbTypeFromClass(Class<?> cls) {
- return H2DatabaseType.fromClass(cls).dBTypeAsString();
+ private String dbTypeFromClass(Class<?> cls, int precision, int scale) {
+ String dbType = H2DatabaseType.fromClass(cls).dBTypeAsString();
+
+ if (precision != -1 && dbType.equalsIgnoreCase(H2DatabaseType.VARCHAR.dBTypeAsString()))
+ return dbType + "(" + precision + ")";
+
+ return dbType;
}
/**
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java
----------------------------------------------------------------------
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 0a0398b..9e88f16 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
@@ -631,7 +631,8 @@ public class DdlStatementsProcessor {
HashMap<String, Object> dfltValues = new HashMap<>();
- Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = new HashMap<>();
+ Map<String, Integer> precision = new HashMap<>();
+ Map<String, Integer> scale = new HashMap<>();
for (Map.Entry<String, GridSqlColumn> e : createTbl.columns().entrySet()) {
GridSqlColumn gridCol = e.getValue();
@@ -652,15 +653,27 @@ public class DdlStatementsProcessor {
if (dfltVal != null)
dfltValues.put(e.getKey(), dfltVal);
- if (col.getType() == Value.DECIMAL)
- decimalInfo.put(e.getKey(), F.t((int)col.getPrecision(), col.getScale()));
+ if (col.getType() == Value.DECIMAL) {
+ precision.put(e.getKey(), (int)col.getPrecision());
+
+ scale.put(e.getKey(), col.getScale());
+ }
+
+ if (col.getType() == Value.STRING ||
+ col.getType() == Value.STRING_FIXED ||
+ col.getType() == Value.STRING_IGNORECASE) {
+ precision.put(e.getKey(), (int)col.getPrecision());
+ }
}
if (!F.isEmpty(dfltValues))
res.setDefaultFieldValues(dfltValues);
- if (!F.isEmpty(decimalInfo))
- res.setDecimalInfo(decimalInfo);
+ if (!F.isEmpty(precision))
+ res.setFieldsPrecision(precision);
+
+ if (!F.isEmpty(scale))
+ res.setFieldsScale(scale);
String valTypeName = QueryUtils.createTableValueTypeName(createTbl.schemaName(), createTbl.tableName());
String keyTypeName = QueryUtils.createTableKeyTypeName(valTypeName);
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java
index 361f8b4..ce5c95e 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/IgniteCacheAbstractFieldsQuerySelfTest.java
@@ -17,6 +17,7 @@
package org.apache.ignite.internal.processors.cache;
+import com.google.common.collect.ImmutableMap;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
@@ -35,8 +36,8 @@ import org.apache.ignite.cache.CacheAtomicityMode;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.CacheRebalanceMode;
import org.apache.ignite.cache.CacheWriteSynchronizationMode;
+import org.apache.ignite.cache.QueryEntity;
import org.apache.ignite.cache.affinity.AffinityKey;
-import org.apache.ignite.cache.query.FieldsQueryCursor;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cache.query.annotations.QuerySqlField;
@@ -44,14 +45,13 @@ import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.binary.BinaryMarshaller;
-import org.apache.ignite.internal.processors.cache.index.AbstractSchemaSelfTest;
import org.apache.ignite.internal.processors.cache.query.GridCacheSqlIndexMetadata;
import org.apache.ignite.internal.processors.cache.query.GridCacheSqlMetadata;
import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
-import org.apache.ignite.internal.processors.cache.query.SqlFieldsQueryEx;
import org.apache.ignite.internal.processors.datastructures.GridCacheAtomicLongValue;
import org.apache.ignite.internal.processors.datastructures.GridCacheInternalKeyImpl;
import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata;
+import org.apache.ignite.internal.processors.query.GridQueryProcessor;
import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQuerySplitter;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.X;
@@ -352,7 +352,7 @@ public abstract class IgniteCacheAbstractFieldsQuerySelfTest extends GridCommonA
}
else if (DEFAULT_CACHE_NAME.equals(meta.cacheName()) || noOpCache.getName().equals(meta.cacheName()))
assertTrue("Invalid types size", types.isEmpty());
- else
+ else if (!"cacheWithCustomKeyPrecision".equalsIgnoreCase(meta.cacheName()))
fail("Unknown cache: " + meta.cacheName());
}
}
@@ -383,6 +383,102 @@ public abstract class IgniteCacheAbstractFieldsQuerySelfTest extends GridCommonA
}
/** @throws Exception If failed. */
+ @SuppressWarnings("unchecked")
+ public void testExecuteWithMetaDataAndPrecision() throws Exception {
+ QueryEntity qeWithPrecision = new QueryEntity()
+ .setKeyType("java.lang.Long")
+ .setValueType("TestType")
+ .addQueryField("strField", "java.lang.String", "strField")
+ .setFieldsPrecision(ImmutableMap.of("strField", 999));
+
+ grid(0).getOrCreateCache(cacheConfiguration()
+ .setName("cacheWithPrecision")
+ .setQueryEntities(Collections.singleton(qeWithPrecision)));
+
+ GridQueryProcessor qryProc = grid(0).context().query();
+
+ qryProc.querySqlFields(
+ new SqlFieldsQuery("INSERT INTO TestType(_KEY, strField) VALUES(?, ?)")
+ .setSchema("cacheWithPrecision")
+ .setArgs(1, "ABC"), true);
+
+ qryProc.querySqlFields(
+ new SqlFieldsQuery("INSERT INTO TestType(_KEY, strField) VALUES(?, ?)")
+ .setSchema("cacheWithPrecision")
+ .setArgs(2, "DEF"), true);
+
+
+ QueryCursorImpl<List<?>> cursor = (QueryCursorImpl<List<?>>)qryProc.querySqlFields(
+ new SqlFieldsQuery("SELECT _KEY, strField FROM TestType")
+ .setSchema("cacheWithPrecision"), true);
+
+ List<GridQueryFieldMetadata> fieldsMeta = cursor.fieldsMeta();
+
+ for (GridQueryFieldMetadata meta : fieldsMeta) {
+ if (!meta.fieldName().equalsIgnoreCase("strField"))
+ continue;
+
+ assertEquals(999, meta.precision());
+ }
+ }
+
+ public void testExecuteWithMetaDataAndCustomKeyPrecision() throws Exception {
+ QueryEntity qeWithPrecision = new QueryEntity()
+ .setKeyType("java.lang.String")
+ .setKeyFieldName("my_key")
+ .setValueType("CustomKeyType")
+ .addQueryField("my_key", "java.lang.String", "my_key")
+ .addQueryField("strField", "java.lang.String", "strField")
+ .setFieldsPrecision(ImmutableMap.of("strField", 999, "my_key", 777));
+
+ grid(0).getOrCreateCache(cacheConfiguration()
+ .setName("cacheWithCustomKeyPrecision")
+ .setQueryEntities(Collections.singleton(qeWithPrecision)));
+
+ GridQueryProcessor qryProc = grid(0).context().query();
+
+ qryProc.querySqlFields(
+ new SqlFieldsQuery("INSERT INTO CustomKeyType(my_key, strField) VALUES(?, ?)")
+ .setSchema("cacheWithCustomKeyPrecision")
+ .setArgs("1", "ABC"), true);
+
+ qryProc.querySqlFields(
+ new SqlFieldsQuery("INSERT INTO CustomKeyType(my_key, strField) VALUES(?, ?)")
+ .setSchema("cacheWithCustomKeyPrecision")
+ .setArgs("2", "DEF"), true);
+
+ QueryCursorImpl<List<?>> cursor = (QueryCursorImpl<List<?>>)qryProc.querySqlFields(
+ new SqlFieldsQuery("SELECT my_key, strField FROM CustomKeyType")
+ .setSchema("cacheWithCustomKeyPrecision"), true);
+
+ List<GridQueryFieldMetadata> fieldsMeta = cursor.fieldsMeta();
+
+ int fldCnt = 0;
+
+ for (GridQueryFieldMetadata meta : fieldsMeta) {
+ switch (meta.fieldName()) {
+ case "STRFIELD":
+ assertEquals(999, meta.precision());
+
+ fldCnt++;
+
+ break;
+
+ case "MY_KEY":
+ assertEquals(777, meta.precision());
+
+ fldCnt++;
+
+ break;
+ default:
+ fail("Unknown field - " + meta.fieldName());
+ }
+ }
+
+ assertEquals("Metadata for all fields should be returned.", 2, fldCnt);
+ }
+
+ /** @throws Exception If failed. */
public void testExecuteWithMetaData() throws Exception {
QueryCursorImpl<List<?>> cursor = (QueryCursorImpl<List<?>>)personCache.query(sqlFieldsQuery(
String.format("select p._KEY, p.name, p.age, o.name " +
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java
index 9e65276..96926ea 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/IgniteDecimalSelfTest.java
@@ -32,8 +32,6 @@ 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.IgniteEx;
-import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.lang.IgniteBiTuple;
import org.jetbrains.annotations.NotNull;
import static java.math.RoundingMode.HALF_UP;
@@ -108,11 +106,14 @@ public class IgniteDecimalSelfTest extends AbstractSchemaSelfTest {
queryEntity.addQueryField("id", Integer.class.getName(), null);
queryEntity.addQueryField("amount", BigDecimal.class.getName(), null);
- Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = new HashMap<>();
+ Map<String, Integer> precision = new HashMap<>();
+ Map<String, Integer> scale = new HashMap<>();
- decimalInfo.put("amount", F.t(PRECISION, SCALE));
+ precision.put("amount",PRECISION);
+ scale.put("amount", SCALE);
- queryEntity.setDecimalInfo(decimalInfo);
+ queryEntity.setFieldsPrecision(precision);
+ queryEntity.setFieldsScale(scale);
ccfg.setQueryEntities(Collections.singletonList(queryEntity));
@@ -123,14 +124,14 @@ public class IgniteDecimalSelfTest extends AbstractSchemaSelfTest {
* @throws Exception If failed.
*/
public void testConfiguredFromDdl() throws Exception {
- checkDecimalInfo(DEC_TAB_NAME, VALUE, PRECISION, SCALE);
+ checkPrecisionAndScale(DEC_TAB_NAME, VALUE, PRECISION, SCALE);
}
/**
* @throws Exception If failed.
*/
public void testConfiguredFromQueryEntity() throws Exception {
- checkDecimalInfo(SALARY_TAB_NAME, "amount", PRECISION, SCALE);
+ checkPrecisionAndScale(SALARY_TAB_NAME, "amount", PRECISION, SCALE);
}
/**
@@ -145,7 +146,7 @@ public class IgniteDecimalSelfTest extends AbstractSchemaSelfTest {
IgniteCache<Integer, Salary> cache = grid.createCache(ccfg);
- checkDecimalInfo(tabName, "amount", PRECISION, SCALE);
+ checkPrecisionAndScale(tabName, "amount", PRECISION, SCALE);
}
/**
@@ -160,7 +161,7 @@ public class IgniteDecimalSelfTest extends AbstractSchemaSelfTest {
grid.createCache(ccfg);
- checkDecimalInfo(SalaryWithAnnotations.class.getSimpleName().toUpperCase(), "amount", PRECISION, SCALE);
+ checkPrecisionAndScale(SalaryWithAnnotations.class.getSimpleName().toUpperCase(), "amount", PRECISION, SCALE);
}
/** */
@@ -177,21 +178,22 @@ public class IgniteDecimalSelfTest extends AbstractSchemaSelfTest {
}
/** */
- private void checkDecimalInfo(String tabName, String colName, Integer precision, Integer scale) {
+ private void checkPrecisionAndScale(String tabName, String colName, Integer precision, Integer scale) {
QueryEntity queryEntity = findTableInfo(tabName);
assertNotNull(queryEntity);
- Map<String, IgniteBiTuple<Integer, Integer>> decimalInfo = queryEntity.getDecimalInfo();
+ Map<String, Integer> fieldsPrecision = queryEntity.getFieldsPrecision();
- assertNotNull(decimalInfo);
+ assertNotNull(precision);
- IgniteBiTuple<Integer, Integer> columnInfo = decimalInfo.get(colName);
+ assertEquals(fieldsPrecision.get(colName), precision);
- assertNotNull(columnInfo);
+ Map<String, Integer> fieldsScale = queryEntity.getFieldsScale();
- assertEquals(columnInfo.get1(), precision);
- assertEquals(columnInfo.get2(), scale);
+ assertEquals(fieldsScale.get(colName), scale);
+
+ assertNotNull(scale);
}
/**
@@ -202,7 +204,6 @@ public class IgniteDecimalSelfTest extends AbstractSchemaSelfTest {
IgniteEx ignite = grid(0);
Collection<String> cacheNames = ignite.cacheNames();
-
for (String cacheName : cacheNames) {
CacheConfiguration ccfg = ignite.cache(cacheName).getConfiguration(CacheConfiguration.class);
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCachePartitionedAtomicColumnConstraintsTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCachePartitionedAtomicColumnConstraintsTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCachePartitionedAtomicColumnConstraintsTest.java
new file mode 100644
index 0000000..601090f
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCachePartitionedAtomicColumnConstraintsTest.java
@@ -0,0 +1,398 @@
+/*
+ * 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.sql;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.cache.processor.EntryProcessorResult;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheEntryProcessor;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.QueryEntity;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.NotNull;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.apache.ignite.internal.processors.query.QueryUtils.KEY_FIELD_NAME;
+import static org.apache.ignite.internal.processors.query.QueryUtils.VAL_FIELD_NAME;
+import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause;
+
+/** */
+public class IgniteCachePartitionedAtomicColumnConstraintsTest extends GridCommonAbstractTest {
+ /** */
+ private static final long FUT_TIMEOUT = 10_000L;
+
+ /** */
+ private static final String STR_CACHE_NAME = "STR_STR";
+
+ /** */
+ private static final String STR_ORG_CACHE_NAME = "STR_ORG";
+
+ private static final String STR_ORG_WITH_FIELDS_CACHE_NAME = "STR_ORG_WITH_FIELDS";
+
+ /** */
+ private static final String OBJ_CACHE_NAME = "ORG_ADDRESS";
+
+ /** */
+ private Consumer<Runnable> shouldFail = (op) -> assertThrowsWithCause(op, IgniteException.class);
+
+ /** */
+ private Consumer<Runnable> shouldSucceed = Runnable::run;
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ startGrid(0);
+
+ Map<String, Integer> strStrPrecision = new HashMap<>();
+
+ strStrPrecision.put(KEY_FIELD_NAME, 5);
+ strStrPrecision.put(VAL_FIELD_NAME, 5);
+
+ jcache(grid(0), cacheConfiguration(new QueryEntity(String.class.getName(), String.class.getName())
+ .setFieldsPrecision(strStrPrecision)), STR_CACHE_NAME);
+
+ Map<String, Integer> orgAddressPrecision = new HashMap<>();
+
+ orgAddressPrecision.put("name", 5);
+ orgAddressPrecision.put("address", 5);
+
+ jcache(grid(0), cacheConfiguration(new QueryEntity(Organization.class.getName(), Address.class.getName())
+ .addQueryField("name", "java.lang.String", "name")
+ .addQueryField("address", "java.lang.String", "address")
+ .setFieldsPrecision(orgAddressPrecision)), OBJ_CACHE_NAME);
+
+ Map<String, Integer> strOrgPrecision = new HashMap<>();
+
+ strOrgPrecision.put(KEY_FIELD_NAME, 5);
+
+ jcache(grid(0), cacheConfiguration(new QueryEntity(String.class.getName(), Organization.class.getName())
+ .setFieldsPrecision(strOrgPrecision)), STR_ORG_CACHE_NAME);
+
+ jcache(grid(0), cacheConfiguration(new QueryEntity(String.class.getName(), Organization.class.getName())
+ .addQueryField("name", "java.lang.String", "name")
+ .addQueryField("address", "java.lang.String", "address")
+ .setFieldsPrecision(strOrgPrecision)), STR_ORG_WITH_FIELDS_CACHE_NAME);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutTooLongValueFail() throws Exception {
+ IgniteCache<String, String> cache = jcache(0, STR_CACHE_NAME);
+
+ T2<String, String> val = new T2<>("3", "123456");
+
+ checkPutAll(shouldFail, cache, new T2<>("1", "1"), val);
+
+ checkPutOps(shouldFail, cache, val);
+
+ checkReplaceOps(shouldFail, cache, val, "1");
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutTooLongKeyFail() throws Exception {
+ IgniteCache<String, String> cache = jcache(0, STR_CACHE_NAME);
+
+ T2<String, String> val = new T2<>("123456", "2");
+
+ checkPutAll(shouldFail, cache, new T2<>("1", "1"), val);
+
+ checkPutOps(shouldFail, cache, val);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutTooLongValueFieldFail() throws Exception {
+ IgniteCache<Organization, Address> cache = jcache(0, OBJ_CACHE_NAME);
+
+ T2<Organization, Address> val = new T2<>(new Organization("3"), new Address("123456"));
+
+ checkPutAll(shouldFail, cache, new T2<>(new Organization("1"), new Address("1")), val);
+
+ checkPutOps(shouldFail, cache, val);
+
+ checkReplaceOps(shouldFail, cache, val, new Address("1"));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutTooLongKeyFieldFail() throws Exception {
+ IgniteCache<Organization, Address> cache = jcache(0, OBJ_CACHE_NAME);
+
+ T2<Organization, Address> val = new T2<>(new Organization("123456"), new Address("2"));
+
+ checkPutAll(shouldFail, cache, new T2<>(new Organization("1"), new Address("1")), val);
+
+ checkPutOps(shouldFail, cache, val);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutTooLongKeyFail2() throws Exception {
+ doCheckPutTooLongKeyFail2(STR_ORG_CACHE_NAME);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutTooLongKeyFail3() throws Exception {
+ doCheckPutTooLongKeyFail2(STR_ORG_WITH_FIELDS_CACHE_NAME);
+ }
+
+
+ private void doCheckPutTooLongKeyFail2(String cacheName) {
+ IgniteCache<String, Organization> cache = jcache(0, cacheName);
+
+ T2<String, Organization> val = new T2<>("123456", new Organization("1"));
+
+ checkPutAll(shouldFail, cache, new T2<>("1", new Organization("1")), val);
+
+ checkPutOps(shouldFail, cache, val);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutLongValue() throws Exception {
+ IgniteCache<String, String> cache = jcache(0, STR_CACHE_NAME);
+
+ T2<String, String> val = new T2<>("3", "12345");
+
+ checkPutAll(shouldSucceed, cache, new T2<>("1", "1"), val);
+
+ checkPutOps(shouldSucceed, cache, val);
+
+ checkReplaceOps(shouldSucceed, cache, val, "1");
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutLongKey() throws Exception {
+ IgniteCache<String, String> cache = jcache(0, STR_CACHE_NAME);
+
+ T2<String, String> val = new T2<>("12345", "2");
+
+ checkPutAll(shouldSucceed, cache, new T2<>("1", "1"), val);
+
+ checkPutOps(shouldSucceed, cache, val);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutLongValueField() throws Exception {
+ IgniteCache<Organization, Address> cache = jcache(0, OBJ_CACHE_NAME);
+
+ T2<Organization, Address> val = new T2<>(new Organization("3"), new Address("12345"));
+
+ checkPutAll(shouldSucceed, cache, new T2<>(new Organization("1"), new Address("1")), val);
+
+ checkPutOps(shouldSucceed, cache, val);
+
+ checkReplaceOps(shouldSucceed, cache, val, new Address("1"));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutLongKeyField() throws Exception {
+ IgniteCache<Organization, Address> cache = jcache(0, OBJ_CACHE_NAME);
+
+ T2<Organization, Address> val = new T2<>(new Organization("12345"), new Address("2"));
+
+ checkPutAll(shouldSucceed, cache, new T2<>(new Organization("1"), new Address("1")), val);
+
+ checkPutOps(shouldSucceed, cache, val);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutLongKey2() throws Exception {
+ doCheckPutLongKey2(STR_ORG_CACHE_NAME);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testPutLongKey3() throws Exception {
+ doCheckPutLongKey2(STR_ORG_WITH_FIELDS_CACHE_NAME);
+ }
+
+ private void doCheckPutLongKey2(String cacheName) {
+ IgniteCache<String, Organization> cache = jcache(0, cacheName);
+
+ T2<String, Organization> key2 = new T2<>("12345", new Organization("1"));
+
+ checkPutAll(shouldSucceed, cache, new T2<>("1", new Organization("1")), key2);
+
+ checkPutOps(shouldSucceed, cache, key2);
+ }
+
+ /** */
+ private <K, V> void checkReplaceOps(Consumer<Runnable> checker, IgniteCache<K, V> cache, T2<K, V> val, V okVal) {
+ K k = val.get1();
+ V v = val.get2();
+
+ cache.put(k, okVal);
+
+ CacheEntryProcessor<K, V, ?> entryProcessor = (e, arguments) -> {
+ e.setValue((V)arguments[0]);
+
+ return null;
+ };
+
+ Stream<Runnable> ops = Stream.of(
+ () -> cache.replace(k, v),
+ () -> cache.getAndReplace(k, v),
+ () -> cache.replace(k, okVal, v),
+ () -> cache.invoke(k, entryProcessor, v),
+ () -> cache.replaceAsync(k, v).get(FUT_TIMEOUT),
+ () -> cache.getAndReplaceAsync(k, v).get(FUT_TIMEOUT),
+ () -> cache.replaceAsync(k, okVal, v).get(FUT_TIMEOUT),
+ () -> cache.invokeAsync(k, entryProcessor, v).get(FUT_TIMEOUT)
+ );
+
+ ops.forEach(checker);
+ }
+
+ /** */
+ private <K, V> void checkPutOps(Consumer<Runnable> checker, IgniteCache<K, V> cache, T2<K, V> val) {
+ K k = val.get1();
+ V v = val.get2();
+
+ Stream<Runnable> ops = Stream.of(
+ () -> cache.put(k, v),
+ () -> cache.putIfAbsent(k, v),
+ () -> cache.getAndPut(k, v),
+ () -> cache.getAndPutIfAbsent(k, v),
+ () -> cache.putAsync(k, v).get(FUT_TIMEOUT),
+ () -> cache.putIfAbsentAsync(k, v).get(FUT_TIMEOUT),
+ () -> cache.getAndPutAsync(k, v).get(FUT_TIMEOUT),
+ () -> cache.getAndPutIfAbsentAsync(k, v).get(FUT_TIMEOUT)
+ );
+
+ ops.forEach(checker);
+ }
+
+ /** */
+ private <K, V> void checkPutAll(Consumer<Runnable> checker, IgniteCache<K, V> cache, T2<K, V>... entries) {
+ CacheEntryProcessor<K, V, ?> entryProcessor = (e, arguments) -> {
+ e.setValue(((Iterator<V>)arguments[0]).next());
+
+ return null;
+ };
+
+ Map<K, V> vals = Arrays.stream(entries).collect(Collectors.toMap(T2::get1, T2::get2));
+
+ Stream<Runnable> ops = Stream.of(
+ () -> cache.putAll(vals),
+ () -> cache.putAllAsync(vals).get(FUT_TIMEOUT),
+ () -> {
+ Map<K, ? extends EntryProcessorResult<?>> map =
+ cache.invokeAll(vals.keySet(), entryProcessor, vals.values().iterator());
+
+ for (EntryProcessorResult<?> result : map.values())
+ log.info(">>> " + result.get());
+ },
+ () -> {
+ Map<K, ? extends EntryProcessorResult<?>> map =
+ cache.invokeAllAsync(vals.keySet(), entryProcessor, vals.values().iterator()).get(FUT_TIMEOUT);
+
+ for (EntryProcessorResult<?> result : map.values())
+ log.info(">>> " + result.get());
+ }
+ );
+
+ ops.forEach(checker);
+ }
+
+ /**
+ * @param qryEntity Query entity.
+ * @return Cache configuration.
+ */
+ protected CacheConfiguration cacheConfiguration(QueryEntity qryEntity) {
+ CacheConfiguration<?, ?> cache = defaultCacheConfiguration();
+
+ cache.setCacheMode(cacheMode());
+ cache.setAtomicityMode(atomicityMode());
+ cache.setBackups(1);
+ cache.setWriteSynchronizationMode(FULL_SYNC);
+
+ cache.setQueryEntities(Collections.singletonList(qryEntity));
+
+ return cache;
+ }
+
+ /** */
+ @NotNull protected CacheAtomicityMode atomicityMode() {
+ return ATOMIC;
+ }
+
+ /** */
+ @NotNull protected CacheMode cacheMode() {
+ return PARTITIONED;
+ }
+
+ /** */
+ @SuppressWarnings("UnusedDeclaration")
+ private static class Organization implements Serializable {
+ /** Name. */
+ private final String name;
+
+ /**
+ * @param name Name.
+ */
+ private Organization(String name) {
+ this.name = name;
+ }
+ }
+
+ /** */
+ @SuppressWarnings("UnusedDeclaration")
+ private static class Address implements Serializable {
+ /** Name. */
+ private final String address;
+
+ /**
+ * @param address Address.
+ */
+ private Address(String address) {
+ this.address = address;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCachePartitionedTransactionalColumnConstraintsTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCachePartitionedTransactionalColumnConstraintsTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCachePartitionedTransactionalColumnConstraintsTest.java
new file mode 100644
index 0000000..cd5c979
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCachePartitionedTransactionalColumnConstraintsTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.sql;
+
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.jetbrains.annotations.NotNull;
+
+/** */
+public class IgniteCachePartitionedTransactionalColumnConstraintsTest
+ extends IgniteCachePartitionedAtomicColumnConstraintsTest {
+ /** {@inheritDoc} */
+ @NotNull protected CacheAtomicityMode atomicityMode() {
+ return CacheAtomicityMode.TRANSACTIONAL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCacheReplicatedAtomicColumnConstraintsTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCacheReplicatedAtomicColumnConstraintsTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCacheReplicatedAtomicColumnConstraintsTest.java
new file mode 100644
index 0000000..eba9f64
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCacheReplicatedAtomicColumnConstraintsTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.sql;
+
+import org.apache.ignite.cache.CacheMode;
+import org.jetbrains.annotations.NotNull;
+
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+
+/** */
+public class IgniteCacheReplicatedAtomicColumnConstraintsTest
+ extends IgniteCachePartitionedAtomicColumnConstraintsTest {
+ /** {@inheritDoc} */
+ @NotNull @Override protected CacheMode cacheMode() {
+ return PARTITIONED;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCacheReplicatedTransactionalColumnConstraintsTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCacheReplicatedTransactionalColumnConstraintsTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCacheReplicatedTransactionalColumnConstraintsTest.java
new file mode 100644
index 0000000..bddd69a
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteCacheReplicatedTransactionalColumnConstraintsTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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.sql;
+
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.jetbrains.annotations.NotNull;
+
+/** */
+public class IgniteCacheReplicatedTransactionalColumnConstraintsTest
+ extends IgniteCacheReplicatedAtomicColumnConstraintsTest {
+ /** {@inheritDoc} */
+ @NotNull @Override protected CacheAtomicityMode atomicityMode() {
+ return CacheAtomicityMode.TRANSACTIONAL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteSQLColumnConstraintsTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteSQLColumnConstraintsTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteSQLColumnConstraintsTest.java
new file mode 100644
index 0000000..762743b
--- /dev/null
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/sql/IgniteSQLColumnConstraintsTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.sql;
+
+import java.util.List;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.internal.processors.odbc.SqlStateCode;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.internal.processors.odbc.SqlStateCode.CONSTRAINT_VIOLATION;
+
+/**
+ */
+public class IgniteSQLColumnConstraintsTest extends GridCommonAbstractTest {
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ startGrid(0);
+
+ execSQL("CREATE TABLE varchar_table(id INT PRIMARY KEY, str VARCHAR(5))");
+
+ execSQL("INSERT INTO varchar_table VALUES(?, ?)", 1, "12345");
+
+ execSQL("CREATE TABLE char_table(id INT PRIMARY KEY, str CHAR(5))");
+
+ execSQL("INSERT INTO char_table VALUES(?, ?)", 1, "12345");
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testCreateTableWithTooLongDefault() throws Exception {
+ checkSQLThrows("CREATE TABLE too_long_default(id INT PRIMARY KEY, str CHAR(5) DEFAULT '123456')");
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testInsertTooLongVarchar() throws Exception {
+ checkSQLThrows("INSERT INTO varchar_table VALUES(?, ?)", 2, "123456");
+
+ checkSQLThrows("UPDATE varchar_table SET str = ? WHERE id = ?", "123456", 1);
+
+ checkSQLThrows("MERGE INTO varchar_table(id, str) VALUES(?, ?)", 1, "123456");
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testInsertTooLongChar() throws Exception {
+ checkSQLThrows("INSERT INTO char_table VALUES(?, ?)", 2, "123456");
+
+ checkSQLThrows("UPDATE char_table SET str = ? WHERE id = ?", "123456", 1);
+
+ checkSQLThrows("MERGE INTO char_table(id, str) VALUES(?, ?)", 1, "123456");
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testConstraintsAfterAlterTable() throws Exception {
+ execSQL("CREATE TABLE char_table_2(id INT PRIMARY KEY, field INTEGER)");
+
+ execSQL("ALTER TABLE char_table_2 ADD COLUMN str CHAR(5) NOT NULL");
+
+ execSQL("INSERT INTO char_table_2(id, str) VALUES(?, ?)", 1, "1");
+
+ checkSQLThrows("INSERT INTO char_table_2(id, str) VALUES(?, ?)", 2, "123456");
+
+ checkSQLThrows("UPDATE char_table_2 SET str = ? WHERE id = ?", "123456", 1);
+
+ checkSQLThrows("MERGE INTO char_table_2(id, str) VALUES(?, ?)", 1, "123456");
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testDropColumnWithConstraint() throws Exception {
+ execSQL("CREATE TABLE char_table_3(id INT PRIMARY KEY, field CHAR(5), field2 INTEGER)");
+
+ execSQL("INSERT INTO char_table_3(id, field, field2) VALUES(?, ?, ?)", 1, "12345", 1);
+
+ checkSQLThrows("INSERT INTO char_table_3(id, field, field2) VALUES(?, ?, ?)", 2, "123456", 1);
+
+ execSQL("ALTER TABLE char_table_3 DROP COLUMN field");
+
+ execSQL("INSERT INTO char_table_3(id, field2) VALUES(?, ?)", 3, 3);
+ }
+
+ public void testSqlState() throws Exception {
+ execSQL("CREATE TABLE char_table_4(id INT PRIMARY KEY, field CHAR(5))");
+
+ IgniteSQLException err = (IgniteSQLException)
+ checkSQLThrows("INSERT INTO char_table_4(id, field) VALUES(?, ?)", 1, "123456");
+
+ assertEquals(err.sqlState(), CONSTRAINT_VIOLATION);
+
+ execSQL("INSERT INTO char_table_4(id, field) VALUES(?, ?)", 2, "12345");
+
+ err = (IgniteSQLException)
+ checkSQLThrows("UPDATE char_table_4 SET field = ? WHERE id = ?", "123456", 2);
+
+ assertEquals(err.sqlState(), CONSTRAINT_VIOLATION);
+
+ err = (IgniteSQLException)
+ checkSQLThrows("MERGE INTO char_table_4(id, field) VALUES(?, ?)", 2, "123456");
+
+ assertEquals(err.sqlState(), CONSTRAINT_VIOLATION);
+ }
+
+ /** */
+ private Throwable checkSQLThrows(String sql, Object... args) {
+ return GridTestUtils.assertThrowsWithCause(() -> {
+ execSQL(sql, args);
+
+ return 0;
+ }, IgniteSQLException.class);
+ }
+
+ /** */
+ private List<?> execSQL(String sql, Object... args) {
+ SqlFieldsQuery qry = new SqlFieldsQuery(sql)
+ .setArgs(args);
+
+ return grid(0).context().query().querySqlFields(qry, true).getAll();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/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 a658caf..6b3cace 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
@@ -188,6 +188,11 @@ import org.apache.ignite.internal.processors.query.h2.sql.BaseH2CompareQueryTest
import org.apache.ignite.internal.processors.query.h2.sql.GridQueryParsingTest;
import org.apache.ignite.internal.processors.query.h2.sql.H2CompareBigQueryDistributedJoinsTest;
import org.apache.ignite.internal.processors.query.h2.sql.H2CompareBigQueryTest;
+import org.apache.ignite.internal.processors.sql.IgniteCachePartitionedAtomicColumnConstraintsTest;
+import org.apache.ignite.internal.processors.sql.IgniteCachePartitionedTransactionalColumnConstraintsTest;
+import org.apache.ignite.internal.processors.sql.IgniteCacheReplicatedAtomicColumnConstraintsTest;
+import org.apache.ignite.internal.processors.sql.IgniteCacheReplicatedTransactionalColumnConstraintsTest;
+import org.apache.ignite.internal.processors.sql.IgniteSQLColumnConstraintsTest;
import org.apache.ignite.internal.processors.sql.SqlConnectorConfigurationValidationSelfTest;
import org.apache.ignite.internal.sql.SqlParserBulkLoadSelfTest;
import org.apache.ignite.internal.sql.SqlParserCreateIndexSelfTest;
@@ -444,6 +449,12 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite {
suite.addTestSuite(IgniteSqlDefaultValueTest.class);
suite.addTestSuite(IgniteDecimalSelfTest.class);
+ suite.addTestSuite(IgniteSQLColumnConstraintsTest.class);
+
+ suite.addTestSuite(IgniteCachePartitionedAtomicColumnConstraintsTest.class);
+ suite.addTestSuite(IgniteCachePartitionedTransactionalColumnConstraintsTest.class);
+ suite.addTestSuite(IgniteCacheReplicatedAtomicColumnConstraintsTest.class);
+ suite.addTestSuite(IgniteCacheReplicatedTransactionalColumnConstraintsTest.class);
// H2 Rows on-heap cache
suite.addTestSuite(H2RowCacheSelfTest.class);
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/platforms/cpp/common/include/ignite/common/utils.h
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/common/include/ignite/common/utils.h b/modules/platforms/cpp/common/include/ignite/common/utils.h
index 81b5432..4edbf4b 100644
--- a/modules/platforms/cpp/common/include/ignite/common/utils.h
+++ b/modules/platforms/cpp/common/include/ignite/common/utils.h
@@ -548,4 +548,4 @@ namespace ignite
}
}
-#endif //_IGNITE_COMMON_UTILS
\ No newline at end of file
+#endif //_IGNITE_COMMON_UTILS
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/platforms/cpp/odbc-test/config/queries-default.xml
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/config/queries-default.xml b/modules/platforms/cpp/odbc-test/config/queries-default.xml
index dbe3a10..659ad14 100644
--- a/modules/platforms/cpp/odbc-test/config/queries-default.xml
+++ b/modules/platforms/cpp/odbc-test/config/queries-default.xml
@@ -85,6 +85,12 @@
</bean>
</list>
</property>
+
+ <property name="fieldsPrecision">
+ <map>
+ <entry key="strField" value="60" />
+ </map>
+ </property>
</bean>
</list>
</property>
http://git-wip-us.apache.org/repos/asf/ignite/blob/baab0a6d/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
----------------------------------------------------------------------
diff --git a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
index 8e22e3d..5cacb96 100644
--- a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
+++ b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp
@@ -180,6 +180,8 @@ BOOST_AUTO_TEST_CASE(TestColAttributesColumnLength)
if (!SQL_SUCCEEDED(ret))
BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+ BOOST_CHECK_EQUAL(intVal, 60);
}
BOOST_AUTO_TEST_CASE(TestColAttributesColumnPresicion)
@@ -197,6 +199,8 @@ BOOST_AUTO_TEST_CASE(TestColAttributesColumnPresicion)
if (!SQL_SUCCEEDED(ret))
BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+
+ BOOST_CHECK_EQUAL(intVal, 60);
}
BOOST_AUTO_TEST_CASE(TestColAttributesColumnScale)
@@ -278,6 +282,19 @@ BOOST_AUTO_TEST_CASE(TestGetDataWithSelectQuery)
CheckSingleRowResultSetWithGetData(stmt);
}
+BOOST_AUTO_TEST_CASE(TestInsertTooLongValueFail)
+{
+ Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");
+
+ SQLCHAR insertReq[] =
+ "insert into TestType(_key, strField) VALUES(42, '0123456789012345678901234567890123456789012345678901234567891')";
+
+ SQLRETURN ret = SQLExecDirect(stmt, insertReq, SQL_NTS);
+
+ if (SQL_SUCCEEDED(ret))
+ BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt));
+}
+
BOOST_AUTO_TEST_CASE(TestGetInfoScrollOptions)
{
Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");