Merge branch 'gerrit/trinity' into 'master'

Change-Id: I58d876bddb6ef8e683aec5dea447fb38be3fd5d8
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.1.ddl.sqlpp
index 22a7e71..45c9e04 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.1.ddl.sqlpp
@@ -49,8 +49,14 @@
   user : TwitterUserType?
 };
 
+create type TinySocial.openType as {
+  id: int
+};
+
 create  dataset TwitterUsers(TwitterUserType) primary key `screen-name`;
 
 create  dataset TweetMessages(TweetMessageType) primary key tweetid;
 
-create  dataset TweetMessages2(TweetMessageType2) primary key tweetid;
\ No newline at end of file
+create  dataset TweetMessages2(TweetMessageType2) primary key tweetid;
+
+create  dataset ds(openType) primary key id;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.2.update.sqlpp
index 0c78212..dce0a5f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.2.update.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.2.update.sqlpp
@@ -28,4 +28,6 @@
 
 load  dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`));
 
-load  dataset TweetMessages2 using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`));
\ No newline at end of file
+load  dataset TweetMessages2 using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`));
+
+upsert into ds {"id": 1, "o": { "a": 2, "b": "t", "obj": {"x": 3, "y": {"y1": 1, "y2": [1,2]}, "z": [1,2]}, "array": [1,2,3]}};
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.4.query.sqlpp
new file mode 100644
index 0000000..70b05de
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.4.query.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+/*
+ * Description  : Testing object_values for an open-type record.
+ * Expected Res : Success
+ */
+
+use TinySocial;
+select object_values(ds.o) from ds;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.9.ddl.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.4.ddl.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/objects/object_values/object_values.9.ddl.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_values/object_values.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_values/object_values.4.adm
new file mode 100644
index 0000000..fbd534c
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/objects/object_values/object_values.4.adm
@@ -0,0 +1 @@
+{ "$1": [ 2, "t", { "x": 3, "y": { "y1": 1, "y2": [ 1, 2 ] }, "z": [ 1, 2 ] }, [ 1, 2, 3 ] ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ARecordCaster.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ARecordCaster.java
index 56bdfc5..7354c1e 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ARecordCaster.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/cast/ARecordCaster.java
@@ -194,10 +194,12 @@
 
     private void matchClosedPart(List<IVisitablePointable> fieldNames, List<IVisitablePointable> fieldTypeTags)
             throws HyracksDataException {
-        // sort-merge based match
-        quickSort(fieldNamesSortedIndex, fieldNames, 0, numInputFields - 1);
         int fnStart = 0;
         int reqFnStart = 0;
+        if (fnStart < numInputFields && reqFnStart < reqFieldNames.size()) {
+            // sort-merge based match
+            quickSort(fieldNamesSortedIndex, fieldNames, 0, numInputFields - 1);
+        }
         while (fnStart < numInputFields && reqFnStart < reqFieldNames.size()) {
             int fnPos = fieldNamesSortedIndex[fnStart];
             int reqFnPos = reqFieldNamesSortedIndex[reqFnStart];
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/nonvisitor/ARecordPointable.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/nonvisitor/ARecordPointable.java
index cc3816c..ab86c1d 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/nonvisitor/ARecordPointable.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/pointables/nonvisitor/ARecordPointable.java
@@ -244,7 +244,9 @@
     // -----------------------
 
     public final void getOpenFieldValue(ARecordType recordType, int fieldId, DataOutput dOut) throws IOException {
-        dOut.write(bytes, getOpenFieldValueOffset(recordType, fieldId), getOpenFieldValueSize(recordType, fieldId));
+        // + 1 to include the tag
+        int len = getOpenFieldValueSize(recordType, fieldId) + 1;
+        dOut.write(bytes, getOpenFieldValueOffset(recordType, fieldId), len);
     }
 
     public final int getOpenFieldValueOffset(ARecordType recordType, int fieldId) {
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordValuesEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordValuesEvaluator.java
index 783f4e6..106a899 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordValuesEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/records/RecordValuesEvaluator.java
@@ -20,16 +20,19 @@
 package org.apache.asterix.runtime.evaluators.functions.records;
 
 import java.io.DataOutput;
+import java.io.IOException;
 import java.util.List;
 
 import org.apache.asterix.builders.OrderedListBuilder;
 import org.apache.asterix.om.pointables.ARecordVisitablePointable;
 import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
 import org.apache.asterix.om.pointables.base.IVisitablePointable;
+import org.apache.asterix.om.pointables.nonvisitor.ARecordPointable;
 import org.apache.asterix.om.types.AOrderedListType;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.ATypeTag;
 import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.utils.RecordUtil;
 import org.apache.asterix.runtime.evaluators.functions.CastTypeEvaluator;
 import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
@@ -45,6 +48,9 @@
     private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
     private final DataOutput resultOutput = resultStorage.getDataOutput();
     private final IScalarEvaluator eval0;
+    private final boolean inputRecordOpen;
+    private final ARecordPointable recordPointable;
+    private final ArrayBackedValueStorage fieldValueStorage;
     private OrderedListBuilder listBuilder;
     private ARecordVisitablePointable openRecordPointable;
     private CastTypeEvaluator inputRecordCaster;
@@ -52,9 +58,19 @@
     RecordValuesEvaluator(IScalarEvaluator eval0, ARecordType recordType) {
         this.eval0 = eval0;
         if (recordType != null) {
+            inputRecordOpen = recordType.isOpen() && recordType.getFieldTypes().length == 0;
             openRecordPointable = new ARecordVisitablePointable(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
             inputRecordCaster = new CastTypeEvaluator(BuiltinType.ANY, recordType, eval0);
             listBuilder = new OrderedListBuilder();
+        } else {
+            inputRecordOpen = true;
+        }
+        if (inputRecordOpen) {
+            recordPointable = new ARecordPointable();
+            fieldValueStorage = new ArrayBackedValueStorage();
+        } else {
+            recordPointable = null;
+            fieldValueStorage = null;
         }
     }
 
@@ -72,14 +88,18 @@
             PointableHelper.setNull(result);
             return;
         }
-        inputRecordCaster.evaluate(tuple, inputRecordPointable);
         resultStorage.reset();
-        buildOutputList();
+        if (inputRecordOpen) {
+            buildOutputList();
+        } else {
+            buildOutputList(tuple);
+        }
         result.set(resultStorage);
     }
 
-    private void buildOutputList() throws HyracksDataException {
+    private void buildOutputList(IFrameTupleReference tuple) throws HyracksDataException {
         listBuilder.reset(AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE);
+        inputRecordCaster.evaluate(tuple, inputRecordPointable);
         openRecordPointable.set(inputRecordPointable);
         final List<IVisitablePointable> fieldValues = openRecordPointable.getFieldValues();
         for (int i = 0, valuesCount = fieldValues.size(); i < valuesCount; i++) {
@@ -87,4 +107,21 @@
         }
         listBuilder.write(resultOutput, true);
     }
+
+    private void buildOutputList() throws HyracksDataException {
+        listBuilder.reset(AOrderedListType.FULL_OPEN_ORDEREDLIST_TYPE);
+        recordPointable.set(inputRecordPointable);
+        int openFieldCount = recordPointable.getOpenFieldCount(RecordUtil.FULLY_OPEN_RECORD_TYPE);
+        for (int i = 0; i < openFieldCount; i++) {
+            fieldValueStorage.reset();
+            try {
+                recordPointable.getOpenFieldValue(RecordUtil.FULLY_OPEN_RECORD_TYPE, i,
+                        fieldValueStorage.getDataOutput());
+                listBuilder.addItem(fieldValueStorage);
+            } catch (IOException e) {
+                throw HyracksDataException.create(e);
+            }
+        }
+        listBuilder.write(resultOutput, true);
+    }
 }