[ASTERIXDB-2658][FUN] Add support for array_except() function

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

Details:
- Added array_except function.
- Added test cases for array_except() function.

Change-Id: I7c1befeffdb0f651afab31a4e814842a67d3a54c
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/3743
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/NullMissingTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/NullMissingTest.java
index aadb9b9..3b4f78f 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/NullMissingTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/NullMissingTest.java
@@ -197,6 +197,7 @@
         functionsRequiringTypes.add(new FunctionInfo(BuiltinFunctions.ARRAY_CONTAINS, true));
         functionsRequiringTypes.add(new FunctionInfo(BuiltinFunctions.ARRAY_SORT, true));
         functionsRequiringTypes.add(new FunctionInfo(BuiltinFunctions.ARRAY_DISTINCT, true));
+        functionsRequiringTypes.add(new FunctionInfo(BuiltinFunctions.ARRAY_EXCEPT, true));
         functionsRequiringTypes.add(new FunctionInfo(BuiltinFunctions.EQ, true));
         functionsRequiringTypes.add(new FunctionInfo(BuiltinFunctions.LT, true));
         functionsRequiringTypes.add(new FunctionInfo(BuiltinFunctions.GT, true));
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.1.ddl.sqlpp
new file mode 100755
index 0000000..39c2bbf
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.1.ddl.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop type test if exists;
+create type test as open { id: uuid };
+
+drop dataset test if exists;
+
+create dataset test(test) primary key id autogenerated;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.2.update.sqlpp
new file mode 100755
index 0000000..2577a78
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.2.update.sqlpp
@@ -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.
+ */
+
+use test;
+
+// arrays only
+insert into test([{"f0": 1, "f1": [1, 2], "f2": [1, 3]}]);
+insert into test([{"f0": 2, "f1": [1, 2, 2], "f2": [1, 2]}]);
+insert into test([{"f0": 3, "f1": [1, 2, "2"], "f2": [1, 2]}]);
+insert into test([{"f0": 4, "f1": [1, 2, "out"], "f2": [1, "out"]}]);
+insert into test([{"f0": 5, "f1": [1, 2, "in"], "f2": [1, "out"]}]);
+insert into test([{"f0": 6, "f1": [1, 2, {{1, 2}}, {{2, 1}}], "f2": [1, {{2, 1}}]}]);
+insert into test([{"f0": 7, "f1": ["in", "iN", "OUT"], "f2": ["OUT", "IN"]}]);
+insert into test([{"f0": 8, "f1": [1, 2, 3, {"f1": "hi"}], "f2": [1, 2]}]);
+insert into test([{"f0": 9, "f1": [1, 2, 3, {"f1": "hi"}], "f2": [1, 2, {"f1": "hi"}]}]);
+insert into test([{"f0": 10, "f1": [1, 2, 3, {"f1": "hi"}], "f2": [1, 2, {"f2": "hi"}]}]);
+insert into test([{"f0": 11, "f1": [1, 2, 3, {"f1": "hi"}, {"f2": "hi"}], "f2": [1, 2, {"f2": "hi"}]}]);
+insert into test([{"f0": 12, "f1": [1, 2, 3, {"f1": "hi"}, {"f2": "hi"}], "f2": [1, 2, {"f1": "hi"}, {"f2": "hi"}]}]);
+insert into test([{"f0": 13, "f1": [double("INF"), double("-INF"), float("INF"), float("-INF"), missing, null, 1], "f2": [double("INF"), float("-INF"), missing, null]}]);
+insert into test([{"f0": 14, "f1": [{"f1": "1", "f2": "2", "f3": "3"}, 2, 3], "f2": [{"f3": "3", "f1": "1", "f2": "2"}]}]);
+insert into test([{"f0": 15, "f1": [1, null, missing], "f2": [1]}]);
+insert into test([{"f0": 16, "f1": [1, null, missing], "f2": [1, null]}]);
+insert into test([{"f0": 17, "f1": [1, null, missing], "f2": [1, missing]}]);
+insert into test([{"f0": 18, "f1": [1, null, missing], "f2": [1, missing, null]}]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.3.query.sqlpp
new file mode 100755
index 0000000..35ab1ab
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.3.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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 test;
+
+select value array_except(f1, f2) from test order by f0 asc;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.4.ddl.sqlpp
new file mode 100755
index 0000000..f12a2b7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/001/array_except.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 test;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.1.ddl.sqlpp
new file mode 100755
index 0000000..39c2bbf
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.1.ddl.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop type test if exists;
+create type test as open { id: uuid };
+
+drop dataset test if exists;
+
+create dataset test(test) primary key id autogenerated;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.2.update.sqlpp
new file mode 100755
index 0000000..d311ad9
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.2.update.sqlpp
@@ -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.
+ */
+
+use test;
+
+// combination of arrays and multisets
+insert into test([{"f0": 1, "f1": {{1, 2}}, "f2": {{1, 3}}}]);
+insert into test([{"f0": 2, "f1": {{1, 2, 2}}, "f2": {{1, 2}}}]);
+insert into test([{"f0": 3, "f1": {{1, 2, "2"}}, "f2": {{1, 2}}}]);
+insert into test([{"f0": 4, "f1": {{1, 2, "out"}}, "f2": [1, "out"]}]);
+insert into test([{"f0": 5, "f1": {{1, 2, "in"}}, "f2": [1, "out"]}]);
+insert into test([{"f0": 6, "f1": {{1, 2, {{1, 2}}, {{2, 1}}}}, "f2": [1, {{2, 1}}]}]);
+insert into test([{"f0": 7, "f1": {{"in", "iN", "OUT"}}, "f2": ["OUT", "IN"]}]);
+insert into test([{"f0": 8, "f1": {{1, 2, 3, {"f1": "hi"}}}, "f2": [1, 2]}]);
+insert into test([{"f0": 9, "f1": {{1, 2, 3, {"f1": "hi"}}}, "f2": [1, 2, {"f1": "hi"}]}]);
+insert into test([{"f0": 10, "f1": [1, 2, 3, {"f1": "hi"}], "f2": {{1, 2, {"f2": "hi"}}}}]);
+insert into test([{"f0": 11, "f1": [1, 2, 3, {"f1": "hi"}, {"f2": "hi"}], "f2": {{1, 2, {"f2": "hi"}}}}]);
+insert into test([{"f0": 12, "f1": [1, 2, 3, {"f1": "hi"}, {"f2": "hi"}], "f2": {{1, 2, {"f1": "hi"}, {"f2": "hi"}}}}]);
+insert into test([{"f0": 13, "f1": [double("INF"), double("-INF"), float("INF"), float("-INF"), missing, null, 1], "f2": {{double("INF"), float("-INF"), missing, null}}}]);
+insert into test([{"f0": 14, "f1": [{"f1": "1", "f2": "2", "f3": "3"}, 2, 3], "f2": {{{"f3": "3", "f1": "1", "f2": "2"}}}}]);
+insert into test([{"f0": 15, "f1": {{1, null, missing}}, "f2": {{1}}}]);
+insert into test([{"f0": 16, "f1": {{1, null, missing}}, "f2": {{1, null}}}]);
+insert into test([{"f0": 17, "f1": {{1, null, missing}}, "f2": [1, missing]}]);
+insert into test([{"f0": 18, "f1": {{1, null, missing}}, "f2": [1, missing, null]}]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.3.query.sqlpp
new file mode 100755
index 0000000..35ab1ab
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.3.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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 test;
+
+select value array_except(f1, f2) from test order by f0 asc;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.4.ddl.sqlpp
new file mode 100755
index 0000000..f12a2b7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/002/array_except.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 test;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.1.ddl.sqlpp
new file mode 100755
index 0000000..39c2bbf
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.1.ddl.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop type test if exists;
+create type test as open { id: uuid };
+
+drop dataset test if exists;
+
+create dataset test(test) primary key id autogenerated;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.2.update.sqlpp
new file mode 100755
index 0000000..b2157b5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.2.update.sqlpp
@@ -0,0 +1,28 @@
+/*
+ * 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 test;
+
+insert into test([{"f0": 1, "f1": 1, "f2": [1, 2]}]);
+insert into test([{"f0": 2, "f1": null, "f2": [1, 2]}]);
+insert into test([{"f0": 3, "f1": [1, 2], "f2": "string"}]);
+insert into test([{"f0": 4, "f1": missing, "f2": [1, 2]}]);
+insert into test([{"f0": 5, "f1": [1, 2], "f2": missing}]);
+insert into test([{"f0": 6, "f1": null, "f2": missing}]);
+insert into test([{"f0": 7, "f1": "bad", "f2": missing}]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.3.query.sqlpp
new file mode 100755
index 0000000..ccb084a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.3.query.sqlpp
@@ -0,0 +1,30 @@
+/*
+ * 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 test;
+
+select value [
+(select value array_except(f1, f2) is null from test where f0 = 1)[0],
+(select value array_except(f1, f2) is null from test where f0 = 2)[0],
+(select value array_except(f1, f2) is null from test where f0 = 3)[0],
+(select value array_except(f1, f2) is missing from test where f0 = 4)[0],
+(select value array_except(f1, f2) is missing from test where f0 = 5)[0],
+(select value array_except(f1, f2) is missing from test where f0 = 6)[0],
+(select value array_except(f1, f2) is missing from test where f0 = 7)[0]
+];
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.4.ddl.sqlpp
new file mode 100755
index 0000000..f12a2b7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/003/array_except.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 test;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/004/array_except.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/004/array_except.1.query.sqlpp
new file mode 100755
index 0000000..d593cbb
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/004/array_except.1.query.sqlpp
@@ -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.
+ */
+
+// arrays only
+[
+array_except([1, 2], [1, 3]),
+array_except([1, 2, 2], [1, 2]),
+array_except([1, 2, "2"], [1, 2]),
+array_except([1, 2, "out"], [1, "out"]),
+array_except([1, 2, "in"], [1, "out"]),
+array_except([1, 2, {{1, 2}}, {{2, 1}}], [1, {{2, 1}}]),
+array_except(["in", "iN", "OUT"], ["OUT", "IN"]),
+array_except([1, 2, 3, {"f1": "hi"}], [1, 2]),
+array_except([1, 2, 3, {"f1": "hi"}], [1, 2, {"f1": "hi"}]),
+array_except([1, 2, 3, {"f1": "hi"}], [1, 2, {"f2": "hi"}]),
+array_except([1, 2, 3, {"f1": "hi"}, {"f2": "hi"}], [1, 2, {"f2": "hi"}]),
+array_except([1, 2, 3, {"f1": "hi"}, {"f2": "hi"}], [1, 2, {"f1": "hi"}, {"f2": "hi"}]),
+array_except([double("INF"), double("-INF"), float("INF"), float("-INF"), missing, null, 1], [double("INF"), float("-INF"), missing, null]),
+array_except([{"f1": "1", "f2": "2", "f3": "3"}, 2, 3], [{"f3": "3", "f1": "1", "f2": "2"}]),
+array_except([1, missing, null], [1]),
+array_except([1, missing, null], [1, missing]),
+array_except([1, missing, null], [1, null]),
+array_except([1, missing, null], [1, missing, null])
+];
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/005/array_except.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/005/array_except.1.query.sqlpp
new file mode 100755
index 0000000..4f0c4de
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/005/array_except.1.query.sqlpp
@@ -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.
+ */
+
+// Arrays and multisets
+[
+array_except({{1, 2}}, {{1, 3}}),
+array_except({{1, 2, 2}}, {{1, 2}}),
+array_except({{1, 2, "2"}}, {{1, 2}}),
+array_except({{1, 2, "out"}}, [1, "out"]),
+array_except({{1, 2, "in"}}, [1, "out"]),
+array_except({{1, 2, {{1, 2}}, {{2, 1}}}}, [1, {{2, 1}}]),
+array_except({{"in", "iN", "OUT"}}, ["OUT", "IN"]),
+array_except({{1, 2, 3, {"f1": "hi"}}}, [1, 2]),
+array_except({{1, 2, 3, {"f1": "hi"}}}, [1, 2, {"f1": "hi"}]),
+array_except([1, 2, 3, {"f1": "hi"}], {{1, 2, {"f2": "hi"}}}),
+array_except([1, 2, 3, {"f1": "hi"}, {"f2": "hi"}], {{1, 2, {"f2": "hi"}}}),
+array_except([1, 2, 3, {"f1": "hi"}, {"f2": "hi"}], {{1, 2, {"f1": "hi"}, {"f2": "hi"}}}),
+array_except([double("INF"), double("-INF"), float("INF"), float("-INF"), missing, null, 1], {{double("INF"), float("-INF"), missing, null}}),
+array_except([{"f1": "1", "f2": "2", "f3": "3"}, 2, 3], {{{"f3": "3", "f1": "1", "f2": "2"}}}),
+array_except({{1, missing, null}}, {{1}}),
+array_except({{1, missing, null}}, {{1, missing}}),
+array_except({{1, missing, null}}, [1, null]),
+array_except({{1, missing, null}}, [1, missing, null])
+];
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/006/array_except.1.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/006/array_except.1.query.sqlpp
new file mode 100755
index 0000000..a8f0514
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_except/006/array_except.1.query.sqlpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+[
+array_except(1, [1, 2]) is null,
+array_except(null, [1, 2]) is null,
+array_except([1, 2], "string") is null,
+array_except(missing, [1, 2]) is missing,
+array_except([1, 2], missing) is missing,
+array_except(null, missing) is missing,
+array_except("bad", missing) is missing
+];
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/001/array_except.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/001/array_except.3.adm
new file mode 100644
index 0000000..e8f2fd0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/001/array_except.3.adm
@@ -0,0 +1,18 @@
+[ 2 ]
+[  ]
+[ "2" ]
+[ 2 ]
+[ 2, "in" ]
+[ 2, {{ 1, 2 }} ]
+[ "in", "iN" ]
+[ 3, { "f1": "hi" } ]
+[ 3 ]
+[ 3, { "f1": "hi" } ]
+[ 3, { "f1": "hi" } ]
+[ 3 ]
+[ 1 ]
+[ 2, 3 ]
+[ null, null ]
+[ null ]
+[ null ]
+[  ]
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/002/array_except.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/002/array_except.3.adm
new file mode 100644
index 0000000..7f96e9f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/002/array_except.3.adm
@@ -0,0 +1,18 @@
+{{ 2 }}
+{{  }}
+{{ "2" }}
+{{ 2 }}
+{{ 2, "in" }}
+{{ 2, {{ 1, 2 }} }}
+{{ "in", "iN" }}
+{{ 3, { "f1": "hi" } }}
+{{ 3 }}
+[ 3, { "f1": "hi" } ]
+[ 3, { "f1": "hi" } ]
+[ 3 ]
+[ 1 ]
+[ 2, 3 ]
+{{ null, null }}
+{{ null }}
+{{ null }}
+{{ }}
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/003/array_except.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/003/array_except.3.adm
new file mode 100644
index 0000000..01de1f0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/003/array_except.3.adm
@@ -0,0 +1 @@
+[ true, true, true, true, true, true, true ]
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/004/array_except.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/004/array_except.1.adm
new file mode 100644
index 0000000..e98340b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/004/array_except.1.adm
@@ -0,0 +1 @@
+[ [ 2 ], [  ], [ "2" ], [ 2 ], [ 2, "in" ], [ 2, {{ 1, 2 }} ], [ "in", "iN" ], [ 3, { "f1": "hi" } ], [ 3 ], [ 3, { "f1": "hi" } ], [ 3, { "f1": "hi" } ], [ 3 ], [ 1 ], [ 2, 3 ], [ null, null ], [ null ], [ null ], [  ] ]
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/005/array_except.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/005/array_except.1.adm
new file mode 100644
index 0000000..466739a
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/005/array_except.1.adm
@@ -0,0 +1 @@
+[ {{ 2 }}, {{  }}, {{ "2" }}, {{ 2 }}, {{ 2, "in" }}, {{ 2, {{ 1, 2 }} }}, {{ "in", "iN" }}, {{ 3, { "f1": "hi" } }}, {{ 3 }}, [ 3, { "f1": "hi" } ], [ 3, { "f1": "hi" } ], [ 3 ], [ 1 ], [ 2, 3 ], {{ null, null }}, {{ null }}, {{ null }}, {{ }} ]
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/006/array_except.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/006/array_except.1.adm
new file mode 100644
index 0000000..01de1f0
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_except/006/array_except.1.adm
@@ -0,0 +1 @@
+[ true, true, true, true, true, true, true ]
\ No newline at end of file
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 ba0a084..055c51b 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -2814,6 +2814,36 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="array_fun">
+      <compilation-unit name="array_except/001">
+        <output-dir compare="Text">array_except/001</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="array_fun">
+      <compilation-unit name="array_except/002">
+        <output-dir compare="Text">array_except/002</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="array_fun">
+      <compilation-unit name="array_except/003">
+        <output-dir compare="Text">array_except/003</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="array_fun">
+      <compilation-unit name="array_except/004">
+        <output-dir compare="Text">array_except/004</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="array_fun">
+      <compilation-unit name="array_except/005">
+        <output-dir compare="Text">array_except/005</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="array_fun">
+      <compilation-unit name="array_except/006">
+        <output-dir compare="Text">array_except/006</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="array_fun">
       <compilation-unit name="array_errors">
         <output-dir compare="Text">array_errors</output-dir>
         <expected-error>Input contains different list types (in line 25, at column 8)</expected-error>
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 1397b1a..953abf0 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
@@ -67,6 +67,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.ArrayExceptTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.ArrayIfNullTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.ArrayRangeTypeComputer;
 import org.apache.asterix.om.typecomputer.impl.ArrayRepeatTypeComputer;
@@ -260,6 +261,8 @@
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-slice", 2);
     public static final FunctionIdentifier ARRAY_SLICE_WITH_END_POSITION =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-slice", 3);
+    public static final FunctionIdentifier ARRAY_EXCEPT =
+            new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-except", 2);
 
     // objects
     public static final FunctionIdentifier RECORD_MERGE =
@@ -2200,6 +2203,7 @@
         addFunction(ARRAY_STAR, OpenARecordTypeComputer.INSTANCE, true);
         addFunction(ARRAY_SLICE_WITH_END_POSITION, AListTypeComputer.INSTANCE_SLICE, true);
         addFunction(ARRAY_SLICE_WITHOUT_END_POSITION, AListTypeComputer.INSTANCE_SLICE, true);
+        addFunction(ARRAY_EXCEPT, ArrayExceptTypeComputer.INSTANCE, true);
 
         // objects
         addFunction(RECORD_MERGE, RecordMergeTypeComputer.INSTANCE, true);
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayExceptTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayExceptTypeComputer.java
new file mode 100644
index 0000000..3471128
--- /dev/null
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayExceptTypeComputer.java
@@ -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.
+ */
+
+package org.apache.asterix.om.typecomputer.impl;
+
+import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer;
+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;
+
+public class ArrayExceptTypeComputer extends AbstractResultTypeComputer {
+
+    public static final ArrayExceptTypeComputer INSTANCE = new ArrayExceptTypeComputer();
+
+    private ArrayExceptTypeComputer() {
+    }
+
+    @Override
+    protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException {
+        IAType arg1Type = strippedInputTypes[0];
+        IAType arg2Type = strippedInputTypes[1];
+
+        switch (arg1Type.getTypeTag()) {
+            case ARRAY:
+            case MULTISET:
+            case ANY:
+                switch (arg2Type.getTypeTag()) {
+                    case ARRAY:
+                    case MULTISET:
+                    case ANY:
+                        return arg1Type;
+                    default:
+                        return BuiltinType.ANULL;
+                }
+            default:
+                return BuiltinType.ANULL;
+        }
+    }
+}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayExceptDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayExceptDescriptor.java
new file mode 100644
index 0000000..d4e3fac
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayExceptDescriptor.java
@@ -0,0 +1,235 @@
+/*
+ * 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 static org.apache.asterix.om.types.EnumDeserializer.ATYPETAGDESERIALIZER;
+
+import java.io.DataOutput;
+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.common.annotations.MissingNullInOutFunction;
+import org.apache.asterix.formats.nontagged.BinaryComparatorFactoryProvider;
+import org.apache.asterix.om.exceptions.ExceptionUtil;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+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.BuiltinType;
+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.asterix.runtime.utils.DescriptorFactoryUtil;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.dataflow.value.IBinaryComparator;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+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;
+
+/**
+ * array_except(arg1, arg2) takes 2 arguments, arg1 is an array, arg2 is an array, and returns an array with all
+ * the items in arg1 array except for the items in arg2 array.
+ */
+
+@MissingNullInOutFunction
+public class ArrayExceptDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+    private static final long serialVersionUID = 1L;
+    private IAType[] argTypes;
+
+    public static final IFunctionDescriptorFactory FACTORY =
+            DescriptorFactoryUtil.createFactory(ArrayExceptDescriptor::new, FunctionTypeInferers.SET_ARGUMENTS_TYPE);
+
+    @Override
+    public void setImmutableStates(Object... states) {
+        argTypes = (IAType[]) states;
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.ARRAY_EXCEPT;
+    }
+
+    @Override
+    public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args)
+            throws AlgebricksException {
+        return new IScalarEvaluatorFactory() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public IScalarEvaluator createScalarEvaluator(final IEvaluatorContext ctx) throws HyracksDataException {
+                return new ArrayExceptEval(args, ctx, sourceLoc, getIdentifier(), argTypes);
+            }
+        };
+    }
+
+    private class ArrayExceptEval extends AbstractScalarEval {
+
+        private final IEvaluatorContext ctx;
+
+        // Result
+        private final ArrayBackedValueStorage storage = new ArrayBackedValueStorage();
+        private final DataOutput storageOutput = storage.getDataOutput();
+
+        // List items (result is always a list of type string)
+        private final IAsterixListBuilder orderedListBuilder = new OrderedListBuilder();
+        private final IAsterixListBuilder unorderedListBuilder = new UnorderedListBuilder();
+
+        // Arguments
+        private final IScalarEvaluator arg1Eval;
+        private final IScalarEvaluator arg2Eval;
+        private final IPointable arg1Pointable = new VoidPointable();
+        private final IPointable arg2Pointable = new VoidPointable();
+
+        // List items
+        private final ListAccessor arg1ListAccessor = new ListAccessor();
+        private final ListAccessor arg2ListAccessor = new ListAccessor();
+        private IPointable arg1ListItem = new VoidPointable();
+        private IPointable arg2ListItem = new VoidPointable();
+        private ArrayBackedValueStorage arg1Storage = new ArrayBackedValueStorage();
+        private ArrayBackedValueStorage arg2Storage = new ArrayBackedValueStorage();
+
+        // Comparator
+        private IBinaryComparator comparator;
+
+        ArrayExceptEval(IScalarEvaluatorFactory[] args, IEvaluatorContext ctx, SourceLocation sourceLocation,
+                FunctionIdentifier functionIdentifier, IAType[] argTypes) throws HyracksDataException {
+            super(sourceLocation, functionIdentifier);
+
+            this.ctx = ctx;
+
+            arg1Eval = args[0].createScalarEvaluator(ctx);
+            arg2Eval = args[1].createScalarEvaluator(ctx);
+
+            IAType leftType =
+                    (argTypes[0].getTypeTag() == ATypeTag.ARRAY || argTypes[0].getTypeTag() == ATypeTag.MULTISET)
+                            ? ((AbstractCollectionType) argTypes[0]).getItemType() : BuiltinType.ANY;
+
+            IAType rightType =
+                    (argTypes[1].getTypeTag() == ATypeTag.ARRAY || argTypes[1].getTypeTag() == ATypeTag.MULTISET)
+                            ? ((AbstractCollectionType) argTypes[1]).getItemType() : BuiltinType.ANY;
+
+            comparator = BinaryComparatorFactoryProvider.INSTANCE.getBinaryComparatorFactory(leftType, rightType, true)
+                    .createBinaryComparator();
+        }
+
+        @Override
+        public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
+            arg1Eval.evaluate(tuple, arg1Pointable);
+            arg2Eval.evaluate(tuple, arg2Pointable);
+
+            if (PointableHelper.checkAndSetMissingOrNull(result, arg1Pointable, arg2Pointable)) {
+                return;
+            }
+
+            byte[] arg1Bytes = arg1Pointable.getByteArray();
+            int arg1StartOffset = arg1Pointable.getStartOffset();
+            ATypeTag arg1TypeTag = ATYPETAGDESERIALIZER.deserialize(arg1Bytes[arg1StartOffset]);
+
+            byte[] arg2Bytes = arg2Pointable.getByteArray();
+            int arg2StartOffset = arg2Pointable.getStartOffset();
+            ATypeTag arg2TypeTag = ATYPETAGDESERIALIZER.deserialize(arg2Bytes[arg2StartOffset]);
+
+            if (!arg1TypeTag.isListType()) {
+                ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, functionIdentifier, arg1Bytes[arg1StartOffset], 0,
+                        ATypeTag.ARRAY);
+                PointableHelper.setNull(result);
+                return;
+            }
+
+            if (!arg2TypeTag.isListType()) {
+                ExceptionUtil.warnTypeMismatch(ctx, sourceLoc, functionIdentifier, arg2Bytes[arg2StartOffset], 1,
+                        ATypeTag.ARRAY);
+                PointableHelper.setNull(result);
+                return;
+            }
+
+            // Reset the lists
+            arg1ListAccessor.reset(arg1Bytes, arg1StartOffset);
+            arg2ListAccessor.reset(arg2Bytes, arg2StartOffset);
+
+            // If any of the lists is empty, return the first list as is
+            if (arg1ListAccessor.size() == 0 || arg2ListAccessor.size() == 0) {
+                result.set(arg1Pointable);
+                return;
+            }
+
+            // Builder collection type
+            IAsterixListBuilder resultListBuilder =
+                    arg1ListAccessor.getListType() == ATypeTag.ARRAY ? orderedListBuilder : unorderedListBuilder;
+            AbstractCollectionType collectionType;
+
+            // If it is not a known list type, use open type
+            if (!argTypes[0].getTypeTag().isListType()) {
+                collectionType = (AbstractCollectionType) DefaultOpenFieldType
+                        .getDefaultOpenFieldType(arg1ListAccessor.getListType());
+            } else {
+                // known list type, use it
+                collectionType = (AbstractCollectionType) argTypes[0];
+            }
+
+            resultListBuilder.reset(collectionType);
+
+            try {
+                // Filter the items
+                boolean isItemFound;
+                for (int i = 0; i < arg1ListAccessor.size(); i++) {
+                    isItemFound = false;
+                    arg1Storage.reset();
+                    arg1ListAccessor.getOrWriteItem(i, arg1ListItem, arg1Storage);
+
+                    // Check if the item exists in second list
+                    for (int j = 0; j < arg2ListAccessor.size(); j++) {
+                        arg2Storage.reset();
+                        arg2ListAccessor.getOrWriteItem(j, arg2ListItem, arg2Storage);
+
+                        // Found the item in second list
+                        if (comparator.compare(arg1ListItem.getByteArray(), arg1ListItem.getStartOffset(),
+                                arg1ListItem.getLength(), arg2ListItem.getByteArray(), arg2ListItem.getStartOffset(),
+                                arg2ListItem.getLength()) == 0) {
+                            isItemFound = true;
+                            break;
+                        }
+                    }
+
+                    // Add the item if it is not found
+                    if (!isItemFound) {
+                        resultListBuilder.addItem(arg1ListItem);
+                    }
+                }
+            } catch (IOException ex) {
+                throw HyracksDataException.create(ex);
+            }
+
+            storage.reset();
+            resultListBuilder.write(storageOutput, true);
+            result.set(storage);
+        }
+    }
+}
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 0d8557f..13f8d7c 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
@@ -297,6 +297,7 @@
 import org.apache.asterix.runtime.evaluators.functions.ArrayConcatDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.ArrayContainsDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.ArrayDistinctDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.ArrayExceptDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.ArrayFlattenDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.ArrayIfNullDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.ArrayInsertDescriptor;
@@ -598,6 +599,7 @@
         fc.add(ArraySymDiffDescriptor.FACTORY);
         fc.add(ArraySymDiffnDescriptor.FACTORY);
         fc.add(ArrayStarDescriptor.FACTORY);
+        fc.add(ArrayExceptDescriptor.FACTORY);
 
         // unnesting functions
         fc.add(TidRunningAggregateDescriptor.FACTORY);