Yingyi Bu has uploaded a new change for review.

  https://asterix-gerrit.ics.uci.edu/703

Change subject: ASTERIXDB-865: fix query compilation for if-else expression.
......................................................................

ASTERIXDB-865: fix query compilation for if-else expression.

Change-Id: I80e7995e814180fe567818263c79493901af284c
---
M 
asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CheckFilterExpressionTypeRule.java
M 
asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
M 
asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
A asterix-app/data/page_views.adm
A asterix-app/src/test/resources/optimizerts/queries/query-ASTERIXDB-1203.aql
A asterix-app/src/test/resources/optimizerts/queries/query-ASTERIXDB-865.aql
A asterix-app/src/test/resources/optimizerts/results/query-ASTERIXDB-1203.plan
A asterix-app/src/test/resources/optimizerts/results/query-ASTERIXDB-865.plan
M 
asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-1.plan
M 
asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-2.plan
A 
asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.1.ddl.aql
A 
asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.2.update.aql
A 
asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.3.query.aql
A 
asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.1.ddl.aql
A 
asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.2.update.aql
A 
asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.3.query.aql
A 
asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.1.adm
A 
asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.1.adm
M asterix-app/src/test/resources/runtimets/testsuite.xml
M 
asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeCompatibilityChecker.java
20 files changed, 542 insertions(+), 90 deletions(-)


  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/03/703/1

diff --git 
a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CheckFilterExpressionTypeRule.java
 
b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CheckFilterExpressionTypeRule.java
index 3eadba3..cda7619 100644
--- 
a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CheckFilterExpressionTypeRule.java
+++ 
b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/CheckFilterExpressionTypeRule.java
@@ -19,12 +19,11 @@
 
 package org.apache.asterix.optimizer.rules;
 
-import org.apache.commons.lang3.mutable.Mutable;
-
 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.util.NonTaggedFormatUtil;
