test recursive nested record-within-list

git-svn-id: https://asterixdb.googlecode.com/svn/branches/asterix_opentype@334 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 afb01ef..b79be86 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
@@ -110,7 +110,8 @@
                         ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) expr;
                         if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
                             return false;
-                        rewriteRecordFuncExpr(funcExpr, requiredRecordType, inputRecordType);
+                        IVariableTypeEnvironment assignEnv = oldAssignOperator.computeOutputTypeEnvironment(context);
+                        rewriteFuncExpr(funcExpr, requiredRecordType, inputRecordType, assignEnv);
                     }
                     context.computeAndSetTypeEnvironmentForOperator(originalAssign);
                 }
@@ -123,27 +124,28 @@
         return true;
     }
 
+    private void rewriteFuncExpr(ScalarFunctionCallExpression funcExpr, IAType reqType, IAType inputType,
+            IVariableTypeEnvironment env) throws AlgebricksException {
+        if (funcExpr.getFunctionIdentifier() == AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR) {
+            rewriteListFuncExpr(funcExpr, (AbstractCollectionType) reqType, (AbstractCollectionType) inputType, env);
+        }
+        if (funcExpr.getFunctionIdentifier() == AsterixBuiltinFunctions.UNORDERED_LIST_CONSTRUCTOR) {
+            rewriteListFuncExpr(funcExpr, (AbstractCollectionType) reqType, (AbstractCollectionType) inputType, env);
+        } else if (reqType.getTypeTag().equals(ATypeTag.RECORD)) {
+            rewriteRecordFuncExpr(funcExpr, (ARecordType) reqType, (ARecordType) inputType, env);
+        }
+    }
+
     private void rewriteRecordFuncExpr(ScalarFunctionCallExpression funcExpr, ARecordType requiredRecordType,
-            ARecordType inputRecordType) {
+            ARecordType inputRecordType, IVariableTypeEnvironment env) throws AlgebricksException {
         if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
             return;
         TypeComputerUtilities.setRequiredAndInputTypes(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);
-        }
+        staticRecordTypeCast(funcExpr, requiredRecordType, inputRecordType, env);
     }
 
     private void rewriteListFuncExpr(ScalarFunctionCallExpression funcExpr, AbstractCollectionType requiredListType,
-            AbstractCollectionType inputListType) {
+            AbstractCollectionType inputListType, IVariableTypeEnvironment env) throws AlgebricksException {
         if (TypeComputerUtilities.getRequiredType(funcExpr) != null)
             return;
 
@@ -158,12 +160,19 @@
             ILogicalExpression arg = args.get(j).getValue();
             if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
                 ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) arg;
-                rewriteFuncExpr(argFunc, itemType, inputItemType);
+                IAType currentItemType = (IAType) env.getType(argFunc);
+                if (inputItemType == null || inputItemType == BuiltinType.ANY) {
+                    currentItemType = (IAType) env.getType(argFunc);
+                    rewriteFuncExpr(argFunc, itemType, currentItemType, env);
+                } else {
+                    rewriteFuncExpr(argFunc, itemType, inputItemType, env);
+                }
             }
         }
     }
 
-    private void staticRecordTypeCast(ScalarFunctionCallExpression func, ARecordType reqType, ARecordType inputType) {
+    private void staticRecordTypeCast(ScalarFunctionCallExpression func, ARecordType reqType, ARecordType inputType,
+            IVariableTypeEnvironment env) throws AlgebricksException {
         IAType[] reqFieldTypes = reqType.getFieldTypes();
         String[] reqFieldNames = reqType.getFieldNames();
         IAType[] inputFieldTypes = inputType.getFieldTypes();
@@ -186,6 +195,9 @@
             String fieldName = inputFieldNames[i];
             IAType fieldType = inputFieldTypes[i];
 
+            if (2 * i + 1 > func.getArguments().size())
+                break;
+
             ILogicalExpression arg = func.getArguments().get(2 * i + 1).getValue();
             matched = false;
             for (int j = 0; j < reqFieldNames.length; j++) {
@@ -199,7 +211,7 @@
 
                         if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
                             ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
-                            rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
+                            rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
                         }
                         break;
                     }
@@ -218,7 +230,7 @@
                             // rewrite record expr
                             if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
                                 ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
-                                rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
+                                rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
                             }
                             break;
                         }
@@ -227,7 +239,7 @@
                     // match the record field: need cast
                     if (arg.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
                         ScalarFunctionCallExpression scalarFunc = (ScalarFunctionCallExpression) arg;
-                        rewriteFuncExpr(scalarFunc, reqFieldType, fieldType);
+                        rewriteFuncExpr(scalarFunc, reqFieldType, fieldType, env);
                         fieldPermutation[j] = i;
                         openFields[i] = false;
                         matched = true;
@@ -319,9 +331,9 @@
                     if (inputFieldTypes[i].getTypeTag() == ATypeTag.UNORDEREDLIST) {
                         reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
                     }
-                    if (TypeComputerUtilities.getRequiredType((AbstractFunctionCallExpression)argExpr) == null) {
+                    if (TypeComputerUtilities.getRequiredType((AbstractFunctionCallExpression) argExpr) == null) {
                         ScalarFunctionCallExpression argFunc = (ScalarFunctionCallExpression) argExpr;
-                        rewriteFuncExpr(argFunc, reqFieldType, inputFieldTypes[i]);
+                        rewriteFuncExpr(argFunc, reqFieldType, inputFieldTypes[i], env);
                     }
                 }
                 arguments.add(fExprRef);
diff --git a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o-recursive.aql b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o-recursive.aql
index 5b92f28..6c8264f 100644
--- a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o-recursive.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-c2o-recursive.aql
@@ -13,11 +13,16 @@
   street: string,
   city: string
 }
