Ali Alsuliman has uploaded a new change for review.

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

Change subject: [NO ISSUE][FUN] Implement array_append function
......................................................................

[NO ISSUE][FUN] Implement array_append function

- user model changes: no
- storage format changes: no
- interface changes: no

details:
This is part of implementing array functions.
The array_append takes an input list and values to be
appended and return a new list with all the values.
array_append(list, val1,...)

Change-Id: I0a65549957060beee4579b903e6bd323745fb875
---
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.1.ddl.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.2.update.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.3.query.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.ddl.sqlpp
A 
asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.3.adm
M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
M 
asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
M asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
M 
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
M 
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java
A 
asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java
A 
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayAppendDescriptor.java
M 
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java
M 
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
M 
asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
15 files changed, 424 insertions(+), 15 deletions(-)


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

diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.1.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.1.ddl.sqlpp
new file mode 100755
index 0000000..1c55a9a
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.1.ddl.sqlpp
@@ -0,0 +1,56 @@
+/*
+ * 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 TinySocial if exists;
+create  dataverse TinySocial;
+
+use TinySocial;
+
+
+create type TinySocial.TwitterUserType as
+{
+  `screen-name` : string,
+  lang : string,
+  friends_count : bigint,
+  statuses_count : bigint,
+  name : string,
+  followers_count : bigint
+};
+
+create type TinySocial.TweetMessageType as
+ closed {
+  tweetid : string,
+  user : TwitterUserType,
+  `sender-location` : point?,
+  `send-time` : datetime,
+  `referred-topics` : {{string}},
+  `message-text` : string
+};
+
+create type t1 AS {
+
+};
+
+create type t2 AS {
+id: int,
+compType: t1
+};
+
+create  dataset TweetMessages(TweetMessageType) primary key tweetid hints 
(`CARDINALITY`=`100`);
+create dataset d1(t2) primary key id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.2.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.2.update.sqlpp
new file mode 100755
index 0000000..2767210
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.2.update.sqlpp
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use TinySocial;
+
+load  dataset TweetMessages using localfs 
((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`));
+
+insert into d1([
+{"id":1, "compType":{"sth":33}},
+{"id":2, "compType":{"sth":44}}
+]);
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.3.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.3.query.sqlpp
new file mode 100755
index 0000000..cd56363
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.3.query.sqlpp
@@ -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.
+ */
+
+use TinySocial;
+
+{
+  "t1": (select array_append(t.`referred-topics`, "sth", 5) from TweetMessages 
t),
+  "t2": (select array_append([3, "John"], (select value v.compType from d1 
v))),
+  "t3": (select array_append([3], 7, null, missing)),
+  "t4": (select array_append("non_array", 5)),
+  "t5": (select array_append("non_array", 5, missing)),
+  "t6": (select array_append([], 5, 10, 12.0, "sth")),
+  "t7": (select array_append(missing, 3, 9)),
+  "t8": (select array_append(null, 3, 9))
+};
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.ddl.sqlpp
new file mode 100755
index 0000000..3f8c8ec
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.ddl.sqlpp
@@ -0,0 +1,20 @@
+/*
+ * 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 TinySocial;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.3.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.3.adm
new file mode 100644
index 0000000..fb5f4e9
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.3.adm
@@ -0,0 +1 @@
+{ "t1": [ { "$1": {{ "iphone", "platform", "sth", 5 }} }, { "$1": {{ 
"verizon", "shortcut-menu", "sth", 5 }} }, { "$1": {{ "sprint", 
"voice-command", "sth", 5 }} }, { "$1": {{ "verizon", "voicemail-service", 
"sth", 5 }} }, { "$1": {{ "t-mobile", "customization", "sth", 5 }} }, { "$1": 
{{ "motorola", "speed", "sth", 5 }} }, { "$1": {{ "motorola", "speed", "sth", 5 
}} }, { "$1": {{ "iphone", "voice-clarity", "sth", 5 }} }, { "$1": {{ 
"samsung", "platform", "sth", 5 }} }, { "$1": {{ "verizon", "voice-clarity", 
"sth", 5 }} }, { "$1": {{ "samsung", "voice-command", "sth", 5 }} }, { "$1": {{ 
"t-mobile", "shortcut-menu", "sth", 5 }} } ], "t2": [ { "$2": [ 3, "John", [ { 
"sth": 33 }, { "sth": 44 } ] ] } ], "t3": [ {  } ], "t4": [ { "$4": null } ], 
"t5": [ {  } ], "t6": [ { "$6": [ 5, 10, 12.0, "sth" ] } ], "t7": [ {  } ], 
"t8": [ { "$8": null } ] }
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml 
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 4376ca6..1b9e15c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -982,6 +982,13 @@
       </compilation-unit>
     </test-case>
   </test-group>
+  <test-group name="array_fun">
+    <test-case FilePath="array_fun">
+      <compilation-unit name="array_append">
+        <output-dir compare="Text">array_append</output-dir>
+      </compilation-unit>
+    </test-case>
+  </test-group>
   <test-group name="boolean">
     <test-case FilePath="boolean">
       <compilation-unit name="and_01">
diff --git 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
index de399eb..05f7b2e 100644
--- 
a/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
+++ 
b/asterixdb/asterix-common/src/main/java/org/apache/asterix/common/exceptions/ErrorCode.java
@@ -166,6 +166,7 @@
     public static final int UNKNOWN_INDEX = 1083;
     public static final int INDEX_EXISTS = 1084;
     public static final int TYPE_EXISTS = 1085;
+    public static final int COMPILATION_INVALID_NUM_OF_ARGS = 1086;
 
     // Feed errors
     public static final int DATAFLOW_ILLEGAL_STATE = 3001;
diff --git 
a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties 
b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
index f0a36bf..73f5957 100644
--- a/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
+++ b/asterixdb/asterix-common/src/main/resources/asx_errormsg/en.properties
@@ -153,6 +153,7 @@
 1083 = Cannot find index with name %1$s
 1084 = An index with this name %1$s already exists
 1085 = A datatype with this name %1$s already exists
+1086 = Invalid number of arguments: at least %1$d arguments are required for 
function %2$s
 
 # Feed Errors
 3001 = Illegal state.
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index a80ba28..6e11005 100644
--- 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -53,6 +53,7 @@
 import org.apache.asterix.om.typecomputer.impl.AUUIDTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.AYearMonthDurationTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.AnyTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.ArrayAppendTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.BooleanFunctionTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.BooleanOnlyTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.BooleanOrMissingTypeComputer;
@@ -135,15 +136,12 @@
     }
 
     private static final FunctionInfoRepository registeredFunctions = new 
FunctionInfoRepository();
-
     private static final Map<IFunctionInfo, ATypeHierarchy.Domain> 
registeredFunctionsDomain = new HashMap<>();
 
     // it is supposed to be an identity mapping
     private static final Map<IFunctionInfo, IFunctionInfo> 
builtinPublicFunctionsSet = new HashMap<>();
     private static final Map<IFunctionInfo, IFunctionInfo> 
builtinPrivateFunctionsSet = new HashMap<>();
-
     private static final Map<IFunctionInfo, IResultTypeComputer> 
funTypeComputer = new HashMap<>();
-
     private static final Set<IFunctionInfo> builtinAggregateFunctions = new 
HashSet<>();
     private static final Map<IFunctionInfo, IFunctionToDataSourceRewriter> 
datasourceFunctions = new HashMap<>();
     private static final Set<IFunctionInfo> similarityFunctions = new 
HashSet<>();
@@ -164,14 +162,12 @@
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "get-handle", 
2);
     public static final FunctionIdentifier GET_DATA =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "get-data", 
2);
-
     public static final FunctionIdentifier GET_ITEM =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "get-item", 
2);
     public static final FunctionIdentifier ANY_COLLECTION_MEMBER =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"any-collection-member", 1);
     public static final FunctionIdentifier LISTIFY = new 
FunctionIdentifier(FunctionConstants.ASTERIX_NS, "listify", 1);
     public static final FunctionIdentifier LEN = new 
FunctionIdentifier(FunctionConstants.ASTERIX_NS, "len", 1);
-
     public static final FunctionIdentifier CONCAT_NON_NULL =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"concat-non-null", FunctionIdentifier.VARARGS);
     public static final FunctionIdentifier EMPTY_STREAM =
@@ -185,6 +181,10 @@
 
     public static final FunctionIdentifier DEEP_EQUAL =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "deep-equal", 
2);
+
+    // array functions
+    public static final FunctionIdentifier ARRAY_APPEND =
+            new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"array-append", FunctionIdentifier.VARARGS);
 
     // objects
     public static final FunctionIdentifier RECORD_MERGE =
@@ -298,7 +298,8 @@
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"find-binary", 2);
     public static final FunctionIdentifier FIND_BINARY_FROM =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"find-binary", 3);
-    // String funcitons
+
+    // String functions
     public static final FunctionIdentifier STRING_EQUAL =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"string-equal", 2);
     public static final FunctionIdentifier STRING_MATCHES =
@@ -390,6 +391,7 @@
     public static final FunctionIdentifier MAKE_FIELD_NAME_HANDLE =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"make-field-name-handle", 1);
 
+    // aggregate functions
     public static final FunctionIdentifier AVG = new 
FunctionIdentifier(FunctionConstants.ASTERIX_NS, "agg-avg", 1);
     public static final FunctionIdentifier COUNT = new 
FunctionIdentifier(FunctionConstants.ASTERIX_NS, "agg-count", 1);
     public static final FunctionIdentifier SUM = new 
FunctionIdentifier(FunctionConstants.ASTERIX_NS, "agg-sum", 1);
@@ -442,7 +444,6 @@
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"intermediate-avg-serial", 1);
 
     // distinct aggregate functions
-
     public static final FunctionIdentifier COUNT_DISTINCT =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"agg-count-distinct", 1);
     public static final FunctionIdentifier SCALAR_COUNT_DISTINCT =
@@ -541,6 +542,7 @@
     public static final FunctionIdentifier SCALAR_SQL_MIN_DISTINCT =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"sql-min-distinct", 1);
 
+    // unnesting functions
     public static final FunctionIdentifier SCAN_COLLECTION =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, 
"scan-collection", 1);
     public static final FunctionIdentifier SUBSET_COLLECTION =
@@ -548,7 +550,7 @@
 
     public static final FunctionIdentifier RANGE = new 
FunctionIdentifier(FunctionConstants.ASTERIX_NS, "range", 2);
 
-    // fuzzy functions:
+    // fuzzy functions
     public static final FunctionIdentifier FUZZY_EQ =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "fuzzy-eq", 
2);
 
@@ -1091,7 +1093,7 @@
         addPrivateFunction(OR, BooleanFunctionTypeComputer.INSTANCE, true);
         addPrivateFunction(NUMERIC_ADD, 
NumericAddSubMulDivTypeComputer.INSTANCE, true);
 
-        // Deep equality
+        // deep equality
         addFunction(DEEP_EQUAL, BooleanFunctionTypeComputer.INSTANCE, true);
 
         // and then, Asterix builtin functions
@@ -1449,6 +1451,9 @@
         addPrivateFunction(UNORDERED_LIST_CONSTRUCTOR, 
UnorderedListConstructorTypeComputer.INSTANCE, true);
         addFunction(WORD_TOKENS, OrderedListOfAStringTypeComputer.INSTANCE, 
true);
 
+        // array functions
+        addFunction(ARRAY_APPEND, ArrayAppendTypeComputer.INSTANCE, true);
+
         // objects
         addFunction(RECORD_MERGE, RecordMergeTypeComputer.INSTANCE, true);
         addFunction(RECORD_CONCAT, OpenARecordTypeComputer.INSTANCE, true);
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java
index ae7c996..60a4985 100644
--- 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/base/AbstractResultTypeComputer.java
@@ -68,7 +68,8 @@
      * @param expr
      *            the expression under consideration.
      * @param strippedInputTypes,
-     *            the stripped input types.
+     *            the stripped input types. When the function propagates null 
& missing, they can be any type except
+     *            null, missing, and union.
      * @return the result type without considering optional types.
      * @throws AlgebricksException
      */