+import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
@@ -45,7 +44,8 @@
 public class CheckFilterExpressionTypeRule implements IAlgebraicRewriteRule {
 
     @Override
-    public boolean rewritePre(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context) throws AlgebricksException {
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, 
IOptimizationContext context)
+            throws AlgebricksException {
         return false;
     }
 
@@ -62,8 +62,8 @@
         IAType condType = (IAType) env.getType(condition);
         if (condType.getTypeTag() != ATypeTag.BOOLEAN && condType.getTypeTag() 
!= ATypeTag.ANY
                 && !isPossibleBoolean(condType)) {
-            throw new AlgebricksException("The select condition " + 
condition.toString()
-                    + " should be of the boolean type.");
+            throw new AlgebricksException(
+                    "The select condition " + condition.toString() + " should 
be of the boolean type.");
         }
         return false;
     }
diff --git 
a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
 
b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
index a9b8e99..3dc854b 100644
--- 
a/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
+++ 
b/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/PushFieldAccessRule.java
@@ -63,6 +63,7 @@
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.GroupByOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.NestedTupleSourceOperator;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.visitors.VariableUtilities;
+import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
 import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
 
 public class PushFieldAccessRule implements IAlgebraicRewriteRule {
@@ -190,6 +191,9 @@
                 && !(op2.getOperatorTag() == LogicalOperatorTag.SELECT && 
isAccessToIndexedField(access, context))) {
             return false;
         }
+        if (!OperatorPropertiesUtil.canFieldAccessBePushedThroughSelect(op2)) {
+            return false;
+        }
         if (tryingToPushThroughSelectionWithSameDataSource(access, op2)) {
             return false;
         }
diff --git 
a/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
 
b/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index 28de56b..a26aed9 100644
--- 
a/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ 
b/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -21,6 +21,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -110,6 +111,7 @@
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.StatefulFunctionCallExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
@@ -715,50 +717,90 @@
         // on top of which there is a selection whose condition is varCond.
         // Similarly, we create one subplan for the "else" branch, in which the
         // selection is not(varCond).
-        // Finally, we concatenate the results. (??)
+        // Finally, we concatenate the results.
 
         Pair<ILogicalOperator, LogicalVariable> pCond = 
ifexpr.getCondExpr().accept(this, tupSource);
         ILogicalOperator opCond = pCond.first;
         LogicalVariable varCond = pCond.second;
 
-        SubplanOperator sp = new SubplanOperator();
-
-        Mutable<ILogicalOperator> nestedSource = new 
MutableObject<ILogicalOperator>(
-                new NestedTupleSourceOperator(new 
MutableObject<ILogicalOperator>(sp)));
-
-        // Enters/exists subplan for the then-expr and the else-expr 
respectively.
+        //Creates a subplan for the "then" branch.
         context.enterSubplan();
-        Pair<ILogicalOperator, LogicalVariable> pThen = 
ifexpr.getThenExpr().accept(this, nestedSource);
-        SelectOperator sel1 = new SelectOperator(
-                new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(varCond)), false, null);
-        sel1.getInputs().add(new MutableObject<ILogicalOperator>(pThen.first));
+        SubplanOperator spThen = new SubplanOperator();
+        spThen.getInputs().add(new MutableObject<ILogicalOperator>(opCond));
+        Mutable<ILogicalOperator> nestedSourceThen = new 
MutableObject<ILogicalOperator>(
+                new NestedTupleSourceOperator(new 
MutableObject<ILogicalOperator>(spThen)));
+        List<Mutable<ILogicalExpression>> selectArguments = new ArrayList<>();
+        selectArguments.add(new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(varCond)));
+        selectArguments.add(new 
MutableObject<ILogicalExpression>(ConstantExpression.TRUE));
+        AbstractFunctionCallExpression selectExpr = new 
StatefulFunctionCallExpression(
+                FunctionUtil.getFunctionInfo(AlgebricksBuiltinFunctions.EQ), 
null, selectArguments);
+        SelectOperator sel1 = new SelectOperator(new 
MutableObject<ILogicalExpression>(selectExpr), false, null);
+        sel1.getInputs().add(nestedSourceThen);
+        Pair<ILogicalOperator, LogicalVariable> pThen = 
ifexpr.getThenExpr().accept(this,
+                new MutableObject<ILogicalOperator>(sel1));
+        LogicalVariable thenVar = context.newVar();
+        AggregateOperator thenAgg = new 
AggregateOperator(Collections.singletonList(thenVar),
+                Collections.singletonList(new 
MutableObject<ILogicalExpression>(new AggregateFunctionCallExpression(
+                        
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.LISTIFY), false,
+                        Collections.singletonList(new 
MutableObject<ILogicalExpression>(
+                                new 
VariableReferenceExpression(pThen.second)))))));
+        thenAgg.getInputs().add(new 
MutableObject<ILogicalOperator>(pThen.first));
+        ILogicalPlan planForThenBranch = new ALogicalPlanImpl(new 
MutableObject<ILogicalOperator>(thenAgg));
+        spThen.getNestedPlans().add(planForThenBranch);
         context.exitSubplan();
 
+        // Creates a subplan for the "else" branch.
         context.enterSubplan();
-        Pair<ILogicalOperator, LogicalVariable> pElse = 
ifexpr.getElseExpr().accept(this, nestedSource);
-        AbstractFunctionCallExpression notVarCond = new 
ScalarFunctionCallExpression(
-                FunctionUtil.getFunctionInfo(AlgebricksBuiltinFunctions.NOT),
-                new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(varCond)));
+        SubplanOperator spElse = new SubplanOperator();
+        spElse.getInputs().add(new MutableObject<ILogicalOperator>(spThen));
+        Mutable<ILogicalOperator> nestedSourceElse = new 
MutableObject<ILogicalOperator>(
+                new NestedTupleSourceOperator(new 
MutableObject<ILogicalOperator>(spElse)));
+        AbstractFunctionCallExpression notVarCond = new 
StatefulFunctionCallExpression(
+                FunctionUtil.getFunctionInfo(AlgebricksBuiltinFunctions.NOT), 
null, Collections.singletonList(
+                        new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(varCond))));
         SelectOperator sel2 = new SelectOperator(new 
MutableObject<ILogicalExpression>(notVarCond), false, null);
-        sel2.getInputs().add(new MutableObject<ILogicalOperator>(pElse.first));
+        sel2.getInputs().add(nestedSourceElse);
+        LogicalVariable elseVar = context.newVar();
+        Pair<ILogicalOperator, LogicalVariable> pElse = 
ifexpr.getElseExpr().accept(this,
+                new MutableObject<ILogicalOperator>(sel2));
+        AggregateOperator elseAgg = new 
AggregateOperator(Collections.singletonList(elseVar),
+                Collections.singletonList(new 
MutableObject<ILogicalExpression>(new AggregateFunctionCallExpression(
+                        
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.LISTIFY), false,
+                        Collections.singletonList(new 
MutableObject<ILogicalExpression>(
+                                new 
VariableReferenceExpression(pElse.second)))))));
+        elseAgg.getInputs().add(new 
MutableObject<ILogicalOperator>(pElse.first));
+        ILogicalPlan planForElseBranch = new ALogicalPlanImpl(new 
MutableObject<ILogicalOperator>(elseAgg));
+        spElse.getNestedPlans().add(planForElseBranch);
         context.exitSubplan();
 
