>From Wail Alkowaileet <[email protected]>:

Wail Alkowaileet has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17496 )


Change subject: [WIP] Fix column assembler for repeated complex values
......................................................................

[WIP] Fix column assembler for repeated complex values

Change-Id: Ib2cede772f3db534b6c0c93c10d51ec076747e19
---
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/PrimitiveValueAssembler.java
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/PrimitiveColumnValuesReader.java
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/RepeatedPrimitiveValueAssembler.java
A 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/EndOfRepeatedGroupAssembler.java
M 
asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyPrimitiveColumnValueReader.java
M 
asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyRepeatedPrimitiveColumnValueReader.java
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AbstractPrimitiveValueAssembler.java
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/IColumnValuesReader.java
M 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/RepeatedPrimitiveColumnValuesReader.java
A 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerState.java
A 
asterixdb/asterix-column/src/main/java/org/apache/asterix/column/util/SchemaStringBuilderVisitor.java
14 files changed, 392 insertions(+), 71 deletions(-)



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

diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AbstractPrimitiveValueAssembler.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AbstractPrimitiveValueAssembler.java
index 5e2ef28..0d7c9c88 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AbstractPrimitiveValueAssembler.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AbstractPrimitiveValueAssembler.java
@@ -81,14 +81,18 @@
         return reader.getColumnIndex();
     }

-    public final void skip(int count) throws HyracksDataException {
+    public void skip(int count) throws HyracksDataException {
         reader.skip(count);
     }

+    public boolean isEndOfGroupAssembler() {
+        return false;
+    }
+
     /**
      * Move to the next primitive value assembler
      *
      * @return the index of the next value
      */
-    public abstract int next() throws HyracksDataException;
+    public abstract int next(AssemblerState state) throws HyracksDataException;
 }
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java
index 969a091..43885f2 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerBuilderVisitor.java
@@ -56,6 +56,7 @@
 
     //Recursion info
     private final IntList delimiters;
+    private IColumnValuesReader delegateRepeatedReader;
     private int level;

     public AssemblerBuilderVisitor(QueryColumnMetadata columnMetadata, 
IColumnValuesReaderFactory readerFactory,
@@ -67,13 +68,13 @@
         delimiters = new IntArrayList();
     }

