abdullah alamoudi has uploaded a new change for review.
https://asterix-gerrit.ics.uci.edu/1146
Change subject: ASTERIXDB-1451: Fix type propagation to enforced indexes
......................................................................
ASTERIXDB-1451: Fix type propagation to enforced indexes
This change includes the following:
- Introduce cast function in case of delete operation
after the primary index to ensure types are passed
correctly to enforced indexes.
- Introduce cast function in case of upsert operation
before old secondary keys extraction to ensure types
are passed correctly to enforced indexes.
- Replace all record casts with open field casts.
- Sonar-Qube fixes.
Change-Id: I6a80105798ea1c86a6a0eb69a79b9573b54931b7
---
M
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
M
asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
M
asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-3.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/insert-and-scan-dataset-with-index.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-insert-secondary-index.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
M
asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.1.ddl.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.2.update.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.3.ddl.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.4.update.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.5.query.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.1.ddl.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.2.update.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.3.ddl.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.4.update.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.5.query.aql
A
asterixdb/asterix-app/src/test/resources/runtimets/results/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.5.adm
A
asterixdb/asterix-app/src/test/resources/runtimets/results/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.5.adm
M asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml
M
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Index.java
M
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java
M
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/CastTypeComputer.java
M
hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java
30 files changed, 889 insertions(+), 574 deletions(-)
git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb
refs/changes/46/1146/1
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
index c64258f..fbbc2f1 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
@@ -20,10 +20,9 @@
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
-import java.util.LinkedHashMap;
+import java.util.HashMap;
import java.util.List;
-import java.util.Stack;
+import java.util.Map;
import org.apache.asterix.common.config.DatasetConfig.DatasetType;
import org.apache.asterix.common.config.DatasetConfig.IndexType;
@@ -32,25 +31,22 @@
import org.apache.asterix.metadata.declared.AqlDataSource;
import org.apache.asterix.metadata.declared.AqlIndex;
import org.apache.asterix.metadata.declared.AqlMetadataProvider;
-import org.apache.asterix.metadata.declared.DatasetDataSource;
import org.apache.asterix.metadata.entities.Dataset;
import org.apache.asterix.metadata.entities.Index;
import org.apache.asterix.metadata.entities.InternalDatasetDetails;
import org.apache.asterix.om.base.AInt32;
import org.apache.asterix.om.base.AOrderedList;
import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.base.IAObject;
import org.apache.asterix.om.constants.AsterixConstantValue;
import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
import org.apache.asterix.om.typecomputer.base.TypeCastUtils;
import org.apache.asterix.om.types.AOrderedListType;
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.AUnionType;
import org.apache.asterix.om.types.BuiltinType;
import org.apache.asterix.om.types.IAType;
-import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
import org.apache.asterix.om.util.NonTaggedFormatUtil;
-import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -74,9 +70,16 @@
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteUpsertOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.InsertDeleteUpsertOperator.Kind;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
+import
org.apache.hyracks.algebricks.core.algebra.operators.logical.SinkOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.TokenizeOperator;
import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+/**
+ * This rule matches the pattern:
+ * assign --> insert-delete-upsert --> sink
+ * and produces
+ * assign --> insert-delete-upsert --> *(secondary indexes
index-insert-delete-upsert) --> sink
+ */
public class IntroduceSecondaryIndexInsertDeleteRule implements
IAlgebraicRewriteRule {
@Override
@@ -92,36 +95,22 @@
if (op0.getOperatorTag() != LogicalOperatorTag.SINK) {
return false;
}
- AbstractLogicalOperator op1 = (AbstractLogicalOperator)
op0.getInputs().get(0).getValue();
+ SinkOperator sinkOp = (SinkOperator) op0;
+ AbstractLogicalOperator op1 = (AbstractLogicalOperator)
sinkOp.getInputs().get(0).getValue();
if (op1.getOperatorTag() != LogicalOperatorTag.INSERT_DELETE_UPSERT) {
return false;
}
FunctionIdentifier fid = null;
/** find the record variable */
- InsertDeleteUpsertOperator insertOp = (InsertDeleteUpsertOperator) op1;
- boolean isBulkload = insertOp.isBulkload();
- ILogicalExpression recordExpr =
insertOp.getPayloadExpression().getValue();
- List<Mutable<ILogicalExpression>> metaExprs =
insertOp.getAdditionalNonFilteringExpressions();
- LogicalVariable recordVar = null;
- LogicalVariable metaVar = null;
- List<LogicalVariable> usedRecordVars = new ArrayList<>();
- /** assume the payload is always a single variable expression */
- recordExpr.getUsedVariables(usedRecordVars);
- if (usedRecordVars.size() == 1) {
- recordVar = usedRecordVars.get(0);
- }
- if (metaExprs != null) {
- List<LogicalVariable> metaVars = new ArrayList<>();
- for (Mutable<ILogicalExpression> expr : metaExprs) {
- expr.getValue().getUsedVariables(metaVars);
- }
- if (metaVars.size() > 1) {
- throw new AlgebricksException(
- "Number of meta fields can't be more than 1. Number of
meta fields found = " + metaVars.size());
- }
- metaVar = metaVars.get(0);
- }
+ InsertDeleteUpsertOperator primaryIndexModificationOp =
(InsertDeleteUpsertOperator) op1;
+ boolean isBulkload = primaryIndexModificationOp.isBulkload();
+ ILogicalExpression newRecordExpr =
primaryIndexModificationOp.getPayloadExpression().getValue();
+ List<Mutable<ILogicalExpression>> newMetaExprs =
+
primaryIndexModificationOp.getAdditionalNonFilteringExpressions();
+ LogicalVariable newRecordVar;
+ LogicalVariable newMetaVar = null;
+ List<LogicalVariable> usedNewRecordVars = new ArrayList<>();
/**
* op2 is the assign operator which extracts primary keys from the
input
@@ -129,14 +118,18 @@
*/
AbstractLogicalOperator op2 = (AbstractLogicalOperator)
op1.getInputs().get(0).getValue();
- if (recordVar == null) {
+ /** assume the payload is always a single variable expression */
+ newRecordExpr.getUsedVariables(usedNewRecordVars);
+ if (usedNewRecordVars.size() == 1) {
+ newRecordVar = usedNewRecordVars.get(0);
+ } else {
/**
* For the case primary key-assignment expressions are constant
* expressions, find assign op that creates record to be
* inserted/deleted.
*/
while (fid != AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR) {
- if (op2.getInputs().size() == 0) {
+ if (op2.getInputs().isEmpty()) {
return false;
}
op2 = (AbstractLogicalOperator)
op2.getInputs().get(0).getValue();
@@ -146,13 +139,25 @@
AssignOperator assignOp = (AssignOperator) op2;
ILogicalExpression assignExpr =
assignOp.getExpressions().get(0).getValue();
if (assignExpr.getExpressionTag() ==
LogicalExpressionTag.FUNCTION_CALL) {
- ScalarFunctionCallExpression funcExpr =
- (ScalarFunctionCallExpression)
assignOp.getExpressions().get(0).getValue();
+ ScalarFunctionCallExpression funcExpr =
(ScalarFunctionCallExpression) assignOp.getExpressions()
+ .get(0).getValue();
fid = funcExpr.getFunctionIdentifier();
}
}
AssignOperator assignOp2 = (AssignOperator) op2;
- recordVar = assignOp2.getVariables().get(0);
+ newRecordVar = assignOp2.getVariables().get(0);
+ }
+
+ if (newMetaExprs != null) {
+ List<LogicalVariable> metaVars = new ArrayList<>();
+ for (Mutable<ILogicalExpression> expr : newMetaExprs) {
+ expr.getValue().getUsedVariables(metaVars);
+ }
+ if (metaVars.size() > 1) {
+ throw new AlgebricksException(
+ "Number of meta fields can't be more than 1. Number of
meta fields found = " + metaVars.size());
+ }
+ newMetaVar = metaVars.get(0);
}
/*
@@ -160,10 +165,10 @@
* Note: We have two operators:
* 1. An InsertDeleteOperator (primary)
* 2. An IndexInsertDeleteOperator (secondary)
- * The current insertOp is of the first type
+ * The current primaryIndexModificationOp is of the first type
*/
- AqlDataSource datasetSource = (AqlDataSource) insertOp.getDataSource();
+ AqlDataSource datasetSource = (AqlDataSource)
primaryIndexModificationOp.getDataSource();
AqlMetadataProvider mp = (AqlMetadataProvider)
context.getMetadataProvider();
String dataverseName = datasetSource.getId().getDataverseName();
String datasetName = datasetSource.getId().getDatasourceName();
@@ -175,7 +180,7 @@
return false;
}
- // Create operators for secondary index insert/delete.
+ // Create operators for secondary index insert / delete.
String itemTypeName = dataset.getItemTypeName();
IAType itemType = mp.findType(dataset.getItemTypeDataverseName(),
itemTypeName);
if (itemType.getTypeTag() != ATypeTag.RECORD) {
@@ -187,9 +192,6 @@
if (dataset.hasMetaPart()) {
metaType = (ARecordType)
mp.findType(dataset.getMetaItemTypeDataverseName(),
dataset.getMetaItemTypeName());
}
- // recType might be replaced with enforced record type and we want to
keep a reference to the original record
- // type
- ARecordType originalRecType = recType;
List<Index> indexes = mp.getDatasetIndexes(dataset.getDataverseName(),
dataset.getDatasetName());
// Set the top operator pointer to the primary
IndexInsertDeleteOperator
ILogicalOperator currentTop = op1;
@@ -197,39 +199,28 @@
// Put an n-gram or a keyword index in the later stage of index-update,
// since TokenizeOperator needs to be involved.
- Collections.sort(indexes, new Comparator<Index>() {
- @Override
- public int compare(Index o1, Index o2) {
- return o1.getIndexType().ordinal() -
o2.getIndexType().ordinal();
- }
-
- });
-
- // Check whether multiple indexes exist
- int secondaryIndexTotalCnt = 0;
- for (Index index : indexes) {
- if (index.isSecondaryIndex()) {
- secondaryIndexTotalCnt++;
- }
- }
+ Collections.sort(indexes, (o1, o2) -> o1.getIndexType().ordinal() -
o2.getIndexType().ordinal());
// At this point, we have the data type info, and the indexes info as
well
+ int secondaryIndexTotalCnt = indexes.size() - 1;
if (secondaryIndexTotalCnt > 0) {
- op0.getInputs().clear();
+ sinkOp.getInputs().clear();
+ } else {
+ return false;
}
// Initialize inputs to the SINK operator Op0 (The SINK) is now
without input
-
// Prepare filtering field information (This is the filter created
using the "filter with" key word in the
// create dataset ddl)
List<String> filteringFields = ((InternalDatasetDetails)
dataset.getDatasetDetails()).getFilterField();
- List<LogicalVariable> filteringVars = null;
+ List<LogicalVariable> filteringVars;
List<Mutable<ILogicalExpression>> filteringExpressions = null;
if (filteringFields != null) {
// The filter field var already exists. we can simply get it from
the insert op
- filteringVars = new ArrayList<LogicalVariable>();
- filteringExpressions = new
ArrayList<Mutable<ILogicalExpression>>();
- for (Mutable<ILogicalExpression> filteringExpression :
insertOp.getAdditionalFilteringExpressions()) {
+ filteringVars = new ArrayList<>();
+ filteringExpressions = new ArrayList<>();
+ for (Mutable<ILogicalExpression> filteringExpression :
primaryIndexModificationOp
+ .getAdditionalFilteringExpressions()) {
filteringExpression.getValue().getUsedVariables(filteringVars);
for (LogicalVariable var : filteringVars) {
filteringExpressions
@@ -237,51 +228,10 @@
}
}
}
- LogicalVariable enforcedRecordVar = recordVar;
-
- /*
- * if the index is enforcing field types (For open indexes), We add a
cast
- * operator to ensure type safety
- */
- if (insertOp.getOperation() == Kind.INSERT || insertOp.getOperation()
== Kind.UPSERT) {
- try {
- DatasetDataSource ds = (DatasetDataSource)
(insertOp.getDataSource());
- ARecordType insertRecType = (ARecordType) ds.getItemType();
- // create the expected record type = the original + the
optional open field
- ARecordType enforcedType = createEnforcedType(insertRecType,
indexes);
- if (!enforcedType.equals(insertRecType)) {
- // A new variable which represents the casted record
- LogicalVariable castedRecVar = context.newVar();
- context.addNotToBeInlinedVar(castedRecVar);
- //introduce casting to enforced type
- AbstractFunctionCallExpression castFunc = new
ScalarFunctionCallExpression(
-
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CAST_TYPE));
- // The first argument is the record
- castFunc.getArguments()
- .add(new
MutableObject<ILogicalExpression>(insertOp.getPayloadExpression().getValue()));
- TypeCastUtils.setRequiredAndInputTypes(castFunc,
enforcedType, insertRecType);
- // AssignOperator puts in the cast var the casted record
- AssignOperator castedRecordAssignOperator =
- new AssignOperator(castedRecVar, new
MutableObject<ILogicalExpression>(castFunc));
- // Connect the current top of the plan to the cast operator
-
castedRecordAssignOperator.getInputs().addAll(currentTop.getInputs());
- currentTop.getInputs().clear();
- currentTop.getInputs().add(new
MutableObject<>(castedRecordAssignOperator));
- enforcedRecordVar = castedRecVar;
- recType = enforcedType;
-
context.computeAndSetTypeEnvironmentForOperator(castedRecordAssignOperator);
-
context.computeAndSetTypeEnvironmentForOperator(currentTop);
- // We don't need to cast the old rec, we just need an
assignment function that extracts the SK
- // and an expression which reference the new variables.
- }
- } catch (AsterixException e) {
- throw new AlgebricksException(e);
- }
- }
// Replicate Operator is applied only when doing the bulk-load.
- AbstractLogicalOperator replicateOp = null;
- if (secondaryIndexTotalCnt > 1 && insertOp.isBulkload()) {
+ ReplicateOperator replicateOp = null;
+ if (secondaryIndexTotalCnt > 1 &&
primaryIndexModificationOp.isBulkload()) {
// Split the logical plan into "each secondary index update branch"
// to replicate each <PK,RECORD> pair.
replicateOp = new ReplicateOperator(secondaryIndexTotalCnt);
@@ -289,6 +239,40 @@
replicateOp.setExecutionMode(ExecutionMode.PARTITIONED);
context.computeAndSetTypeEnvironmentForOperator(replicateOp);
currentTop = replicateOp;
+ }
+
+ Map<IndexFieldId, LogicalVariable> fieldVarsForOldRecord = new
HashMap<>();
+ Map<IndexFieldId, LogicalVariable> fieldVarsForNewRecord = new
HashMap<>();
+ /*
+ * if the index is enforcing field types (For open indexes), We add a
cast
+ * operator to ensure type safety
+ */
+ try {
+ if (primaryIndexModificationOp.getOperation() == Kind.INSERT
+ || primaryIndexModificationOp.getOperation() == Kind.UPSERT
+ /* Actually, delete should not be here but it is now until
issue
+ * https://issues.apache.org/jira/browse/ASTERIXDB-1507
+ * is solved
+ */
+ || primaryIndexModificationOp.getOperation() ==
Kind.DELETE) {
+ prepareVarsAndExpressions(context, dataset, indexes,
fieldVarsForNewRecord, recType,
+ metaType, newRecordVar, newMetaVar,
primaryIndexModificationOp, false);
+ if (replicateOp != null) {
+
context.computeAndSetTypeEnvironmentForOperator(replicateOp);
+ }
+ }
+ if (primaryIndexModificationOp.getOperation() == Kind.UPSERT
+ /* Actually, delete should be here but it is not until issue
+ * https://issues.apache.org/jira/browse/ASTERIXDB-1507
+ * is solved
+ */) {
+ List<LogicalVariable> prevMetaVars =
primaryIndexModificationOp.getPrevAdditionalNonFilteringVars();
+ LogicalVariable prevMetaVar = prevMetaVars == null ? null :
prevMetaVars.get(0);
+ currentTop = prepareVarsAndExpressions(context, dataset,
indexes, fieldVarsForOldRecord, recType,
+ metaType,
primaryIndexModificationOp.getPrevRecordVar(), prevMetaVar, currentTop, true);
+ }
+ } catch (AsterixException e) {
+ throw new AlgebricksException(e);
}
// Iterate each secondary index and applying Index Update operations.
@@ -300,88 +284,36 @@
hasSecondaryIndex = true;
// Get the secondary fields names and types
List<List<String>> secondaryKeyFields = index.getKeyFieldNames();
- List<IAType> secondaryKeyTypes = index.getKeyFieldTypes();
- List<LogicalVariable> secondaryKeyVars = new
ArrayList<LogicalVariable>();
- List<Integer> indicators = index.getKeyFieldSourceIndicators();
- List<Mutable<ILogicalExpression>> expressions = new
ArrayList<Mutable<ILogicalExpression>>();
- List<Mutable<ILogicalExpression>> secondaryExpressions = new
ArrayList<Mutable<ILogicalExpression>>();
+ List<LogicalVariable> secondaryKeyVars = new ArrayList<>();
+ List<Mutable<ILogicalExpression>> secondaryExpressions = new
ArrayList<>();
+ List<Mutable<ILogicalExpression>> prevSecondaryExpressions = new
ArrayList<>();
+ ILogicalOperator replicateOutput;
for (int i = 0; i < secondaryKeyFields.size(); i++) {
- List<String> secondaryKey = secondaryKeyFields.get(i);
- ARecordType sourceType = recType;
- LogicalVariable sourceVar = enforcedRecordVar;
- if (dataset.hasMetaPart()) {
- sourceType = indicators.get(i).intValue() == 0 ? recType :
metaType;
- sourceVar = indicators.get(i).intValue() == 0 ?
enforcedRecordVar : metaVar;
+ IndexFieldId indexFieldId =
+ new
IndexFieldId(index.getKeyFieldSourceIndicators().get(i),
secondaryKeyFields.get(i));
+ LogicalVariable skVar =
fieldVarsForNewRecord.get(indexFieldId);
+ secondaryKeyVars.add(skVar);
+ secondaryExpressions.add(new MutableObject<ILogicalExpression>(
+ new VariableReferenceExpression(skVar)));
+ if (primaryIndexModificationOp.getOperation() == Kind.UPSERT) {
+ prevSecondaryExpressions.add(new
MutableObject<ILogicalExpression>(
+ new
VariableReferenceExpression(fieldVarsForOldRecord.get(indexFieldId))));
}
- prepareVarAndExpression(secondaryKey,
sourceType.getFieldNames(), sourceVar, expressions,
- secondaryKeyVars, context);
- }
- // Used with upsert operation
- // in case of upsert, we need vars and expressions for the old SK
as well.
- List<LogicalVariable> prevSecondaryKeyVars = null;
- List<Mutable<ILogicalExpression>> prevExpressions = null;
- List<Mutable<ILogicalExpression>> prevSecondaryExpressions = null;
- AssignOperator prevSecondaryKeyAssign = null;
- if (insertOp.getOperation() == Kind.UPSERT) {
- prevSecondaryKeyVars = new ArrayList<LogicalVariable>();
- prevExpressions = new ArrayList<Mutable<ILogicalExpression>>();
- prevSecondaryExpressions = new
ArrayList<Mutable<ILogicalExpression>>();
- for (int i = 0; i < secondaryKeyFields.size(); i++) {
- List<String> secondaryKey = secondaryKeyFields.get(i);
- prepareVarAndExpression(secondaryKey,
- (indicators.get(i).intValue() == 0) ?
originalRecType.getFieldNames()
- : metaType.getFieldNames(),
- (indicators.get(i).intValue() == 0) ?
insertOp.getPrevRecordVar()
- :
insertOp.getPrevAdditionalNonFilteringVars().get(0),
- prevExpressions, prevSecondaryKeyVars, context);
- }
- prevSecondaryKeyAssign = new
AssignOperator(prevSecondaryKeyVars, prevExpressions);
- }
- AssignOperator assign = new AssignOperator(secondaryKeyVars,
expressions);
- AssignOperator topAssign = assign;
- if (insertOp.getOperation() == Kind.UPSERT) {
- prevSecondaryKeyAssign.getInputs().add(new
MutableObject<ILogicalOperator>(topAssign));
- topAssign = prevSecondaryKeyAssign;
- }
- // Only apply replicate operator when doing bulk-load
- if (secondaryIndexTotalCnt > 1 && insertOp.isBulkload()) {
- assign.getInputs().add(new
MutableObject<ILogicalOperator>(replicateOp));
- } else {
- assign.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
}
- context.computeAndSetTypeEnvironmentForOperator(assign);
- if (insertOp.getOperation() == Kind.UPSERT) {
-
context.computeAndSetTypeEnvironmentForOperator(prevSecondaryKeyAssign);
- }
- currentTop = topAssign;
-
- // in case of an Upsert operation, the currentTop is an assign
which has the old secondary keys + the new secondary keys
- if (index.getIndexType() == IndexType.BTREE ||
index.getIndexType() == IndexType.SINGLE_PARTITION_WORD_INVIX
- || index.getIndexType() ==
IndexType.SINGLE_PARTITION_NGRAM_INVIX
- || index.getIndexType() ==
IndexType.LENGTH_PARTITIONED_WORD_INVIX
- || index.getIndexType() ==
IndexType.LENGTH_PARTITIONED_NGRAM_INVIX) {
+ IndexInsertDeleteUpsertOperator indexUpdate;
+ if (index.getIndexType() != IndexType.RTREE) {
// Create an expression per key
- for (LogicalVariable secondaryKeyVar : secondaryKeyVars) {
- secondaryExpressions.add(
- new MutableObject<ILogicalExpression>(new
VariableReferenceExpression(secondaryKeyVar)));
- }
- Mutable<ILogicalExpression> filterExpression = null;
- if (insertOp.getOperation() == Kind.UPSERT) {
- for (LogicalVariable oldSecondaryKeyVar :
prevSecondaryKeyVars) {
- prevSecondaryExpressions.add(new
MutableObject<ILogicalExpression>(
- new
VariableReferenceExpression(oldSecondaryKeyVar)));
- }
- } else {
- filterExpression = createFilterExpression(secondaryKeyVars,
- context.getOutputTypeEnvironment(currentTop),
false);
- }
+ Mutable<ILogicalExpression> filterExpression =
+ (primaryIndexModificationOp.getOperation() ==
Kind.UPSERT) ? null
+ : createFilterExpression(secondaryKeyVars,
+
context.getOutputTypeEnvironment(currentTop), index.isEnforcingKeyFileds());
AqlIndex dataSourceIndex = new AqlIndex(index, dataverseName,
datasetName, mp);
// Introduce the TokenizeOperator only when doing bulk-load,
// and index type is keyword or n-gram.
- if (index.getIndexType() != IndexType.BTREE &&
insertOp.isBulkload()) {
+ if (index.getIndexType() != IndexType.BTREE &&
primaryIndexModificationOp.isBulkload()) {
// Note: Bulk load case, we don't need to take care of it
for upsert operation
// Check whether the index is length-partitioned or not.
// If partitioned, [input variables to TokenizeOperator,
@@ -391,27 +323,25 @@
// and fed into the IndexInsertDeleteOperator.
// Input variables are passed since TokenizeOperator is
not an
// filtering operator.
- boolean isPartitioned = false;
- if (index.getIndexType() ==
IndexType.LENGTH_PARTITIONED_WORD_INVIX
- || index.getIndexType() ==
IndexType.LENGTH_PARTITIONED_NGRAM_INVIX) {
- isPartitioned = true;
- }
+ boolean isPartitioned = index.getIndexType() ==
IndexType.LENGTH_PARTITIONED_WORD_INVIX
+ || index.getIndexType() ==
IndexType.LENGTH_PARTITIONED_NGRAM_INVIX;
// Create a new logical variable - token
- List<LogicalVariable> tokenizeKeyVars = new
ArrayList<LogicalVariable>();
- List<Mutable<ILogicalExpression>> tokenizeKeyExprs = new
ArrayList<Mutable<ILogicalExpression>>();
+ List<LogicalVariable> tokenizeKeyVars = new ArrayList<>();
+ List<Mutable<ILogicalExpression>> tokenizeKeyExprs = new
ArrayList<>();
LogicalVariable tokenVar = context.newVar();
tokenizeKeyVars.add(tokenVar);
tokenizeKeyExprs
.add(new MutableObject<ILogicalExpression>(new
VariableReferenceExpression(tokenVar)));
// Check the field type of the secondary key.
- IAType secondaryKeyType = null;
- Pair<IAType, Boolean> keyPairType =
-
Index.getNonNullableKeyFieldType(secondaryKeyFields.get(0), recType);
+ IAType secondaryKeyType;
+ Pair<IAType, Boolean> keyPairType =
Index.getNonNullableOpenFieldType(
+ index.getKeyFieldTypes().get(0),
secondaryKeyFields.get(0),
+ recType);
secondaryKeyType = keyPairType.first;
- List<Object> varTypes = new ArrayList<Object>();
+ List<Object> varTypes = new ArrayList<>();
varTypes.add(NonTaggedFormatUtil.getTokenType(secondaryKeyType));
// If the index is a length-partitioned, then create
@@ -428,64 +358,52 @@
// TokenizeOperator to tokenize [SK, PK] pairs
TokenizeOperator tokenUpdate = new
TokenizeOperator(dataSourceIndex,
- insertOp.getPrimaryKeyExpressions(),
secondaryExpressions, tokenizeKeyVars,
- filterExpression, insertOp.getOperation(),
insertOp.isBulkload(), isPartitioned, varTypes);
- tokenUpdate.getInputs().add(new
MutableObject<ILogicalOperator>(assign));
+
primaryIndexModificationOp.getPrimaryKeyExpressions(), secondaryExpressions,
+ tokenizeKeyVars,
+ filterExpression,
primaryIndexModificationOp.getOperation(),
+ primaryIndexModificationOp.isBulkload(),
isPartitioned, varTypes);
+ tokenUpdate.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
context.computeAndSetTypeEnvironmentForOperator(tokenUpdate);
-
- IndexInsertDeleteUpsertOperator indexUpdate =
- new
IndexInsertDeleteUpsertOperator(dataSourceIndex,
insertOp.getPrimaryKeyExpressions(),
- tokenizeKeyExprs, filterExpression,
insertOp.getOperation(), insertOp.isBulkload(),
-
insertOp.getAdditionalNonFilteringExpressions() == null ? 0
- :
insertOp.getAdditionalNonFilteringExpressions().size());
+ replicateOutput = tokenUpdate;
+ indexUpdate = new
IndexInsertDeleteUpsertOperator(dataSourceIndex,
+
primaryIndexModificationOp.getPrimaryKeyExpressions(), tokenizeKeyExprs,
filterExpression,
+ primaryIndexModificationOp.getOperation(),
primaryIndexModificationOp.isBulkload(),
+
primaryIndexModificationOp.getAdditionalNonFilteringExpressions() == null ? 0
+ :
primaryIndexModificationOp.getAdditionalNonFilteringExpressions().size());
indexUpdate.setAdditionalFilteringExpressions(filteringExpressions);
indexUpdate.getInputs().add(new
MutableObject<ILogicalOperator>(tokenUpdate));
-
-
context.computeAndSetTypeEnvironmentForOperator(indexUpdate);
-
- currentTop = indexUpdate;
- op0.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
-
} else {
// When TokenizeOperator is not needed
- IndexInsertDeleteUpsertOperator indexUpdate =
- new
IndexInsertDeleteUpsertOperator(dataSourceIndex,
insertOp.getPrimaryKeyExpressions(),
- secondaryExpressions, filterExpression,
insertOp.getOperation(),
- insertOp.isBulkload(),
insertOp.getAdditionalNonFilteringExpressions() == null ? 0
- :
insertOp.getAdditionalNonFilteringExpressions().size());
-
+ indexUpdate = new
IndexInsertDeleteUpsertOperator(dataSourceIndex,
+
primaryIndexModificationOp.getPrimaryKeyExpressions(), secondaryExpressions,
+ filterExpression,
+ primaryIndexModificationOp.getOperation(),
primaryIndexModificationOp.isBulkload(),
+
primaryIndexModificationOp.getAdditionalNonFilteringExpressions() == null ? 0
+ :
primaryIndexModificationOp.getAdditionalNonFilteringExpressions().size());
indexUpdate.setAdditionalFilteringExpressions(filteringExpressions);
+ replicateOutput = indexUpdate;
// We add the necessary expressions for upsert
- if (insertOp.getOperation() == Kind.UPSERT) {
+ if (primaryIndexModificationOp.getOperation() ==
Kind.UPSERT) {
indexUpdate.setPrevSecondaryKeyExprs(prevSecondaryExpressions);
if (filteringFields != null) {
indexUpdate.setPrevAdditionalFilteringExpression(new
MutableObject<ILogicalExpression>(
- new
VariableReferenceExpression(insertOp.getPrevFilterVar())));
+ new
VariableReferenceExpression(primaryIndexModificationOp.getPrevFilterVar())));
}
}
indexUpdate.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
-
- currentTop = indexUpdate;
-
context.computeAndSetTypeEnvironmentForOperator(indexUpdate);
-
- if (insertOp.isBulkload()) {
- op0.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
- }
-
}
-
- } else if (index.getIndexType() == IndexType.RTREE) {
+ } else {
// Get type, dimensions and number of keys
- Pair<IAType, Boolean> keyPairType =
-
Index.getNonNullableOpenFieldType(secondaryKeyTypes.get(0),
secondaryKeyFields.get(0), recType);
+ Pair<IAType, Boolean> keyPairType =
Index.getNonNullableOpenFieldType(index.getKeyFieldTypes().get(0),
+ secondaryKeyFields.get(0), recType);
IAType spatialType = keyPairType.first;
- boolean isPointMBR =
- spatialType.getTypeTag() == ATypeTag.POINT ||
spatialType.getTypeTag() == ATypeTag.POINT3D;
+ boolean isPointMBR = spatialType.getTypeTag() == ATypeTag.POINT
+ || spatialType.getTypeTag() == ATypeTag.POINT3D;
int dimension =
NonTaggedFormatUtil.getNumDimensions(spatialType.getTypeTag());
int numKeys = (isPointMBR && isBulkload) ? dimension :
dimension * 2;
// Get variables and expressions
- List<LogicalVariable> keyVarList = new
ArrayList<LogicalVariable>();
- List<Mutable<ILogicalExpression>> keyExprList = new
ArrayList<Mutable<ILogicalExpression>>();
+ List<LogicalVariable> keyVarList = new ArrayList<>();
+ List<Mutable<ILogicalExpression>> keyExprList = new
ArrayList<>();
for (int i = 0; i < numKeys; i++) {
LogicalVariable keyVar = context.newVar();
keyVarList.add(keyVar);
@@ -499,6 +417,7 @@
new ConstantExpression(new
AsterixConstantValue(new AInt32(i)))));
keyExprList.add(new
MutableObject<ILogicalExpression>(createMBR));
}
+ secondaryExpressions.clear();
for (LogicalVariable secondaryKeyVar : keyVarList) {
secondaryExpressions.add(
new MutableObject<ILogicalExpression>(new
VariableReferenceExpression(secondaryKeyVar)));
@@ -514,11 +433,12 @@
AssignOperator assignCoordinates = new
AssignOperator(keyVarList, keyExprList);
assignCoordinates.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
context.computeAndSetTypeEnvironmentForOperator(assignCoordinates);
+ replicateOutput = assignCoordinates;
Mutable<ILogicalExpression> filterExpression = null;
AssignOperator originalAssignCoordinates = null;
// We do something similar for previous key if the operation
is an upsert
- if (insertOp.getOperation() == Kind.UPSERT) {
- List<LogicalVariable> originalKeyVarList = new
ArrayList<LogicalVariable>();
+ if (primaryIndexModificationOp.getOperation() == Kind.UPSERT) {
+ List<LogicalVariable> originalKeyVarList = new
ArrayList<>();
List<Mutable<ILogicalExpression>> originalKeyExprList =
new ArrayList<>();
// we don't do any filtering since nulls are expected here
and there
for (int i = 0; i < numKeys; i++) {
@@ -526,25 +446,17 @@
originalKeyVarList.add(keyVar);
AbstractFunctionCallExpression createMBR = new
ScalarFunctionCallExpression(
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CREATE_MBR));
- createMBR.getArguments().add(new
MutableObject<ILogicalExpression>(
- new
VariableReferenceExpression(prevSecondaryKeyVars.get(0))));
+
createMBR.getArguments().add(prevSecondaryExpressions.get(0));
createMBR.getArguments().add(new
MutableObject<ILogicalExpression>(
new ConstantExpression(new
AsterixConstantValue(new AInt32(dimension)))));
createMBR.getArguments().add(new
MutableObject<ILogicalExpression>(
new ConstantExpression(new
AsterixConstantValue(new AInt32(i)))));
originalKeyExprList.add(new
MutableObject<ILogicalExpression>(createMBR));
}
+ prevSecondaryExpressions.clear();
for (LogicalVariable secondaryKeyVar : originalKeyVarList)
{
prevSecondaryExpressions.add(new
MutableObject<ILogicalExpression>(
new
VariableReferenceExpression(secondaryKeyVar)));
- }
- if (isPointMBR && isBulkload) {
- //for PointMBR optimization: see
SecondaryRTreeOperationsHelper.buildLoadingJobSpec() and
- //createFieldPermutationForBulkLoadOp(int) for more
details.
- for (LogicalVariable secondaryKeyVar :
originalKeyVarList) {
- prevSecondaryExpressions.add(new
MutableObject<ILogicalExpression>(
- new
VariableReferenceExpression(secondaryKeyVar)));
- }
}
originalAssignCoordinates = new
AssignOperator(originalKeyVarList, originalKeyExprList);
originalAssignCoordinates.getInputs().add(new
MutableObject<ILogicalOperator>(assignCoordinates));
@@ -557,17 +469,17 @@
context.getOutputTypeEnvironment(assignCoordinates), forceFilter);
}
AqlIndex dataSourceIndex = new AqlIndex(index, dataverseName,
datasetName, mp);
- IndexInsertDeleteUpsertOperator indexUpdate =
- new IndexInsertDeleteUpsertOperator(dataSourceIndex,
insertOp.getPrimaryKeyExpressions(),
- secondaryExpressions, filterExpression,
insertOp.getOperation(), insertOp.isBulkload(),
-
insertOp.getAdditionalNonFilteringExpressions() == null ? 0
- :
insertOp.getAdditionalNonFilteringExpressions().size());
+ indexUpdate = new
IndexInsertDeleteUpsertOperator(dataSourceIndex,
+ primaryIndexModificationOp.getPrimaryKeyExpressions(),
secondaryExpressions, filterExpression,
+ primaryIndexModificationOp.getOperation(),
primaryIndexModificationOp.isBulkload(),
+
primaryIndexModificationOp.getAdditionalNonFilteringExpressions() == null ? 0
+ :
primaryIndexModificationOp.getAdditionalNonFilteringExpressions().size());
indexUpdate.setAdditionalFilteringExpressions(filteringExpressions);
- if (insertOp.getOperation() == Kind.UPSERT) {
+ if (primaryIndexModificationOp.getOperation() == Kind.UPSERT) {
// set old secondary key expressions
if (filteringFields != null) {
indexUpdate.setPrevAdditionalFilteringExpression(new
MutableObject<ILogicalExpression>(
- new
VariableReferenceExpression(insertOp.getPrevFilterVar())));
+ new
VariableReferenceExpression(primaryIndexModificationOp.getPrevFilterVar())));
}
// set filtering expressions
indexUpdate.setPrevSecondaryKeyExprs(prevSecondaryExpressions);
@@ -576,14 +488,16 @@
} else {
indexUpdate.getInputs().add(new
MutableObject<ILogicalOperator>(assignCoordinates));
}
+ }
+ context.computeAndSetTypeEnvironmentForOperator(indexUpdate);
+ if (!primaryIndexModificationOp.isBulkload() ||
secondaryIndexTotalCnt == 1) {
currentTop = indexUpdate;
- context.computeAndSetTypeEnvironmentForOperator(indexUpdate);
-
- if (insertOp.isBulkload()) {
- // For bulk load, we connect all fanned out insert
operator to a single SINK operator
- op0.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
- }
-
+ } else {
+ replicateOp.getOutputs().add(new
MutableObject<>(replicateOutput));
+ }
+ if (primaryIndexModificationOp.isBulkload()) {
+ // For bulk load, we connect all fanned out insert operator to
a single SINK operator
+ sinkOp.getInputs().add(new
MutableObject<ILogicalOperator>(indexUpdate));
}
}
@@ -591,183 +505,149 @@
return false;
}
- if (!insertOp.isBulkload()) {
+ if (!primaryIndexModificationOp.isBulkload()) {
// If this is an upsert, we need to
// Remove the current input to the SINK operator (It is actually
already removed above)
- op0.getInputs().clear();
+ sinkOp.getInputs().clear();
// Connect the last index update to the SINK
- op0.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
+ sinkOp.getInputs().add(new
MutableObject<ILogicalOperator>(currentTop));
}
return true;
}
- // Merges typed index fields with specified recordType, allowing indexed
fields to be optional.
- // I.e. the type { "personId":int32, "name": string, "address" : {
"street": string } } with typed indexes on age:int32, address.state:string
- // will be merged into type { "personId":int32, "name": string,
"age": int32? "address" : { "street": string, "state": string? } }
- // Used by open indexes to enforce the type of an indexed record
- public static ARecordType createEnforcedType(ARecordType initialType,
List<Index> indexes)
- throws AsterixException, AlgebricksException {
- ARecordType enforcedType = initialType;
+ private ILogicalOperator prepareVarsAndExpressions(IOptimizationContext
context, Dataset dataset,
+ List<Index> indexes, Map<IndexFieldId, LogicalVariable>
fieldVarsForNewRecord, ARecordType recType,
+ ARecordType metaType, LogicalVariable recordVar, LogicalVariable
metaVar, ILogicalOperator currentTop,
+ boolean afterOp) throws AlgebricksException {
+ List<LogicalVariable> vars = new ArrayList<>();
+ List<Mutable<ILogicalExpression>> exprs = new ArrayList<>();
for (Index index : indexes) {
- if (!index.isSecondaryIndex() || !index.isEnforcingKeyFileds()) {
+ if (index.isPrimaryIndex()) {
continue;
}
- if (index.hasMetaFields()) {
- throw new AlgebricksException("Indexing an open field is only
supported on the record part");
- }
+ List<IAType> skTypes = index.getKeyFieldTypes();
+ List<List<String>> skNames = index.getKeyFieldNames();
+ List<Integer> indicators = index.getKeyFieldSourceIndicators();
for (int i = 0; i < index.getKeyFieldNames().size(); i++) {
- Stack<Pair<ARecordType, String>> nestedTypeStack = new
Stack<Pair<ARecordType, String>>();
- List<String> splits = index.getKeyFieldNames().get(i);
- ARecordType nestedFieldType = enforcedType;
- boolean openRecords = false;
- String bridgeName = nestedFieldType.getTypeName();
- int j;
- // Build the stack for the enforced type
- for (j = 1; j < splits.size(); j++) {
- nestedTypeStack.push(new Pair<ARecordType,
String>(nestedFieldType, splits.get(j - 1)));
- bridgeName = nestedFieldType.getTypeName();
- nestedFieldType = (ARecordType)
enforcedType.getSubFieldType(splits.subList(0, j));
- if (nestedFieldType == null) {
- openRecords = true;
- break;
- }
+ IndexFieldId indexFieldId = new
IndexFieldId(indicators.get(i), skNames.get(i));
+ if (fieldVarsForNewRecord.containsKey(indexFieldId)) {
+ // already handled in a previous index
+ continue;
}
- if (openRecords == true) {
- // create the smallest record
- enforcedType = new ARecordType(splits.get(splits.size() -
2),
- new String[] { splits.get(splits.size() - 1) },
- new IAType[] {
AUnionType.createUnknownableType(index.getKeyFieldTypes().get(i)) }, true);
- // create the open part of the nested field
- for (int k = splits.size() - 3; k > (j - 2); k--) {
- enforcedType = new ARecordType(splits.get(k), new
String[] { splits.get(k + 1) },
- new IAType[] {
AUnionType.createUnknownableType(enforcedType) }, true);
- }
- // Bridge the gap
- Pair<ARecordType, String> gapPair = nestedTypeStack.pop();
- ARecordType parent = gapPair.first;
-
- IAType[] parentFieldTypes =
ArrayUtils.addAll(parent.getFieldTypes().clone(),
- new IAType[] {
AUnionType.createUnknownableType(enforcedType) });
- enforcedType = new ARecordType(bridgeName,
- ArrayUtils.addAll(parent.getFieldNames(),
enforcedType.getTypeName()), parentFieldTypes,
- true);
+ ARecordType sourceType = dataset.hasMetaPart()
+ ? indicators.get(i).intValue() ==
Index.RECORD_INDICATOR ? recType : metaType : recType;
+ LogicalVariable sourceVar = dataset.hasMetaPart()
+ ? indicators.get(i).intValue() ==
Index.RECORD_INDICATOR ? recordVar : metaVar
+ : recordVar;
+ LogicalVariable fieldVar = context.newVar();
+ // create record variable ref
+ Mutable<ILogicalExpression> varRef =
+ new MutableObject<>(new
VariableReferenceExpression(sourceVar));
+ IAType fieldType =
sourceType.getSubFieldType(indexFieldId.fieldName);
+ AbstractFunctionCallExpression theFieldAccessFunc;
+ if (fieldType == null) {
+ // Open field. must prevent inlining to maintain the cast
before the primaryOp and
+ // make handling of records with incorrect value type for
this field easier and cleaner
+ context.addNotToBeInlinedVar(fieldVar);
+ // create field access
+ AbstractFunctionCallExpression fieldAccessFunc =
+ getOpenOrNestedFieldAccessFunction(varRef,
indexFieldId.fieldName);
+ // create cast
+ theFieldAccessFunc = new ScalarFunctionCallExpression(
+
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CAST_TYPE));
+ // The first argument is the field
+ theFieldAccessFunc.getArguments()
+ .add(new
MutableObject<ILogicalExpression>(fieldAccessFunc));
+ TypeCastUtils.setRequiredAndInputTypes(theFieldAccessFunc,
skTypes.get(i),
+ BuiltinType.ANY);
} else {
- //Schema is closed all the way to the field
- //enforced fields are either null or strongly typed
- LinkedHashMap<String, IAType> recordNameTypesMap =
createRecordNameTypeMap(nestedFieldType);
- // if a an enforced field already exists and the type is
correct
- IAType enforcedFieldType =
recordNameTypesMap.get(splits.get(splits.size() - 1));
- if (enforcedFieldType != null &&
enforcedFieldType.getTypeTag() == ATypeTag.UNION
- && ((AUnionType)
enforcedFieldType).isUnknownableType()) {
- enforcedFieldType = ((AUnionType)
enforcedFieldType).getActualType();
- }
- if (enforcedFieldType != null &&
!ATypeHierarchy.canPromote(enforcedFieldType.getTypeTag(),
- index.getKeyFieldTypes().get(i).getTypeTag())) {
- throw new AlgebricksException("Cannot enforce field "
+ index.getKeyFieldNames().get(i)
- + " to have type " +
index.getKeyFieldTypes().get(i));
- }
- if (enforcedFieldType == null) {
- recordNameTypesMap.put(splits.get(splits.size() - 1),
-
AUnionType.createUnknownableType(index.getKeyFieldTypes().get(i)));
- }
- enforcedType = new
ARecordType(nestedFieldType.getTypeName(),
- recordNameTypesMap.keySet().toArray(new
String[recordNameTypesMap.size()]),
- recordNameTypesMap.values().toArray(new
IAType[recordNameTypesMap.size()]),
- nestedFieldType.isOpen());
+ // Get the desired field position
+ int pos = getFieldPosition(sourceType.getFieldNames(),
indexFieldId.fieldName);
+ // Field not found --> This is either an open field or a
nested field. it can't be accessed by index
+ theFieldAccessFunc =
+ (pos == -1) ?
getOpenOrNestedFieldAccessFunction(varRef, indexFieldId.fieldName)
+ : getClosedFieldAccessFunction(varRef,
pos);
}
-
- // Create the enforcedtype for the nested fields in the
schema, from the ground up
- if (nestedTypeStack.size() > 0) {
- while (!nestedTypeStack.isEmpty()) {
- Pair<ARecordType, String> nestedTypePair =
nestedTypeStack.pop();
- ARecordType nestedRecType = nestedTypePair.first;
- IAType[] nestedRecTypeFieldTypes =
nestedRecType.getFieldTypes().clone();
-
nestedRecTypeFieldTypes[nestedRecType.getFieldIndex(nestedTypePair.second)] =
enforcedType;
- enforcedType = new
ARecordType(nestedRecType.getTypeName() + "_enforced",
- nestedRecType.getFieldNames(),
nestedRecTypeFieldTypes, nestedRecType.isOpen());
- }
- }
+ vars.add(fieldVar);
+ exprs.add(new
MutableObject<ILogicalExpression>(theFieldAccessFunc));
+ fieldVarsForNewRecord.put(indexFieldId, fieldVar);
}
}
- return enforcedType;
+ // AssignOperator assigns secondary keys to their vars
+ AssignOperator castedFieldAssignOperator = new AssignOperator(vars,
exprs);
+ return introduceNewOp(context, currentTop, castedFieldAssignOperator,
afterOp);
}
- private static LinkedHashMap<String, IAType>
createRecordNameTypeMap(ARecordType nestedFieldType) {
- LinkedHashMap<String, IAType> recordNameTypesMap = new
LinkedHashMap<>();
- for (int j = 0; j < nestedFieldType.getFieldNames().length; j++) {
- recordNameTypesMap.put(nestedFieldType.getFieldNames()[j],
nestedFieldType.getFieldTypes()[j]);
+ private static ILogicalOperator introduceNewOp(IOptimizationContext
context, ILogicalOperator currentTopOp,
+ ILogicalOperator newOp, boolean afterOp) throws
AlgebricksException {
+ if (afterOp) {
+ newOp.getInputs().add(new MutableObject<>(currentTopOp));
+ context.computeAndSetTypeEnvironmentForOperator(newOp);
+ return newOp;
+ } else {
+ newOp.getInputs().addAll(currentTopOp.getInputs());
+ currentTopOp.getInputs().clear();
+ currentTopOp.getInputs().add(new MutableObject<>(newOp));
+ context.computeAndSetTypeEnvironmentForOperator(newOp);
+ context.computeAndSetTypeEnvironmentForOperator(currentTopOp);
+ return currentTopOp;
}
- return recordNameTypesMap;
}
- /***
- * This method takes a list of {fields}: a subset of {recordFields}, the
original record variable
- * and populate expressions with expressions which evaluate to those
fields (using field access functions) and
- * variables to represent them
- *
- * @param fields
- * desired fields
- * @param recordFields
- * all the record fields
- * @param recordVar
- * the record variable
- * @param expressions
- * @param vars
- * @param context
- * @throws AlgebricksException
- */
- @SuppressWarnings("unchecked")
- private void prepareVarAndExpression(List<String> fields, String[]
recordFields, LogicalVariable recordVar,
- List<Mutable<ILogicalExpression>> expressions,
List<LogicalVariable> vars, IOptimizationContext context)
- throws AlgebricksException {
- // Get a reference to the record variable
- Mutable<ILogicalExpression> varRef = new MutableObject<>(new
VariableReferenceExpression(recordVar));
- // Get the desired field position
- int pos = -1;
+ private static int getFieldPosition(String[] recordFields, List<String>
fields) {
if (fields.size() == 1) {
for (int j = 0; j < recordFields.length; j++) {
if (recordFields[j].equals(fields.get(0))) {
- pos = j;
- break;
+ return j;
}
}
}
- // Field not found --> This is either an open field or a nested field.
it can't be accessed by index
- AbstractFunctionCallExpression func;
- if (pos == -1) {
- if (fields.size() > 1) {
- AOrderedList fieldList = new AOrderedList(new
AOrderedListType(BuiltinType.ASTRING, null));
- for (int i = 0; i < fields.size(); i++) {
- fieldList.add(new AString(fields.get(i)));
- }
- Mutable<ILogicalExpression> fieldRef = new
MutableObject<ILogicalExpression>(
- new ConstantExpression(new
AsterixConstantValue(fieldList)));
- // Create an expression for the nested case
- func = new ScalarFunctionCallExpression(
-
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.FIELD_ACCESS_NESTED),
varRef, fieldRef);
- } else {
- Mutable<ILogicalExpression> fieldRef = new
MutableObject<ILogicalExpression>(
- new ConstantExpression(new AsterixConstantValue(new
AString(fields.get(0)))));
- // Create an expression for the open field case (By name)
- func = new ScalarFunctionCallExpression(
-
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.FIELD_ACCESS_BY_NAME),
varRef, fieldRef);
- }
- } else {
- // Assumes the indexed field is in the closed portion of the type.
- Mutable<ILogicalExpression> indexRef = new
MutableObject<ILogicalExpression>(
- new ConstantExpression(new AsterixConstantValue(new
AInt32(pos))));
- func = new ScalarFunctionCallExpression(
-
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.FIELD_ACCESS_BY_INDEX),
varRef, indexRef);
- }
- expressions.add(new MutableObject<ILogicalExpression>(func));
- LogicalVariable newVar = context.newVar();
- vars.add(newVar);
+ return -1;
}
- @SuppressWarnings("unchecked")
+ private static AbstractFunctionCallExpression
getClosedFieldAccessFunction(Mutable<ILogicalExpression> varRef,
+ int position) {
+ Mutable<ILogicalExpression> indexRef = new MutableObject<>(
+ new ConstantExpression(new AsterixConstantValue(new
AInt32(position))));
+ return new ScalarFunctionCallExpression(
+
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.FIELD_ACCESS_BY_INDEX),
varRef, indexRef);
+ }
+
+ private static AbstractFunctionCallExpression
getOpenOrNestedFieldAccessFunction(Mutable<ILogicalExpression> varRef,
+ List<String> fields) {
+ ScalarFunctionCallExpression func;
+ if (fields.size() > 1) {
+ IAObject fieldList = stringListToAOrderedList(fields);
+ Mutable<ILogicalExpression> fieldRef =
constantToMutableLogicalExpression(fieldList);
+ // Create an expression for the nested case
+ func = new ScalarFunctionCallExpression(
+
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.FIELD_ACCESS_NESTED),
varRef, fieldRef);
+ } else {
+ IAObject fieldList = new AString(fields.get(0));
+ Mutable<ILogicalExpression> fieldRef =
constantToMutableLogicalExpression(fieldList);
+ // Create an expression for the open field case (By name)
+ func = new ScalarFunctionCallExpression(
+
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.FIELD_ACCESS_BY_NAME),
varRef, fieldRef);
+ }
+ return func;
+ }
+
+ private static AOrderedList stringListToAOrderedList(List<String> fields) {
+ AOrderedList fieldList = new AOrderedList(new
AOrderedListType(BuiltinType.ASTRING, null));
+ for (int i = 0; i < fields.size(); i++) {
+ fieldList.add(new AString(fields.get(i)));
+ }
+ return fieldList;
+ }
+
+ private static Mutable<ILogicalExpression>
constantToMutableLogicalExpression(IAObject constantObject) {
+ return new MutableObject<>(
+ new ConstantExpression(new
AsterixConstantValue(constantObject)));
+ }
+
private Mutable<ILogicalExpression>
createFilterExpression(List<LogicalVariable> secondaryKeyVars,
IVariableTypeEnvironment typeEnv, boolean forceFilter) throws
AlgebricksException {
- List<Mutable<ILogicalExpression>> filterExpressions = new
ArrayList<Mutable<ILogicalExpression>>();
+ List<Mutable<ILogicalExpression>> filterExpressions = new
ArrayList<>();
// Add 'is not null' to all nullable secondary index keys as a
filtering
// condition.
for (LogicalVariable secondaryKeyVar : secondaryKeyVars) {
@@ -775,26 +655,50 @@
if (!NonTaggedFormatUtil.isOptional(secondaryKeyType) &&
!forceFilter) {
continue;
}
- ScalarFunctionCallExpression isUnknownFuncExpr =
- new
ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.IS_UNKOWN),
- new MutableObject<ILogicalExpression>(new
VariableReferenceExpression(secondaryKeyVar)));
- ScalarFunctionCallExpression notFuncExpr =
- new
ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.NOT),
- new
MutableObject<ILogicalExpression>(isUnknownFuncExpr));
+ ScalarFunctionCallExpression isUnknownFuncExpr = new
ScalarFunctionCallExpression(
+
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.IS_UNKOWN),
+ new MutableObject<ILogicalExpression>(new
VariableReferenceExpression(secondaryKeyVar)));
+ ScalarFunctionCallExpression notFuncExpr = new
ScalarFunctionCallExpression(
+ FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.NOT),
+ new MutableObject<ILogicalExpression>(isUnknownFuncExpr));
filterExpressions.add(new
MutableObject<ILogicalExpression>(notFuncExpr));
}
// No nullable secondary keys.
if (filterExpressions.isEmpty()) {
return null;
}
- Mutable<ILogicalExpression> filterExpression = null;
+ Mutable<ILogicalExpression> filterExpression;
if (filterExpressions.size() > 1) {
// Create a conjunctive condition.
- filterExpression = new MutableObject<ILogicalExpression>(new
ScalarFunctionCallExpression(
+ filterExpression = new MutableObject<>(new
ScalarFunctionCallExpression(
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.AND),
filterExpressions));
} else {
filterExpression = filterExpressions.get(0);
}
return filterExpression;
}
+
+ private class IndexFieldId {
+ private int indicator;
+ private List<String> fieldName;
+
+ public IndexFieldId(int indicator, List<String> fieldName) {
+ this.indicator = indicator;
+ this.fieldName = fieldName;
+ }
+
+ @Override
+ public int hashCode() {
+ return indicator | fieldName.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof IndexFieldId) {
+ IndexFieldId oIndexFieldId = (IndexFieldId) o;
+ return indicator == oIndexFieldId.indicator &&
fieldName.equals(oIndexFieldId.fieldName);
+ }
+ return false;
+ }
+ }
}
diff --git
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
index eac35cd..ba79534 100644
---
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
+++
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
@@ -506,9 +506,10 @@
* the expression reference
* @param argExpr
* the original expression
+ * @throws AlgebricksException
*/
private static void injectCastFunction(IFunctionInfo funcInfo, IAType
reqType, IAType inputType,
- Mutable<ILogicalExpression> exprRef, ILogicalExpression argExpr) {
+ Mutable<ILogicalExpression> exprRef, ILogicalExpression argExpr)
throws AlgebricksException {
ScalarFunctionCallExpression cast = new
ScalarFunctionCallExpression(funcInfo);
cast.getArguments().add(new
MutableObject<ILogicalExpression>(argExpr));
exprRef.setValue(cast);
diff --git
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
index b430807..09c47de 100644
---
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
+++
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
@@ -29,11 +29,13 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Random;
+import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -152,9 +154,10 @@
import org.apache.asterix.metadata.utils.MetadataLockManager;
import org.apache.asterix.om.types.ARecordType;
import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
import org.apache.asterix.om.types.IAType;
import org.apache.asterix.om.types.TypeSignature;
-import
org.apache.asterix.optimizer.rules.IntroduceSecondaryIndexInsertDeleteRule;
+import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
import org.apache.asterix.runtime.util.AsterixAppContextInfo;
import org.apache.asterix.runtime.util.AsterixClusterProperties;
import
org.apache.asterix.transaction.management.service.transaction.DatasetIdFactory;
@@ -175,6 +178,7 @@
import org.apache.asterix.translator.util.ValidateUtil;
import org.apache.asterix.util.FlushDatasetUtils;
import org.apache.asterix.util.JobUtils;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableObject;
@@ -976,7 +980,7 @@
ARecordType enforcedType = null;
if (stmtCreateIndex.isEnforced()) {
- enforcedType =
IntroduceSecondaryIndexInsertDeleteRule.createEnforcedType(aRecordType,
+ enforcedType = createEnforcedType(aRecordType,
Lists.newArrayList(index));
}
@@ -2473,7 +2477,7 @@
dataverseName);
jobsToExecute.add(DatasetOperations.compactDatasetJobSpec(dataverse,
datasetName, metadataProvider));
ARecordType aRecordType = (ARecordType) dt.getDatatype();
- ARecordType enforcedType =
IntroduceSecondaryIndexInsertDeleteRule.createEnforcedType(
+ ARecordType enforcedType = createEnforcedType(
aRecordType, indexes);
if (ds.getDatasetType() == DatasetType.INTERNAL) {
for (int j = 0; j < indexes.size(); j++) {
@@ -3124,4 +3128,102 @@
rewriter.rewrite(stmt);
}
+ // Merges typed index fields with specified recordType, allowing indexed
fields to be optional.
+ // I.e. the type { "personId":int32, "name": string, "address" : {
"street": string } } with typed indexes on age:int32, address.state:string
+ // will be merged into type { "personId":int32, "name": string,
"age": int32? "address" : { "street": string, "state": string? } }
+ // Used by open indexes to enforce the type of an indexed record
+ private static ARecordType createEnforcedType(ARecordType initialType,
List<Index> indexes)
+ throws AlgebricksException {
+ ARecordType enforcedType = initialType;
+ for (Index index : indexes) {
+ if (!index.isSecondaryIndex() || !index.isEnforcingKeyFileds()) {
+ continue;
+ }
+ if (index.hasMetaFields()) {
+ throw new AlgebricksException("Indexing an open field is only
supported on the record part");
+ }
+ for (int i = 0; i < index.getKeyFieldNames().size(); i++) {
+ Stack<Pair<ARecordType, String>> nestedTypeStack = new
Stack<>();
+ List<String> splits = index.getKeyFieldNames().get(i);
+ ARecordType nestedFieldType = enforcedType;
+ boolean openRecords = false;
+ String bridgeName = nestedFieldType.getTypeName();
+ int j;
+ // Build the stack for the enforced type
+ for (j = 1; j < splits.size(); j++) {
+ nestedTypeStack.push(new Pair<ARecordType,
String>(nestedFieldType, splits.get(j - 1)));
+ bridgeName = nestedFieldType.getTypeName();
+ nestedFieldType = (ARecordType)
enforcedType.getSubFieldType(splits.subList(0, j));
+ if (nestedFieldType == null) {
+ openRecords = true;
+ break;
+ }
+ }
+ if (openRecords) {
+ // create the smallest record
+ enforcedType = new ARecordType(splits.get(splits.size() -
2),
+ new String[] { splits.get(splits.size() - 1) },
+ new IAType[] {
AUnionType.createUnknownableType(index.getKeyFieldTypes().get(i)) }, true);
+ // create the open part of the nested field
+ for (int k = splits.size() - 3; k > (j - 2); k--) {
+ enforcedType = new ARecordType(splits.get(k), new
String[] { splits.get(k + 1) },
+ new IAType[] {
AUnionType.createUnknownableType(enforcedType) }, true);
+ }
+ // Bridge the gap
+ Pair<ARecordType, String> gapPair = nestedTypeStack.pop();
+ ARecordType parent = gapPair.first;
+
+ IAType[] parentFieldTypes =
ArrayUtils.addAll(parent.getFieldTypes().clone(),
+ new IAType[] {
AUnionType.createUnknownableType(enforcedType) });
+ enforcedType = new ARecordType(bridgeName,
+ ArrayUtils.addAll(parent.getFieldNames(),
enforcedType.getTypeName()), parentFieldTypes,
+ true);
+ } else {
+ //Schema is closed all the way to the field
+ //enforced fields are either null or strongly typed
+ LinkedHashMap<String, IAType> recordNameTypesMap =
createRecordNameTypeMap(nestedFieldType);
+ // if a an enforced field already exists and the type is
correct
+ IAType enforcedFieldType =
recordNameTypesMap.get(splits.get(splits.size() - 1));
+ if (enforcedFieldType != null &&
enforcedFieldType.getTypeTag() == ATypeTag.UNION
+ && ((AUnionType)
enforcedFieldType).isUnknownableType()) {
+ enforcedFieldType = ((AUnionType)
enforcedFieldType).getActualType();
+ }
+ if (enforcedFieldType != null &&
!ATypeHierarchy.canPromote(enforcedFieldType.getTypeTag(),
+ index.getKeyFieldTypes().get(i).getTypeTag())) {
+ throw new AlgebricksException("Cannot enforce field "
+ index.getKeyFieldNames().get(i)
+ + " to have type " +
index.getKeyFieldTypes().get(i));
+ }
+ if (enforcedFieldType == null) {
+ recordNameTypesMap.put(splits.get(splits.size() - 1),
+
AUnionType.createUnknownableType(index.getKeyFieldTypes().get(i)));
+ }
+ enforcedType = new
ARecordType(nestedFieldType.getTypeName(),
+ recordNameTypesMap.keySet().toArray(new
String[recordNameTypesMap.size()]),
+ recordNameTypesMap.values().toArray(new
IAType[recordNameTypesMap.size()]),
+ nestedFieldType.isOpen());
+ }
+
+ // Create the enforced type for the nested fields in the
schema, from the ground up
+ if (!nestedTypeStack.empty()) {
+ while (!nestedTypeStack.isEmpty()) {
+ Pair<ARecordType, String> nestedTypePair =
nestedTypeStack.pop();
+ ARecordType nestedRecType = nestedTypePair.first;
+ IAType[] nestedRecTypeFieldTypes =
nestedRecType.getFieldTypes().clone();
+
nestedRecTypeFieldTypes[nestedRecType.getFieldIndex(nestedTypePair.second)] =
enforcedType;
+ enforcedType = new
ARecordType(nestedRecType.getTypeName() + "_enforced",
+ nestedRecType.getFieldNames(),
nestedRecTypeFieldTypes, nestedRecType.isOpen());
+ }
+ }
+ }
+ }
+ return enforcedType;
+ }
+
+ private static LinkedHashMap<String, IAType>
createRecordNameTypeMap(ARecordType nestedFieldType) {
+ LinkedHashMap<String, IAType> recordNameTypesMap = new
LinkedHashMap<>();
+ for (int j = 0; j < nestedFieldType.getFieldNames().length; j++) {
+ recordNameTypesMap.put(nestedFieldType.getFieldNames()[j],
nestedFieldType.getFieldTypes()[j]);
+ }
+ return recordNameTypesMap;
+ }
}
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
index c65c71c..4e6eef4 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-1.plan
@@ -4,18 +4,17 @@
-- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- BTREE_SEARCH |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STABLE_SORT [$$11(ASC)] |PARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$11]
|PARTITIONED|
- -- UNNEST |UNPARTITIONED|
- -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$11(ASC)] |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$11]
|PARTITIONED|
+ -- UNNEST |UNPARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
index 25b3396..a96a3be 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-2.plan
@@ -4,24 +4,23 @@
-- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- BTREE_SEARCH |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STABLE_SORT [$$13(ASC)] |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE
|PARTITIONED|
- -- BTREE_SEARCH |PARTITIONED|
- -- BROADCAST_EXCHANGE
|PARTITIONED|
- -- UNNEST |UNPARTITIONED|
- -- EMPTY_TUPLE_SOURCE
|UNPARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STABLE_SORT [$$13(ASC)] |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- BROADCAST_EXCHANGE
|PARTITIONED|
+ -- UNNEST |UNPARTITIONED|
+ -- EMPTY_TUPLE_SOURCE
|UNPARTITIONED|
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-3.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-3.plan
index 1cb56c9..1f686bd 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-3.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/disjunction-to-join-delete-3.plan
@@ -4,23 +4,22 @@
-- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$8] |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- HYBRID_HASH_JOIN [$$11][$$9] |PARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$11]
|PARTITIONED|
- -- UNNEST |UNPARTITIONED|
- -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$9] |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE
|PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$8] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- HYBRID_HASH_JOIN [$$11][$$9] |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$11] |PARTITIONED|
+ -- UNNEST |UNPARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |UNPARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$9] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/insert-and-scan-dataset-with-index.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/insert-and-scan-dataset-with-index.plan
index 8bc296b..9623371 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/insert-and-scan-dataset-with-index.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/insert-and-scan-dataset-with-index.plan
@@ -4,17 +4,16 @@
-- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- HASH_PARTITION_EXCHANGE [$$10] |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- HASH_PARTITION_EXCHANGE [$$10] |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
-- ASSIGN |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
index ca4a6c2..317b163 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-delete-rtree-secondary-index.plan
@@ -17,16 +17,15 @@
-- STREAM_PROJECT |PARTITIONED|
-- ASSIGN |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- BTREE_SEARCH |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- BTREE_SEARCH |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-insert-secondary-index.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-insert-secondary-index.plan
index 5806723..0ca0482 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-insert-secondary-index.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/scan-insert-secondary-index.plan
@@ -4,21 +4,19 @@
-- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INDEX_INSERT_DELETE |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
-- ASSIGN |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
-- ASSIGN |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE
|PARTITIONED|
- -- EMPTY_TUPLE_SOURCE
|PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
index 31de832..c469ca8 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-ngram-index-search-in-delete.plan
@@ -4,16 +4,15 @@
-- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
index 0c406e2..49569d4 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-rtree-index-search-in-delete.plan
@@ -6,16 +6,15 @@
-- STREAM_PROJECT |PARTITIONED|
-- ASSIGN |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
index 31de832..1ba839d 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-secondary-btree-index-search-in-delete.plan
@@ -4,16 +4,15 @@
-- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
index 31de832..1ba839d 100644
---
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
+++
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/skip-index/skip-word-index-search-in-delete.plan
@@ -4,16 +4,15 @@
-- INDEX_INSERT_DELETE |PARTITIONED|
-- ONE_TO_ONE_EXCHANGE |PARTITIONED|
-- STREAM_PROJECT |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- INSERT_DELETE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- MATERIALIZE |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- ASSIGN |PARTITIONED|
- -- STREAM_SELECT |PARTITIONED|
- -- STREAM_PROJECT |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- DATASOURCE_SCAN |PARTITIONED|
- -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
- -- EMPTY_TUPLE_SOURCE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- INSERT_DELETE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- MATERIALIZE |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- ASSIGN |PARTITIONED|
+ -- STREAM_SELECT |PARTITIONED|
+ -- STREAM_PROJECT |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- DATASOURCE_SCAN |PARTITIONED|
+ -- ONE_TO_ONE_EXCHANGE |PARTITIONED|
+ -- EMPTY_TUPLE_SOURCE |PARTITIONED|
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.1.ddl.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.1.ddl.aql
new file mode 100644
index 0000000..92d8f7d
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.1.ddl.aql
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+/*
+* Description : Delete from enforced index and validate deletion
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type OrderOpenType as open {
+ o_orderkey: int64
+}
+
+create dataset OrdersOpen(OrderOpenType)
+primary key o_orderkey;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.2.update.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.2.update.aql
new file mode 100644
index 0000000..ad05499
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.2.update.aql
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+/*
+* Description : Delete from enforced index and validate deletion
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+use dataverse test;
+
+insert into dataset OrdersOpen (
+ {"o_orderkey": 1,
+ "o_custkey": 1}
+)
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.3.ddl.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.3.ddl.aql
new file mode 100644
index 0000000..af5b71d
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.3.ddl.aql
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+/*
+* Description : Delete from enforced index and validate deletion
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+use dataverse test;
+
+create index idx_Orders_Custkey on
+OrdersOpen(o_custkey:int32?) enforced;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.4.update.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.4.update.aql
new file mode 100644
index 0000000..588b9e2
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.4.update.aql
@@ -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.
+ */
+/*
+* Description : Delete from enforced index and validate deletion
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+use dataverse test;
+
+delete $v from dataset OrdersOpen
+where $v. o_orderkey = 1;
+
+insert into dataset OrdersOpen (
+ {"o_orderkey": 1,
+ "o_custkey": 2}
+);
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.5.query.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.5.query.aql
new file mode 100644
index 0000000..e6ac100
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.5.query.aql
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+/*
+* Description : Delete from enforced index and validate deletion
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+use dataverse test;
+
+let $l := for $o in dataset('OrdersOpen')
+where $o.o_custkey >=-1
+return $o.o_orderKey
+return count($l);
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.1.ddl.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.1.ddl.aql
new file mode 100644
index 0000000..f710221
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.1.ddl.aql
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+/*
+* Description : Upsert from enforced index and validate result
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type OrderOpenType as open {
+ o_orderkey: int64
+}
+
+create dataset OrdersOpen(OrderOpenType)
+primary key o_orderkey;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.2.update.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.2.update.aql
new file mode 100644
index 0000000..1e4c7cd
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.2.update.aql
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+/*
+* Description : Upsert from enforced index and validate result
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+use dataverse test;
+
+insert into dataset OrdersOpen (
+ {"o_orderkey": 1,
+ "o_custkey": 1}
+)
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.3.ddl.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.3.ddl.aql
new file mode 100644
index 0000000..0cf0fab
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.3.ddl.aql
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+/*
+* Description : Upsert from enforced index and validate result
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+use dataverse test;
+
+create index idx_Orders_Custkey on
+OrdersOpen(o_custkey:int32?) enforced;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.4.update.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.4.update.aql
new file mode 100644
index 0000000..b7c6ec8
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.4.update.aql
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+/*
+* Description : Upsert from enforced index and validate result
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+use dataverse test;
+
+upsert into dataset OrdersOpen (
+ {"o_orderkey": 1,
+ "o_custkey": 2}
+);
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.5.query.aql
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.5.query.aql
new file mode 100644
index 0000000..7e5ef7c
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.5.query.aql
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+/*
+* Description : Upsert from enforced index and validate result
+* Expected Res : Success
+* Date : 22 Aug 2016
+*/
+use dataverse test;
+
+let $l := for $o in dataset('OrdersOpen')
+where $o.o_custkey >=-1
+return $o.o_orderKey
+return count($l);
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/results/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.5.adm
b/asterixdb/asterix-app/src/test/resources/runtimets/results/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.5.adm
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/results/open-index-enforced/type-checking/enforced-type-delete/enforced-type-delete.5.adm
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/results/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.5.adm
b/asterixdb/asterix-app/src/test/resources/runtimets/results/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.5.adm
new file mode 100644
index 0000000..56a6051
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/results/open-index-enforced/type-checking/enforced-type-upsert/enforced-type-upsert.5.adm
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml
index 6c65a62..6f65a50 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite.xml
@@ -3511,6 +3511,18 @@
</compilation-unit>
</test-case>
</test-group>
+ <test-group name="open-index-enforced/type-checking">
+ <test-case FilePath="open-index-enforced/type-checking">
+ <compilation-unit name="enforced-type-delete">
+ <output-dir compare="Text">enforced-type-delete</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="open-index-enforced/type-checking">
+ <compilation-unit name="enforced-type-upsert">
+ <output-dir compare="Text">enforced-type-upsert</output-dir>
+ </compilation-unit>
+ </test-case>
+ </test-group>
</test-group>
<test-group name="nested-open-index">
<test-group name="nested-open-index/index-join">
diff --git
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Index.java
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Index.java
index bdf9ed0..f33a2b6 100644
---
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Index.java
+++
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Index.java
@@ -37,6 +37,8 @@
public class Index implements IMetadataEntity<Index>, Comparable<Index> {
private static final long serialVersionUID = 1L;
+ public static final int RECORD_INDICATOR = 0;
+ public static final int META_INDICATOR = 1;
private final String dataverseName;
// Enforced to be unique within a dataverse.
diff --git
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java
index 04883e4..549a34e 100644
---
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java
+++
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/TypeCastUtils.java
@@ -19,7 +19,11 @@
package org.apache.asterix.om.typecomputer.base;
+import org.apache.asterix.om.typecomputer.impl.TypeComputeUtils;
+import org.apache.asterix.om.types.ATypeTag;
import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
public class TypeCastUtils {
@@ -27,14 +31,19 @@
private TypeCastUtils() {
}
- public static boolean
setRequiredAndInputTypes(AbstractFunctionCallExpression expr, IAType
requiredRecordType,
- IAType inputRecordType) {
+ public static boolean
setRequiredAndInputTypes(AbstractFunctionCallExpression expr, IAType
requiredType,
+ IAType inputType) throws AlgebricksException {
boolean changed = false;
Object[] opaqueParameters = expr.getOpaqueParameters();
if (opaqueParameters == null) {
opaqueParameters = new Object[2];
- opaqueParameters[0] = requiredRecordType;
- opaqueParameters[1] = inputRecordType;
+ opaqueParameters[0] = requiredType;
+ opaqueParameters[1] = inputType;
+ if (TypeComputeUtils.getActualType(inputType).getTypeTag() !=
ATypeTag.ANY
+ && !ATypeHierarchy.isCompatible(requiredType.getTypeTag(),
+
TypeComputeUtils.getActualType(inputType).getTypeTag())) {
+ throw new AlgebricksException(inputType + " can't be casted to
" + requiredType);
+ }
expr.setOpaqueParameters(opaqueParameters);
changed = true;
}
diff --git
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/CastTypeComputer.java
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/CastTypeComputer.java
index 64f85cb..e4a751b 100644
---
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/CastTypeComputer.java
+++
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/CastTypeComputer.java
@@ -19,28 +19,22 @@
package org.apache.asterix.om.typecomputer.impl;
-import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
+import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
import org.apache.asterix.om.typecomputer.base.TypeCastUtils;
import org.apache.asterix.om.types.IAType;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
-import
org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
-import
org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
-import org.apache.hyracks.algebricks.core.algebra.metadata.IMetadataProvider;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
/**
* The type computer for the cast-list function
- *
- * @author yingyib
*/
-public class CastTypeComputer implements IResultTypeComputer {
+public class CastTypeComputer extends AbstractResultTypeComputer {
public static final CastTypeComputer INSTANCE = new CastTypeComputer();
@Override
- public IAType computeType(ILogicalExpression expression,
IVariableTypeEnvironment env,
- IMetadataProvider<?, ?> metadataProvider) throws
AlgebricksException {
- ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression)
expression;
- return TypeCastUtils.getRequiredType(funcExpr);
+ protected IAType getResultType(ILogicalExpression expr, IAType...
strippedInputTypes) throws AlgebricksException {
+ return TypeCastUtils.getRequiredType((AbstractFunctionCallExpression)
expr);
}
}
diff --git
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java
index e966406..0d50dc2 100644
---
a/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java
+++
b/hyracks-fullstack/algebricks/algebricks-core/src/main/java/org/apache/hyracks/algebricks/core/algebra/operators/logical/visitors/UsedVariableVisitor.java
@@ -46,12 +46,12 @@
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.IntersectOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterJoinOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestMapOperator;
+import
org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.LimitOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.MaterializeOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.OrderOperator.IOrder;
-import
org.apache.hyracks.algebricks.core.algebra.operators.logical.LeftOuterUnnestOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.PartitioningSplitOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.ProjectOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.ReplicateOperator;
@@ -68,8 +68,8 @@
import
org.apache.hyracks.algebricks.core.algebra.operators.logical.WriteResultOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.physical.HashPartitionExchangePOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.physical.HashPartitionMergeExchangePOperator;
-import
org.apache.hyracks.algebricks.core.algebra.operators.physical.RangePartitionMergeExchangePOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.physical.RangePartitionExchangePOperator;
+import
org.apache.hyracks.algebricks.core.algebra.operators.physical.RangePartitionMergeExchangePOperator;
import
org.apache.hyracks.algebricks.core.algebra.operators.physical.SortMergeExchangePOperator;
import org.apache.hyracks.algebricks.core.algebra.properties.OrderColumn;
import
org.apache.hyracks.algebricks.core.algebra.visitors.ILogicalOperatorVisitor;
@@ -436,6 +436,9 @@
@Override
public Void visitReplicateOperator(ReplicateOperator op, Void arg) throws
AlgebricksException {
+ for (Mutable<ILogicalOperator> outputOp : op.getOutputs()) {
+ VariableUtilities.getUsedVariables(outputOp.getValue(),
usedVariables);
+ }
return null;
}
--
To view, visit https://asterix-gerrit.ics.uci.edu/1146
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I6a80105798ea1c86a6a0eb69a79b9573b54931b7
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: abdullah alamoudi <[email protected]>