-        ILogicalPlan p1 = new ALogicalPlanImpl(new 
MutableObject<ILogicalOperator>(sel1));
-        sp.getNestedPlans().add(p1);
-        ILogicalPlan p2 = new ALogicalPlanImpl(new 
MutableObject<ILogicalOperator>(sel2));
-        sp.getNestedPlans().add(p2);
+        // Uses switch-case function to select the results of two branches.
+        LogicalVariable selectVar = context.newVar();
+        List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
+        arguments.add(new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(varCond)));
+        arguments.add(new 
MutableObject<ILogicalExpression>(ConstantExpression.TRUE));
+        arguments.add(new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(thenVar)));
+        arguments.add(new 
MutableObject<ILogicalExpression>(ConstantExpression.FALSE));
+        arguments.add(new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(elseVar)));
+        AbstractFunctionCallExpression swithCaseExpr = new 
ScalarFunctionCallExpression(
+                
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.SWITCH_CASE), arguments);
+        AssignOperator assignOp = new AssignOperator(selectVar, new 
MutableObject<ILogicalExpression>(swithCaseExpr));
+        assignOp.getInputs().add(new MutableObject<ILogicalOperator>(spElse));
 
-        Mutable<ILogicalOperator> opCondRef = new 
MutableObject<ILogicalOperator>(opCond);
-        sp.getInputs().add(opCondRef);
+        // Unnests the result.
+        LogicalVariable unnestVar = context.newVar();
+        UnnestOperator unnestOp = new UnnestOperator(unnestVar,
+                new MutableObject<ILogicalExpression>(new 
UnnestingFunctionCallExpression(
+                        
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.SCAN_COLLECTION),
+                        Collections.singletonList(
+                                new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(selectVar))))));
+        unnestOp.getInputs().add(new 
MutableObject<ILogicalOperator>(assignOp));
 
-        LogicalVariable resV = context.newVar();
-        AbstractFunctionCallExpression concatNonNull = new 
ScalarFunctionCallExpression(
-                
FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CONCAT_NON_NULL),
-                new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(pThen.second)),
-                new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(pElse.second)));
-        AssignOperator a = new AssignOperator(resV, new 
MutableObject<ILogicalExpression>(concatNonNull));
-        a.getInputs().add(new MutableObject<ILogicalOperator>(sp));
-        return new Pair<ILogicalOperator, LogicalVariable>(a, resV);
+        // Produces the final result.
+        LogicalVariable resultVar = context.newVar();
+        AssignOperator finalAssignOp = new AssignOperator(resultVar,
+                new MutableObject<ILogicalExpression>(new 
VariableReferenceExpression(unnestVar)));
+        finalAssignOp.getInputs().add(new 
MutableObject<ILogicalOperator>(unnestOp));
+        return new Pair<ILogicalOperator, LogicalVariable>(finalAssignOp, 
resultVar);
     }
 
     @Override
@@ -1239,7 +1281,7 @@
         return k == Kind.LITERAL_EXPRESSION || k == 