-    public List<AbstractPrimitiveValueAssembler> 
createValueAssemblers(AbstractSchemaNode requestedSchema,
+    public AbstractPrimitiveValueAssembler[] 
createValueAssemblers(AbstractSchemaNode requestedSchema,
             ARecordType declaredType) throws HyracksDataException {
         EmptyAssembler root = new EmptyAssembler();
         AssemblerInfo info = new AssemblerInfo(declaredType, root);
         level = 0;
         rootAssembler = requestedSchema.accept(this, info);
-        return valueAssemblers;
+        return valueAssemblers.toArray(new AbstractPrimitiveValueAssembler[0]);
     }

     public AbstractValueAssembler getRootAssembler() {
@@ -147,14 +148,25 @@
         delimiters.add(level - 1);
         level++;

+        IColumnValuesReader previousDelegate = delegateRepeatedReader;
+        delegateRepeatedReader = null;
+
         IAType itemDeclaredType = getChildType(itemNode, 
declaredType.getItemType());
         AssemblerInfo itemInfo = new AssemblerInfo(itemDeclaredType, 
arrayAssembler, false);
         itemNode.accept(this, itemInfo);

         //Add the array assembler to the last repeated value assembler
-        RepeatedPrimitiveValueAssembler repeatedAssembler =
-                (RepeatedPrimitiveValueAssembler) 
valueAssemblers.get(valueAssemblers.size() - 1);
-        repeatedAssembler.addArray(arrayAssembler);
+        AbstractPrimitiveValueAssembler lastAssembler = 
valueAssemblers.get(valueAssemblers.size() - 1);
+        EndOfRepeatedGroupAssembler endOfGroupAssembler;
+        if (lastAssembler.isEndOfGroupAssembler()) {
+            endOfGroupAssembler = (EndOfRepeatedGroupAssembler) lastAssembler;
+        } else {
+            endOfGroupAssembler = new 
EndOfRepeatedGroupAssembler(delegateRepeatedReader);
+            valueAssemblers.add(endOfGroupAssembler);
+        }
+        endOfGroupAssembler.addArray(arrayAssembler);
+
+        delegateRepeatedReader = previousDelegate;

         level--;
         delimiters.removeInt(delimiters.size() - 1);
@@ -186,7 +198,8 @@
         if (!delimiters.isEmpty()) {
             IColumnValuesReader reader = 
readerFactory.createValueReader(primitiveNode.getTypeTag(),
                     primitiveNode.getColumnIndex(), level, getDelimiters());
-            assembler = new RepeatedPrimitiveValueAssembler(level, info, 
reader, valueGetter);
+
+            assembler = new RepeatedPrimitiveValueAssembler(level, info, 
reader, valueGetter, setDelegate(reader));

         } else {
             IColumnValuesReader reader = 
readerFactory.createValueReader(primitiveNode.getTypeTag(),
@@ -220,4 +233,12 @@
             return BuiltinType.getBuiltinType(childTypeTag);
         }
     }
+
+    private boolean setDelegate(IColumnValuesReader reader) {
+        if (delegateRepeatedReader == null || 
delegateRepeatedReader.getColumnIndex() > reader.getColumnIndex()) {
+            delegateRepeatedReader = reader;
+            return true;
+        }
+        return false;
+    }
 }
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerState.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerState.java
new file mode 100644
index 0000000..27df5b7
--- /dev/null
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/AssemblerState.java
@@ -0,0 +1,39 @@
+/*
+ * 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.column.assembler;
+
+public class AssemblerState {
+    private boolean inGroup;
+
+    public AssemblerState() {
+        clear();
+    }
+
+    public void setInGroup() {
+        this.inGroup = true;
+    }
+
+    public boolean isInGroup() {
+        return inGroup;
+    }
+
+    public void clear() {
+        this.inGroup = false;
+    }
+}
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/EndOfRepeatedGroupAssembler.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/EndOfRepeatedGroupAssembler.java
new file mode 100644
index 0000000..e7f2d9d
--- /dev/null
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/EndOfRepeatedGroupAssembler.java
@@ -0,0 +1,81 @@
+/*
+ * 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.column.assembler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.column.assembler.value.MissingValueGetter;
+import org.apache.asterix.column.values.IColumnValuesReader;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+public class EndOfRepeatedGroupAssembler extends 
AbstractPrimitiveValueAssembler {
+    private final List<ArrayValueAssembler> arrays;
+
+    EndOfRepeatedGroupAssembler(IColumnValuesReader reader) {
+        super(reader.getLevel(), new AssemblerInfo(), reader, 
MissingValueGetter.INSTANCE);
+        arrays = new ArrayList<>();
+    }
+
+    public void addArray(ArrayValueAssembler assembler) {
+        arrays.add(assembler);
+    }
+
+    @Override
+    public int next(AssemblerState state) throws HyracksDataException {
+        //Initially, go to the next primitive assembler
+        int nextIndex = NEXT_ASSEMBLER;
+        /*
+         * This assembler is a delegate of a repeated group
+         * The delimiter index tells us that this assembler is responsible for 
a finished group
+         */
+        int delimiterIndex = reader.getDelimiterIndex();
+        if (delimiterIndex < arrays.size() && reader.isDelimiter()) {
+            //Also finish the next group
+            delimiterIndex++;
+        }
+
+        int numberOfFinishedGroups = Math.min(delimiterIndex, arrays.size());
+        for (int i = 0; i < numberOfFinishedGroups; i++) {
+            //I'm the delegate for this group of repeated values and the 
group(s) is finished
+            ArrayValueAssembler assembler = arrays.get(i);
+            assembler.end();
+        }
+
+        //Is the repeated group (determined by the delimiter index) still 
unfinished?
+        if (delimiterIndex < arrays.size()) {
+            //Yes, go to the first value of the unfinished repeated group
+            nextIndex = arrays.get(delimiterIndex).getFirstValueIndex();
+            state.setInGroup();
+        } else {
+            state.clear();
+        }
+        return nextIndex;
+    }
+
+    @Override
+    public boolean isEndOfGroupAssembler() {
+        return true;
+    }
+
+    @Override
+    public void skip(int count) throws HyracksDataException {
+        // noOp
+    }
+}
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/PrimitiveValueAssembler.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/PrimitiveValueAssembler.java
index 4f7778c..eb88778 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/PrimitiveValueAssembler.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/PrimitiveValueAssembler.java
@@ -29,9 +29,9 @@
     }

     @Override