diff --git 
a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java
 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java
new file mode 100755
index 0000000..c2aaa97
--- /dev/null
+++ 
b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package org.apache.asterix.om.typecomputer.impl;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
+import org.apache.asterix.om.types.AOrderedListType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnorderedListType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+
+public class ArrayAppendTypeComputer extends AbstractResultTypeComputer {
+
+    public static final ArrayAppendTypeComputer INSTANCE = new 
ArrayAppendTypeComputer();
+
+    @Override
+    protected IAType getResultType(ILogicalExpression expr, IAType... 
strippedInputTypes) throws AlgebricksException {
+        if (strippedInputTypes.length < 2) {
+            String functionName = ((AbstractFunctionCallExpression) 
expr).getFunctionIdentifier().getName();
+            throw new 
CompilationException(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS, 2, 
functionName);
+        }
+        // type tag at [0] should be array or multiset.
+        ATypeTag typeTag = strippedInputTypes[0].getTypeTag();
+        IAType resultType;
+        if (typeTag == ATypeTag.ARRAY) {
+            resultType = new AOrderedListType(BuiltinType.ANY, null);
+        } else {
+            resultType = new AUnorderedListType(BuiltinType.ANY, null);
+        }
+        return resultType;
+    }
+}
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayAppendDescriptor.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayAppendDescriptor.java
new file mode 100755
index 0000000..d493f98
--- /dev/null
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayAppendDescriptor.java
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+package org.apache.asterix.runtime.evaluators.functions;
+
+import java.io.IOException;
+
+import org.apache.asterix.builders.IAsterixListBuilder;
+import org.apache.asterix.builders.OrderedListBuilder;
+import org.apache.asterix.builders.UnorderedListBuilder;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptor;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.om.functions.IFunctionTypeInferer;
+import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AbstractCollectionType;
+import org.apache.asterix.om.types.IAType;
+import 
org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.asterix.runtime.evaluators.common.ListAccessor;
+import org.apache.asterix.runtime.functions.FunctionTypeInferers;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class ArrayAppendDescriptor extends 
AbstractScalarFunctionDynamicDescriptor {
+    private static final long serialVersionUID = 1L;
+    private IAType[] argTypes;
+
+    public static final IFunctionDescriptorFactory FACTORY = new 
IFunctionDescriptorFactory() {
+        @Override
+        public IFunctionDescriptor createFunctionDescriptor() {
+            return new ArrayAppendDescriptor();
+        }
+
+        @Override
+        public IFunctionTypeInferer createFunctionTypeInferer() {
+            return FunctionTypeInferers.SET_ARGUMENTS_TYPE;
+        }
+    };
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ARRAY_APPEND;
+    }
+
+    @Override
+    public IScalarEvaluatorFactory createEvaluatorFactory(final 
IScalarEvaluatorFactory[] args)
+            throws AlgebricksException {
+        return new IScalarEvaluatorFactory() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public IScalarEvaluator createScalarEvaluator(final 
IHyracksTaskContext ctx) throws HyracksDataException {
+                return new ArrayAppendFunction(args, ctx);
+            }
+        };
+    }
+
+    @Override
+    public void setImmutableStates(Object... states) {
+        argTypes = new IAType[states.length];
+        for (int i = 0; i < states.length; i++) {
+            argTypes[i] = (IAType) states[i];
+        }
+    }
+
+    public class ArrayAppendFunction implements IScalarEvaluator {
+        private final ArrayBackedValueStorage storage;
+        private final IPointable listArg;
+        private final IPointable[] appendedValues;
+        private final IScalarEvaluator listArgEval;
+        private final IScalarEvaluator[] appendedValuesEval;
+
+        public ArrayAppendFunction(IScalarEvaluatorFactory[] args, 
IHyracksTaskContext ctx)
+                throws HyracksDataException {
+            storage = new ArrayBackedValueStorage();
+            listArg = new VoidPointable();
+            listArgEval = args[0].createScalarEvaluator(ctx);
+            appendedValues = new IPointable[args.length - 1];
+            appendedValuesEval = new IScalarEvaluator[args.length - 1];
+            for (int i = 1; i < args.length; i++) {
+                appendedValues[i - 1] = new VoidPointable();
+                appendedValuesEval[i - 1] = args[i].createScalarEvaluator(ctx);
+            }
+        }
+
+        @Override
+        public void evaluate(IFrameTupleReference tuple, IPointable result) 
throws HyracksDataException {
+            // get the list argument, 1st argument, make sure it's a list
+            listArgEval.evaluate(tuple, listArg);
+            byte listArgType = 
listArg.getByteArray()[listArg.getStartOffset()];
+
+            CastTypeEvaluator caster = null;
+            AbstractCollectionType listType = null;
+            IAsterixListBuilder listBuilder = null;
+            // create the new list to be returned. The item type is always 
"ANY"
+            // cast the input list and make it open
+            if (listArgType == ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG) {
+                listBuilder = new OrderedListBuilder();
+                listType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
+                caster = new CastTypeEvaluator(listType, argTypes[0], 
listArgEval);
+                caster.evaluate(tuple, listArg);
+            } else if (listArgType == 
ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG) {
+                listBuilder = new UnorderedListBuilder();
+                listType = 
DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
+                caster = new CastTypeEvaluator(listType, argTypes[0], 
listArgEval);
+                caster.evaluate(tuple, listArg);
+            }
+            // else, don't return null right away. evaluate rest of args as 
some may be missing, return missing instead
+            IAType defaultOpenType;
+            for (int i = 0; i < appendedValuesEval.length; i++) {
+                // cast to open if necessary
+                defaultOpenType = 
DefaultOpenFieldType.getDefaultOpenFieldType(argTypes[i + 1].getTypeTag());
+                if (defaultOpenType != null && caster != null) {
+                    caster.reset(defaultOpenType, argTypes[i + 1], 
appendedValuesEval[i]);
+                    caster.evaluate(tuple, appendedValues[i]);
+                } else {
+                    // either no casting is needed (e.g. int and the like) or 
evaluate normally for the below case:
+                    // when caster == null, it means the first arg was not a 
list and a null would be returned but
+                    // evaluate values to be appended normally in case missing 
exists and return missing instead of null
+                    appendedValuesEval[i].evaluate(tuple, appendedValues[i]);
+                }
+            }
+
+            if (listArgType != ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG
+                    && listArgType != 
ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG) {
+                PointableHelper.setNull(result);
+                return;
+            }
+
+            // arguments are good: no nulls/missings and 1st arg is a list
+            listBuilder.reset(listType);
+            ListAccessor listAccessor = new ListAccessor();
+            listAccessor.reset(listArg.getByteArray(), 
listArg.getStartOffset());
+            try {
+                // get the list items one by one and append to the new list
+                for (int i = 0; i < listAccessor.size(); i++) {
+                    storage.reset();
+                    listAccessor.writeItem(i, storage.getDataOutput());
+                    listBuilder.addItem(storage);
+                }
+                // append the values arguments
+                for (IPointable appendedValue : appendedValues) {
+                    listBuilder.addItem(appendedValue);
+                }
+                storage.reset();
+                listBuilder.write(storage.getDataOutput(), true);
+                result.set(storage);
+            } catch (IOException e) {
+                throw HyracksDataException.create(e);
+            }
+        }
+    }
+}
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java
index 524b2ed..f0ca6ae 100644
--- 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java
@@ -35,12 +35,12 @@
 
 class CastTypeEvaluator implements IScalarEvaluator {
 
-    private final IScalarEvaluator argEvaluator;
+    private IScalarEvaluator argEvaluator;
     private final IPointable argPointable = new VoidPointable();
 
     private final PointableAllocator allocator = new PointableAllocator();
-    private final IVisitablePointable inputPointable;
-    private final IVisitablePointable resultPointable;
+    private IVisitablePointable inputPointable;
+    private IVisitablePointable resultPointable;
 
     private final ACastVisitor castVisitor;
     private final Triple<IVisitablePointable, IAType, Boolean> arg;
@@ -69,8 +69,16 @@
         result.set(resultPointable);
     }
 