Kind.LIST_CONSTRUCTOR_EXPRESSION
                 || k == Kind.RECORD_CONSTRUCTOR_EXPRESSION || k == 
Kind.VARIABLE_EXPRESSION || k == Kind.CALL_EXPRESSION
                 || k == Kind.OP_EXPRESSION || k == 
Kind.FIELD_ACCESSOR_EXPRESSION || k == Kind.INDEX_ACCESSOR_EXPRESSION
-                || k == Kind.UNARY_EXPRESSION;
+                || k == Kind.UNARY_EXPRESSION || k == Kind.IF_EXPRESSION;
     }
 
     protected <T> List<T> mkSingletonArrayList(T item) {
diff --git a/asterix-app/data/page_views.adm b/asterix-app/data/page_views.adm
new file mode 100644
index 0000000..1316638
--- /dev/null
+++ b/asterix-app/data/page_views.adm
@@ -0,0 +1,9 @@
+{"user":"keren", "action": 1, "timespent": 2, "query_term":"qt", "ip_addr": 3, 
"timestamp": 4, "estimated_revenue": 5.0, 
+"page_info" : { "a":"aaa","b":"bbb" }, 
+"page_links": {{  
{"b":"ccc","d":"ddd","e":"eee"},{"b":"fff","g":"ggg","h":"hhh"} }} 
+}
+{"user":"keren1", "action": 2, "timespent": 2, "query_term":"qt", "ip_addr": 
3, "timestamp": 4, "estimated_revenue": 5.0, 
+"page_info" : { "a":"aaa","b":"bbb" }, 
+"page_links": {{  
{"c":"ccc","d":"ddd","a":"eee"},{"f":"fff","g":"ggg","b":"bbb"} }} 
+}
+
diff --git 
a/asterix-app/src/test/resources/optimizerts/queries/query-ASTERIXDB-1203.aql 
b/asterix-app/src/test/resources/optimizerts/queries/query-ASTERIXDB-1203.aql
new file mode 100644
index 0000000..e2f31ec
--- /dev/null
+++ 
b/asterix-app/src/test/resources/optimizerts/queries/query-ASTERIXDB-1203.aql
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+/* This test is to verify the fix for ASTERIXDB-1203. */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type ifType as open
+{
+    id: int32
+}
+
+create dataset ifds(ifType)
+primary key id;
+
+for $x in dataset ifds
+where ( 
+if ($x.names.count = "1") then
+   $x.names.name.firstName = "wail"
+else
+   (some $v in $x.names.name satisfies $v.firstName = "wail")
+)
+return $x;
diff --git 
a/asterix-app/src/test/resources/optimizerts/queries/query-ASTERIXDB-865.aql 
b/asterix-app/src/test/resources/optimizerts/queries/query-ASTERIXDB-865.aql
new file mode 100644
index 0000000..99ce0c7
--- /dev/null
+++ b/asterix-app/src/test/resources/optimizerts/queries/query-ASTERIXDB-865.aql
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/* This test is to verify the fix for ASTERIXDB-865. */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type page_info_type as open {}
+
+create type page_views_type as closed {
+    user: string,
+    action: int32,
+    timespent: int32,
+    query_term: string,
+    ip_addr: int32, 
+    timestamp: int32,
+    estimated_revenue: double,
+    page_info: page_info_type,
+    page_links: {{ page_info_type}}
+}
+
+create dataset page_views(page_views_type)
+primary key user;
+
+for $t in dataset page_views
+let $header := if ($t.action = 1)
+    then [ $t.page_info.a ]
+    else 
+        for $pl in $t.page_links
+        return $pl.b
+for $h in $header
+return
+{ "user": $t.user, "header": $h }
+;
diff --git 
a/asterix-app/src/test/resources/optimizerts/results/query-ASTERIXDB-1203.plan 
b/asterix-app/src/test/resources/optimizerts/results/query-ASTERIXDB-1203.plan
new file mode 100644
index 0000000..9dc7a8a
--- /dev/null
+++ 
b/asterix-app/src/test/resources/optimizerts/results/query-ASTERIXDB-1203.plan
@@ -0,0 +1,36 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- STREAM_SELECT  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- UNNEST  |PARTITIONED|
+            -- STREAM_PROJECT  |PARTITIONED|
+              -- ASSIGN  |PARTITIONED|
+                -- SUBPLAN  |PARTITIONED|
+                        {
+                          -- AGGREGATE  |LOCAL|
+                            -- AGGREGATE  |LOCAL|
+                              -- STREAM_SELECT  |LOCAL|
+                                -- ASSIGN  |LOCAL|
+                                  -- UNNEST  |LOCAL|
+                                    -- ASSIGN  |LOCAL|
+                                      -- ASSIGN  |LOCAL|
+                                        -- STREAM_SELECT  |LOCAL|
+                                          -- NESTED_TUPLE_SOURCE  |LOCAL|
+                        }
+                  -- SUBPLAN  |PARTITIONED|
+                          {
+                            -- AGGREGATE  |LOCAL|
+                              -- ASSIGN  |LOCAL|
+                                -- ASSIGN  |LOCAL|
+                                  -- ASSIGN  |LOCAL|
+                                    -- ASSIGN  |LOCAL|
+                                      -- STREAM_SELECT  |LOCAL|
+                                        -- NESTED_TUPLE_SOURCE  |LOCAL|
+                          }
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterix-app/src/test/resources/optimizerts/results/query-ASTERIXDB-865.plan 
b/asterix-app/src/test/resources/optimizerts/results/query-ASTERIXDB-865.plan
new file mode 100644
index 0000000..6ff5cee
--- /dev/null
+++ 
b/asterix-app/src/test/resources/optimizerts/results/query-ASTERIXDB-865.plan
@@ -0,0 +1,35 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- UNNEST  |PARTITIONED|
+            -- STREAM_PROJECT  |PARTITIONED|
+              -- UNNEST  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- ASSIGN  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- SUBPLAN  |PARTITIONED|
+                              {
+                                -- AGGREGATE  |LOCAL|
+                                  -- AGGREGATE  |LOCAL|
+                                    -- ASSIGN  |LOCAL|
+                                      -- UNNEST  |LOCAL|
+                                        -- ASSIGN  |LOCAL|
+                                          -- STREAM_SELECT  |LOCAL|
+                                            -- NESTED_TUPLE_SOURCE  |LOCAL|
+                              }
+                        -- SUBPLAN  |PARTITIONED|
+                                {
+                                  -- AGGREGATE  |LOCAL|
+                                    -- ASSIGN  |LOCAL|
+                                      -- ASSIGN  |LOCAL|
+                                        -- ASSIGN  |LOCAL|
+                                          -- STREAM_SELECT  |LOCAL|
+                                            -- NESTED_TUPLE_SOURCE  |LOCAL|
+                                }
+                          -- ASSIGN  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- DATASOURCE_SCAN  |PARTITIONED|
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
diff --git 
a/asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-1.plan
 
b/asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-1.plan
index ebbee79..3664ed8 100644
--- 
a/asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-1.plan
+++ 
b/asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-1.plan
@@ -23,23 +23,25 @@
                                 -- ASSIGN  |UNPARTITIONED|
                                   -- STREAM_PROJECT  |UNPARTITIONED|
                                     -- UNNEST  |UNPARTITIONED|
-                                      -- SUBPLAN  |UNPARTITIONED|
-                                              {
-                                                -- SUBPLAN  |UNPARTITIONED|
-                                                        {
-                                                          -- AGGREGATE  
|UNPARTITIONED|
-                                                            -- STREAM_SELECT  
|UNPARTITIONED|
-                                                              -- UNNEST  
|UNPARTITIONED|
-                                                                -- SUBPLAN  
|UNPARTITIONED|
-                                                                        {
-                                                                          -- 
AGGREGATE  |UNPARTITIONED|
-                                                                            -- 
IN_MEMORY_STABLE_SORT [$$21(ASC)]  |UNPARTITIONED|
-                                                                              
-- UNNEST  |UNPARTITIONED|
-                                                                               
 -- NESTED_TUPLE_SOURCE  |UNPARTITIONED|
-                                                                        }
-                                                                  -- 
NESTED_TUPLE_SOURCE  |UNPARTITIONED|
-                                                        }
-                                                  -- NESTED_TUPLE_SOURCE  
|UNPARTITIONED|
-                                              }
-                                        -- ASSIGN  |UNPARTITIONED|
-                                          -- EMPTY_TUPLE_SOURCE  
|UNPARTITIONED|
+                                      -- STREAM_PROJECT  |UNPARTITIONED|
+                                        -- SUBPLAN  |UNPARTITIONED|
+                                                {
+                                                  -- ASSIGN  |UNPARTITIONED|
+                                                    -- SUBPLAN  |UNPARTITIONED|
+                                                            {
+                                                              -- AGGREGATE  
|UNPARTITIONED|
+                                                                -- 
STREAM_SELECT  |UNPARTITIONED|
+                                                                  -- UNNEST  
|UNPARTITIONED|
+                                                                    -- SUBPLAN 
 |UNPARTITIONED|
+                                                                            {
+                                                                              
-- AGGREGATE  |UNPARTITIONED|
+                                                                               
 -- IN_MEMORY_STABLE_SORT [$$21(ASC)]  |UNPARTITIONED|
+                                                                               
   -- UNNEST  |UNPARTITIONED|
+                                                                               
     -- NESTED_TUPLE_SOURCE  |UNPARTITIONED|
+                                                                            }
+                                                                      -- 
NESTED_TUPLE_SOURCE  |UNPARTITIONED|
+                                                            }
+                                                      -- NESTED_TUPLE_SOURCE  
|UNPARTITIONED|
+                                                }
+                                          -- ASSIGN  |UNPARTITIONED|
+                                            -- EMPTY_TUPLE_SOURCE  
|UNPARTITIONED|
diff --git 
a/asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-2.plan
 
b/asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-2.plan
index a6e7496..caf4c48 100644
--- 
a/asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-2.plan
+++ 
b/asterix-app/src/test/resources/optimizerts/results/udfs/query-ASTERIXDB-1308-2.plan
@@ -9,22 +9,23 @@
                             {
                               -- SUBPLAN  |LOCAL|
                                       {
-                                        -- SUBPLAN  |LOCAL|
-                                                {
-                                                  -- AGGREGATE  |LOCAL|
-                                                    -- STREAM_SELECT  |LOCAL|
-                                                      -- ASSIGN  |LOCAL|
-                                                        -- UNNEST  |LOCAL|
-                                                          -- SUBPLAN  |LOCAL|
-                                                                  {
-                                                                    -- 
AGGREGATE  |LOCAL|
-                                                                      -- 
IN_MEMORY_STABLE_SORT [$$38(ASC)]  |LOCAL|
-                                                                        -- 
UNNEST  |LOCAL|
-                                                                          -- 
NESTED_TUPLE_SOURCE  |LOCAL|
-                                                                  }
-                                                            -- 
NESTED_TUPLE_SOURCE  |LOCAL|
-                                                }
-                                          -- NESTED_TUPLE_SOURCE  |LOCAL|
+                                        -- ASSIGN  |LOCAL|
+                                          -- SUBPLAN  |LOCAL|
+                                                  {
+                                                    -- AGGREGATE  |LOCAL|
+                                                      -- STREAM_SELECT  |LOCAL|
+                                                        -- ASSIGN  |LOCAL|
+                                                          -- UNNEST  |LOCAL|
+                                                            -- SUBPLAN  |LOCAL|
+                                                                    {
+                                                                      -- 
AGGREGATE  |LOCAL|
+                                                                        -- 
IN_MEMORY_STABLE_SORT [$$38(ASC)]  |LOCAL|
+                                                                          -- 
UNNEST  |LOCAL|
+                                                                            -- 
NESTED_TUPLE_SOURCE  |LOCAL|
+                                                                    }
+                                                              -- 
NESTED_TUPLE_SOURCE  |LOCAL|
+                                                  }
+                                            -- NESTED_TUPLE_SOURCE  |LOCAL|
                                       }
                                 -- SUBPLAN  |LOCAL|
                                         {
@@ -38,22 +39,23 @@
                             }
                       -- SUBPLAN  |LOCAL|
                               {
-                                -- SUBPLAN  |LOCAL|
-                                        {
-                                          -- AGGREGATE  |LOCAL|
-                                            -- STREAM_SELECT  |LOCAL|
-                                              -- ASSIGN  |LOCAL|
-                                                -- UNNEST  |LOCAL|
-                                                  -- SUBPLAN  |LOCAL|
-                                                          {
-                                                            -- AGGREGATE  
|LOCAL|
-                                                              -- 
IN_MEMORY_STABLE_SORT [$$31(ASC)]  |LOCAL|
-                                                                -- UNNEST  
|LOCAL|
-                                                                  -- 
NESTED_TUPLE_SOURCE  |LOCAL|
-                                                          }
-                                                    -- NESTED_TUPLE_SOURCE  
|LOCAL|
-                                        }
-                                  -- NESTED_TUPLE_SOURCE  |LOCAL|
+                                -- ASSIGN  |LOCAL|
+                                  -- SUBPLAN  |LOCAL|
+                                          {
+                                            -- AGGREGATE  |LOCAL|
+                                              -- STREAM_SELECT  |LOCAL|
+                                                -- ASSIGN  |LOCAL|
+                                                  -- UNNEST  |LOCAL|
+                                                    -- SUBPLAN  |LOCAL|
+                                                            {
+                                                              -- AGGREGATE  
|LOCAL|
+                                                                -- 
IN_MEMORY_STABLE_SORT [$$31(ASC)]  |LOCAL|
+                                                                  -- UNNEST  
|LOCAL|
+                                                                    -- 
NESTED_TUPLE_SOURCE  |LOCAL|
+                                                            }
+                                                      -- NESTED_TUPLE_SOURCE  
|LOCAL|
+                                          }
+                                    -- NESTED_TUPLE_SOURCE  |LOCAL|
                               }
                         -- NESTED_TUPLE_SOURCE  |LOCAL|
                   }
diff --git 
a/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.1.ddl.aql
 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.1.ddl.aql
new file mode 100644
index 0000000..44468b1
--- /dev/null
+++ 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.1.ddl.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.
+ */
+
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type ifType as open
+{
+    id: int32
+}
+
+create dataset ifds(ifType)
+primary key id;
+
diff --git 
a/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.2.update.aql
 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.2.update.aql
new file mode 100644
index 0000000..e55fed2
--- /dev/null
+++ 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.2.update.aql
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use dataverse test;
+
+insert into dataset ifds(
+{
+    "id":0,
+    "names":{
+        "count": "1",
+        "name" :{
+            "firstName" : "wail",
+            "lastName" : "Alkowaileet"
+        }
+    }
+}
+)
+
+insert into dataset ifds(
+{
+    "id":1,
+    "names":{
+        "count": "2",
+        "name" :[
+        {
+            "firstName" : "wail",
+            "lastName" : "Alkowaileet"
+        },
+        {
+            "firstName" : "Sattam",
+            "lastName" : "Alsubaiee"
+        }
+        ]
+    }
+}
+)
diff --git 
a/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.3.query.aql
 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.3.query.aql
new file mode 100644
index 0000000..e77a7e9
--- /dev/null
+++ 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.3.query.aql
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/* This test is to verify the fix for ASTERIXDB-1203. */
+
+use dataverse test;
+
+for $x in dataset ifds
+where ( 
+if ($x.names.count = "1") then
+   $x.names.name.firstName = "wail"
+else
+   (some $v in $x.names.name satisfies $v.firstName = "wail")
+)
+return $x;
diff --git 
a/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.1.ddl.aql
 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.1.ddl.aql
new file mode 100644
index 0000000..d60c947
--- /dev/null
+++ 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.1.ddl.aql
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type page_info_type as open {}
+
+create type page_views_type as closed {
+    user: string,
+    action: int32,
+    timespent: int32,
+    query_term: string,
+    ip_addr: int32, 
+    timestamp: int32,
+    estimated_revenue: double,
+    page_info: page_info_type,
+    page_links: {{ page_info_type}}
+}
+
+create dataset page_views(page_views_type)
+primary key user;
diff --git 
a/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.2.update.aql
 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.2.update.aql
new file mode 100644
index 0000000..e42334b
--- /dev/null
+++ 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.2.update.aql
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use dataverse test;
+
+load dataset page_views using localfs
+(("path"="asterix_nc1://data/page_views.adm"),("format"="adm"));
diff --git 
a/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.3.query.aql
 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.3.query.aql
new file mode 100644
index 0000000..fd81077
--- /dev/null
+++ 
b/asterix-app/src/test/resources/runtimets/queries/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.3.query.aql
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/* This test is to verify the fix for ASTERIXDB-865. */
+
+use dataverse test;
+
+for $t in dataset page_views
+let $header := if ($t.action = 1)
+    then [ $t.page_info.a ]
+    else 
+        for $pl in $t.page_links
+        return $pl.b
+for $h in $header
+order by $t.user, $h
+return
+{ "user": $t.user, "header": $h }
+;
+
diff --git 
a/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.1.adm
 
b/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.1.adm
new file mode 100644
index 0000000..4082360
--- /dev/null
+++ 
b/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-1203/query-ASTERIXDB-1203.1.adm
@@ -0,0 +1,2 @@
+{ "id": 1i32, "names": { "count": "2", "name": [ { "firstName": "wail", 
"lastName": "Alkowaileet" }, { "firstName": "Sattam", "lastName": "Alsubaiee" } 
] } }
+{ "id": 0i32, "names": { "count": "1", "name": { "firstName": "wail", 
"lastName": "Alkowaileet" } } }
diff --git 
a/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.1.adm
 
b/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.1.adm
new file mode 100644
index 0000000..5c19bfd
--- /dev/null
+++ 
b/asterix-app/src/test/resources/runtimets/results/misc/query-ASTERIXDB-865/query-ASTERIXDB-865.1.adm
@@ -0,0 +1,3 @@
+{ "user": "keren", "header": "aaa" }
+{ "user": "keren1", "header": null }
+{ "user": "keren1", "header": "bbb" }
diff --git a/asterix-app/src/test/resources/runtimets/testsuite.xml 
b/asterix-app/src/test/resources/runtimets/testsuite.xml
index 67db6af..550dc08 100644
--- a/asterix-app/src/test/resources/runtimets/testsuite.xml
+++ b/asterix-app/src/test/resources/runtimets/testsuite.xml
@@ -3011,6 +3011,16 @@
                 <output-dir compare="Text">prefix-search</output-dir>
             </compilation-unit>
         </test-case>
+        <test-case FilePath="misc">
+            <compilation-unit name="query-ASTERIXDB-865">
+                <output-dir compare="Text">query-ASTERIXDB-865</output-dir>
+            </compilation-unit>
+        </test-case>
+        <test-case FilePath="misc">
+            <compilation-unit name="query-ASTERIXDB-1203">
+                <output-dir compare="Text">query-ASTERIXDB-1203</output-dir>
+            </compilation-unit>
+        </test-case>
     </test-group>
     <test-group name="open-index-enforced">
         <test-group FilePath="open-index-enforced/error-checking">
diff --git 
a/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeCompatibilityChecker.java
 
b/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeCompatibilityChecker.java
index 9d2c2ed..565ed02 100644
--- 
a/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeCompatibilityChecker.java
+++ 
b/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeCompatibilityChecker.java
@@ -47,8 +47,9 @@
             for (IAType t : typeList) {
                 if (t.getTypeTag() != ATypeTag.NULL) {
                     //CONCAT_NON_NULL cannot return null because it's only 
used for if-else construct
-                    if (!possibleTypes.contains(t))
+                    if (!possibleTypes.contains(t)) {
                         possibleTypes.add(t);
+                    }
                 } else {
                     nullEncountered = true;
                 }
@@ -75,6 +76,6 @@
                     return possibleTypes.get(0);
                 }
         }
-        return null;
+        return BuiltinType.ANY;
     }
 }

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/703
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I80e7995e814180fe567818263c79493901af284c
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Yingyi Bu <[email protected]>

Reply via email to