+create type Dept as open{
+	name: string,
+	id: int32
+}
 
 create type testtype as closed {
   name: string,
   id: string,
-  address: AddressType?
+  address: AddressType?,
+  department: {{Dept}}?
 }
 
 create type testtype2 as open {
@@ -30,7 +35,7 @@
 create dataset testds2(testtype2) partitioned by key id;
 
 insert into dataset testds (
-{ "id": "001", "name": "Person One", "address": {"street": "3019 DBH",  "city": "Irvine", "zip": 92697} }
+{ "id": "001", "name": "Person One", "address": {"street": "3019 DBH",  "city": "Irvine", "zip": 92697}, "department": {{ {"name":"CS", "id":299, "review":5}, {"name":"EE", "id":399} }} }
 );
 
 insert into dataset testds (
diff --git a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c-recursive.aql b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c-recursive.aql
index 493b2cc..2070e20 100644
--- a/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c-recursive.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/dml/opentype-o2c-recursive.aql
@@ -14,6 +14,11 @@
   city: string
 }
 
+create type Dept as closed{
+	name: string,
+	id: int32
+}
+
 create type testtype as open {
   name: string,
   id: string
@@ -22,7 +27,8 @@
 create type testtype2 as closed {
   name: string,
   id: string,
-  address: AddressType?
+  address: AddressType?,
+  department: {{Dept}}?
 }
 
 create dataset testds(testtype) partitioned by key id;
@@ -30,7 +36,7 @@
 create dataset testds2(testtype2) partitioned by key id;
 
 insert into dataset testds (
-{ "id": "001", "name": "Person One", "address": {"street": "3019 DBH",  "city": "Irvine", "zip": 92697} }
+{ "id": "001", "name": "Person One", "address": {"street": "3019 DBH",  "city": "Irvine", "zip": 92697}, "department": {{ {"name":"CS", "id":299}, {"name":"EE", "id":399} }} }
 );
 
 insert into dataset testds (
diff --git a/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o-recursive.adm b/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o-recursive.adm
index 8088fff..60a389c 100644
--- a/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o-recursive.adm
+++ b/asterix-app/src/test/resources/runtimets/results/dml/opentype-c2o-recursive.adm
@@ -1,4 +1,4 @@
-{ "name": "Person One", "id": "001", "address": { "street": "3019 DBH", "city": "Irvine", "zip": 92697 } }
-{ "name": "Person Two", "id": "002", "address": null }
-{ "name": "Person Three", "id": "003", "address": { "street": "2019 DBH", "city": "Irvine" } }
-{ "name": "Person Four", "id": "004", "address": { "street": "1019 DBH", "city": "irvine", "property": { "zip": 92697, "review": "positive" } } }
+{ "name": "Person One", "id": "001", "address": { "street": "3019 DBH", "city": "Irvine", "zip": 92697 }, "department": {{ { "name": "CS", "id": 299, "review": 5 }, { "name": "EE", "id": 399 } }} }
+{ "name": "Person Two", "id": "002", "address": null, "department": null }
+{ "name": "Person Three", "id": "003", "address": { "street": "2019 DBH", "city": "Irvine" }, "department": null }
+{ "name": "Person Four", "id": "004", "address": { "street": "1019 DBH", "city": "irvine", "property": { "zip": 92697, "review": "positive" } }, "department": null }
diff --git a/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c-recursive.adm b/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c-recursive.adm
index 8088fff..c67c3cb 100644
--- a/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c-recursive.adm
+++ b/asterix-app/src/test/resources/runtimets/results/dml/opentype-o2c-recursive.adm
@@ -1,4 +1,4 @@
-{ "name": "Person One", "id": "001", "address": { "street": "3019 DBH", "city": "Irvine", "zip": 92697 } }
-{ "name": "Person Two", "id": "002", "address": null }
-{ "name": "Person Three", "id": "003", "address": { "street": "2019 DBH", "city": "Irvine" } }
-{ "name": "Person Four", "id": "004", "address": { "street": "1019 DBH", "city": "irvine", "property": { "zip": 92697, "review": "positive" } } }
+{ "name": "Person One", "id": "001", "address": { "street": "3019 DBH", "city": "Irvine", "zip": 92697 }, "department": {{ { "name": "CS", "id": 299 }, { "name": "EE", "id": 399 } }} }
+{ "name": "Person Two", "id": "002", "address": null, "department": null }
+{ "name": "Person Three", "id": "003", "address": { "street": "2019 DBH", "city": "Irvine" }, "department": null }
+{ "name": "Person Four", "id": "004", "address": { "street": "1019 DBH", "city": "irvine", "property": { "zip": 92697, "review": "positive" } }, "department": null }