Heri Ramampiaro has uploaded a new change for review.
https://asterix-gerrit.ics.uci.edu/523
Change subject: ASTERIXDB-944: added an AQL function that prints internal data
format
......................................................................
ASTERIXDB-944: added an AQL function that prints internal data format
The adm-to-bytes implemented here is for debugging/documentation. It prints an
accurate picture of the internal representation of an ADM instance, i.e., a
slightly marked up version of the bytes used to represent the instance.
Change-Id: I31d0b2ec2d8686531833811937596c3dca660b1e
---
A asterix-doc/src/site/markdown/aql/admdebuggerfunctions.md
M
asterix-om/src/main/java/org/apache/asterix/om/functions/AsterixBuiltinFunctions.java
A
asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AdmToBytesTypeComputer.java
A
asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeComputerUtils.java
A
asterix-om/src/main/java/org/apache/asterix/om/util/admdebugger/AnnotatedFieldNameComputerUtil.java
A
asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesDescriptor.java
A
asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesFactory.java
A
asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesHelper.java
A
asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableUtils.java
A
asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/AdmToBytesVisitor.java
A
asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/ListBytesProcessor.java
A
asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/RecordBytesProcessor.java
M
asterix-runtime/src/main/java/org/apache/asterix/runtime/formats/NonTaggedDataFormat.java
13 files changed, 1,683 insertions(+), 13 deletions(-)
git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb
refs/changes/23/523/1
diff --git a/asterix-doc/src/site/markdown/aql/admdebuggerfunctions.md
b/asterix-doc/src/site/markdown/aql/admdebuggerfunctions.md
new file mode 100644
index 0000000..097403f
--- /dev/null
+++ b/asterix-doc/src/site/markdown/aql/admdebuggerfunctions.md
@@ -0,0 +1,68 @@
+### adm-to-bytes ###
+* Syntax:
+
+ adm-to-bytes(var1, number)
+
+
+ * Displays the annotated bytes of a data value. The main goal with this
function is to debug the object serialization
+ process in AsterixDB and to show how data being stored look like. Its mainly
used for debugging purposes.
+ * Arguments:
+ * `var1`: a data value, including record, list, string, and number.
+ * `number`: a number value from 0 to infinty ("INF") specifying the nested
level of a record.
+ `number = 0` prints the raw byte array value, `number = 1` or higher
prints the byte arrays with
+ corresponding annotations. This function is mainly used for debugging.
+ * Return Value:
+ * A record showing the raw byte array or annotaded byte arrays.
+
+
+ * Example:
+
+ let $r1 := {"id":1,
+ "project":"AsterixDB",
+ "address":{"city":"Irvine", "state":"CA"},
+ "related":["Hivestrix", "Preglix", "Apache VXQuery"] }
+ return adm-to-bytes($r1, <Level>);
+
+ * The expected results are:
+
+ Level=0:
+
+ { "RawBytes": "[24, 0, 0, 0, -127, 0, 0, 0, 4, 0, 0, 0, 25, 0, 0, 0,
33, 0, 0, 0, 44,
+ 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9, 65, 115, 116, 101, 114,
105, 120, 68, 66,
+ 0, 0, 0, 29, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 25, 0, 6, 73, 114,
118, 105, 110, 101,
+ 0, 2, 67, 65, 13, 0, 0, 0, 58, 0, 0, 0, 3, 0, 0, 0, 22, 0, 0, 0, 33,
0, 0, 0, 42, 0,
+ 9, 72, 105, 118, 101, 115, 116, 114, 105, 120, 0, 7, 80, 114, 101,
103, 108, 105, 120,
+ 0, 14, 65, 112, 97, 99, 104, 101, 32, 86, 88, 81, 117, 101, 114,
121]" }
+
+ Level=1:
+
+ { "Tag": "[24]", "Length": "[0, 0, 0, -127]", "NumberOfClosedFields":
"[0, 0, 0, 4]",
+ "ClosedFieldOffsets": "[0, 0, 0, 25, 0, 0, 0, 33, 0, 0, 0, 44, 0, 0,
0, 72]",
+ "ClosedFields": "[0, 0, 0, 0, 0, 0, 0, 1, 0, 9, 65, 115, 116, 101,
114, 105, 120,
+ 68, 66, 0, 0, 0, 29, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 25, 0, 6, 73,
114, 118, 105,
+ 110, 101, 0, 2, 67, 65, 13, 0, 0, 0, 58, 0, 0, 0, 3, 0, 0, 0, 22, 0,
0, 0, 33, 0, 0,
+ 0, 42, 0, 9, 72, 105, 118, 101, 115, 116, 114, 105, 120, 0, 7, 80,
114, 101, 103,
+ 108, 105, 120, 0, 14, 65, 112, 97, 99, 104, 101, 32, 86, 88, 81, 117,
101, 114, 121]" }
+
+ Level=2:
+
+ { "id": { "Tag": "[4]", "Value": "[0, 0, 0, 0, 0, 0, 0, 1]" },
"project": { "Tag": "[13]",
+ "Value": "[65, 115, 116, 101, 114, 105, 120, 68, 66]", "Length":
"[9]" }, "address":
+ { "Tag": "[24]", "Length": "[0, 0, 0, 29]", "NumberOfClosedFields":
"[0, 0, 0, 2]",
+ "ClosedFieldOffsets": "[0, 0, 0, 17, 0, 0, 0, 25]", "ClosedFields":
"[0, 6, 73, 114, 118,
+ 105, 110, 101, 0, 2, 67, 65]" }, "related": { "Tag": "[22]",
"ItemType": "[13]",
+ "Length": "[0, 0, 0, 58]", "NumberOfItems": "[0, 0, 0, 3]",
"ItemOffsets": "[0, 0, 0, 22,
+ 0, 0, 0, 33, 0, 0, 0, 42]", "Value": "[0, 9, 72, 105, 118, 101, 115,
116, 114, 105, 120,
+ 0, 7, 80, 114, 101, 103, 108, 105, 120, 0, 14, 65, 112, 97, 99, 104,
101, 32, 86, 88, 81,
+ 117, 101, 114, 121]" } }
+
+ Level>=3 (including "INF"):
+
+ { "id": { "Tag": "[4]", "Value": "[0, 0, 0, 0, 0, 0, 0, 1]" },
"project": { "Tag": "[13]",
+ "Length": "[9]", "Value": "[65, 115, 116, 101, 114, 105, 120, 68, 66]"
},
+ "address": { "city": { "Tag": "[13]", "Length": "[0, 6]", "Value":
"[73, 114, 118, 105,
+ 110, 101]" }, "state": { "Tag": "[13]", "Length": "[0, 2]", "Value":
"[67, 65]" } },
+ "related": { "Tag": "[22]", "ItemType": "[13]", "Length": "[0, 0, 0,
58]", "NumberOfItems":
+ "[0, 0, 0, 3]", "ItemOffsets": "[0, 0, 0, 22, 0, 0, 0, 33, 0, 0, 0,
42]", "Value": "[0, 9,
+ 72, 105, 118, 101, 115, 116, 114, 105, 120, 0, 7, 80, 114, 101, 103,
108, 105, 120, 0, 14,
+ 65, 112, 97, 99, 104, 101, 32, 86, 88, 81, 117, 101, 114, 121]" } }
diff --git
a/asterix-om/src/main/java/org/apache/asterix/om/functions/AsterixBuiltinFunctions.java
b/asterix-om/src/main/java/org/apache/asterix/om/functions/AsterixBuiltinFunctions.java
index ad4831f..fd0a745 100644
---
a/asterix-om/src/main/java/org/apache/asterix/om/functions/AsterixBuiltinFunctions.java
+++
b/asterix-om/src/main/java/org/apache/asterix/om/functions/AsterixBuiltinFunctions.java
@@ -18,12 +18,6 @@
*/
package org.apache.asterix.om.functions;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import org.apache.asterix.common.functions.FunctionConstants;
import org.apache.asterix.common.functions.FunctionSignature;
import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
@@ -40,6 +34,7 @@
import org.apache.asterix.om.typecomputer.impl.AStringTypeComputer;
import org.apache.asterix.om.typecomputer.impl.ATimeTypeComputer;
import org.apache.asterix.om.typecomputer.impl.AUUIDTypeComputer;
+import org.apache.asterix.om.typecomputer.impl.AdmToBytesTypeComputer;
import org.apache.asterix.om.typecomputer.impl.AnyTypeComputer;
import
org.apache.asterix.om.typecomputer.impl.BinaryBooleanOrNullFunctionTypeComputer;
import
org.apache.asterix.om.typecomputer.impl.BinaryStringBoolOrNullTypeComputer;
@@ -117,6 +112,12 @@
import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
public class AsterixBuiltinFunctions {
public enum SpatialFilterKind {
@@ -190,6 +191,9 @@
"get-record-fields", 1);
public final static FunctionIdentifier GET_RECORD_FIELD_VALUE = new
FunctionIdentifier(FunctionConstants.ASTERIX_NS,
"get-record-field-value", 2);
+
+ public final static FunctionIdentifier ADM_TO_BYTES = new
FunctionIdentifier(
+ FunctionConstants.ASTERIX_NS, "adm-to-bytes", 2);
// numeric
public final static FunctionIdentifier NUMERIC_UNARY_MINUS = new
FunctionIdentifier(FunctionConstants.ASTERIX_NS,
@@ -942,6 +946,8 @@
addFunction(GET_RECORD_FIELDS, OrderedListOfAnyTypeComputer.INSTANCE,
true);
addFunction(GET_RECORD_FIELD_VALUE,
FieldAccessNestedResultType.INSTANCE, true);
+ addFunction(ADM_TO_BYTES, AdmToBytesTypeComputer.INSTANCE, true);
+
// temporal type accessors
addFunction(ACCESSOR_TEMPORAL_YEAR,
OptionalAInt64TypeComputer.INSTANCE, true);
addFunction(ACCESSOR_TEMPORAL_MONTH,
OptionalAInt64TypeComputer.INSTANCE, true);
diff --git
a/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AdmToBytesTypeComputer.java
b/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AdmToBytesTypeComputer.java
new file mode 100644
index 0000000..fcaa2d8
--- /dev/null
+++
b/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AdmToBytesTypeComputer.java
@@ -0,0 +1,226 @@
+/*
+ * 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.AsterixException;
+import org.apache.asterix.om.base.AInt64;
+import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.base.IAObject;
+import org.apache.asterix.om.constants.AsterixConstantValue;
+import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
+import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
+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.AUnionType;
+import org.apache.asterix.om.types.AUnorderedListType;
+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.om.types.TypeHelper;
+import org.apache.asterix.om.util.admdebugger.AnnotatedFieldNameComputerUtil;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
+import
org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import org.apache.hyracks.algebricks.core.algebra.metadata.IMetadataProvider;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.exceptions.HyracksException;
+
+public class AdmToBytesTypeComputer implements IResultTypeComputer {
+ public static final AdmToBytesTypeComputer INSTANCE = new
AdmToBytesTypeComputer();
+ private final long VARIABLE_OUTPULEVEL = -1;
+ private long outputLevel = 0;
+
+ private AdmToBytesTypeComputer() {
+ }
+
+ public static AbstractCollectionType extractListType(IAType type) {
+ if (type.getTypeTag() == ATypeTag.UNORDEREDLIST)
+ return TypeComputerUtils.extractUnorderedListType(type);
+ else
+ return TypeComputerUtils.extractOrderedListType(type);
+ }
+
+ private long getLevel(IAType inputType1, ILogicalExpression expr) throws
AlgebricksException {
+ // Treat null as a level = 0
+ if (inputType1.getTypeTag() == ATypeTag.NULL) {
+ return 0;
+ }
+
+ // If input level is a variable
+ if (expr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
+ return VARIABLE_OUTPULEVEL;
+ }
+
+ if (expr.getExpressionTag() != LogicalExpressionTag.CONSTANT)
+ throw new AlgebricksException("Expected a variable or either an
integer or a string (INF) constant"
+ + " but got a " + expr.getExpressionTag());
+
+ ConstantExpression constExpr = (ConstantExpression) expr;
+ IAObject value = ((AsterixConstantValue)
constExpr.getValue()).getObject();
+
+ switch (inputType1.getTypeTag()) {
+ case INT64:
+ return ((AInt64) value).getLongValue();
+ case STRING:
+ String valStr = ((AString) value).getStringValue();
+ if (valStr.equals("INF")) { // Check if infinity
+ return Long.MAX_VALUE;
+ } else { // We accept also numbers expressed as string
+ for (int i = 0; i < valStr.length(); i++) {
+ if (!Character.isDigit(valStr.charAt(i))) {
+ throw new AlgebricksException("Invalid number.
Expected argument is a number from 0 "
+ + "to INF, where INF is infinity");
+ }
+ }
+ return Long.parseLong(valStr);
+ }
+ default:
+ throw new AlgebricksException("Invalid argument. Expected a
number from 0 "
+ + "to INF, where INF is infinity, but got " +
inputType1);
+ }
+ }
+
+ @Override
+ public IAType computeType(ILogicalExpression expression,
IVariableTypeEnvironment env,
+ IMetadataProvider<?, ?> metadataProvider) throws
AlgebricksException {
+ AbstractFunctionCallExpression funcExpr =
(AbstractFunctionCallExpression) expression;
+
+ ILogicalExpression expr1 = funcExpr.getArguments().get(1).getValue();
+ IAType type1 = (IAType) env.getType(expr1);
+ outputLevel = getLevel(type1, expr1);
+
+ // If level is unknown at translation time (input is a variable)
+ if (outputLevel == VARIABLE_OUTPULEVEL) {
+ IAType resultType =
DefaultOpenFieldType.getDefaultOpenFieldType(type1.getTypeTag());
+ if (resultType == null) {
+ return DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
+ }
+ return resultType;
+ }
+
+ // If for printing of the raw bytes only
+ if (outputLevel == 0) {
+ try {
+ return new ARecordType("RawBytes", new String[] { "RawBytes"
}, new IAType[] { BuiltinType.ASTRING },
+ false);
+ } catch (HyracksDataException | AsterixException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+
+ // For printing annotated byte arrays (outputLevel > 0)
+ return computeResultType((IAType)
env.getType(funcExpr.getArguments().get(0).getValue()), 1);
+ }
+
+ private IAType computeResultType(IAType inType, long nestedLevel) throws
AlgebricksException {
+ IAType inputType = inType;
+ IAType resultType;
+
+ if (TypeHelper.canBeNull(inputType)) {
+ return AUnionType.createNullableType(AnnotatedFieldNameComputerUtil
+ .getNullableAnnotatedFieldsRecordType(true));
+ }
+
+ // If the input type is not a record or level = 1, not a complex
object or reached the lowest nesting level we
+ // print out the annotated byte with no nesting level processing
+ if (outputLevel == 1 || !inputType.getTypeTag().isDerivedType() ||
nestedLevel == outputLevel) {
+ resultType =
AnnotatedFieldNameComputerUtil.getAnnotatedBytesRecordType(inputType.getTypeTag());
+ } else { // Is a list or a record and outputLevel > 1
+ switch (inputType.getTypeTag()) {
+ case RECORD:
+ resultType = getResultRecordType(inputType, nestedLevel);
+ break;
+ case UNION:
+ resultType = computeResultType(inputType, nestedLevel);
+ break;
+ default: //an UNORDEREDLIST or ORDEREDLIST
+ resultType = getResultListType(inputType, nestedLevel);
+ }
+ }
+
+ return resultType;
+ }
+
+ private IAType getResultListType(IAType inputType, long nestedLevel)
throws AlgebricksException {
+ AbstractCollectionType inputListType = extractListType(inputType);
+ if (inputListType.getItemType().getTypeTag() == ATypeTag.ANY ||
inputListType == null) {
+ return creatListType(inputType.getTypeTag(), BuiltinType.ANY,
"annotated-bytes-open-type");
+ }
+ return getNestedList(inputListType, nestedLevel);
+ }
+
+ private IAType getNestedList(AbstractCollectionType inputListType, long
nestedLevel) throws AlgebricksException {
+ IAType inputItemType = inputListType.getItemType();
+ ATypeTag inputItemTypeTypeTag = inputItemType.getTypeTag();
+ IAType reqItemType;
+ if (inputItemTypeTypeTag.isDerivedType() && nestedLevel < outputLevel)
{
+ reqItemType = computeResultType(inputItemType, nestedLevel + 1);
+ } else {
+ reqItemType =
AnnotatedFieldNameComputerUtil.getAnnotatedBytesRecordType(inputItemType.getTypeTag());
+ }
+ return creatListType(inputListType.getTypeTag(), reqItemType,
"annotated-bytes(" + inputListType.getTypeName()
+ + ")");
+ }
+
+ private IAType creatListType(ATypeTag typeTag, IAType itemType, String
typeName) throws AlgebricksException {
+ switch (typeTag) {
+ case ORDEREDLIST:
+ return new AOrderedListType(itemType, typeName);
+ case UNORDEREDLIST:
+ return new AUnorderedListType(itemType, typeName);
+ default:
+ throw new AlgebricksException("Not a valid AsterixDB list");
+ }
+ }
+
+ private IAType getResultRecordType(IAType inputType, long nestedLevel)
throws AlgebricksException {
+ ARecordType inputRecordType =
TypeComputerUtils.extractRecordType(inputType);
+ if (inputRecordType == null) {
+ return DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
+ }
+ return getNestedRecordFields(inputRecordType, nestedLevel);
+ }
+
+ private ARecordType getNestedRecordFields(ARecordType inputType, long
nestedLevel) throws AlgebricksException {
+ try {
+ String fieldNames[] = inputType.getFieldNames();
+ IAType fieldTypes[] = inputType.getFieldTypes();
+
+ IAType[] newTypes = new IAType[fieldNames.length];
+ for (int i = 0; i < fieldTypes.length; i++) {
+ ATypeTag fieldTypeTag = fieldTypes[i].getTypeTag();
+ if (fieldTypeTag.isDerivedType() && nestedLevel < outputLevel)
{
+ newTypes[i] = computeResultType(fieldTypes[i], nestedLevel
+ 1);
+ } else {
+ newTypes[i] = AnnotatedFieldNameComputerUtil
+
.getAnnotatedBytesRecordType(fieldTypes[i].getTypeTag());
+ }
+ }
+ String typeName = "annotated-bytes(" + inputType.getTypeName() +
")";
+ return new ARecordType(typeName, fieldNames, newTypes,
inputType.isOpen());
+
+ } catch (AsterixException | HyracksException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+}
diff --git
a/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeComputerUtils.java
b/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeComputerUtils.java
new file mode 100644
index 0000000..3834ae4
--- /dev/null
+++
b/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/TypeComputerUtils.java
@@ -0,0 +1,80 @@
+/*
+ * 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.types.AOrderedListType;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.AUnorderedListType;
+import org.apache.asterix.om.types.IAType;
+
+public class TypeComputerUtils {
+
+ private TypeComputerUtils() {
+
+ }
+
+ public static ARecordType extractRecordType(IAType t) {
+ if (t.getTypeTag() == ATypeTag.RECORD) {
+ return (ARecordType) t;
+ }
+
+ if (t.getTypeTag() == ATypeTag.UNION) {
+ IAType innerType = ((AUnionType) t).getUnionList().get(1);
+ if (innerType.getTypeTag() == ATypeTag.RECORD) {
+ return (ARecordType) innerType;
+ }
+ }
+
+ return null;
+ }
+
+ public static AOrderedListType extractOrderedListType(IAType t) {
+ if (t.getTypeTag() == ATypeTag.ORDEREDLIST) {
+ return (AOrderedListType) t;
+ }
+
+ if (t.getTypeTag() == ATypeTag.UNION) {
+ IAType innerType = ((AUnionType) t).getUnionList().get(1);
+ if (innerType.getTypeTag() == ATypeTag.ORDEREDLIST) {
+ return (AOrderedListType) innerType;
+ }
+ }
+
+ return null;
+ }
+
+ public static AUnorderedListType extractUnorderedListType(IAType t) {
+ if (t.getTypeTag() == ATypeTag.UNORDEREDLIST) {
+ return (AUnorderedListType) t;
+ }
+
+ if (t.getTypeTag() == ATypeTag.UNION) {
+ IAType innerType = ((AUnionType) t).getUnionList().get(1);
+ if (innerType.getTypeTag() == ATypeTag.UNORDEREDLIST) {
+ return (AUnorderedListType) innerType;
+ }
+ }
+
+ return null;
+ }
+
+
+}
diff --git
a/asterix-om/src/main/java/org/apache/asterix/om/util/admdebugger/AnnotatedFieldNameComputerUtil.java
b/asterix-om/src/main/java/org/apache/asterix/om/util/admdebugger/AnnotatedFieldNameComputerUtil.java
new file mode 100644
index 0000000..a5eae65
--- /dev/null
+++
b/asterix-om/src/main/java/org/apache/asterix/om/util/admdebugger/AnnotatedFieldNameComputerUtil.java
@@ -0,0 +1,131 @@
+/*
+ * 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.util.admdebugger;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+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.types.IAType;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public class AnnotatedFieldNameComputerUtil {
+ private AnnotatedFieldNameComputerUtil() {
+ }
+
+ public static ARecordType getAnnotatedBytesRecordType(ATypeTag typeTag)
throws AlgebricksException {
+ switch (typeTag) {
+ case RECORD:
+ return
createAnnotatedFieldsRecordType(ByteAnnotationField.recordFields, true);
+ case ORDEREDLIST:
+ case UNORDEREDLIST:
+ return
createAnnotatedFieldsRecordType(ByteAnnotationField.listFields, false);
+ case STRING:
+ return
createAnnotatedFieldsRecordType(ByteAnnotationField.stringObjectFields, false);
+ case UNION:
+ return getNullableAnnotatedFieldsRecordType(true);
+ case NULL:
+ return getNullableAnnotatedFieldsRecordType(false);
+ default:
+ return
createAnnotatedFieldsRecordType(ByteAnnotationField.asterixObjectFields, true);
+ }
+ }
+
+ public static ARecordType getNullableAnnotatedFieldsRecordType(boolean
isOpen) throws AlgebricksException {
+ try {
+ return new ARecordType("NullableAnnotationRecord",
+ new String[] { ByteAnnotationField.TAG.fieldName() }, new
IAType[] { BuiltinType.ASTRING }, isOpen);
+ } catch (AsterixException | HyracksDataException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+
+ private static ARecordType
createAnnotatedFieldsRecordType(Set<ByteAnnotationField> fields, boolean isOpen)
+ throws AlgebricksException {
+ String fieldNames[] = new String[fields.size()];
+ IAType fieldTypes[] = new IAType[fields.size()];
+ try {
+ int j = 0;
+ for (ByteAnnotationField baf : fields) {
+ fieldNames[j] = baf.fieldName();
+ fieldTypes[j] = BuiltinType.ASTRING;
+ j++;
+ }
+ return new ARecordType("ByteArrayfields", fieldNames, fieldTypes,
isOpen);
+
+ } catch (HyracksDataException | AsterixException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+
+ public enum ByteAnnotationField {
+ // Common
+ TAG("Tag"),
+
+ // FOR RECORDS
+ // (required)
+ NUMBER_CLOSED_FIELDS("NumberOfClosedFields"),
+ CLOSED_FIELD_OFFSETS("ClosedFieldOffsets"),
+ CLOSED_FIELDS("ClosedFields"),
+ // Optional
+ NULLBITMAP("NullBitMap"),
+ IS_EXPANDED("IsExpanded"),
+ OPENPART_OFFSET("OpenPartOffset"),
+ NUMBER_OF_OPEN_FIELDS("NumberOfOpenFields"),
+ OPEN_FIELDS_HASH_OFFSET("OpenfieldHashCodeAndOffsets"),
+ OPEN_FIELDS("OpenFields"),
+
+ // FOR LISTS
+ ITEM_TYPE("ItemType"),
+ NUMBER_OF_ITEMS("NumberOfItems"),
+ ITEM_OFFSETS("ItemOffsets"),
+
+ // FOR PRIMITIVE TYPES
+ VALUE("Value"),
+
+ // For all but numeric values
+ LENGTH("Length");
+
+ public static EnumSet<ByteAnnotationField> recordFields =
EnumSet.of(TAG, LENGTH,
+ NUMBER_CLOSED_FIELDS, CLOSED_FIELD_OFFSETS, CLOSED_FIELDS);
+ public static EnumSet<ByteAnnotationField> listFields =
EnumSet.of(TAG, ITEM_TYPE, LENGTH, NUMBER_OF_ITEMS,
+ ITEM_OFFSETS, VALUE);
+ public static EnumSet<ByteAnnotationField> stringObjectFields =
EnumSet.of(TAG, LENGTH, VALUE);
+ public static EnumSet<ByteAnnotationField> asterixObjectFields =
EnumSet.of(TAG, VALUE); // All other objects
+
+ private String fieldName;
+
+ ByteAnnotationField(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ @Override
+ public String toString() {
+ return "{" + fieldName + "}";
+ }
+
+ public String fieldName() {
+ return this.fieldName;
+ }
+ }
+}
diff --git
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesDescriptor.java
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesDescriptor.java
new file mode 100644
index 0000000..e62e741
--- /dev/null
+++
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesDescriptor.java
@@ -0,0 +1,75 @@
+/*
+ * 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 org.apache.asterix.om.functions.AsterixBuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptor;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.om.typecomputer.impl.TypeComputerUtils;
+import org.apache.asterix.om.types.IAType;
+import
org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory;
+
+public class AdmToBytesDescriptor extends
AbstractScalarFunctionDynamicDescriptor {
+ private static final long serialVersionUID = 1L;
+
+ private IAType outputType;
+ private IAType inputType;
+
+ public static final IFunctionDescriptorFactory FACTORY = new
IFunctionDescriptorFactory() {
+ public IFunctionDescriptor createFunctionDescriptor() {
+ return new AdmToBytesDescriptor();
+ }
+ };
+
+
+ public void reset(IAType outputType, IAType inType) {
+ switch (inType.getTypeTag()) {
+ case RECORD:
+ this.inputType = TypeComputerUtils.extractRecordType(inType);
+ break;
+ case UNORDEREDLIST:
+ this.inputType =
TypeComputerUtils.extractUnorderedListType(inType);
+ break;
+ case ORDEREDLIST:
+ this.inputType =
TypeComputerUtils.extractOrderedListType(inType);
+ break;
+ default:
+ this.inputType = inType;
+ }
+
+ this.outputType = outputType;
+
+ }
+
+
+ private AdmToBytesDescriptor() {
+
+ }
+
+ public ICopyEvaluatorFactory createEvaluatorFactory(final
ICopyEvaluatorFactory[] args) throws AlgebricksException {
+ return new AdmToBytesFactory(args[0], args[1], inputType, outputType);
+ }
+
+ @Override public FunctionIdentifier getIdentifier() {
+ return AsterixBuiltinFunctions.ADM_TO_BYTES;
+ }
+}
diff --git
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesFactory.java
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesFactory.java
new file mode 100644
index 0000000..82e4763
--- /dev/null
+++
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesFactory.java
@@ -0,0 +1,219 @@
+/*
+ * 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.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.asterix.builders.IARecordBuilder;
+import org.apache.asterix.builders.RecordBuilder;
+import org.apache.asterix.common.exceptions.AsterixException;
+import
org.apache.asterix.dataflow.data.nontagged.serde.AStringSerializerDeserializer;
+import org.apache.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import org.apache.asterix.om.base.ANull;
+import org.apache.asterix.om.base.AString;
+import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
+import org.apache.asterix.om.pointables.PointableAllocator;
+import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
+import org.apache.asterix.om.pointables.base.IVisitablePointable;
+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.types.EnumDeserializer;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.runtime.RuntimeRecordTypeInfo;
+import org.apache.asterix.om.util.ResettableByteArrayOutputStream;
+import
org.apache.asterix.runtime.evaluators.visitors.admdebugging.AdmToBytesVisitor;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+import org.apache.hyracks.algebricks.runtime.base.ICopyEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory;
+import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IDataOutputProvider;
+import org.apache.hyracks.data.std.api.IValueReference;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+import org.apache.hyracks.util.string.UTF8StringUtil;
+
+/**
+ * Check each field in a record and prints out the serialized values of the
fields
+ */
+public class AdmToBytesFactory implements ICopyEvaluatorFactory {
+ private static final byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
+ private ICopyEvaluatorFactory inputEvalFactory;
+ private ICopyEvaluatorFactory levelEvalFactory;
+ private IAType outputType;
+ private IAType inputArgType;
+
+ public AdmToBytesFactory(ICopyEvaluatorFactory inputEvalFactory,
ICopyEvaluatorFactory levelEvalFactory,
+ IAType inputArgType, IAType outputType) {
+ this.levelEvalFactory = levelEvalFactory;
+ this.inputEvalFactory = inputEvalFactory;
+ this.outputType = outputType;
+ this.inputArgType = inputArgType;
+ }
+
+ @Override
+ public ICopyEvaluator createEvaluator(final IDataOutputProvider output)
throws AlgebricksException {
+ @SuppressWarnings("unchecked")
+ final ISerializerDeserializer<ANull> nullSerde =
AqlSerializerDeserializerProvider.INSTANCE
+ .getSerializerDeserializer(BuiltinType.ANULL);
+
+ return new ICopyEvaluator() {
+ private final AString RAW_BYTES_FIELD_NAME = new
AString("RawBytes");
+ private final AString INFINITY_STR = new AString("INF");
+ private final RuntimeRecordTypeInfo runtimeRecordTypeInfo = new
RuntimeRecordTypeInfo();
+ private final AStringSerializerDeserializer aStringSerDer = new
AStringSerializerDeserializer();
+ private final ArrayBackedValueStorage outInput0 = new
ArrayBackedValueStorage();
+ private final ICopyEvaluator eval0 =
inputEvalFactory.createEvaluator(outInput0);
+ private final ArrayBackedValueStorage outInput1 = new
ArrayBackedValueStorage();
+ private final ICopyEvaluator eval1 =
levelEvalFactory.createEvaluator(outInput1);
+ private final ResettableByteArrayOutputStream bos = new
ResettableByteArrayOutputStream();
+ private final DataOutputStream dos = new DataOutputStream(bos);
+ private final IARecordBuilder recordBuilder = new RecordBuilder();
+ private final AdmToBytesHelper admToBytesHelper = new
AdmToBytesHelper(new PointableUtils());
+ private final PointableAllocator allocator = new
PointableAllocator();
+ private final IVisitablePointable levelPointable =
allocator.allocateEmpty();
+ private final IVisitablePointable inputPointable = PointableUtils
+ .allocatePointable(allocator, inputArgType);
+ private final IVisitablePointable tempReference =
allocator.allocateEmpty();
+ private AdmToBytesVisitor visitor;
+
+ @Override
+ public void evaluate(IFrameTupleReference tuple) throws
AlgebricksException {
+ outInput0.reset();
+ eval0.evaluate(tuple);
+ outInput1.reset();
+ eval1.evaluate(tuple);
+ bos.reset();
+
+ if (outInput0.getByteArray()[0] == SER_NULL_TYPE_TAG) {
+ try {
+ nullSerde.serialize(ANull.NULL,
output.getDataOutput());
+ } catch (HyracksDataException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+ // Get the serialized values from an input
+ inputPointable.set(outInput0);
+ if (outputType.getTypeTag() == ATypeTag.RECORD) {
+ runtimeRecordTypeInfo.reset((ARecordType) outputType);
+ }
+ try {
+ // Get the level
+ long outputLevel = getOutputLevel();
+ visitor = new AdmToBytesVisitor(admToBytesHelper,
outputLevel);
+ // Return only an array of raw byte
+ if (outputLevel < 1) {
+ printRawBytes(inputPointable);
+ } else {
+ Triple<IAType, RuntimeRecordTypeInfo, Long> arg = new
Triple<>(outputType,
+ runtimeRecordTypeInfo, 1L);
+ IVisitablePointable resultPointable =
inputPointable.accept(visitor, arg);
+
output.getDataOutput().write(resultPointable.getByteArray(),
resultPointable.getStartOffset(),
+ resultPointable.getLength());
+ }
+ } catch (AsterixException | HyracksDataException e) {
+ throw new AlgebricksException("Unable to display
serialized value of the input " + inputArgType);
+ } catch (IOException e) {
+ new AlgebricksException("Error parsing input argument
#2.");
+ }
+
+ }
+
+ private long getOutputLevel() throws AlgebricksException {
+ if (outInput1.getByteArray()[0] == SER_NULL_TYPE_TAG) {
+ return 0;
+ }
+ // Level input arg type check
+ levelPointable.set(outInput1);
+ ATypeTag tag = PointableUtils.getTypeTag(levelPointable);
+ if (tag != ATypeTag.INT64 && tag != ATypeTag.STRING) {
+ throw new
AlgebricksException(AsterixBuiltinFunctions.ADM_TO_BYTES.getName()
+ + ": expects input type (ADM object, INT32|STRING)
but got ("
+ +
EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(outInput0.getByteArray()[0])
+ ", "
+ + tag + ")");
+ }
+ try {
+ if (tag == ATypeTag.STRING) {
+ // Serialize "INF"
+ int start = bos.size();
+ dos.writeByte(ATypeTag.STRING.serialize());
+ aStringSerDer.serialize(INFINITY_STR, dos);
+ int end = bos.size();
+ tempReference.set(bos.getByteArray(), start, end -
start);
+ if (PointableUtils.isEqual(levelPointable,
tempReference)) {
+ return Long.MAX_VALUE;
+ } else {
+ StringBuilder sb = new StringBuilder();
+ sb = UTF8StringUtil.toString(sb,
levelPointable.getByteArray(),
+ levelPointable.getStartOffset() + 1);
+ // Will throw an exception if not a number
+ return Long.parseLong(sb.toString());
+ }
+ } else {
+ return PointableUtils.getLongValue(levelPointable,
true);
+ }
+ } catch (IOException e) {
+ throw new AlgebricksException(e);
+ }
+ }
+
+ // Print a raw byte array
+ private void printRawBytes(IValueReference vr) throws
AlgebricksException {
+ try {
+ byte[] b = vr.getByteArray();
+ int offset = vr.getStartOffset();
+ int length = vr.getLength();
+
+ ARecordType reqRecType;
+ if (outputType != null && outputType.getTypeTag() ==
ATypeTag.RECORD) {
+ reqRecType = (ARecordType) outputType;
+ } else {
+ reqRecType =
DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
+ }
+ recordBuilder.reset(reqRecType);
+ recordBuilder.init();
+
+ int start = bos.size();
+ dos.writeByte(ATypeTag.STRING.serialize());
+ aStringSerDer.serialize(RAW_BYTES_FIELD_NAME, dos);
+ int end = bos.size();
+ tempReference.set(bos.getByteArray(), start, end - start);
+
+ int pos =
runtimeRecordTypeInfo.getFieldIndex(tempReference.getByteArray(),
+ tempReference.getStartOffset() + 1,
tempReference.getLength() - 1);
+ IVisitablePointable byteArrayBuffer =
allocator.allocateFieldValue(BuiltinType.ASTRING);
+ if (pos >= 0) {
+ admToBytesHelper.setByteArrayStringPointableValue(b,
offset, length, byteArrayBuffer, true);
+ recordBuilder.addField(pos, byteArrayBuffer);
+ } else {
+ admToBytesHelper.setByteArrayStringPointableValue(b,
offset, length, byteArrayBuffer, true);
+ recordBuilder.addField(tempReference, byteArrayBuffer);
+ }
+ recordBuilder.write(output.getDataOutput(), true);
+ } catch (AsterixException | IOException e) {
+ throw new AlgebricksException("Error parsing input
argument #2. " + e);
+ }
+ }
+ };
+ }
+}
diff --git
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesHelper.java
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesHelper.java
new file mode 100644
index 0000000..a2164c8
--- /dev/null
+++
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AdmToBytesHelper.java
@@ -0,0 +1,322 @@
+/*
+ * 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.DataOutputStream;
+import java.io.IOException;
+import org.apache.asterix.builders.IARecordBuilder;
+import org.apache.asterix.builders.RecordBuilder;
+import org.apache.asterix.common.exceptions.AsterixException;
+import
org.apache.asterix.dataflow.data.nontagged.serde.AInt32SerializerDeserializer;
+import org.apache.asterix.om.pointables.ARecordVisitablePointable;
+import org.apache.asterix.om.pointables.PointableAllocator;
+import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
+import org.apache.asterix.om.pointables.base.IVisitablePointable;
+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.types.EnumDeserializer;
+import org.apache.asterix.om.util.NonTaggedFormatUtil;
+import
org.apache.asterix.om.util.admdebugger.AnnotatedFieldNameComputerUtil.ByteAnnotationField;
+import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
+import org.apache.hyracks.data.std.util.ByteArrayAccessibleOutputStream;
+import org.apache.hyracks.util.string.UTF8StringUtil;
+
+public class AdmToBytesHelper {
+ private final int MAX_NUMBER_OF_MARKS = 12; // Max number of marks in a
record + 1 for the end mark
+ private final int[] marks = new int[MAX_NUMBER_OF_MARKS];
+ private final String[] markNames = new String[MAX_NUMBER_OF_MARKS];
+ private final StringBuilder valueHolder = new StringBuilder();
+ private final PointableAllocator allocator = new PointableAllocator();
+ private final IARecordBuilder recordBuilder = new RecordBuilder();
+ private final ArrayBackedValueStorage nameBuffer = new
ArrayBackedValueStorage();
+ private final ArrayBackedValueStorage valueBuffer = new
ArrayBackedValueStorage();
+ private final IVisitablePointable byteArrayStringPointable =
allocator.allocateFieldValue(BuiltinType.ASTRING);
+ private final ByteArrayAccessibleOutputStream outputBos = new
ByteArrayAccessibleOutputStream();
+ private final DataOutputStream outputDos = new DataOutputStream(outputBos);
+ private PointableUtils pointableUtils;
+
+ public AdmToBytesHelper(PointableUtils pointableUtils) {
+ this.pointableUtils = pointableUtils;
+ }
+
+ public ARecordVisitablePointable getAnnotatedByteArray(IVisitablePointable
valuePointable) throws AsterixException {
+ return getAnnotatedByteArray(valuePointable,
DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
+ }
+
+ public ARecordVisitablePointable getAnnotatedByteArray(IVisitablePointable
valuePointable,
+ ARecordType requiredRecType) throws AsterixException {
+ allocator.reset();
+
+ IVisitablePointable annotationRecordPointable =
allocator.allocateRecordValue(requiredRecType);
+ getAnnotatedByteArray(valuePointable, requiredRecType,
annotationRecordPointable);
+ return (ARecordVisitablePointable) annotationRecordPointable;
+ }
+
+ public void getAnnotatedByteArray(IVisitablePointable valuePointable,
ARecordType requiredRecType,
+ IVisitablePointable annotatedByteArrayPointable) throws
AsterixException {
+ int markCount = getByteArrayMarkers(valuePointable);
+
+ recordBuilder.reset(requiredRecType);
+ recordBuilder.init();
+ try {
+ for (int i = 0; i < markCount; i++) {
+ int id = recordBuilder.getFieldId(markNames[i]);
+
setByteArrayStringPointableValue(valuePointable.getByteArray(), marks[i],
(marks[i + 1] - marks[i]),
+ byteArrayStringPointable, true);
+ if (id >= 0) {
+ recordBuilder.addField(id, byteArrayStringPointable);
+ } else {
+ nameBuffer.reset();
+ pointableUtils.serializeString(markNames[i], nameBuffer,
true);
+ recordBuilder.addField(nameBuffer,
byteArrayStringPointable);
+ }
+ }
+ outputBos.reset();
+ recordBuilder.write(outputDos, true);
+ annotatedByteArrayPointable.set(outputBos.getByteArray(), 0,
outputBos.size());
+ } catch (IOException e) {
+ throw new AsterixException(e);
+ }
+ }
+
+ /**
+ * Print a byte array as a string
+ *
+ * @param bytes
+ * The array of bytes
+ * @param offset
+ * The start offset for to read from
+ * @param length
+ * The number of the bytes to read
+ * @param resultPointable
+ * Pointer to where the string is to be stored after
serialization
+ * @param writeTag
+ * A flag specifying whether we should add a tag byte at the
start of the string pointable
+ */
+ public void setByteArrayStringPointableValue(byte bytes[], int offset, int
length,
+ IVisitablePointable resultPointable, boolean writeTag) throws
AsterixException {
+ int end = offset + length;
+
+ valueHolder.setLength(0);
+ valueHolder.append("[" + bytes[offset]);
+ for (int i = offset + 1; i < end; i++) {
+ valueHolder.append(", " + bytes[i]);
+ }
+ valueHolder.append("]");
+ valueBuffer.reset();
+ pointableUtils.serializeString(valueHolder.toString(), valueBuffer,
writeTag);
+ resultPointable.set(valueBuffer.getByteArray(),
valueBuffer.getStartOffset(), valueBuffer.getLength());
+ }
+
+ private int getByteArrayMarkers(IVisitablePointable valuePointable) throws
AsterixException {
+ byte[] bytes = valuePointable.getByteArray();
+ int offset = valuePointable.getStartOffset();
+ int length = valuePointable.getLength();
+ ATypeTag typeTag =
EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(bytes[offset]);
+
+ int markCount = 0;
+ switch (typeTag) {
+ case RECORD:
+ markCount = getRecordByteArrayMarkers(bytes, offset,
+ ((ARecordVisitablePointable)
valuePointable).getInputRecordType());
+ break;
+ case UNORDEREDLIST:
+ case ORDEREDLIST:
+ markCount = getListByteArrayMarkers(bytes, offset);
+ break;
+ case STRING:
+ markCount = getStringByteArrayMarkes(bytes, offset, length);
+ break;
+ case NULL:
+ markCount = setMark(0, ByteAnnotationField.TAG, offset);
+ break;
+ default:
+ markCount = setMark(0, ByteAnnotationField.TAG, offset);
+ markCount = setMark(markCount, ByteAnnotationField.VALUE,
offset + 1);
+
+ }
+ // Set an end mark
+ marks[markCount] = offset + length;
+ return markCount;
+ }
+
+ /**
+ * 1 byte - tag, 13
+ * x bytes - variable number length bytes
+ * y bytes - value of x-length byte array of the value of the string
+ *
+ */
+ private int getStringByteArrayMarkes(byte bytes[], int offset, int length)
{
+ int s = offset;
+ int i = setMark(0, ByteAnnotationField.TAG, s);
+ s++;
+ i = setMark(i, ByteAnnotationField.LENGTH, s);
+
+ // Get the string length
+ int utflen = UTF8StringUtil.getUTFLength(bytes, offset + 1);
+ if (utflen > 0) { // If not an empty string
+ s = offset + (length - utflen);
+ i = setMark(i, ByteAnnotationField.VALUE, s);
+ }
+ return i;
+ }
+
+ /*
+ *
+ * 1 byte - Orderedlist (or Unorderedlist) tag, 22 (excluded when type is
known)
+ * 1 byte - Type of items on the list
+ * 4 bytes - Total number of bytes
+ * 4 bytes - Number of items
+ * if (type of list items is string, record, or list (length is not
constant))
+ * 4 bytes per item (offsets)
+ * for each item
+ * Bytes of the item (In the case of a list of ANY, the items will
include type tags)
+ */
+ private int getListByteArrayMarkers(byte bytes[], int offset) throws
AsterixException {
+ int s = offset;
+ int i = setMark(0, ByteAnnotationField.TAG, s);
+ s++;
+ // 1 byte - Type of items on the list
+ i = setMark(i, ByteAnnotationField.ITEM_TYPE, s);
+ s++;
+ //4 bytes - Total number of bytes
+ i = setMark(i, ByteAnnotationField.LENGTH, s);
+ s += 4;
+ //4 bytes - Number of items
+ i = setMark(i, ByteAnnotationField.NUMBER_OF_ITEMS, s);
+ int numberOfItems = AInt32SerializerDeserializer.getInt(bytes, s);
+ s += 4;
+ // 4 bytes for each item
+ i = setMark(i, ByteAnnotationField.ITEM_OFFSETS, s);
+ s += 4 * numberOfItems;
+ // The rest is the values of the items
+ return setMark(i, ByteAnnotationField.VALUE, s);
+ }
+
+ /*
+ *
+ * 1 byte - Record tag, 24 (excluded when type is known)
+ * 4 bytes - Total number of bytes
+ * if (recordType is not closed)
+ * 1 byte - Boolean isExpanded
+ * if (isExpanded)
+ * 4 bytes - Offset to open part
+ * 4 bytes - Number of closed fields
+ * if (recordType hasNullableFields)
+ * ceil (numberOfFields / 8) bytes - Nullbitmap (1 bit per field, "1"
means field is Null for this record)
+ * for each closed field that is not Null for this record
+ * 4 bytes - Closed field offset
+ * for each closed field that is not Null for this record
+ * Bytes of the field (type is known from recordtype, so the bytes will
not have a type tag)
+ * if (isExpanded)
+ * 4 bytes - Number of open fields
+ * for each open field
+ * 4 bytes - Hash code
+ * 4 bytes - Offset
+ * for each open field
+ * Bytes of the field name (String, no type tag)
+ * Bytes of the field (with type tag)
+ *
+ */
+ private int getRecordByteArrayMarkers(byte bytes[], int offset,
ARecordType inputRecType) throws AsterixException {
+ int s = offset;
+ int openPartOffset = 0;
+ boolean isExpanded = false;
+
+ int numberOfSchemaFields = 0;
+
+ // Tag mark
+ // 1 byte - Record tag, 24 (excluded when type is known)
+ int i = setMark(0, ByteAnnotationField.TAG, s);
+
+ // Length
+ // 4 bytes - Total number of bytes
+ i = setMark(i, ByteAnnotationField.LENGTH, s + 1);
+
+ if (inputRecType == null) {
+ openPartOffset = s + AInt32SerializerDeserializer.getInt(bytes, s
+ 6);
+ i = setMark(i, ByteAnnotationField.OPENPART_OFFSET,
openPartOffset);
+ s += 8;
+ isExpanded = true;
+ } else {
+ numberOfSchemaFields = inputRecType.getFieldNames().length;
+ if (inputRecType.isOpen()) {
+ i = setMark(i, ByteAnnotationField.IS_EXPANDED, s + 5);
+ isExpanded = bytes[s + 5] == 1 ? true : false;
+ if (isExpanded) {
+ openPartOffset = s +
AInt32SerializerDeserializer.getInt(bytes, s + 6);
+ i = setMark(i, ByteAnnotationField.OPENPART_OFFSET, s + 6);
+ s += 10;
+ } else {
+ s += 6;
+ }
+ } else {
+ s += 5;
+ }
+ }
+
+ //4 bytes - Number of closed fields
+ i = setMark(i, ByteAnnotationField.NUMBER_CLOSED_FIELDS, s);
+ s += 4;
+
+ if (numberOfSchemaFields > 0) {
+ boolean hasNullableFields =
NonTaggedFormatUtil.hasNullableField(inputRecType);
+ int nullBitMapLength = 0;
+ if (hasNullableFields) {
+ // Nullbitmap bytes
+ i = setMark(i, ByteAnnotationField.NULLBITMAP, s);
+ nullBitMapLength = (numberOfSchemaFields % 8 == 0 ?
numberOfSchemaFields / 8
+ : numberOfSchemaFields / 8 + 1);
+ }
+
+ // Offset of the closed field values
+ s += nullBitMapLength;
+ i = setMark(i, ByteAnnotationField.CLOSED_FIELD_OFFSETS, s);
+
+ // Offset of the closed field values
+ s += 4 * numberOfSchemaFields;
+ i = setMark(i, ByteAnnotationField.CLOSED_FIELDS, s);
+ }
+
+ if (isExpanded) {
+ int numberOfOpenFields =
AInt32SerializerDeserializer.getInt(bytes, openPartOffset);
+ // 4 bytes - Number of open fields
+ s = openPartOffset;
+ i = setMark(i, ByteAnnotationField.NUMBER_OF_OPEN_FIELDS, s);
+ s += 4;
+
+ // 4 bytes openfield offsets and 4 Hash code for each field
+ i = setMark(i, ByteAnnotationField.OPEN_FIELDS_HASH_OFFSET, s);
+ s += 8 * numberOfOpenFields;
+
+ // Open fields
+ i = setMark(i, ByteAnnotationField.OPEN_FIELDS, s);
+ }
+
+ return i;
+ }
+
+ private int setMark(int index, ByteAnnotationField field, int offset) {
+ markNames[index] = field.fieldName();
+ marks[index] = offset;
+ return index + 1;
+ }
+}
diff --git
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableUtils.java
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableUtils.java
new file mode 100644
index 0000000..e12573f
--- /dev/null
+++
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/PointableUtils.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.DataOutput;
+import java.io.IOException;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import
org.apache.asterix.dataflow.data.nontagged.serde.AStringSerializerDeserializer;
+import org.apache.asterix.om.base.AMutableString;
+import org.apache.asterix.om.pointables.PointableAllocator;
+import org.apache.asterix.om.pointables.base.IVisitablePointable;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.EnumDeserializer;
+import org.apache.asterix.om.types.IAType;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.api.dataflow.value.IBinaryComparator;
+import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.accessors.PointableBinaryComparatorFactory;
+import org.apache.hyracks.data.std.api.IMutableValueStorage;
+import org.apache.hyracks.data.std.api.IValueReference;
+import org.apache.hyracks.data.std.primitive.IntegerPointable;
+import org.apache.hyracks.data.std.primitive.LongPointable;
+import org.apache.hyracks.data.std.primitive.ShortPointable;
+import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
+
+/**
+ * An utility class for some frequently used methods like checking the
equality between two pointables (binary values)
+ * (e.g., field names), string value of a fieldname pointable, getting the
typetag of a pointable, etc.
+ * Note: To get the typetag of a fieldvalue (i) in a record, it is recommended
to use the getFieldTypeTags().get(i)
+ * method rather than getting it from fhe field value itself.
+ */
+
+public class PointableUtils {
+ private static final IBinaryComparator STRING_BINARY_COMPARATOR =
PointableBinaryComparatorFactory.of(
+ UTF8StringPointable.FACTORY).createBinaryComparator();
+ private final ISerializerDeserializer strSerde = new
AStringSerializerDeserializer();
+ private final AMutableString aString = new AMutableString("");
+
+ public PointableUtils() {
+ }
+
+ public static int compareStringBinValues(IValueReference a,
IValueReference b) throws HyracksDataException {
+ // start+1 and len-1 due to type tag ignore (only interested in String
value)
+ return STRING_BINARY_COMPARATOR.compare(a.getByteArray(),
a.getStartOffset() + 1, a.getLength() - 1,
+ b.getByteArray(), b.getStartOffset() + 1, b.getLength() - 1);
+ }
+
+ public static boolean isEqual(IValueReference a, IValueReference b) throws
HyracksDataException {
+ return (compareStringBinValues(a, b) == 0);
+ }
+
+ public static boolean byteArrayEqual(IValueReference valueRef1,
IValueReference valueRef2)
+ throws HyracksDataException {
+ return byteArrayEqual(valueRef1, valueRef2, 3);
+ }
+
+ public static boolean byteArrayEqual(IValueReference valueRef1,
IValueReference valueRef2, int dataOffset)
+ throws HyracksDataException {
+ if (valueRef1 == null || valueRef2 == null) {
+ return false;
+ }
+ if (valueRef1 == valueRef2) {
+ return true;
+ }
+
+ int length1 = valueRef1.getLength();
+ int length2 = valueRef2.getLength();
+
+ if (length1 != length2) {
+ return false;
+ }
+
+ byte[] bytes1 = valueRef1.getByteArray();
+ byte[] bytes2 = valueRef2.getByteArray();
+ int start1 = valueRef1.getStartOffset() + dataOffset;
+ int start2 = valueRef2.getStartOffset() + dataOffset;
+
+ int end = start1 + length1 - dataOffset;
+
+ for (int i = start1, j = start2; i < end; i++, j++) {
+ if (bytes1[i] != bytes2[j]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static IVisitablePointable allocatePointable(PointableAllocator pa,
IAType type) {
+ if (type == null) {
+ return pa.allocateEmpty();
+ }
+
+ switch (type.getTypeTag()) {
+ case RECORD:
+ return pa.allocateRecordValue(type);
+ case ORDEREDLIST:
+ case UNORDEREDLIST:
+ return pa.allocateListValue(type);
+ default:
+ return pa.allocateFieldValue(type);
+ }
+
+ }
+
+ public static long getLongValue(IValueReference valuePointable, boolean
isTagged) throws AlgebricksException {
+ ATypeTag tag = getTypeTag(valuePointable);
+
+ int offset = isTagged ? valuePointable.getStartOffset() + 1 :
valuePointable.getStartOffset();
+
+ switch (tag) {
+ case INT64:
+ return LongPointable.getLong(valuePointable.getByteArray(),
offset);
+ case INT32:
+ return
IntegerPointable.getInteger(valuePointable.getByteArray(), offset);
+ case INT16:
+ return ShortPointable.getShort(valuePointable.getByteArray(),
offset);
+ default:
+ throw new AlgebricksException("Unsupported type " + tag);
+ }
+ }
+
+ public static boolean sameType(ATypeTag typeTag, IVisitablePointable
visitablePointable) {
+ return (getTypeTag(visitablePointable) == typeTag);
+ }
+
+ public static ATypeTag getTypeTag(IValueReference visitablePointable) {
+ byte[] bytes = visitablePointable.getByteArray();
+ int s = visitablePointable.getStartOffset();
+ return EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(bytes[s]);
+ }
+
+ /**
+ * @param str
+ * The input string
+ * @param vs
+ * The storage buffer
+ * @param writeTag
+ * Specifying whether a tag for the string should also be
written
+ * @throws AlgebricksException
+ */
+ public void serializeString(String str, IMutableValueStorage vs, boolean
writeTag) throws AsterixException {
+ vs.reset();
+ try {
+ DataOutput output = vs.getDataOutput();
+ if (writeTag) {
+ output.write(ATypeTag.STRING.serialize());
+ }
+ aString.setValue(str);
+ strSerde.serialize(aString, output);
+ } catch (IOException e) {
+ throw new AsterixException("Could not serialize " + str);
+ }
+ }
+
+ public void serializeString(String str, IMutableValueStorage vs) throws
AsterixException {
+ serializeString(str, vs, false);
+ }
+}
diff --git
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/AdmToBytesVisitor.java
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/AdmToBytesVisitor.java
new file mode 100644
index 0000000..65d5f85
--- /dev/null
+++
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/AdmToBytesVisitor.java
@@ -0,0 +1,123 @@
+/*
+ * 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.visitors.admdebugging;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.om.pointables.AFlatValuePointable;
+import org.apache.asterix.om.pointables.AListVisitablePointable;
+import org.apache.asterix.om.pointables.ARecordVisitablePointable;
+import org.apache.asterix.om.pointables.PointableAllocator;
+import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
+import org.apache.asterix.om.pointables.base.IVisitablePointable;
+import org.apache.asterix.om.pointables.visitor.IVisitablePointableVisitor;
+import org.apache.asterix.om.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.runtime.RuntimeRecordTypeInfo;
+import org.apache.asterix.runtime.evaluators.functions.AdmToBytesHelper;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+
+public class AdmToBytesVisitor implements
+ IVisitablePointableVisitor<IVisitablePointable, Triple<IAType,
RuntimeRecordTypeInfo, Long>> {
+
+ private final Map<IVisitablePointable, RecordBytesProcessor>
rProcessorToAnnotatedBytes = new HashMap<>();
+ private final Map<IVisitablePointable, ListBytesProcessor>
lProcessorToAnnotatedBytes = new HashMap<>();
+ private final PointableAllocator allocator = new PointableAllocator();
+ private final IVisitablePointable resultPointable =
allocator.allocateEmpty();
+ private RecordBytesProcessor recordBytesProcessor;
+ private ListBytesProcessor listBytesProcessor;
+ private AdmToBytesHelper admToBytesHelper;
+
+ private long outputLevel = 0;
+
+ public AdmToBytesVisitor(AdmToBytesHelper admToBytesHelper, long
outputLevel) {
+ this.admToBytesHelper = admToBytesHelper;
+ this.outputLevel = outputLevel;
+ }
+
+ @Override
+ public IVisitablePointable visit(AListVisitablePointable pointable,
Triple<IAType, RuntimeRecordTypeInfo, Long> arg)
+ throws AsterixException {
+ if (outputLevel == 1
+ || (arg.third == outputLevel && arg.first.getTypeTag() !=
ATypeTag.UNORDEREDLIST && arg.first
+ .getTypeTag() != ATypeTag.ORDEREDLIST)) {
+ computeResultPointable(pointable, arg.first, resultPointable);
+ return resultPointable;
+ }
+
+ listBytesProcessor = lProcessorToAnnotatedBytes.get(pointable);
+ if (listBytesProcessor == null) {
+ listBytesProcessor = new ListBytesProcessor();
+ lProcessorToAnnotatedBytes.put(pointable, listBytesProcessor);
+ }
+ if (arg.first.getTypeTag() == ATypeTag.ANY) {
+ arg.first = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
+ if (pointable.ordered()) {
+ arg.first =
DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
+ }
+ }
+ listBytesProcessor.accessList(pointable, outputLevel, this, arg.first,
arg.third, resultPointable);
+ return resultPointable;
+ }
+
+ @Override
+ public IVisitablePointable visit(ARecordVisitablePointable pointable,
+ Triple<IAType, RuntimeRecordTypeInfo, Long> arg) throws
AsterixException {
+
+ if (outputLevel == 1 || arg.third == outputLevel) {
+ computeResultPointable(pointable, arg.first, resultPointable);
+ return resultPointable;
+ }
+
+ RuntimeRecordTypeInfo runtimeRecordTypeInfo = arg.second;
+ if (arg.first.getTypeTag() == ATypeTag.ANY) {
+ arg.first = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
+ }
+ ARecordType requiredType = (ARecordType) arg.first;
+
+ recordBytesProcessor = rProcessorToAnnotatedBytes.get(pointable);
+ if (recordBytesProcessor == null) {
+ recordBytesProcessor = new RecordBytesProcessor();
+ rProcessorToAnnotatedBytes.put(pointable, recordBytesProcessor);
+ }
+ recordBytesProcessor.accessRecord(pointable, this, requiredType,
runtimeRecordTypeInfo, arg.third,
+ resultPointable);
+ return resultPointable;
+ }
+
+ @Override
+ public IVisitablePointable visit(AFlatValuePointable pointable,
Triple<IAType, RuntimeRecordTypeInfo, Long> arg)
+ throws AsterixException {
+ computeResultPointable(pointable, arg.first, resultPointable);
+ return resultPointable;
+ }
+
+ public void computeResultPointable(IVisitablePointable inputPointable,
IAType requiredType,
+ IVisitablePointable outputPointable) throws AsterixException {
+ if (requiredType != null && requiredType.getTypeTag() ==
ATypeTag.RECORD) {
+ admToBytesHelper.getAnnotatedByteArray(inputPointable,
(ARecordType) requiredType, outputPointable);
+ } else {
+ admToBytesHelper.getAnnotatedByteArray(inputPointable,
DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE,
+ outputPointable);
+ }
+ }
+}
diff --git
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/ListBytesProcessor.java
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/ListBytesProcessor.java
new file mode 100644
index 0000000..0f5acd1
--- /dev/null
+++
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/ListBytesProcessor.java
@@ -0,0 +1,127 @@
+/*
+ * 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.visitors.admdebugging;
+
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.util.List;
+
+import org.apache.asterix.builders.OrderedListBuilder;
+import org.apache.asterix.builders.UnorderedListBuilder;
+import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.om.pointables.AListVisitablePointable;
+import org.apache.asterix.om.pointables.PointableAllocator;
+import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
+import org.apache.asterix.om.pointables.base.IVisitablePointable;
+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.AUnorderedListType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.runtime.RuntimeRecordTypeInfo;
+import org.apache.asterix.runtime.evaluators.functions.PointableUtils;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IValueReference;
+import org.apache.hyracks.data.std.util.ByteArrayAccessibleOutputStream;
+
+public class ListBytesProcessor {
+ // pointable allocator
+ private final PointableAllocator allocator = new PointableAllocator();
+ private final IVisitablePointable itemTempReference =
allocator.allocateEmpty();
+ private final Triple<IAType, RuntimeRecordTypeInfo, Long> itemVisitorArg =
new Triple<>(null,
+ new RuntimeRecordTypeInfo(), 1L);
+ private final UnorderedListBuilder unOrderedListBuilder = new
UnorderedListBuilder();
+ private final OrderedListBuilder orderedListBuilder = new
OrderedListBuilder();
+ private final ByteArrayAccessibleOutputStream dataBos = new
ByteArrayAccessibleOutputStream();
+ private final DataOutput dataDos = new DataOutputStream(dataBos);
+ private IAType reqItemType;
+
+ public void accessList(AListVisitablePointable pointable, long
outputLevel, AdmToBytesVisitor visitor,
+ IAType requiredType, long nestedLevel, IVisitablePointable
resultPointable) throws AsterixException {
+ // Printing just the highest level of the annotated bytes
+ ATypeTag reqTypeTag = requiredType.getTypeTag();
+
+ if (requiredType != null && reqTypeTag != ATypeTag.ANY) {
+ if (reqTypeTag == ATypeTag.UNORDEREDLIST) {
+ unOrderedListBuilder.reset((AUnorderedListType) requiredType);
+ reqItemType = ((AUnorderedListType)
requiredType).getItemType();
+ }
+ if (reqTypeTag == ATypeTag.ORDEREDLIST) {
+ orderedListBuilder.reset((AOrderedListType) requiredType);
+ reqItemType = ((AOrderedListType) requiredType).getItemType();
+ }
+ } else {
+ if (pointable.ordered()) {
+
orderedListBuilder.reset(DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE);
+ } else {
+
orderedListBuilder.reset(DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE);
+ }
+ reqItemType = BuiltinType.ANY;
+ }
+
+ List<IVisitablePointable> items = pointable.getItems();
+ List<IVisitablePointable> itemTypeTags = pointable.getItemTags();
+
+ try {
+ for (int i = 0; i < items.size(); i++) {
+ IVisitablePointable item = items.get(i);
+ IVisitablePointable itemTypeTag = itemTypeTags.get(i);
+ ATypeTag typeTag = PointableUtils.getTypeTag(itemTypeTag);
+
+ // If reached the max nesting level just "print" the annotated
byte record for this item
+ if (nestedLevel == outputLevel) {
+ visitor.computeResultPointable(item, reqItemType,
itemTempReference);
+ addListItem(reqTypeTag, itemTempReference);
+ } else {
+ if (reqItemType == null ||
reqItemType.getTypeTag().equals(ATypeTag.ANY)) {
+ itemVisitorArg.first =
DefaultOpenFieldType.getDefaultOpenFieldType(typeTag);
+ } else {
+ itemVisitorArg.first = reqItemType;
+ if (reqItemType.getTypeTag().equals(ATypeTag.RECORD)) {
+ itemVisitorArg.second.reset((ARecordType)
reqItemType);
+ }
+ }
+ itemVisitorArg.third = nestedLevel + 1;
+ addListItem(reqTypeTag, (item.accept(visitor,
itemVisitorArg)));
+ }
+ }
+ dataBos.reset();
+ if (reqTypeTag == ATypeTag.ORDEREDLIST) {
+ orderedListBuilder.write(dataDos, true);
+ }
+ if (reqTypeTag == ATypeTag.UNORDEREDLIST) {
+ unOrderedListBuilder.write(dataDos, true);
+ }
+ resultPointable.set(dataBos.getByteArray(), 0, dataBos.size());
+ } catch (HyracksDataException e) {
+ throw new AsterixException(e);
+ }
+ }
+
+ private void addListItem(ATypeTag listTypeTag, IValueReference
itemReference) throws HyracksDataException {
+ if (listTypeTag == ATypeTag.ORDEREDLIST) {
+ orderedListBuilder.addItem(itemReference);
+ }
+ if (listTypeTag == ATypeTag.UNORDEREDLIST) {
+ unOrderedListBuilder.addItem(itemReference);
+ }
+ }
+}
diff --git
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/RecordBytesProcessor.java
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/RecordBytesProcessor.java
new file mode 100644
index 0000000..4867071
--- /dev/null
+++
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/visitors/admdebugging/RecordBytesProcessor.java
@@ -0,0 +1,102 @@
+/*
+ * 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.visitors.admdebugging;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+import org.apache.asterix.builders.RecordBuilder;
+import org.apache.asterix.common.exceptions.AsterixException;
+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.types.ARecordType;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.runtime.RuntimeRecordTypeInfo;
+import org.apache.asterix.om.util.NonTaggedFormatUtil;
+import org.apache.asterix.runtime.evaluators.functions.PointableUtils;
+import org.apache.hyracks.algebricks.common.utils.Triple;
+import org.apache.hyracks.data.std.util.ByteArrayAccessibleOutputStream;
+
+class RecordBytesProcessor {
+ private final ByteArrayAccessibleOutputStream outputBos = new
ByteArrayAccessibleOutputStream();
+ private final DataOutputStream outputDos = new DataOutputStream(outputBos);
+
+ private final Triple<IAType, RuntimeRecordTypeInfo, Long> nestedVisitorArg
= new Triple<>(null,
+ new RuntimeRecordTypeInfo(), 1L);
+
+ private final RecordBuilder recordBuilder = new RecordBuilder();
+
+ public void accessRecord(ARecordVisitablePointable pointable,
AdmToBytesVisitor visitor, ARecordType requiredType,
+ RuntimeRecordTypeInfo runtimeRecordTypeInfo, long nestedLevel,
IVisitablePointable resultPointable)
+ throws AsterixException {
+ try {
+ List<IVisitablePointable> fieldNames = pointable.getFieldNames();
+ List<IVisitablePointable> fieldValues = pointable.getFieldValues();
+ List<IVisitablePointable> fieldTypeTags =
pointable.getFieldTypeTags();
+ outputBos.reset();
+
+ IAType reqFieldTypes[] = requiredType.getFieldTypes();
+ recordBuilder.reset(requiredType);
+ recordBuilder.init();
+
+ for (int i = 0; i < fieldNames.size(); i++) {
+ IVisitablePointable fieldValue = fieldValues.get(i);
+ IVisitablePointable fieldName = fieldNames.get(i);
+ ATypeTag fieldTypeTag =
PointableUtils.getTypeTag(fieldTypeTags.get(i));
+
+ int pos =
runtimeRecordTypeInfo.getFieldIndex(fieldName.getByteArray(),
fieldName.getStartOffset() + 1,
+ fieldName.getLength() - 1);
+
+ if (pos >= 0 && fieldTypeTag != null) {
+ IAType reqfieldType = reqFieldTypes[pos];
+ if (NonTaggedFormatUtil.isOptional(reqFieldTypes[pos])) {
+ if (fieldTypeTags.get(pos) == null
+ || PointableUtils.sameType(ATypeTag.NULL,
fieldTypeTags.get(pos))) {
+ reqfieldType = ((AUnionType)
reqFieldTypes[pos]).getUnionList().get(0);
+ } else {
+ reqfieldType = ((AUnionType)
reqFieldTypes[pos]).getNullableType();
+ }
+ }
+ nestedVisitorArg.first = reqfieldType;
+ if (reqfieldType.getTypeTag() == ATypeTag.RECORD) {
+ nestedVisitorArg.second.reset((ARecordType)
reqfieldType);
+ }
+ } else {
+ nestedVisitorArg.first =
DefaultOpenFieldType.getDefaultOpenFieldType(fieldTypeTag);
+ }
+ nestedVisitorArg.third = nestedLevel + 1;
+ IVisitablePointable tempFieldReference =
fieldValue.accept(visitor, nestedVisitorArg);
+
+ if (pos >= 0) {
+ recordBuilder.addField(pos, tempFieldReference);
+ } else {
+ recordBuilder.addField(fieldNames.get(i),
tempFieldReference);
+ }
+ }
+ recordBuilder.write(outputDos, true);
+ resultPointable.set(outputBos.getByteArray(), 0, outputBos.size());
+ } catch (IOException e) {
+ throw new AsterixException(e);
+ }
+ }
+}
diff --git
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/formats/NonTaggedDataFormat.java
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/formats/NonTaggedDataFormat.java
index ef7a6c8..e3ae85d 100644
---
a/asterix-runtime/src/main/java/org/apache/asterix/runtime/formats/NonTaggedDataFormat.java
+++
b/asterix-runtime/src/main/java/org/apache/asterix/runtime/formats/NonTaggedDataFormat.java
@@ -23,6 +23,7 @@
import org.apache.asterix.common.parse.IParseFileSplitsDecl;
import org.apache.asterix.dataflow.data.nontagged.AqlNullWriterFactory;
import org.apache.asterix.formats.base.IDataFormat;
+import org.apache.asterix.formats.nontagged.AqlADMPrinterFactoryProvider;
import org.apache.asterix.formats.nontagged.AqlBinaryBooleanInspectorImpl;
import org.apache.asterix.formats.nontagged.AqlBinaryComparatorFactoryProvider;
import
org.apache.asterix.formats.nontagged.AqlBinaryHashFunctionFactoryProvider;
@@ -33,7 +34,6 @@
import
org.apache.asterix.formats.nontagged.AqlLosslessJSONPrinterFactoryProvider;
import
org.apache.asterix.formats.nontagged.AqlNormalizedKeyComputerFactoryProvider;
import
org.apache.asterix.formats.nontagged.AqlPredicateEvaluatorFactoryProvider;
-import org.apache.asterix.formats.nontagged.AqlADMPrinterFactoryProvider;
import org.apache.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
import org.apache.asterix.formats.nontagged.AqlTypeTraitProvider;
import org.apache.asterix.om.base.ABoolean;
@@ -161,12 +161,12 @@
import
org.apache.asterix.runtime.evaluators.constructors.AYearMonthDurationConstructorDescriptor;
import
org.apache.asterix.runtime.evaluators.constructors.ClosedRecordConstructorDescriptor;
import
org.apache.asterix.runtime.evaluators.constructors.OpenRecordConstructorDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.AdmToBytesDescriptor;
import org.apache.asterix.runtime.evaluators.functions.AndDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.AnyCollectionMemberDescriptor;
import org.apache.asterix.runtime.evaluators.functions.CastListDescriptor;
import org.apache.asterix.runtime.evaluators.functions.CastRecordDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.CodePointToStringDescriptor;
-import
org.apache.asterix.runtime.evaluators.functions.StringContainsDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.CountHashedGramTokensDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.CountHashedWordTokensDescriptor;
import org.apache.asterix.runtime.evaluators.functions.CreateCircleDescriptor;
@@ -182,7 +182,6 @@
import
org.apache.asterix.runtime.evaluators.functions.EditDistanceListIsFilterable;
import
org.apache.asterix.runtime.evaluators.functions.EditDistanceStringIsFilterable;
import org.apache.asterix.runtime.evaluators.functions.EmbedTypeDescriptor;
-import
org.apache.asterix.runtime.evaluators.functions.StringEndsWithDescriptor;
import org.apache.asterix.runtime.evaluators.functions.FlowRecordDescriptor;
import org.apache.asterix.runtime.evaluators.functions.FuzzyEqDescriptor;
import org.apache.asterix.runtime.evaluators.functions.GetItemDescriptor;
@@ -193,7 +192,6 @@
import org.apache.asterix.runtime.evaluators.functions.IsNullDescriptor;
import org.apache.asterix.runtime.evaluators.functions.IsSystemNullDescriptor;
import org.apache.asterix.runtime.evaluators.functions.LenDescriptor;
-import org.apache.asterix.runtime.evaluators.functions.StringLikeDescriptor;
import org.apache.asterix.runtime.evaluators.functions.NotDescriptor;
import org.apache.asterix.runtime.evaluators.functions.NotNullDescriptor;
import org.apache.asterix.runtime.evaluators.functions.NumericAbsDescriptor;
@@ -223,16 +221,19 @@
import org.apache.asterix.runtime.evaluators.functions.SpatialCellDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.SpatialDistanceDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.SpatialIntersectDescriptor;
-import
org.apache.asterix.runtime.evaluators.functions.StringStartsWithDescriptor;
import org.apache.asterix.runtime.evaluators.functions.StringConcatDescriptor;
+import
org.apache.asterix.runtime.evaluators.functions.StringContainsDescriptor;
+import
org.apache.asterix.runtime.evaluators.functions.StringEndsWithDescriptor;
import org.apache.asterix.runtime.evaluators.functions.StringEqualDescriptor;
import org.apache.asterix.runtime.evaluators.functions.StringJoinDescriptor;
import org.apache.asterix.runtime.evaluators.functions.StringLengthDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.StringLikeDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.StringLowerCaseDescriptor;
import org.apache.asterix.runtime.evaluators.functions.StringMatchesDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.StringMatchesWithFlagDescriptor;
import org.apache.asterix.runtime.evaluators.functions.StringReplaceDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.StringReplaceWithFlagsDescriptor;
+import
org.apache.asterix.runtime.evaluators.functions.StringStartsWithDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.StringToCodePointDescriptor;
import
org.apache.asterix.runtime.evaluators.functions.StringUpperCaseDescriptor;
import org.apache.asterix.runtime.evaluators.functions.Substring2Descriptor;
@@ -311,6 +312,8 @@
import org.apache.asterix.runtime.unnestingfunctions.std.RangeDescriptor;
import
org.apache.asterix.runtime.unnestingfunctions.std.ScanCollectionDescriptor;
import
org.apache.asterix.runtime.unnestingfunctions.std.SubsetCollectionDescriptor;
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
import org.apache.hyracks.algebricks.common.exceptions.NotImplementedException;
import org.apache.hyracks.algebricks.common.utils.Triple;
@@ -350,8 +353,6 @@
import org.apache.hyracks.dataflow.common.data.parsers.LongParserFactory;
import org.apache.hyracks.dataflow.common.data.parsers.UTF8StringParserFactory;
import org.apache.hyracks.dataflow.std.file.ITupleParserFactory;
-import org.apache.commons.lang3.mutable.Mutable;
-import org.apache.commons.lang3.mutable.MutableObject;
import java.io.DataOutput;
import java.io.IOException;
@@ -688,6 +689,9 @@
temp.add(AIntervalStartFromDateTimeConstructorDescriptor.FACTORY);
temp.add(AIntervalStartFromTimeConstructorDescriptor.FACTORY);
+ // For debugging
+ temp.add(AdmToBytesDescriptor.FACTORY);
+
IFunctionManager mgr = new FunctionManagerImpl();
for (IFunctionDescriptorFactory fdFactory : temp) {
mgr.registerFunction(fdFactory);
@@ -934,6 +938,16 @@
((RecordMergeDescriptor) fd).reset(outType, type0, type1);
}
});
+ functionTypeInferers.put(AsterixBuiltinFunctions.ADM_TO_BYTES, new
FunctionTypeInferer() {
+
+ @Override public void infer(ILogicalExpression expr,
IFunctionDescriptor fd,
+ IVariableTypeEnvironment context) throws
AlgebricksException {
+ AbstractFunctionCallExpression f =
(AbstractFunctionCallExpression) expr;
+ IAType outType = (IAType) context.getType(expr);
+ IAType intype0 = (IAType)
context.getType(f.getArguments().get(0).getValue());
+ ((AdmToBytesDescriptor) fd).reset(outType, intype0);
+ }
+ });
functionTypeInferers.put(AsterixBuiltinFunctions.CAST_RECORD, new
FunctionTypeInferer() {
public void infer(ILogicalExpression expr, IFunctionDescriptor fd,
IVariableTypeEnvironment context) throws AlgebricksException {
AbstractFunctionCallExpression funcExpr =
(AbstractFunctionCallExpression) expr;
--
To view, visit https://asterix-gerrit.ics.uci.edu/523
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I31d0b2ec2d8686531833811937596c3dca660b1e
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Heri Ramampiaro <[email protected]>