support static/dyanmic recursive casting for collections
git-svn-id: https://asterixdb.googlecode.com/svn/branches/asterix_opentype@323 eaa15691-b419-025a-1212-ee371bd00084
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
index 0b429a9..845e4d3 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/IntroduceStaticTypeCastRule.java
@@ -15,9 +15,11 @@
import edu.uci.ics.asterix.om.types.ARecordType;
import edu.uci.ics.asterix.om.types.ATypeTag;
import edu.uci.ics.asterix.om.types.AUnionType;
+import edu.uci.ics.asterix.om.types.AbstractCollectionType;
import edu.uci.ics.asterix.om.types.BuiltinType;
import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
+import edu.uci.ics.asterix.runtime.accessors.base.DefaultOpenFieldType;
import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalOperator;
@@ -25,7 +27,6 @@
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalVariable;
-import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
@@ -37,10 +38,6 @@
public class IntroduceStaticTypeCastRule implements IAlgebraicRewriteRule {
- // nested open field rec type
- private static ARecordType nestedOpenRecType = new ARecordType("nested-open", new String[] {}, new IAType[] {},
- true);
-
@Override
public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
return false;
@@ -112,7 +109,7 @@
ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) expr;
if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
return false;
- rewriteFuncExpr(funcExpr, requiredRecordType, inputRecordType);
+ rewriteRecordFuncExpr(funcExpr, requiredRecordType, inputRecordType);
}
context.computeAndSetTypeEnvironmentForOperator(originalAssign);
}
@@ -125,27 +122,47 @@
return true;
}
- private void rewriteFuncExpr(ScalarFunctionCallExpression funcExpr, ARecordType requiredRecordType,
+ private void rewriteRecordFuncExpr(ScalarFunctionCallExpression funcExpr, ARecordType requiredRecordType,
ARecordType inputRecordType) {
+ if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
+ return;
TypeComputerUtilities.setRequiredAndInputTypes(funcExpr, requiredRecordType, inputRecordType);
- staticTypeCast(funcExpr, requiredRecordType, inputRecordType);
+ staticRecordTypeCast(funcExpr, requiredRecordType, inputRecordType);
+ }
+
+ private void rewriteFuncExpr(ScalarFunctionCallExpression funcExpr, IAType reqType, IAType inputType) {
+ if (funcExpr.getFunctionIdentifier() == AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR) {
+ rewriteListFuncExpr(funcExpr, (AbstractCollectionType) reqType, (AbstractCollectionType) inputType);
+ }
+ if (funcExpr.getFunctionIdentifier() == AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR) {
+ rewriteListFuncExpr(funcExpr, (AbstractCollectionType) reqType, (AbstractCollectionType) inputType);
+ } else if (reqType.getTypeTag().equals(ATypeTag.RECORD)) {
+ rewriteRecordFuncExpr(funcExpr, (ARecordType) reqType, (ARecordType) inputType);
+ }
+ }
+
+ private void rewriteListFuncExpr(ScalarFunctionCallExpression funcExpr, AbstractCollectionType requiredListType,
+ AbstractCollectionType inputListType) {
+ if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
+ return;
+
+ TypeComputerUtilities.setRequiredAndInputTypes(funcExpr, requiredListType, inputListType);
List<Mutable<ILogicalExpression>> args = funcExpr.getArguments();
- int openPartStart = requiredRecordType.getFieldTypes().length * 2;
- if (requiredRecordType.isOpen()) {
- for (int j = openPartStart; j < args.size(); j++) {
- ILogicalExpression arg = args.get(j).getValue();
- if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
- AbstractFunctionCallExpression argFunc = (AbstractFunctionCallExpression) arg;
- if (argFunc.getFunctionIdentifier() == AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR
- || argFunc.getFunctionIdentifier() == AsterixBuiltinFunctions.ORDERED_LIST_CONSTRUCTOR) {
- TypeComputerUtilities.setOpenType(argFunc, true);
- }
- }
+
+ IAType itemType = requiredListType.getItemType();
+ if (itemType == null || itemType.getTypeTag().equals(ATypeTag.ANY))
+ return;
+ IAType inputItemType = inputListType.getItemType();
+ for (int j = 0; j < args.size(); j++) {
+ ILogicalExpression arg = args.get(j).getValue();
+ if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+ ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) arg;
+ rewriteFuncExpr(argFunc, itemType, inputItemType);
}
}
}
- private void staticTypeCast(ScalarFunctionCallExpression func, ARecordType reqType, ARecordType inputType) {
+ private void staticRecordTypeCast(ScalarFunctionCallExpression func, ARecordType reqType, ARecordType inputType) {
IAType[] reqFieldTypes = reqType.getFieldTypes();
String[] reqFieldNames = reqType.getFieldNames();
IAType[] inputFieldTypes = inputType.getFieldTypes();
@@ -167,6 +184,8 @@
for (int i = 0; i < inputFieldNames.length; i++) {
String fieldName = inputFieldNames[i];
IAType fieldType = inputFieldTypes[i];
+
+ ILogicalExpression arg = func.getArguments().get(2 * i + 1).getValue();
matched = false;
for (int j = 0; j < reqFieldNames.length; j++) {
String reqFieldName = reqFieldNames[j];
@@ -177,10 +196,9 @@
openFields[i] = false;
matched = true;
- if (fieldType.getTypeTag() == ATypeTag.RECORD) {
- ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) func
- .getArguments().get(2 * i + 1).getValue();
- rewriteFuncExpr(scalarFunc, (ARecordType) reqFieldType, (ARecordType) fieldType);
+ if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+ ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
+ rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
}
break;
}
@@ -197,21 +215,18 @@
matched = true;
// rewrite record expr
- if (reqFieldType.getTypeTag() == ATypeTag.RECORD
- && fieldType.getTypeTag() == ATypeTag.RECORD) {
- ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) func
- .getArguments().get(2 * i + 1).getValue();
- rewriteFuncExpr(scalarFunc, (ARecordType) reqFieldType, (ARecordType) fieldType);
+ if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+ ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
+ rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
}
break;
}
}
// match the record field: need cast
- if (reqFieldType.getTypeTag() == ATypeTag.RECORD && fieldType.getTypeTag() == ATypeTag.RECORD) {
- ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) func.getArguments()
- .get(2 * i + 1).getValue();
- rewriteFuncExpr(scalarFunc, (ARecordType) reqFieldType, (ARecordType) fieldType);
+ if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+ ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
+ rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
fieldPermutation[j] = i;
openFields[i] = false;
matched = true;
@@ -290,9 +305,23 @@
if (openFields[i]) {
arguments.add(argumentsClone.get(2 * i));
Mutable<ILogicalExpression> fExprRef = argumentsClone.get(2 * i + 1);
- if (inputFieldTypes[i].getTypeTag() == ATypeTag.RECORD) {
- ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) fExprRef.getValue();
- rewriteFuncExpr(funcExpr, nestedOpenRecType, (ARecordType) inputFieldTypes[i]);
+ ILogicalExpression argExpr = fExprRef.getValue();
+
+ if (argExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
+ IAType reqFieldType = inputFieldTypes[i];
+ if (inputFieldTypes[i].getTypeTag() == ATypeTag.RECORD) {
+ reqFieldType = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
+ }
+ if (inputFieldTypes[i].getTypeTag() == ATypeTag.ORDEREDLIST) {
+ reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
+ }
+ if (inputFieldTypes[i].getTypeTag() == ATypeTag.UNORDEREDLIST) {
+ reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
+ }
+ if (!reqFieldType.equals(inputFieldTypes[i])) {
+ ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) fExprRef.getValue();
+ rewriteFuncExpr(argFunc, reqFieldType, inputFieldTypes[i]);
+ }
}
arguments.add(fExprRef);
}
diff --git a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o.aql b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o.aql
index e29ccdc..a63e2df 100644
--- a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o.aql
@@ -12,7 +12,7 @@
create type testtype as closed {
id: string,
name: string,
- hobby: string?
+ hobby: {{string}}?
}
/*
@@ -28,19 +28,19 @@
create dataset testds2(testtype2) partitioned by key id;
insert into dataset testds (
-{ "hobby": "music", "id": "001", "name": "Person Three"}
+{ "hobby": {{"music", "coding"}}, "id": "001", "name": "Person Three"}
);
insert into dataset testds (
-{ "name": "Person One", "id": "002", "hobby": "sports"}
+{ "name": "Person One", "id": "002", "hobby": {{"sports"}} }
);
insert into dataset testds (
-{ "id": "003", "hobby": "movie", "name": "Person Two"}
+{ "id": "003", "hobby": {{"movie", "sports"}}, "name": "Person Two"}
);
insert into dataset testds (
-{ "id": "004", "name": "Person Four", "hobby": "swimming"}
+{ "id": "004", "name": "Person Four", "hobby": {{"swimming"}} }
);
insert into dataset testds (
diff --git a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c.aql b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c.aql
index a6ed9cc..015aa7b 100644
--- a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c.aql
@@ -16,7 +16,7 @@
}
create type testtype2 as closed {
- hobby: string?,
+ hobby: {{string}}?,
id: string,
name: string
}
@@ -26,19 +26,19 @@
create dataset testds2(testtype2) partitioned by key id;
insert into dataset testds (
-{ "id": "001", "hobby": "music", "name": "Person Three"}
+{ "id": "001", "hobby": {{"music"}}, "name": "Person Three"}
);
insert into dataset testds (
-{ "id": "002", "name": "Person Three", "hobby": "football"}
+{ "id": "002", "name": "Person Three", "hobby": {{"football"}}}
);
insert into dataset testds (
-{ "id": "003", "name": "Person Three", "hobby": "movie"}
+{ "id": "003", "name": "Person Three", "hobby": {{"movie", "coding", "debugging"}}}
);
insert into dataset testds (
-{ "name": "Person Three", "hobby": "swimming", "id": "004"}
+{ "name": "Person Three", "hobby": {{"swimming", "music"}}, "id": "004"}
);
insert into dataset testds (
diff --git a/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o.adm b/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o.adm
index 5e7a349..6086a08 100644
--- a/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o.adm
+++ b/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o.adm
@@ -1,5 +1,5 @@
-{ "id": "001", "name": "Person Three", "hobby": "music" }
-{ "id": "002", "name": "Person One", "hobby": "sports" }
-{ "id": "003", "name": "Person Two", "hobby": "movie" }
-{ "id": "004", "name": "Person Four", "hobby": "swimming" }
+{ "id": "001", "name": "Person Three", "hobby": {{ "music", "coding" }} }
+{ "id": "002", "name": "Person One", "hobby": {{ "sports" }} }
+{ "id": "003", "name": "Person Two", "hobby": {{ "movie", "sports" }} }
+{ "id": "004", "name": "Person Four", "hobby": {{ "swimming" }} }
{ "id": "005", "name": "Person Five", "hobby": null }
diff --git a/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c.adm b/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c.adm
index d9c778b..92809fd 100644
--- a/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c.adm
+++ b/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c.adm
@@ -1,5 +1,5 @@
-{ "hobby": "music", "id": "001", "name": "Person Three" }
-{ "hobby": "football", "id": "002", "name": "Person Three" }
-{ "hobby": "movie", "id": "003", "name": "Person Three" }
-{ "hobby": "swimming", "id": "004", "name": "Person Three" }
+{ "hobby": {{ "music" }}, "id": "001", "name": "Person Three" }
+{ "hobby": {{ "football" }}, "id": "002", "name": "Person Three" }
+{ "hobby": {{ "movie", "coding", "debugging" }}, "id": "003", "name": "Person Three" }
+{ "hobby": {{ "swimming", "music" }}, "id": "004", "name": "Person Three" }
{ "hobby": null, "id": "005", "name": "Person Five" }
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/base/TypeComputerUtilities.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/base/TypeComputerUtilities.java
index e8786ec..293aef1 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/base/TypeComputerUtilities.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/base/TypeComputerUtilities.java
@@ -1,28 +1,12 @@
package edu.uci.ics.asterix.om.typecomputer.base;
-import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
public class TypeComputerUtilities {
- public static void setOpenType(AbstractFunctionCallExpression expr, boolean openType) {
- Boolean openField = true;
- Object[] opaqueParameters = new Object[1];
- opaqueParameters[0] = openField;
- expr.setOpaqueParameters(opaqueParameters);
- }
-
- public static boolean isOpenType(AbstractFunctionCallExpression expr) {
- boolean openType = false;
- Object[] opaqueParameters = expr.getOpaqueParameters();
- if (opaqueParameters != null) {
- openType = (Boolean) opaqueParameters[0];
- }
- return openType;
- }
-
- public static boolean setRequiredAndInputTypes(AbstractFunctionCallExpression expr, ARecordType requiredRecordType,
- ARecordType inputRecordType) {
+ public static boolean setRequiredAndInputTypes(AbstractFunctionCallExpression expr, IAType requiredRecordType,
+ IAType inputRecordType) {
boolean changed = false;
Object opaqueParameter = expr.getOpaqueParameters();
if (opaqueParameter == null) {
@@ -35,19 +19,19 @@
return changed;
}
- public static ARecordType getRequiredType(AbstractFunctionCallExpression expr) {
+ public static IAType getRequiredType(AbstractFunctionCallExpression expr) {
Object[] type = expr.getOpaqueParameters();
if (type != null) {
- ARecordType recordType = (ARecordType) type[0];
+ IAType recordType = (IAType) type[0];
return recordType;
} else
return null;
}
- public static ARecordType getInputType(AbstractFunctionCallExpression expr) {
+ public static IAType getInputType(AbstractFunctionCallExpression expr) {
Object[] type = expr.getOpaqueParameters();
if (type != null) {
- ARecordType recordType = (ARecordType) type[1];
+ IAType recordType = (IAType) type[1];
return recordType;
} else
return null;
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
index 6a17a46..39485ab 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/ClosedRecordConstructorResultType.java
@@ -31,7 +31,7 @@
/**
* if type has been top-down propagated, use the enforced type
*/
- ARecordType type = TypeComputerUtilities.getRequiredType(f);
+ ARecordType type = (ARecordType) TypeComputerUtilities.getRequiredType(f);
if (type != null)
return type;
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
index 8b27a82..790ca3f 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OpenRecordConstructorResultType.java
@@ -33,7 +33,7 @@
/**
* if type has been top-down propagated, use the enforced type
*/
- ARecordType type = TypeComputerUtilities.getRequiredType(f);
+ ARecordType type = (ARecordType) TypeComputerUtilities.getRequiredType(f);
if (type != null)
return type;
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OrderedListConstructorResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OrderedListConstructorResultType.java
index 47f239b..c4e35b6 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OrderedListConstructorResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/OrderedListConstructorResultType.java
@@ -7,7 +7,6 @@
import edu.uci.ics.asterix.om.types.AOrderedListType;
import edu.uci.ics.asterix.om.types.ATypeTag;
import edu.uci.ics.asterix.om.types.AUnionType;
-import edu.uci.ics.asterix.om.types.BuiltinType;
import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -24,26 +23,28 @@
public AOrderedListType computeType(ILogicalExpression expression, IVariableTypeEnvironment env,
IMetadataProvider<?, ?> metadataProvider) throws AlgebricksException {
AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) expression;
- boolean openType = TypeComputerUtilities.isOpenType(f);
- int n = f.getArguments().size();
- if (n == 0 || openType) {
- return new AOrderedListType(BuiltinType.ANY, null);
- } else {
- ArrayList<IAType> types = new ArrayList<IAType>();
- for (int k = 0; k < f.getArguments().size(); k++) {
- IAType type = (IAType) env.getType(f.getArguments().get(k).getValue());
- if (type.getTypeTag() == ATypeTag.UNION && NonTaggedFormatUtil.isOptionalField((AUnionType) type))
- type = ((AUnionType) type).getUnionList()
- .get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST);
- if (types.indexOf(type) < 0) {
- types.add(type);
- }
- }
- if (types.size() == 1) {
- return new AOrderedListType(types.get(0), null);
- } else {
- throw new AlgebricksException("You can not construct a heterogenous list.");
+
+ /**
+ * if type has been top-down propagated, use the enforced type
+ */
+ AOrderedListType reqType = (AOrderedListType) TypeComputerUtilities.getRequiredType(f);
+ if (reqType != null)
+ return reqType;
+
+ ArrayList<IAType> types = new ArrayList<IAType>();
+ for (int k = 0; k < f.getArguments().size(); k++) {
+ IAType type = (IAType) env.getType(f.getArguments().get(k).getValue());
+ if (type.getTypeTag() == ATypeTag.UNION && NonTaggedFormatUtil.isOptionalField((AUnionType) type))
+ type = ((AUnionType) type).getUnionList().get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST);
+ if (types.indexOf(type) < 0) {
+ types.add(type);
}
}
+ if (types.size() == 1) {
+ return new AOrderedListType(types.get(0), null);
+ } else {
+ throw new AlgebricksException("You can not construct a heterogenous list.");
+ }
+
}
}
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/UnorderedListConstructorResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/UnorderedListConstructorResultType.java
index 0e03e6d..21c473d 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/UnorderedListConstructorResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/UnorderedListConstructorResultType.java
@@ -7,7 +7,6 @@
import edu.uci.ics.asterix.om.types.ATypeTag;
import edu.uci.ics.asterix.om.types.AUnionType;
import edu.uci.ics.asterix.om.types.AUnorderedListType;
-import edu.uci.ics.asterix.om.types.BuiltinType;
import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -24,26 +23,28 @@
public AUnorderedListType computeType(ILogicalExpression expression, IVariableTypeEnvironment env,
IMetadataProvider<?, ?> metadataProvider) throws AlgebricksException {
AbstractFunctionCallExpression f = (AbstractFunctionCallExpression) expression;
- boolean openType = TypeComputerUtilities.isOpenType(f);
- int n = f.getArguments().size();
- if (n == 0 || openType) {
- return new AUnorderedListType(BuiltinType.ANY, null);
- } else {
- ArrayList<IAType> types = new ArrayList<IAType>();
- for (int k = 0; k < f.getArguments().size(); k++) {
- IAType type = (IAType) env.getType(f.getArguments().get(k).getValue());
- if (type.getTypeTag() == ATypeTag.UNION && NonTaggedFormatUtil.isOptionalField((AUnionType) type))
- type = ((AUnionType) type).getUnionList()
- .get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST);
- if (types.indexOf(type) < 0) {
- types.add(type);
- }
- }
- if (types.size() == 1) {
- return new AUnorderedListType(types.get(0), null);
- } else {
- throw new AlgebricksException("You can not construct a heterogenous list.");
+
+ /**
+ * if type has been top-down propagated, use the enforced type
+ */
+ AUnorderedListType reqType = (AUnorderedListType) TypeComputerUtilities.getRequiredType(f);
+ if (reqType != null)
+ return reqType;
+
+ ArrayList<IAType> types = new ArrayList<IAType>();
+ for (int k = 0; k < f.getArguments().size(); k++) {
+ IAType type = (IAType) env.getType(f.getArguments().get(k).getValue());
+ if (type.getTypeTag() == ATypeTag.UNION && NonTaggedFormatUtil.isOptionalField((AUnionType) type))
+ type = ((AUnionType) type).getUnionList().get(NonTaggedFormatUtil.OPTIONAL_TYPE_INDEX_IN_UNION_LIST);
+ if (types.indexOf(type) < 0) {
+ types.add(type);
}
}
+ if (types.size() == 1) {
+ return new AUnorderedListType(types.get(0), null);
+ } else {
+ throw new AlgebricksException("You can not construct a heterogenous list.");
+ }
+
}
}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AListAccessor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AListAccessor.java
index 8599d38..8056d09 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AListAccessor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AListAccessor.java
@@ -24,7 +24,6 @@
}
};
- private AbstractCollectionType inputType;
private IAType itemType;
private ATypeTag itemTag;
private boolean typedItemList = false;
@@ -33,16 +32,11 @@
private List<IBinaryAccessor> itemTags = new ArrayList<IBinaryAccessor>();
private AccessorAllocator allocator = new AccessorAllocator();
- private byte[] typeBuffer = new byte[32768];
- private ResettableByteArrayOutputStream typeBos = new ResettableByteArrayOutputStream();
- private DataOutputStream typeDos = new DataOutputStream(typeBos);
-
private byte[] dataBuffer = new byte[32768];
private ResettableByteArrayOutputStream dataBos = new ResettableByteArrayOutputStream();
private DataOutputStream dataDos = new DataOutputStream(dataBos);
private AListAccessor(AbstractCollectionType inputType) {
- this.inputType = inputType;
if (inputType != null && inputType.getItemType() != null) {
itemType = inputType.getItemType();
if (itemType.getTypeTag() == ATypeTag.ANY) {
@@ -59,19 +53,10 @@
private void reset() {
allocator.reset();
items.clear();
-
- typeBos.setByteArray(typeBuffer, 0);
+ itemTags.clear();
dataBos.setByteArray(dataBuffer, 0);
}
- public List<IBinaryAccessor> getItems() {
- return items;
- }
-
- public List<IBinaryAccessor> getItemTags() {
- return itemTags;
- }
-
@Override
public void reset(byte[] b, int s, int len) {
reset();
@@ -97,20 +82,46 @@
if (typedItemList) {
for (int i = 0; i < numberOfitems; i++) {
itemLength = NonTaggedFormatUtil.getFieldValueLength(b, itemOffset, itemTag, false);
- IBinaryAccessor field = allocator.allocateFieldValue(itemType);
- field.reset(b, itemOffset, itemLength);
+ IBinaryAccessor tag = allocator.allocateFieldType();
+ IBinaryAccessor item = allocator.allocateFieldValue(itemType);
+
+ // set item type tag
+ int start = dataBos.size();
+ dataDos.writeByte(itemTag.serialize());
+ int end = dataBos.size();
+ tag.reset(dataBuffer, start, end - start);
+ itemTags.add(tag);
+
+ // set item value
+ start = dataBos.size();
+ dataDos.writeByte(itemTag.serialize());
+ dataDos.write(b, itemOffset, itemLength);
+ end = dataBos.size();
+ item.reset(dataBuffer, start, end - start);
itemOffset += itemLength;
+ items.add(item);
}
} else {
for (int i = 0; i < numberOfitems; i++) {
itemTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(b[itemOffset]);
itemLength = NonTaggedFormatUtil.getFieldValueLength(b, itemOffset, itemTag, true) + 1;
- IBinaryAccessor field = allocator.allocateFieldValue(itemType);
- field.reset(b, itemOffset, itemLength);
+ IBinaryAccessor tag = allocator.allocateFieldType();
+ IBinaryAccessor item = allocator.allocateFieldValue(itemType);
+
+ // set item type tag
+ int start = dataBos.size();
+ dataDos.writeByte(itemTag.serialize());
+ int end = dataBos.size();
+ tag.reset(dataBuffer, start, end - start);
+ itemTags.add(tag);
+
+ // open part field already include the type tag
+ item.reset(b, itemOffset, itemLength);
itemOffset += itemLength;
+ items.add(item);
}
}
- } catch (AsterixException e) {
+ } catch (Exception e) {
throw new IllegalStateException(e);
}
}
@@ -120,4 +131,11 @@
return vistor.visit(this, tag);
}
+ public List<IBinaryAccessor> getItems() {
+ return items;
+ }
+
+ public List<IBinaryAccessor> getItemTags() {
+ return itemTags;
+ }
}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/ARecordAccessor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/ARecordAccessor.java
index 686aa8e..776cdc0 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/ARecordAccessor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/ARecordAccessor.java
@@ -29,7 +29,6 @@
import edu.uci.ics.asterix.om.types.EnumDeserializer;
import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.asterix.om.util.NonTaggedFormatUtil;
-import edu.uci.ics.asterix.runtime.accessors.base.DefaultOpenFieldType;
import edu.uci.ics.asterix.runtime.accessors.base.IBinaryAccessor;
import edu.uci.ics.asterix.runtime.accessors.visitor.IBinaryAccessorVisitor;
import edu.uci.ics.asterix.runtime.util.ResettableByteArrayOutputStream;
@@ -238,12 +237,7 @@
fieldValueLength = NonTaggedFormatUtil.getFieldValueLength(b, fieldOffset, typeTag, true) + 1;
// allocate
- IBinaryAccessor fieldValueAccessor;
-
- if (typeTag == ATypeTag.RECORD)
- fieldValueAccessor = allocator.allocateFieldValue(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
- else
- fieldValueAccessor = allocator.allocateFieldValue(null);
+ IBinaryAccessor fieldValueAccessor = allocator.allocateFieldValue(typeTag);
fieldValueAccessor.reset(b, fieldOffset, fieldValueLength);
fieldValues.add(fieldValueAccessor);
fieldOffset += fieldValueLength;
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AccessorAllocator.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AccessorAllocator.java
index c177b1f..82c56b5 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AccessorAllocator.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/AccessorAllocator.java
@@ -2,6 +2,7 @@
import edu.uci.ics.asterix.om.types.ATypeTag;
import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.asterix.runtime.accessors.base.DefaultOpenFieldType;
import edu.uci.ics.asterix.runtime.accessors.base.IBinaryAccessor;
import edu.uci.ics.asterix.runtime.util.container.IElementAllocator;
import edu.uci.ics.asterix.runtime.util.container.ListElementAllocator;
@@ -33,6 +34,19 @@
else
return flatArtifactAllocator.allocate(null);
}
+
+ public IBinaryAccessor allocateFieldValue(ATypeTag typeTag) {
+ if(typeTag == null)
+ return flatArtifactAllocator.allocate(null);
+ else if (typeTag.equals(ATypeTag.RECORD))
+ return nestedRecValueAllocator.allocate(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
+ else if (typeTag.equals(ATypeTag.UNORDEREDLIST))
+ return nestedListValueAllocator.allocate(DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE);
+ else if(typeTag.equals(ATypeTag.ORDEREDLIST))
+ return nestedListValueAllocator.allocate(DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE);
+ else
+ return flatArtifactAllocator.allocate(null);
+ }
public IBinaryAccessor allocateNestedListValue(IAType type) {
return nestedListValueAllocator.allocate(type);
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/base/DefaultOpenFieldType.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/base/DefaultOpenFieldType.java
index 1544f66..dca89f5 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/base/DefaultOpenFieldType.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/base/DefaultOpenFieldType.java
@@ -2,6 +2,7 @@
import edu.uci.ics.asterix.om.types.AOrderedListType;
import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.ATypeTag;
import edu.uci.ics.asterix.om.types.AUnorderedListType;
import edu.uci.ics.asterix.om.types.BuiltinType;
import edu.uci.ics.asterix.om.types.IAType;
@@ -19,5 +20,16 @@
// nested open list type
public static AUnorderedListType NESTED_OPEN_AUNORDERED_LIST_TYPE = new AUnorderedListType(BuiltinType.ANY,
"nested-unordered-list");
+
+ public static IAType getDefaultOpenFieldType(ATypeTag tag){
+ if(tag.equals(ATypeTag.RECORD))
+ return NESTED_OPEN_RECORD_TYPE;
+ if(tag.equals(ATypeTag.ORDEREDLIST))
+ return NESTED_OPEN_AORDERED_LIST_TYPE;
+ if(tag.equals(ATypeTag.UNORDEREDLIST))
+ return NESTED_OPEN_AUNORDERED_LIST_TYPE;
+ else
+ return null;
+ }
}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ACastVisitor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ACastVisitor.java
index c84f28e..65d8275 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ACastVisitor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ACastVisitor.java
@@ -5,6 +5,7 @@
import edu.uci.ics.asterix.common.exceptions.AsterixException;
import edu.uci.ics.asterix.om.types.ARecordType;
+import edu.uci.ics.asterix.om.types.AbstractCollectionType;
import edu.uci.ics.asterix.om.types.IAType;
import edu.uci.ics.asterix.runtime.accessors.AFlatValueAccessor;
import edu.uci.ics.asterix.runtime.accessors.AListAccessor;
@@ -16,9 +17,20 @@
public class ACastVisitor implements IBinaryAccessorVisitor<Void, Triple<IBinaryAccessor, IAType, Boolean>> {
private Map<IBinaryAccessor, ARecordCaster> raccessorToCaster = new HashMap<IBinaryAccessor, ARecordCaster>();
+ private Map<IBinaryAccessor, AListCaster> laccessorToCaster = new HashMap<IBinaryAccessor, AListCaster>();
@Override
- public Void visit(AListAccessor accessor, Triple<IBinaryAccessor, IAType, Boolean> arg) {
+ public Void visit(AListAccessor accessor, Triple<IBinaryAccessor, IAType, Boolean> arg) throws AsterixException {
+ AListCaster caster = laccessorToCaster.get(accessor);
+ if (caster == null) {
+ caster = new AListCaster();
+ laccessorToCaster.put(accessor, caster);
+ }
+ try {
+ caster.castList(accessor, arg.first, (AbstractCollectionType) arg.second, this);
+ } catch (Exception e) {
+ throw new AsterixException(e);
+ }
return null;
}
@@ -39,7 +51,7 @@
@Override
public Void visit(AFlatValueAccessor accessor, Triple<IBinaryAccessor, IAType, Boolean> arg) {
- //set the pointer for result
+ // set the pointer for result
arg.first.reset(accessor.getBytes(), accessor.getStartIndex(), accessor.getLength());
return null;
}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/AListCaster.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/AListCaster.java
new file mode 100644
index 0000000..776c359
--- /dev/null
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/AListCaster.java
@@ -0,0 +1,86 @@
+package edu.uci.ics.asterix.runtime.accessors.cast;
+
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import edu.uci.ics.asterix.builders.OrderedListBuilder;
+import edu.uci.ics.asterix.builders.UnorderedListBuilder;
+import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.asterix.om.types.AOrderedListType;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.AUnorderedListType;
+import edu.uci.ics.asterix.om.types.AbstractCollectionType;
+import edu.uci.ics.asterix.om.types.EnumDeserializer;
+import edu.uci.ics.asterix.om.types.IAType;
+import edu.uci.ics.asterix.runtime.accessors.AFlatValueAccessor;
+import edu.uci.ics.asterix.runtime.accessors.AListAccessor;
+import edu.uci.ics.asterix.runtime.accessors.base.DefaultOpenFieldType;
+import edu.uci.ics.asterix.runtime.accessors.base.IBinaryAccessor;
+import edu.uci.ics.asterix.runtime.util.ResettableByteArrayOutputStream;
+import edu.uci.ics.hyracks.algebricks.common.utils.Triple;
+
+class AListCaster {
+
+ private IAType reqItemType;
+ private IBinaryAccessor itemTempReference = AFlatValueAccessor.FACTORY.createElement(null);
+ private Triple<IBinaryAccessor, IAType, Boolean> itemVisitorArg = new Triple<IBinaryAccessor, IAType, Boolean>(
+ itemTempReference, null, null);
+
+ private UnorderedListBuilder unOrderedListBuilder = new UnorderedListBuilder();
+ private OrderedListBuilder orderedListBuilder = new OrderedListBuilder();
+
+ private byte[] dataBuffer = new byte[32768];
+ private ResettableByteArrayOutputStream dataBos = new ResettableByteArrayOutputStream();
+ private DataOutput dataDos = new DataOutputStream(dataBos);
+
+ public AListCaster() {
+
+ }
+
+ public void castList(AListAccessor listAccessor, IBinaryAccessor resultAccessor, AbstractCollectionType reqType,
+ ACastVisitor visitor) throws IOException, AsterixException {
+ if (reqType.getTypeTag().equals(ATypeTag.UNORDEREDLIST)) {
+ unOrderedListBuilder.reset((AUnorderedListType) reqType);
+ }
+ if (reqType.getTypeTag().equals(ATypeTag.ORDEREDLIST)) {
+ orderedListBuilder.reset((AOrderedListType) reqType);
+ }
+ dataBos.setByteArray(dataBuffer, 0);
+
+ List<IBinaryAccessor> itemTags = listAccessor.getItemTags();
+ List<IBinaryAccessor> items = listAccessor.getItems();
+
+ int start = dataBos.size();
+ for (int i = 0; i < items.size(); i++) {
+ IBinaryAccessor itemTypeTag = itemTags.get(i);
+ IBinaryAccessor item = items.get(i);
+ ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(itemTypeTag.getBytes()[itemTypeTag
+ .getStartIndex()]);
+ if (reqItemType == null || reqItemType.getTypeTag().equals(ATypeTag.ANY)) {
+ itemVisitorArg.second = DefaultOpenFieldType.getDefaultOpenFieldType(typeTag);
+ item.accept(visitor, itemVisitorArg);
+ } else {
+ if (typeTag != reqItemType.getTypeTag())
+ throw new AsterixException("mismatched item type");
+ itemVisitorArg.second = reqItemType;
+ item.accept(visitor, itemVisitorArg);
+ }
+ if (reqType.getTypeTag().equals(ATypeTag.ORDEREDLIST)) {
+ orderedListBuilder.addItem(itemVisitorArg.first);
+ }
+ if (reqType.getTypeTag().equals(ATypeTag.UNORDEREDLIST)) {
+ unOrderedListBuilder.addItem(itemVisitorArg.first);
+ }
+ }
+ if (reqType.getTypeTag().equals(ATypeTag.ORDEREDLIST)) {
+ orderedListBuilder.write(dataDos, true);
+ }
+ if (reqType.getTypeTag().equals(ATypeTag.UNORDEREDLIST)) {
+ unOrderedListBuilder.write(dataDos, true);
+ }
+ int end = dataBos.size();
+ resultAccessor.reset(dataBuffer, start, end - start);
+ }
+}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ARecordCaster.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ARecordCaster.java
index 8face9c..a4efa58 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ARecordCaster.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/accessors/cast/ARecordCaster.java
@@ -249,8 +249,6 @@
}
field.accept(visitor, nestedVisitorArg);
recBuilder.addField(i, nestedVisitorArg.first);
- //reset the req type
- nestedVisitorArg.second = null;
}
// write the open part
@@ -262,13 +260,9 @@
ATypeTag typeTag = EnumDeserializer.ATYPETAGDESERIALIZER
.deserialize(fieldTypeTag.getBytes()[fieldTypeTag.getStartIndex()]);
- if (typeTag.equals(ATypeTag.RECORD))
- nestedVisitorArg.second = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
+ nestedVisitorArg.second = DefaultOpenFieldType.getDefaultOpenFieldType(typeTag);
field.accept(visitor, nestedVisitorArg);
recBuilder.addField(name, nestedVisitorArg.first);
-
- //reset the req type
- nestedVisitorArg.second = null;
}
}
recBuilder.write(output, true);