+    public void reset(IAType reqType, IAType inputType, IScalarEvaluator 
argEvaluator) {
+        this.argEvaluator = argEvaluator;
+        this.inputPointable = allocatePointable(inputType, reqType);
+        this.resultPointable = allocatePointable(reqType, inputType);
+        this.arg.first = resultPointable;
+        this.arg.second = reqType;
+    }
+
     // Allocates the result pointable.
-    private final IVisitablePointable allocatePointable(IAType 
typeForPointable, IAType typeForOtherSide) {
+    private IVisitablePointable allocatePointable(IAType typeForPointable, 
IAType typeForOtherSide) {
         if (!typeForPointable.equals(BuiltinType.ANY)) {
             return allocator.allocateFieldValue(typeForPointable);
         }
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
index 271a7f0..cd6c2f2 100644
--- 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
@@ -143,6 +143,7 @@
 import 
org.apache.asterix.runtime.evaluators.constructors.UnorderedListConstructorDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.AndDescriptor;
 import 
org.apache.asterix.runtime.evaluators.functions.AnyCollectionMemberDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.ArrayAppendDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.CastTypeDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.CastTypeLaxDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.CheckUnknownDescriptor;
@@ -365,7 +366,10 @@
     public static FunctionCollection createDefaultFunctionCollection() {
         FunctionCollection fc = new FunctionCollection();
 
-        // unnesting function
+        // array functions
+        fc.addGenerated(ArrayAppendDescriptor.FACTORY);
+
+        // unnesting functions
         fc.add(TidRunningAggregateDescriptor.FACTORY);
         fc.add(ScanCollectionDescriptor.FACTORY);
         fc.add(RangeDescriptor.FACTORY);
diff --git 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
index e5a4301..b9c58c7 100644
--- 
a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
+++ 
b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionTypeInferers.java
@@ -79,6 +79,22 @@
         }
     };
 
+    /** Sets the types of the function arguments */
+    public static final IFunctionTypeInferer SET_ARGUMENTS_TYPE = new 
IFunctionTypeInferer() {
+        @Override
+        public void infer(ILogicalExpression expr, IFunctionDescriptor fd, 
IVariableTypeEnvironment context,
+                CompilerProperties compilerProps) throws AlgebricksException {
+            AbstractFunctionCallExpression fce = 
(AbstractFunctionCallExpression) expr;
+            IAType[] argsTypes = new IAType[fce.getArguments().size()];
+            int i = 0;
+            for (Mutable<ILogicalExpression> arg : fce.getArguments()) {
+                argsTypes[i] = TypeComputeUtils.getActualType((IAType) 
context.getType(arg.getValue()));
+                i++;
+            }
+            fd.setImmutableStates((Object[]) argsTypes);
+        }
+    };
+
     public static final class CastTypeInferer implements IFunctionTypeInferer {
         @Override
         public void infer(ILogicalExpression expr, IFunctionDescriptor fd, 
IVariableTypeEnvironment context,

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0a65549957060beee4579b903e6bd323745fb875
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Ali Alsuliman <[email protected]>

Reply via email to