-    public int next() throws HyracksDataException {
+    public int next(AssemblerState state) throws HyracksDataException {
         if (!reader.next()) {
-            throw new IllegalAccessError("no more values, column index: " + 
getColumnIndex());
+            throw new IllegalStateException("no more values, column index: " + 
getColumnIndex());
         } else if (reader.isNull() && (isDelegate() || reader.getLevel() + 1 
== level)) {
             addNullToAncestor(reader.getLevel());
         } else if (reader.isValue()) {
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/RepeatedPrimitiveValueAssembler.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/RepeatedPrimitiveValueAssembler.java
index d4455ec..6a8269f 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/RepeatedPrimitiveValueAssembler.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/assembler/RepeatedPrimitiveValueAssembler.java
@@ -18,38 +18,47 @@
  */
 package org.apache.asterix.column.assembler;

-import java.util.ArrayList;
-import java.util.List;
-
 import org.apache.asterix.column.assembler.value.IValueGetter;
 import org.apache.asterix.column.values.IColumnValuesReader;
 import org.apache.hyracks.api.exceptions.HyracksDataException;

 class RepeatedPrimitiveValueAssembler extends AbstractPrimitiveValueAssembler {
-    private final List<ArrayValueAssembler> arrays;
+    private final boolean arrayDelegate;

     RepeatedPrimitiveValueAssembler(int level, AssemblerInfo info, 
IColumnValuesReader reader,
-            IValueGetter primitiveValue) {
+            IValueGetter primitiveValue, boolean arrayDelegate) {
         super(level, info, reader, primitiveValue);
-        this.arrays = new ArrayList<>();
-    }
-
-    public void addArray(ArrayValueAssembler assembler) {
-        arrays.add(assembler);
+        this.arrayDelegate = arrayDelegate;
     }

     @Override
-    public int next() throws HyracksDataException {
+    public int next(AssemblerState state) throws HyracksDataException {
+        if (arrayDelegate || !state.isInGroup() || reader.isRepeatedValue())
+        /*(!reader.isRepeatedValue()
+        || !reader.isDelimiter() && reader.getDelimiterIndex() < 
currentDelimiter))*/ {
+            next();
+        }
+
+        if (isDelegate()) {
+            getParent().end();
+        }
+
+        //Go to next value
+        return NEXT_ASSEMBLER;
+    }
+
+    private void next() throws HyracksDataException {
         if (!reader.next()) {
-            throw new IllegalAccessError("no more values, column index: " + 
getColumnIndex());
-        } else if (reader.isNull() && (!arrays.isEmpty() || reader.getLevel() 
+ 1 == level)) {
+            throw new IllegalStateException("no more values, column index: " + 
getColumnIndex());
+        } else if (reader.isNull() && (arrayDelegate || reader.getLevel() + 1 
== level)) {
             /*
              * There are two cases here for where the null belongs to:
              * 1- If the null is an array item, then add it
              * 2- If the null is an ancestor, then we only add null if this 
column is the array delegate
-             * (i.e., !arrays.isEmpty())
+             * (i.e., arrayDelegate is true)
              */
             addNullToAncestor(reader.getLevel());
+
         } else if (reader.isMissing() && reader.getLevel() + 1 == level) {
             /*
              * Add a missing item
@@ -58,39 +67,5 @@
         } else if (reader.isValue()) {
             addValueToParent();
         }
-
-        if (isDelegate()) {
-            getParent().end();
-        }
-
-        //Initially, go to the next primitive assembler
-        int nextIndex = NEXT_ASSEMBLER;
-        if (!arrays.isEmpty()) {
-            /*
-             * This assembler is a delegate of a repeated group
-             * The delimiter index tells us that this assembler is responsible 
for a finished group
-             */
-            int delimiterIndex = reader.getDelimiterIndex();
-            if (delimiterIndex < arrays.size() && reader.isDelimiter()) {
-                //Also finish the next group
-                delimiterIndex++;
-            }
-
-            int numberOfFinishedGroups = Math.min(delimiterIndex, 
arrays.size());
-            for (int i = 0; i < numberOfFinishedGroups; i++) {
-                //I'm the delegate for this group of repeated values and the 
group(s) is finished
-                ArrayValueAssembler assembler = arrays.get(i);
-                assembler.end();
-            }
-
-            //Is the repeated group (determined by the delimiter index) still 
unfinished?
-            if (delimiterIndex < arrays.size()) {
-                //Yes, go to the first value of the unfinished repeated group
-                nextIndex = arrays.get(delimiterIndex).getFirstValueIndex();
-            }
-        }
-
-        //Go to next value
-        return nextIndex;
     }
 }
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java
index 71d3ac6..e86f063 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/ColumnAssembler.java
@@ -18,10 +18,9 @@
  */
 package org.apache.asterix.column.operation.query;

-import java.util.List;
-
 import org.apache.asterix.column.assembler.AbstractPrimitiveValueAssembler;
 import org.apache.asterix.column.assembler.AssemblerBuilderVisitor;
+import org.apache.asterix.column.assembler.AssemblerState;
 import org.apache.asterix.column.assembler.ObjectValueAssembler;
 import org.apache.asterix.column.assembler.value.IValueGetterFactory;
 import org.apache.asterix.column.bytes.stream.in.AbstractBytesInputStream;
@@ -32,8 +31,9 @@
 import org.apache.hyracks.data.std.api.IValueReference;

 public final class ColumnAssembler {
-    private final List<AbstractPrimitiveValueAssembler> assemblers;
+    private final AbstractPrimitiveValueAssembler[] assemblers;
     private final ObjectValueAssembler rootAssembler;
+    private final AssemblerState state;
     private int numberOfTuples;
     private int tupleIndex;

@@ -44,6 +44,7 @@
                 new AssemblerBuilderVisitor(columnMetadata, readerFactory, 
valueGetterFactory);
         assemblers = builderVisitor.createValueAssemblers(node, declaredType);
         rootAssembler = (ObjectValueAssembler) 
builderVisitor.getRootAssembler();
+        state = new AssemblerState();
     }

     public void reset(int numberOfTuples) {
@@ -52,11 +53,11 @@
     }

     public void resetColumn(AbstractBytesInputStream stream, int ordinal) 
throws HyracksDataException {
-        assemblers.get(ordinal).reset(stream, numberOfTuples);
+        assemblers[ordinal].reset(stream, numberOfTuples);
     }

     public int getColumnIndex(int ordinal) {
-        return assemblers.get(ordinal).getColumnIndex();
+        return assemblers[ordinal].getColumnIndex();
     }

     public boolean hasNext() {
@@ -72,9 +73,9 @@
         }

         int index = 0;
-        while (index < assemblers.size()) {
-            AbstractPrimitiveValueAssembler assembler = assemblers.get(index);
-            int groupIndex = assembler.next();
+        while (index < assemblers.length) {
+            AbstractPrimitiveValueAssembler assembler = assemblers[index];
+            int groupIndex = assembler.next(state);
             if (groupIndex != AbstractPrimitiveValueAssembler.NEXT_ASSEMBLER) {
                 index = groupIndex;
             } else {
@@ -88,13 +89,13 @@
     }

     public int getNumberOfColumns() {
-        return assemblers.size();
+        return assemblers.length;
     }

     public void skip(int count) throws HyracksDataException {
         tupleIndex += count;
-        for (int i = 0; i < assemblers.size(); i++) {
-            assemblers.get(i).skip(count);
+        for (int i = 0; i < assemblers.length; i++) {
+            assemblers[i].skip(count);
         }
     }
 }
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java
index b9babf1..58ddb5d 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/operation/query/QueryColumnMetadata.java
@@ -172,6 +172,9 @@
         PrimitiveColumnValuesReader[] primaryKeyReaders =
                 createPrimaryKeyReaders(input, readerFactory, 
numberOfPrimaryKeys);

+        //        SchemaStringBuilderVisitor printer = new 
SchemaStringBuilderVisitor(fieldNamesDictionary);
+        //        System.err.println(printer.build(clippedRoot));
+
         if (LOGGER.isInfoEnabled() && filterEvaluator != 
TrueColumnFilterEvaluator.INSTANCE) {
             String filterString = filterEvaluator == 
FalseColumnFilterEvaluator.INSTANCE ? "SKIP_ALL"
                     : 
LogRedactionUtil.userData(filterEvaluatorFactory.toString());
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/util/SchemaStringBuilderVisitor.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/util/SchemaStringBuilderVisitor.java
new file mode 100644
index 0000000..5786221
--- /dev/null
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/util/SchemaStringBuilderVisitor.java
@@ -0,0 +1,149 @@
+/*
+ * 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.column.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.asterix.column.metadata.FieldNamesDictionary;
+import org.apache.asterix.column.metadata.schema.AbstractSchemaNode;
+import org.apache.asterix.column.metadata.schema.ISchemaNodeVisitor;
+import org.apache.asterix.column.metadata.schema.ObjectSchemaNode;
+import org.apache.asterix.column.metadata.schema.UnionSchemaNode;
+import 
org.apache.asterix.column.metadata.schema.collection.AbstractCollectionSchemaNode;
+import org.apache.asterix.column.metadata.schema.primitive.PrimitiveSchemaNode;
+import 
org.apache.asterix.dataflow.data.nontagged.serde.AStringSerializerDeserializer;
+import org.apache.asterix.om.base.AString;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.data.std.api.IValueReference;
+import org.apache.hyracks.data.std.util.ByteArrayAccessibleDataInputStream;
+import org.apache.hyracks.data.std.util.ByteArrayAccessibleInputStream;
+import org.apache.hyracks.util.string.UTF8StringReader;
+import org.apache.hyracks.util.string.UTF8StringWriter;
+
+import it.unimi.dsi.fastutil.ints.IntList;
+
+// TODO log schema changes (also redact)
+// TODO log query schema and redact
+public class SchemaStringBuilderVisitor implements ISchemaNodeVisitor<Void, 
Void> {
+    private final StringBuilder builder;
+    private final List<String> fieldNames;
+
+    private int level;
+    private int indent;
+
+    public SchemaStringBuilderVisitor(FieldNamesDictionary dictionary) throws 
HyracksDataException {
+        builder = new StringBuilder();
+        this.fieldNames = new ArrayList<>();
+        AStringSerializerDeserializer stringSerDer =
+                new AStringSerializerDeserializer(new UTF8StringWriter(), new 
UTF8StringReader());
+        List<IValueReference> extractedFieldNames = dictionary.getFieldNames();
+
+        //Deserialize field names
+        ByteArrayAccessibleInputStream in = new 
ByteArrayAccessibleInputStream(new byte[0], 0, 0);
+        ByteArrayAccessibleDataInputStream dataIn = new 
ByteArrayAccessibleDataInputStream(in);
+        for (IValueReference serFieldName : extractedFieldNames) {
+            in.setContent(serFieldName.getByteArray(), 0, 
serFieldName.getLength());
+            AString fieldName = stringSerDer.deserialize(dataIn);
+            this.fieldNames.add(fieldName.getStringValue());
+        }
+        level = 0;
+        indent = 0;
+    }
+
+    public String build(ObjectSchemaNode root) throws HyracksDataException {
+        builder.append("root\n");
+        visit(root, null);
+        return builder.toString();
+    }
+
+    @Override
+    public Void visit(ObjectSchemaNode objectNode, Void arg) throws 
HyracksDataException {
+        List<AbstractSchemaNode> children = objectNode.getChildren();
+        IntList fieldNameIndexes = objectNode.getChildrenFieldNameIndexes();
+        level++;
+        indent++;
+
+        for (int i = 0; i < children.size(); i++) {
+            String fieldName = fieldNames.get(fieldNameIndexes.getInt(i));
+            AbstractSchemaNode child = children.get(i);
+            append(fieldName, child);
+            child.accept(this, null);
+        }
+
+        level--;
+        indent--;
+        return null;
+    }
+
+    @Override
+    public Void visit(AbstractCollectionSchemaNode collectionNode, Void arg) 
throws HyracksDataException {
+        level++;
+        indent++;
+        AbstractSchemaNode itemNode = collectionNode.getItemNode();
+        append("item", itemNode);
+        itemNode.accept(this, null);
+        level--;
+        indent--;
+        return null;
+    }
+
+    @Override
+    public Void visit(UnionSchemaNode unionNode, Void arg) throws 
HyracksDataException {
+        indent++;
+        for (AbstractSchemaNode child : unionNode.getChildren().values()) {
+            append(child.getTypeTag().toString(), child);
+            child.accept(this, null);
+        }
+        indent--;
+        return null;
+    }
+
+    @Override
+    public Void visit(PrimitiveSchemaNode primitiveNode, Void arg) throws 
HyracksDataException {
+        return null;
+    }
+
+    private void appendLevels(String levels) {
+        appendDecor();
+        builder.append("Def ");
+        builder.append(levels);
+        builder.append('\n');
+    }
+
+    private void appendDecor() {
+        builder.append("|    ".repeat(Math.max(0, indent - 1)));
+        builder.append("|-- ");
+    }
+
+    private void append(String key, AbstractSchemaNode node) {
+        appendDecor();
+        builder.append(key);
+        builder.append(": ");
+        builder.append(node.getTypeTag().toString());
+        builder.append(" <level: ");
+        builder.append(level);
+        if (!node.isNested()) {
+            final PrimitiveSchemaNode primitiveNode = (PrimitiveSchemaNode) 
node;
+            builder.append(", index: ");
+            builder.append(primitiveNode.getColumnIndex());
+        }
+        builder.append(">\n");
+    }
+}
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/IColumnValuesReader.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/IColumnValuesReader.java
index fe23b23..1ee6c36 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/IColumnValuesReader.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/IColumnValuesReader.java
@@ -86,6 +86,13 @@
     boolean isDelimiter();

     /**
+     * @return is the last delimiter (the end of all nested arrays)
+     */
+    boolean isLastDelimiter();
+
+    boolean isRepeatedValue();
+
+    /**
      * @return which delimiter was returned (nested arrays have different 
delimiter indexes)
      */
     int getDelimiterIndex();
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/PrimitiveColumnValuesReader.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/PrimitiveColumnValuesReader.java
index 7ae2954..6d2d87c 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/PrimitiveColumnValuesReader.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/PrimitiveColumnValuesReader.java
@@ -74,6 +74,16 @@
     }

     @Override
+    public boolean isLastDelimiter() {
+        return false;
+    }
+
+    @Override
+    public boolean isRepeatedValue() {
+        return false;
+    }
+
+    @Override
     public int getDelimiterIndex() {
         throw new IllegalStateException("Not a repeated reader");
     }
diff --git 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/RepeatedPrimitiveColumnValuesReader.java
 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/RepeatedPrimitiveColumnValuesReader.java
index 1cd424b..f0044df 100644
--- 
a/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/RepeatedPrimitiveColumnValuesReader.java
+++ 
b/asterixdb/asterix-column/src/main/java/org/apache/asterix/column/values/reader/RepeatedPrimitiveColumnValuesReader.java
@@ -108,11 +108,13 @@
         writer.writeLevel(level);
     }

-    private boolean isRepeatedValue() {
+    @Override
+    public boolean isRepeatedValue() {
         return levelToDelimiterMap[level] < delimiters.length;
     }

-    private boolean isLastDelimiter() {
+    @Override
+    public boolean isLastDelimiter() {
         return isDelimiter() && delimiterIndex == delimiters.length - 1;
     }

diff --git 
a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyPrimitiveColumnValueReader.java
 
b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyPrimitiveColumnValueReader.java
index 115f311..978ec14 100644
--- 
a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyPrimitiveColumnValueReader.java
+++ 
b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyPrimitiveColumnValueReader.java
@@ -55,6 +55,16 @@
     }

     @Override
+    public boolean isLastDelimiter() {
+        return false;
+    }
+
+    @Override
+    public boolean isRepeatedValue() {
+        return false;
+    }
+
+    @Override
     public int getDelimiterIndex() {
         throw new IllegalStateException("Not a repeated reader");
     }
diff --git 
a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyRepeatedPrimitiveColumnValueReader.java
 
b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyRepeatedPrimitiveColumnValueReader.java
index abd1927..c7744c2 100644
--- 
a/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyRepeatedPrimitiveColumnValueReader.java
+++ 
b/asterixdb/asterix-column/src/test/java/org/apache/asterix/column/values/reader/DummyRepeatedPrimitiveColumnValueReader.java
@@ -73,6 +73,16 @@
     }

     @Override
+    public boolean isLastDelimiter() {
+        return isDelimiter() && delimiterIndex == delimiters.length - 1;
+    }
+
+    @Override
+    public boolean isRepeatedValue() {
+        return levelToDelimiterMap[level] < delimiters.length;
+    }
+
+    @Override
     public int getDelimiterIndex() {
         return delimiterIndex;
     }

--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17496
To unsubscribe, or for help writing mail filters, visit 
https://asterix-gerrit.ics.uci.edu/settings

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: Ib2cede772f3db534b6c0c93c10d51ec076747e19
Gerrit-Change-Number: 17496
Gerrit-PatchSet: 1
Gerrit-Owner: Wail Alkowaileet <[email protected]>
Gerrit-MessageType: newchange

Reply via email to