This is an automated email from the ASF dual-hosted git repository.
peeyush pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git
The following commit(s) were added to refs/heads/master by this push:
new f21bb30678 [ASTERIXDB-3263][COMP] Incorrect data inserted when
optional field in closed type
f21bb30678 is described below
commit f21bb306781dfa180a35fbf5112cbe5780acaced
Author: Peeyush Gupta <[email protected]>
AuthorDate: Wed Sep 13 14:35:59 2023 -0700
[ASTERIXDB-3263][COMP] Incorrect data inserted when optional field in
closed type
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- Update the dynamic type cast rule to correctly check type compatibility
in case of insert/upsert.
- Update the constant folding rule to allow constant fold closed records.
Change-Id: I3469da3f4f70759886fe9b98faf99eaaceff1edc
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17778
Reviewed-by: Peeyush Gupta <[email protected]>
Reviewed-by: Ali Alsuliman <[email protected]>
Integration-Tests: Jenkins <[email protected]>
Tested-by: Jenkins <[email protected]>
---
.../optimizer/rules/ConstantFoldingRule.java | 6 +-
.../FullTextContainsParameterCheckAndSetRule.java | 159 ++++++++++++---------
...duceDynamicTypeCastForExternalFunctionRule.java | 3 +-
.../rules/IntroduceDynamicTypeCastRule.java | 31 ++--
.../index-through-object.9.plan | 78 +++++-----
.../insert-primary-key-index-with-auto-gen-pk.plan | 4 +-
.../index-through-object.9.plan | 64 ++++-----
.../dml/insert-closed/insert-closed.1.ddl.sqlpp | 32 +++++
.../dml/insert-closed/insert-closed.2.update.sqlpp | 34 +++++
.../dml/insert-closed/insert-closed.3.query.sqlpp | 22 +++
.../array_fun/array_remove/array_remove.5.plan | 2 +-
.../results/dml/insert-closed/insert-closed.1.adm | 10 ++
.../test/resources/runtimets/testsuite_sqlpp.xml | 5 +
13 files changed, 288 insertions(+), 162 deletions(-)
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
index 9fe1ba4ab2..3b39d7c0ab 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
@@ -395,12 +395,14 @@ public class ConstantFoldingRule implements
IAlgebraicRewriteRule {
if (fi.isExternal()) {
return false;
}
+ IAType returnType = (IAType) _emptyTypeEnv.getType(function);
// skip all functions that would produce records/arrays/multisets
(derived types) in their open format
// this is because constant folding them will make them closed
(currently)
if
(function.getFunctionIdentifier().equals(BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR))
{
- return false;
+ if (returnType.getTypeTag() != ATypeTag.OBJECT ||
((ARecordType) returnType).isOpen()) {
+ return false;
+ }
}
- IAType returnType = (IAType) _emptyTypeEnv.getType(function);
return canConstantFoldType(returnType);
}
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FullTextContainsParameterCheckAndSetRule.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FullTextContainsParameterCheckAndSetRule.java
index 3e4e563cb9..3b2153c80d 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FullTextContainsParameterCheckAndSetRule.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/FullTextContainsParameterCheckAndSetRule.java
@@ -26,9 +26,11 @@ import org.apache.asterix.common.exceptions.ErrorCode;
import org.apache.asterix.common.metadata.DataverseName;
import org.apache.asterix.metadata.declared.MetadataProvider;
import org.apache.asterix.metadata.utils.FullTextUtil;
+import org.apache.asterix.om.base.ARecord;
import org.apache.asterix.om.base.AString;
import org.apache.asterix.om.constants.AsterixConstantValue;
import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.utils.ConstantExpressionUtil;
import
org.apache.asterix.runtime.evaluators.functions.FullTextContainsFunctionDescriptor;
@@ -239,82 +241,111 @@ public class FullTextContainsParameterCheckAndSetRule
implements IAlgebraicRewri
List<Mutable<ILogicalExpression>> newArgs, String
functionName) throws AlgebricksException {
String ftConfigName = null;
- // Get the last parameter - this should be a record-constructor.
- AbstractFunctionCallExpression openRecConsExpr =
(AbstractFunctionCallExpression) expr.getValue();
- FunctionIdentifier openRecConsFi =
openRecConsExpr.getFunctionIdentifier();
- if (openRecConsFi != BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR
- && openRecConsFi !=
BuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR) {
- throw CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
openRecConsExpr.getSourceLocation(),
- functionName, openRecConsFi);
- }
-
- // We multiply 2 because the layout of the arguments are: [expr,
val, expr1, val1, ...]
- if (openRecConsExpr.getArguments().size() >
FullTextContainsFunctionDescriptor.getParamTypeMap().size()
- * 2) {
- throw
CompilationException.create(ErrorCode.TOO_MANY_OPTIONS_FOR_FUNCTION,
- openRecConsExpr.getSourceLocation(), functionName);
- }
-
- if (openRecConsExpr.getArguments().size() % 2 != 0) {
- throw
CompilationException.create(ErrorCode.COMPILATION_INVALID_PARAMETER_NUMBER,
- openRecConsExpr.getSourceLocation(), functionName);
- }
-
- for (int i = 0; i < openRecConsExpr.getArguments().size(); i = i +
2) {
- ILogicalExpression optionExpr =
openRecConsExpr.getArguments().get(i).getValue();
- ILogicalExpression optionExprVal =
openRecConsExpr.getArguments().get(i + 1).getValue();
+ // Get the last parameter - this should be a record-constructor or
a constant expression.
+ if (expr.getValue().getExpressionTag() ==
LogicalExpressionTag.CONSTANT) {
+ ConstantExpression constantExpression = (ConstantExpression)
expr.getValue();
+ ARecord record =
+ (ARecord)
ConstantExpressionUtil.getConstantIaObject(constantExpression, ATypeTag.OBJECT);
+ if (record == null) {
+ throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
+ constantExpression.getSourceLocation(),
functionName,
+ constantExpression.getExpressionTag());
+ }
+ ARecordType recordType = record.getType();
+ if (record.numberOfFields() >
FullTextContainsFunctionDescriptor.getParamTypeMap().size()) {
+ throw
CompilationException.create(ErrorCode.TOO_MANY_OPTIONS_FOR_FUNCTION,
+ constantExpression.getSourceLocation(),
functionName);
+ }
+ for (int i = 0; i < record.numberOfFields(); i++) {
+ String option =
recordType.getFieldNames()[i].toLowerCase();
+ ILogicalExpression optionExpr =
+ new ConstantExpression(new
AsterixConstantValue(new AString(option)));
+ ILogicalExpression optionExprVal =
+ new ConstantExpression(new
AsterixConstantValue(record.getValueByPos(i)));
+ ftConfigName = handleThirdParameterOptions(optionExpr,
optionExprVal, newArgs, functionName);
+ }
+ } else {
+ AbstractFunctionCallExpression openRecConsExpr =
(AbstractFunctionCallExpression) expr.getValue();
+ FunctionIdentifier openRecConsFi =
openRecConsExpr.getFunctionIdentifier();
+ if (openRecConsFi != BuiltinFunctions.OPEN_RECORD_CONSTRUCTOR
+ && openRecConsFi !=
BuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR) {
+ throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
openRecConsExpr.getSourceLocation(),
+ functionName, openRecConsFi);
+ }
- String option =
ConstantExpressionUtil.getStringConstant(optionExpr);
+ // We multiply 2 because the layout of the arguments are:
[expr, val, expr1, val1, ...]
+ if (openRecConsExpr.getArguments().size() >
FullTextContainsFunctionDescriptor.getParamTypeMap().size()
+ * 2) {
+ throw
CompilationException.create(ErrorCode.TOO_MANY_OPTIONS_FOR_FUNCTION,
+ openRecConsExpr.getSourceLocation(), functionName);
+ }
- if (optionExpr.getExpressionTag() !=
LogicalExpressionTag.CONSTANT || option == null) {
- throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
optionExpr.getSourceLocation(),
- functionName, optionExpr.getExpressionTag());
+ if (openRecConsExpr.getArguments().size() % 2 != 0) {
+ throw
CompilationException.create(ErrorCode.COMPILATION_INVALID_PARAMETER_NUMBER,
+ openRecConsExpr.getSourceLocation(), functionName);
}
- option = option.toLowerCase();
- if
(!FullTextContainsFunctionDescriptor.getParamTypeMap().containsKey(option)) {
- throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
optionExprVal.getSourceLocation(),
- functionName, option);
+ for (int i = 0; i < openRecConsExpr.getArguments().size(); i =
i + 2) {
+ ILogicalExpression optionExpr =
openRecConsExpr.getArguments().get(i).getValue();
+ ILogicalExpression optionExprVal =
openRecConsExpr.getArguments().get(i + 1).getValue();
+ ftConfigName = handleThirdParameterOptions(optionExpr,
optionExprVal, newArgs, functionName);
}
+ }
+ return ftConfigName;
+ }
- String optionTypeStringVal = null;
- // If the option value is a constant, then we can check here.
- if (optionExprVal.getExpressionTag() ==
LogicalExpressionTag.CONSTANT) {
- switch
(FullTextContainsFunctionDescriptor.getParamTypeMap().get(option)) {
- case STRING:
- optionTypeStringVal =
ConstantExpressionUtil.getStringConstant(optionExprVal);
- if (optionTypeStringVal == null) {
- throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
- optionExprVal.getSourceLocation(),
functionName, option);
- }
- optionTypeStringVal =
optionTypeStringVal.toLowerCase();
- break;
- default:
- // Currently, we only have a string parameter. So,
the flow doesn't reach here.
- throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
- optionExprVal.getSourceLocation(),
functionName, option);
- }
+ private String handleThirdParameterOptions(ILogicalExpression
optionExpr, ILogicalExpression optionExprVal,
+ List<Mutable<ILogicalExpression>> newArgs, String
functionName) throws AlgebricksException {
+ String ftConfigName = null;
+ String option =
ConstantExpressionUtil.getStringConstant(optionExpr);
+
+ if (optionExpr.getExpressionTag() != LogicalExpressionTag.CONSTANT
|| option == null) {
+ throw CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
optionExpr.getSourceLocation(),
+ functionName, optionExpr.getExpressionTag());
+ }
- // Check the validity of option value
- switch (option) {
- case
FullTextContainsFunctionDescriptor.SEARCH_MODE_OPTION:
- checkSearchModeOption(optionTypeStringVal,
functionName, optionExprVal.getSourceLocation());
- break;
- case
FullTextContainsFunctionDescriptor.FULLTEXT_CONFIG_OPTION:
- checkFullTextConfigOption(optionTypeStringVal,
functionName,
- optionExprVal.getSourceLocation());
- ftConfigName = optionTypeStringVal;
- break;
- default:
+ option = option.toLowerCase();
+ if
(!FullTextContainsFunctionDescriptor.getParamTypeMap().containsKey(option)) {
+ throw CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
optionExprVal.getSourceLocation(),
+ functionName, option);
+ }
+
+ String optionTypeStringVal = null;
+ // If the option value is a constant, then we can check here.
+ if (optionExprVal.getExpressionTag() ==
LogicalExpressionTag.CONSTANT) {
+ switch
(FullTextContainsFunctionDescriptor.getParamTypeMap().get(option)) {
+ case STRING:
+ optionTypeStringVal =
ConstantExpressionUtil.getStringConstant(optionExprVal);
+ if (optionTypeStringVal == null) {
throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
optionExprVal.getSourceLocation(),
functionName, option);
- }
+ }
+ optionTypeStringVal =
optionTypeStringVal.toLowerCase();
+ break;
+ default:
+ // Currently, we only have a string parameter. So, the
flow doesn't reach here.
+ throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
optionExprVal.getSourceLocation(),
+ functionName, option);
}
- // Add this option as arguments to the ftcontains().
- newArgs.add(new MutableObject<ILogicalExpression>(optionExpr));
- newArgs.add(new
MutableObject<ILogicalExpression>(optionExprVal));
+ // Check the validity of option value
+ switch (option) {
+ case FullTextContainsFunctionDescriptor.SEARCH_MODE_OPTION:
+ checkSearchModeOption(optionTypeStringVal,
functionName, optionExprVal.getSourceLocation());
+ break;
+ case
FullTextContainsFunctionDescriptor.FULLTEXT_CONFIG_OPTION:
+ checkFullTextConfigOption(optionTypeStringVal,
functionName, optionExprVal.getSourceLocation());
+ ftConfigName = optionTypeStringVal;
+ break;
+ default:
+ throw
CompilationException.create(ErrorCode.TYPE_UNSUPPORTED,
optionExprVal.getSourceLocation(),
+ functionName, option);
+ }
}
+
+ // Add this option as arguments to the ftcontains().
+ newArgs.add(new MutableObject<>(optionExpr));
+ newArgs.add(new MutableObject<>(optionExprVal));
return ftConfigName;
}
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java
index 22d87ac1d1..e8f9048493 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java
@@ -81,8 +81,7 @@ public class IntroduceDynamicTypeCastForExternalFunctionRule
implements IAlgebra
reqArgType = ((ExternalFunctionInfo)
funcCallExpr.getFunctionInfo()).getParameterTypes().get(i);
if (reqArgType.getTypeTag() == ATypeTag.OBJECT) {
- castFlag =
!IntroduceDynamicTypeCastRule.compatible((ARecordType) reqArgType, inputType,
- argExpr.getValue().getSourceLocation());
+ castFlag =
!IntroduceDynamicTypeCastRule.compatible((ARecordType) reqArgType, inputType,
op);
} else if (reqArgType.getTypeTag() == ATypeTag.ANY) {
IAType inputPrimeType =
TypeComputeUtils.getActualType(inputType);
castFlag = inputPrimeType.getTypeTag().isDerivedType();
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java
index 4044965e00..a9ad7cecd1 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java
@@ -167,7 +167,7 @@ public class IntroduceDynamicTypeCastRule implements
IAlgebraicRewriteRule {
}
/** see whether the input record type needs to be casted */
- boolean cast = !compatible(requiredRecordType, inputRecordType,
op.getSourceLocation());
+ boolean cast = !compatible(requiredRecordType, inputRecordType, op);
if (checkUnknown) {
recordVar = addWrapperFunction(requiredRecordType, recordVar, op,
context, BuiltinFunctions.CHECK_UNKNOWN);
@@ -252,8 +252,9 @@ public class IntroduceDynamicTypeCastRule implements
IAlgebraicRewriteRule {
* @return true if compatible; false otherwise
* @throws AlgebricksException
*/
- public static boolean compatible(ARecordType reqType, IAType inputType,
SourceLocation sourceLoc)
+ public static boolean compatible(ARecordType reqType, IAType inputType,
ILogicalOperator op)
throws AlgebricksException {
+ SourceLocation sourceLoc = op.getSourceLocation();
if (inputType.getTypeTag() == ATypeTag.ANY) {
return false;
}
@@ -279,19 +280,25 @@ public class IntroduceDynamicTypeCastRule implements
IAlgebraicRewriteRule {
return false;
}
IAType reqTypeInside = reqTypes[i];
- if (NonTaggedFormatUtil.isOptional(reqTypes[i])) {
- reqTypeInside = ((AUnionType) reqTypes[i]).getActualType();
- }
IAType inputTypeInside = inputTypes[i];
- if (NonTaggedFormatUtil.isOptional(inputTypes[i])) {
- if (!NonTaggedFormatUtil.isOptional(reqTypes[i])) {
- /** if the required type is not optional, the two types
are incompatible */
+ if (op.getOperatorTag() ==
LogicalOperatorTag.INSERT_DELETE_UPSERT) {
+ if (!reqTypeInside.equals(inputTypeInside)) {
+ return false;
+ }
+ } else {
+ if (NonTaggedFormatUtil.isOptional(reqTypes[i])) {
+ reqTypeInside = ((AUnionType) reqTypes[i]).getActualType();
+ }
+ if (NonTaggedFormatUtil.isOptional(inputTypes[i])) {
+ if (!NonTaggedFormatUtil.isOptional(reqTypes[i])) {
+ /** if the required type is not optional, the two
types are incompatible */
+ return false;
+ }
+ inputTypeInside = ((AUnionType)
inputTypes[i]).getActualType();
+ }
+ if (inputTypeInside.getTypeTag() != ATypeTag.MISSING &&
!reqTypeInside.equals(inputTypeInside)) {
return false;
}
- inputTypeInside = ((AUnionType) inputTypes[i]).getActualType();
- }
- if (inputTypeInside.getTypeTag() != ATypeTag.MISSING &&
!reqTypeInside.equals(inputTypeInside)) {
- return false;
}
}
return true;
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/index-through-object/index-through-object.9.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/index-through-object/index-through-object.9.plan
index 1d2e55b9cb..9b51cb089b 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/index-through-object/index-through-object.9.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/index-through-object/index-through-object.9.plan
@@ -2,46 +2,38 @@
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
-- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- NESTED_LOOP |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- HYBRID_HASH_JOIN [$$82][$$83] |PARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$82] |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- BTREE_SEARCH (Test.Users.Users)
|PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STABLE_SORT [$$106(ASC)] |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- BTREE_SEARCH
(Test.Users.usersNameIdx) |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE
|PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE
|PARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$83] |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- BTREE_SEARCH (Test.Users.Users)
|PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STABLE_SORT [$$110(ASC)] |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- BTREE_SEARCH
(Test.Users.usersNameIdx) |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE
|PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE
|PARTITIONED|
- -- BROADCAST_EXCHANGE |PARTITIONED|
- -- STREAM_SELECT |UNPARTITIONED|
- -- ASSIGN |UNPARTITIONED|
- -- UNNEST |UNPARTITIONED|
- -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
\ No newline at end of file
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- HYBRID_HASH_JOIN [$$88][$$89] |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$88] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH (Test.Users.Users) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$110(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH
(Test.Users.usersNameIdx) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE
|PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$89] |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH (Test.Users.Users) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$114(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH
(Test.Users.usersNameIdx) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE
|PARTITIONED|
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/primary-key-index/insert-primary-key-index-with-auto-gen-pk.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/primary-key-index/insert-primary-key-index-with-auto-gen-pk.plan
index 9a296a5e1c..5f89a6dca1 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/primary-key-index/insert-primary-key-index-with-auto-gen-pk.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/primary-key-index/insert-primary-key-index-with-auto-gen-pk.plan
@@ -4,7 +4,7 @@
-- INSERT_DELETE |PARTITIONED|
-- HASH_PARTITION_EXCHANGE [$$3] |PARTITIONED|
-- ASSIGN |UNPARTITIONED|
- -- STREAM_PROJECT |UNPARTITIONED|
- -- ASSIGN |UNPARTITIONED|
+ -- ASSIGN |UNPARTITIONED|
+ -- STREAM_PROJECT |UNPARTITIONED|
-- ASSIGN |UNPARTITIONED|
-- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/index-through-object/index-through-object.9.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/index-through-object/index-through-object.9.plan
index 75a50b4f76..a7f92e3692 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/index-through-object/index-through-object.9.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results_cbo/index-through-object/index-through-object.9.plan
@@ -2,40 +2,32 @@
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
-- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- NESTED_LOOP |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- HYBRID_HASH_JOIN [$$88][$$89] |PARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$88] |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- REPLICATE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN (Test.Users)
|PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE
|PARTITIONED|
- -- EMPTY_TUPLE_SOURCE
|PARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$89] |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- HYBRID_HASH_JOIN [$$88][$$89] |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$88] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
-- ASSIGN |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- REPLICATE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN (Test.Users)
|PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
- -- BROADCAST_EXCHANGE |PARTITIONED|
- -- STREAM_SELECT |UNPARTITIONED|
- -- ASSIGN |UNPARTITIONED|
- -- UNNEST |UNPARTITIONED|
- -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- REPLICATE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN (Test.Users)
|PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$89] |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- REPLICATE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN (Test.Users) |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.1.ddl.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.1.ddl.sqlpp
new file mode 100644
index 0000000000..b3ab9eb570
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.1.ddl.sqlpp
@@ -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.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+
+use test;
+
+create type testtype01 as
+ closed {
+ id : string,
+ name : string?
+};
+
+create dataset testds01(testtype01) primary key id;
+
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.2.update.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.2.update.sqlpp
new file mode 100644
index 0000000000..8f7d83e11a
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.2.update.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+use test;
+
+insert into testds01([{"id":"1", "name":"John1"}]);
+
+insert into testds01 {"id":"2", "name":"John2"};
+
+insert into testds01([{"id":"3", "name":"John3"}, {"id":"4", "name":"John4"}]);
+
+insert into testds01([{"id":"5", "name":"John5"}, {"id":"6"}]);
+
+insert into testds01([{"id":"7"}, {"id":"8", "name":"John8"}]);
+
+insert into testds01([{"id":"9"}]);
+
+insert into testds01 select element {"id":"10", "name":"John10"};
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.3.query.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.3.query.sqlpp
new file mode 100644
index 0000000000..be5fb5d510
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dml/insert-closed/insert-closed.3.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+use test;
+
+select * from testds01 order by id;
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_remove/array_remove.5.plan
b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_remove/array_remove.5.plan
index 0100d55d11..5b6ddc164a 100644
---
a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_remove/array_remove.5.plan
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_remove/array_remove.5.plan
@@ -2,7 +2,7 @@ distribute result [$$d] [cardinality: 0.0, op-cost: 0.0,
total-cost: 0.0]
-- DISTRIBUTE_RESULT |UNPARTITIONED|
exchange [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-- ONE_TO_ONE_EXCHANGE |UNPARTITIONED|
- unnest $$d <- scan-collection(ordered-list-constructor({"id": 1, "t1":
array-remove(ordered-list-constructor(1, 2, 3, ordered-list-constructor(9, 8),
ordered-list-constructor("str1", "str2"), ordered-list-constructor(90, 100)),
array: [ 9, 8 ], array: [ 90, 100 ])}, {"id": 2, "t2": cast(array: [ array: [
5, 1, 2 ], array: [ 90, 100 ] ])}, {"id": 3, "t3":
cast(array-remove(ordered-list-constructor({"id": 1, "age": 34}, {"id": 2,
"age": 29}, {"id": 3, "age": 90}), {"id": 4, "age": 90}, [...]
+ unnest $$d <- scan-collection(ordered-list-constructor({"id": 1, "t1":
array-remove(ordered-list-constructor(1, 2, 3, ordered-list-constructor(9, 8),
ordered-list-constructor("str1", "str2"), ordered-list-constructor(90, 100)),
array: [ 9, 8 ], array: [ 90, 100 ])}, {"id": 2, "t2": cast(array: [ array: [
5, 1, 2 ], array: [ 90, 100 ] ])}, {"id": 3, "t3": cast(array: [ { "id": 1,
"age": 34 }, { "id": 3, "age": 90 } ])})) [cardinality: 0.0, op-cost: 0.0,
total-cost: 0.0]
-- UNNEST |UNPARTITIONED|
empty-tuple-source [cardinality: 0.0, op-cost: 0.0, total-cost: 0.0]
-- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/results/dml/insert-closed/insert-closed.1.adm
b/asterixdb/asterix-app/src/test/resources/runtimets/results/dml/insert-closed/insert-closed.1.adm
new file mode 100644
index 0000000000..41668759ac
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/results/dml/insert-closed/insert-closed.1.adm
@@ -0,0 +1,10 @@
+{ "testds01": { "id": "1", "name": "John1" } }
+{ "testds01": { "id": "10", "name": "John10" } }
+{ "testds01": { "id": "2", "name": "John2" } }
+{ "testds01": { "id": "3", "name": "John3" } }
+{ "testds01": { "id": "4", "name": "John4" } }
+{ "testds01": { "id": "5", "name": "John5" } }
+{ "testds01": { "id": "6" } }
+{ "testds01": { "id": "7" } }
+{ "testds01": { "id": "8", "name": "John8" } }
+{ "testds01": { "id": "9" } }
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 6d83fb5d84..1800d47e1b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -4569,6 +4569,11 @@
<output-dir compare="Text">insert</output-dir>
</compilation-unit>
</test-case>
+ <test-case FilePath="dml">
+ <compilation-unit name="insert-closed">
+ <output-dir compare="Text">insert-closed</output-dir>
+ </compilation-unit>
+ </test-case>
<test-case FilePath="dml">
<compilation-unit name="insert-duplicated-keys">
<output-dir compare="Text">insert-duplicated-keys</output-dir>