aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinfeng Ni <jni@maprtech.com>2014-05-30 11:07:03 -0700
committerJacques Nadeau <jacques@apache.org>2014-06-10 18:59:28 -0700
commit31b5962250675c45bcbe3c3fe6babeba5deb21fc (patch)
tree831067db75422132682c11a2b764d71396249a5c
parent1226af8bf7b131097c1c6c724d67d126a344570d (diff)
DRILL-927: Run-time code generation support for reading Complex Type.
Fix in RepeatedMapVector.
-rw-r--r--common/src/main/java/org/apache/drill/common/types/Types.java6
-rw-r--r--exec/java-exec/src/main/codegen/templates/BaseReader.java1
-rw-r--r--exec/java-exec/src/main/codegen/templates/NullReader.java7
-rw-r--r--exec/java-exec/src/main/codegen/templates/RepeatedValueVectors.java30
-rw-r--r--exec/java-exec/src/main/codegen/templates/SingularReaderImpl.java210
-rw-r--r--exec/java-exec/src/main/codegen/templates/TypeHelper.java30
-rw-r--r--exec/java-exec/src/main/codegen/templates/ValueHolders.java21
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java285
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java6
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java28
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java99
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/conv/JsonConvertTo.java81
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/record/SimpleVectorWrapper.java2
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/record/TypedFieldId.java14
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java11
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/AbstractContainerVector.java38
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/MapVector.java3
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/RepeatedMapVector.java4
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/fn/JsonWriter.java11
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedListReaderImpl.java5
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedMapReaderImpl.java14
-rw-r--r--exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/SingleLikeRepeatedMapReaderImpl.java89
-rw-r--r--exec/java-exec/src/test/java/org/apache/drill/exec/vector/complex/writer/TestComplexTypeReader.java167
-rw-r--r--exec/java-exec/src/test/resources/jsoninput/vvtypes.json140
24 files changed, 1092 insertions, 210 deletions
diff --git a/common/src/main/java/org/apache/drill/common/types/Types.java b/common/src/main/java/org/apache/drill/common/types/Types.java
index e2c331056..10d84e1d1 100644
--- a/common/src/main/java/org/apache/drill/common/types/Types.java
+++ b/common/src/main/java/org/apache/drill/common/types/Types.java
@@ -46,6 +46,10 @@ public class Types {
return false;
}
+ public static boolean isRepeated(MajorType type){
+ return type.getMode() == REPEATED ;
+ }
+
public static boolean isNumericType(MajorType type){
if(type.getMode() == REPEATED) return false;
@@ -344,6 +348,8 @@ public class Types {
return withMode(MinorType.TIME, mode);
case "binary":
return withMode(MinorType.VARBINARY, mode);
+ case "json":
+ return withMode(MinorType.VARBINARY, mode);
default:
throw new UnsupportedOperationException("Could not determine type: " + typeName);
}
diff --git a/exec/java-exec/src/main/codegen/templates/BaseReader.java b/exec/java-exec/src/main/codegen/templates/BaseReader.java
index 42f482694..d432b7445 100644
--- a/exec/java-exec/src/main/codegen/templates/BaseReader.java
+++ b/exec/java-exec/src/main/codegen/templates/BaseReader.java
@@ -39,6 +39,7 @@ public interface BaseReader extends Positionable{
public interface RepeatedMapReader extends MapReader{
boolean next();
int size();
+ void copyAsValue(MapWriter writer);
}
public interface ListReader extends BaseReader{
diff --git a/exec/java-exec/src/main/codegen/templates/NullReader.java b/exec/java-exec/src/main/codegen/templates/NullReader.java
index 962eeda0b..beec5cb3d 100644
--- a/exec/java-exec/src/main/codegen/templates/NullReader.java
+++ b/exec/java-exec/src/main/codegen/templates/NullReader.java
@@ -34,6 +34,13 @@ public class NullReader extends AbstractBaseReader implements FieldReader{
private NullReader(){
super();
}
+
+ @Override
+ public MajorType getType() {
+ return Types.NULL;
+ }
+
+ public void copyAsValue(MapWriter writer) {}
<#list vv.types as type><#list type.minor as minor><#assign name = minor.class?cap_first />
public void read(Nullable${name}Holder holder){
diff --git a/exec/java-exec/src/main/codegen/templates/RepeatedValueVectors.java b/exec/java-exec/src/main/codegen/templates/RepeatedValueVectors.java
index 657011340..48efc163c 100644
--- a/exec/java-exec/src/main/codegen/templates/RepeatedValueVectors.java
+++ b/exec/java-exec/src/main/codegen/templates/RepeatedValueVectors.java
@@ -130,9 +130,6 @@ package org.apache.drill.exec.vector;
}
}
-
-
-<#if type.major == "VarLen">
public void copyFrom(int inIndex, int outIndex, Repeated${minor.class}Vector v){
int count = v.getAccessor().getCount(inIndex);
getMutator().startNewGroup(outIndex);
@@ -151,16 +148,6 @@ package org.apache.drill.exec.vector;
}
return true;
}
-<#else>
-
- public void copyFrom(int inIndex, int outIndex, Repeated${minor.class}Vector v){
- throw new UnsupportedOperationException();
- }
-
- public boolean copyFromSafe(int inIndex, int outIndex, Repeated${minor.class}Vector v){
- throw new UnsupportedOperationException();
- }
-</#if>
public boolean allocateNewSafe(){
if(!offsets.allocateNewSafe()) return false;
@@ -341,12 +328,17 @@ package org.apache.drill.exec.vector;
public void get(int index, int positionIndex, ${minor.class}Holder holder) {
int offset = offsets.getAccessor().get(index);
assert offset >= 0;
+ assert positionIndex < getCount(index);
values.getAccessor().get(offset + positionIndex, holder);
}
public void get(int index, int positionIndex, Nullable${minor.class}Holder holder) {
int offset = offsets.getAccessor().get(index);
assert offset >= 0;
+ if (positionIndex >= getCount(index)) {
+ holder.isSet = 0;
+ return;
+ }
values.getAccessor().get(offset + positionIndex, holder);
}
@@ -407,9 +399,19 @@ package org.apache.drill.exec.vector;
return (b1 && b2);
}
-
+ <#else>
+
+ public boolean addSafe(int index, ${minor.javaType!type.javaType} srcValue) {
+ if(offsets.getValueCapacity() <= index+1) return false;
+ int nextOffset = offsets.getAccessor().get(index+1);
+ boolean b1 = values.getMutator().setSafe(nextOffset, srcValue);
+ boolean b2 = offsets.getMutator().setSafe(index+1, nextOffset+1);
+ return (b1 && b2);
+ }
+
</#if>
+
public boolean setSafe(int index, Repeated${minor.class}Holder h){
${minor.class}Holder ih = new ${minor.class}Holder();
getMutator().startNewGroup(index);
diff --git a/exec/java-exec/src/main/codegen/templates/SingularReaderImpl.java b/exec/java-exec/src/main/codegen/templates/SingularReaderImpl.java
new file mode 100644
index 000000000..33cedba3c
--- /dev/null
+++ b/exec/java-exec/src/main/codegen/templates/SingularReaderImpl.java
@@ -0,0 +1,210 @@
+/**
+ * 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.
+ */
+
+<@pp.dropOutputFile />
+<#list vv.types as type>
+<#list type.minor as minor>
+<#list ["", "Nullable"] as nullMode>
+<#assign lowerName = minor.class?uncap_first />
+<#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
+<#assign name = minor.class?cap_first />
+<#assign javaType = (minor.javaType!type.javaType) />
+<#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+<#assign safeType=friendlyType />
+<#if safeType=="byte[]"><#assign safeType="ByteArray" /></#if>
+
+<@pp.changeOutputFile name="/org/apache/drill/exec/vector/complex/impl/${nullMode}${name}SingularReaderImpl.java" />
+<#include "/@includes/license.ftl" />
+
+package org.apache.drill.exec.vector.complex.impl;
+
+<#include "/@includes/vv_imports.ftl" />
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.apache.drill.exec.expr.holders.*;
+import org.apache.hadoop.io.Text;
+import org.joda.time.Period;
+import org.mortbay.jetty.servlet.Holder;
+
+@SuppressWarnings("unused")
+public class ${nullMode}${name}SingularReaderImpl extends AbstractFieldReader {
+
+ private ${nullMode}${name}Holder holder;
+
+ public ${nullMode}${name}SingularReaderImpl(${nullMode}${name}Holder holder) {
+ this.holder = holder;
+ }
+
+ @Override
+ public int size() {
+ throw new UnsupportedOperationException("You can't call size on a singular value reader.");
+ }
+
+ @Override
+ public boolean next() {
+ throw new UnsupportedOperationException("You can't call next on a single value reader.");
+ }
+
+ @Override
+ public void setPosition(int index) {
+ throw new UnsupportedOperationException("You can't call next on a single value reader.");
+ }
+
+ @Override
+ public MajorType getType() {
+ return this.holder.getType();
+ }
+
+ @Override
+ public boolean isSet() {
+ return this.holder.isSet();
+ }
+
+ @Override
+ public ${friendlyType} read${safeType}(){
+ <#if nullMode == "Nullable">
+
+ if (!holder.isSet()) {
+ return null;
+ }
+ </#if>
+
+ <#if type.major == "VarLen">
+
+ int length = holder.end - holder.start;
+ byte[] value = new byte [length];
+ holder.buffer.getBytes(holder.start, value, 0, length);
+
+ <#if minor.class == "VarBinary">
+ return value;
+ <#elseif minor.class == "Var16Char">
+ return new String(value);
+ <#elseif minor.class == "VarChar">
+ Text text = new Text();
+ text.set(value);
+ return text;
+ </#if>
+
+ <#elseif minor.class == "Interval">
+ Period p = new Period();
+ return p.plusMonths(holder.months).plusDays(holder.days).plusMillis(holder.milliSeconds);
+
+ <#elseif minor.class == "IntervalDay">
+ Period p = new Period();
+ return p.plusDays(holder.days).plusMillis(holder.milliSeconds);
+
+ <#elseif minor.class == "Decimal9" ||
+ minor.class == "Decimal18" >
+ BigInteger value = BigInteger.valueOf(holder.value);
+ return new BigDecimal(value, holder.scale);
+
+ <#elseif minor.class == "Decimal28Dense" ||
+ minor.class == "Decimal38Dense">
+ return org.apache.drill.common.util.DecimalUtility.getBigDecimalFromDense(holder.buffer,
+ holder.start,
+ holder.nDecimalDigits,
+ holder.scale,
+ holder.maxPrecision,
+ holder.WIDTH);
+
+ <#elseif minor.class == "Decimal28Sparse" ||
+ minor.class == "Decimal38Sparse">
+ return org.apache.drill.common.util.DecimalUtility.getBigDecimalFromSparse(holder.buffer,
+ holder.start,
+ holder.nDecimalDigits,
+ holder.scale);
+
+ <#elseif minor.class == "Bit" >
+ return new Boolean(holder.value != 0);
+ <#else>
+ ${friendlyType} value = new ${friendlyType}(this.holder.value);
+ return value;
+ </#if>
+
+ }
+
+ @Override
+ public Object readObject(){
+
+ <#if nullMode == "Nullable">
+
+ if (!holder.isSet()) {
+ return null;
+ }
+ </#if>
+
+ <#if type.major == "VarLen">
+
+ int length = holder.end - holder.start;
+ byte[] value = new byte [length];
+ holder.buffer.getBytes(holder.start, value, 0, length);
+
+ <#if minor.class == "VarBinary">
+ return value;
+ <#elseif minor.class == "Var16Char">
+ return new String(value);
+ <#elseif minor.class == "VarChar">
+ Text text = new Text();
+ text.set(value);
+ return text;
+ </#if>
+
+ <#elseif minor.class == "Interval">
+ Period p = new Period();
+ return p.plusMonths(holder.months).plusDays(holder.days).plusMillis(holder.milliSeconds);
+
+ <#elseif minor.class == "IntervalDay">
+ Period p = new Period();
+ return p.plusDays(holder.days).plusMillis(holder.milliSeconds);
+
+ <#elseif minor.class == "Decimal9" ||
+ minor.class == "Decimal18" >
+ BigInteger value = BigInteger.valueOf(holder.value);
+ return new BigDecimal(value, holder.scale);
+
+ <#elseif minor.class == "Decimal28Dense" ||
+ minor.class == "Decimal38Dense">
+ return org.apache.drill.common.util.DecimalUtility.getBigDecimalFromDense(holder.buffer,
+ holder.start,
+ holder.nDecimalDigits,
+ holder.scale,
+ holder.maxPrecision,
+ holder.WIDTH);
+
+ <#elseif minor.class == "Decimal28Sparse" ||
+ minor.class == "Decimal38Sparse">
+ return org.apache.drill.common.util.DecimalUtility.getBigDecimalFromSparse(holder.buffer,
+ holder.start,
+ holder.nDecimalDigits,
+ holder.scale);
+
+ <#elseif minor.class == "Bit" >
+ return new Boolean(holder.value != 0);
+ <#else>
+ ${friendlyType} value = new ${friendlyType}(this.holder.value);
+ return value;
+ </#if>
+ }
+
+}
+
+</#list>
+</#list>
+</#list>
diff --git a/exec/java-exec/src/main/codegen/templates/TypeHelper.java b/exec/java-exec/src/main/codegen/templates/TypeHelper.java
index 5f24a3087..8c56d99ef 100644
--- a/exec/java-exec/src/main/codegen/templates/TypeHelper.java
+++ b/exec/java-exec/src/main/codegen/templates/TypeHelper.java
@@ -115,14 +115,17 @@ public class TypeHelper {
}
throw new UnsupportedOperationException();
}
- public static Class<?> getReaderClassName( MinorType type, DataMode mode){
+ public static Class<?> getReaderClassName( MinorType type, DataMode mode, boolean isSingularRepeated){
switch (type) {
case MAP:
switch (mode) {
case REQUIRED:
- return SingleMapReaderImpl.class;
- case REPEATED:
- return RepeatedMapReaderImpl.class;
+ if (!isSingularRepeated)
+ return SingleMapReaderImpl.class;
+ else
+ return SingleLikeRepeatedMapReaderImpl.class;
+ case REPEATED:
+ return RepeatedMapReaderImpl.class;
}
case LIST:
switch (mode) {
@@ -201,6 +204,25 @@ public class TypeHelper {
}
throw new UnsupportedOperationException();
}
+
+ public static Class<?> getSingularReaderImpl( MinorType type, DataMode mode){
+ switch (type) {
+<#list vv.types as type>
+ <#list type.minor as minor>
+ case ${minor.class?upper_case}:
+ switch (mode) {
+ case REQUIRED:
+ return ${minor.class}SingularReaderImpl.class;
+ case OPTIONAL:
+ return Nullable${minor.class}SingularReaderImpl.class;
+ }
+ </#list>
+</#list>
+ default:
+ break;
+ }
+ throw new UnsupportedOperationException();
+ }
public static JType getHolderType(JCodeModel model, MinorType type, DataMode mode){
switch (type) {
diff --git a/exec/java-exec/src/main/codegen/templates/ValueHolders.java b/exec/java-exec/src/main/codegen/templates/ValueHolders.java
index 5cea7e312..cdc4d74b2 100644
--- a/exec/java-exec/src/main/codegen/templates/ValueHolders.java
+++ b/exec/java-exec/src/main/codegen/templates/ValueHolders.java
@@ -32,14 +32,28 @@ package org.apache.drill.exec.expr.holders;
public final class ${className} implements ValueHolder{
public static final MajorType TYPE = Types.${mode.name?lower_case}(MinorType.${minor.class?upper_case});
-
+
+ public MajorType getType() {return TYPE;}
+
<#if mode.name != "Repeated">
public static final int WIDTH = ${type.width};
<#if mode.name == "Optional">
/** Whether the given holder holds a valid value. 1 means non-null. 0 means null. **/
public int isSet;
+
+ public boolean isSet() {
+ return isSet == 1;
+ }
+ <#else>
+
+ public boolean isSet() {
+ return true;
+ }
+
</#if>
+
+
<#if type.major != "VarLen">
@@ -132,6 +146,11 @@ public final class ${className} implements ValueHolder{
/** The Vector holding the actual values. **/
public ${minor.class}Vector vector;
+
+ public boolean isSet() {
+ return true;
+ }
+
</#if>
}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
index 1c012ab61..31cc56307 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/EvaluationVisitor.java
@@ -20,6 +20,7 @@ package org.apache.drill.exec.expr;
import java.util.List;
import java.util.Set;
+import org.apache.commons.io.input.NullReader;
import org.apache.drill.common.expression.CastExpression;
import org.apache.drill.common.expression.ConvertExpression;
import org.apache.drill.common.expression.FunctionCall;
@@ -46,6 +47,7 @@ import org.apache.drill.common.expression.ValueExpressions.QuotedString;
import org.apache.drill.common.expression.ValueExpressions.TimeExpression;
import org.apache.drill.common.expression.ValueExpressions.TimeStampExpression;
import org.apache.drill.common.expression.visitors.AbstractExprVisitor;
+import org.apache.drill.common.types.TypeProtos.DataMode;
import org.apache.drill.common.types.TypeProtos.MajorType;
import org.apache.drill.common.types.TypeProtos.MinorType;
import org.apache.drill.common.types.Types;
@@ -80,33 +82,32 @@ public class EvaluationVisitor {
this.registry = registry;
}
- public HoldingContainer addExpr(LogicalExpression e, ClassGenerator<?> generator){
+ public HoldingContainer addExpr(LogicalExpression e, ClassGenerator<?> generator) {
Set<LogicalExpression> constantBoundaries = ConstantExpressionIdentifier.getConstantExpressionSet(e);
- //Set<LogicalExpression> constantBoundaries = Collections.emptySet();
return e.accept(new ConstantFilter(constantBoundaries), generator);
}
private class EvalVisitor extends AbstractExprVisitor<HoldingContainer, ClassGenerator<?>, RuntimeException> {
-
@Override
public HoldingContainer visitFunctionCall(FunctionCall call, ClassGenerator<?> generator) throws RuntimeException {
- throw new UnsupportedOperationException("FunctionCall is not expected here. "+
- "It should have been converted to FunctionHolderExpression in materialization");
+ throw new UnsupportedOperationException("FunctionCall is not expected here. "
+ + "It should have been converted to FunctionHolderExpression in materialization");
}
@Override
- public HoldingContainer visitFunctionHolderExpression(
- FunctionHolderExpression holderExpr, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitFunctionHolderExpression(FunctionHolderExpression holderExpr,
+ ClassGenerator<?> generator) throws RuntimeException {
// TODO: hack: (Drill/Hive)FuncHolderExpr reference classes in exec so
// code generate methods can't be superclass FunctionHolderExpression
// which is defined in common
if (holderExpr instanceof DrillFuncHolderExpr) {
- DrillFuncHolder holder = ((DrillFuncHolderExpr)holderExpr).getHolder();
+ DrillFuncHolder holder = ((DrillFuncHolderExpr) holderExpr).getHolder();
JVar[] workspaceVars = holder.renderStart(generator, null);
- if(holder.isNested()) generator.getMappingSet().enterChild();
+ if (holder.isNested())
+ generator.getMappingSet().enterChild();
HoldingContainer[] args = new HoldingContainer[holderExpr.args.size()];
for (int i = 0; i < holderExpr.args.size(); i++) {
@@ -115,13 +116,14 @@ public class EvaluationVisitor {
holder.renderMiddle(generator, args, workspaceVars);
- if(holder.isNested()) generator.getMappingSet().exitChild();
+ if (holder.isNested())
+ generator.getMappingSet().exitChild();
return holder.renderEnd(generator, args, workspaceVars);
} else if (holderExpr instanceof HiveFuncHolderExpr) {
- HiveFuncHolder holder = ((HiveFuncHolderExpr)holderExpr).getHolder();
+ HiveFuncHolder holder = ((HiveFuncHolderExpr) holderExpr).getHolder();
HoldingContainer[] args = new HoldingContainer[holderExpr.args.size()];
for (int i = 0; i < holderExpr.args.size(); i++) {
@@ -131,7 +133,8 @@ public class EvaluationVisitor {
return holder.renderEnd(generator, args, holder.renderStart(generator, null));
}
- throw new UnsupportedOperationException(String.format("Unknown expression '%s'", holderExpr.getClass().getCanonicalName()));
+ throw new UnsupportedOperationException(String.format("Unknown expression '%s'", holderExpr.getClass()
+ .getCanonicalName()));
}
@Override
@@ -183,7 +186,6 @@ public class EvaluationVisitor {
return output;
}
-
@Override
public HoldingContainer visitSchemaPath(SchemaPath path, ClassGenerator<?> generator) throws RuntimeException {
throw new UnsupportedOperationException("All schema paths should have been replaced with ValueVectorExpressions.");
@@ -218,21 +220,24 @@ public class EvaluationVisitor {
}
@Override
- public HoldingContainer visitIntervalYearConstant(IntervalYearExpression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitIntervalYearConstant(IntervalYearExpression e, ClassGenerator<?> generator)
+ throws RuntimeException {
HoldingContainer out = generator.declare(e.getMajorType());
generator.getEvalBlock().assign(out.getValue(), JExpr.lit(e.getIntervalYear()));
return out;
}
@Override
- public HoldingContainer visitTimeStampConstant(TimeStampExpression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitTimeStampConstant(TimeStampExpression e, ClassGenerator<?> generator)
+ throws RuntimeException {
HoldingContainer out = generator.declare(e.getMajorType());
generator.getEvalBlock().assign(out.getValue(), JExpr.lit(e.getTimeStamp()));
return out;
}
@Override
- public HoldingContainer visitDoubleConstant(DoubleExpression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitDoubleConstant(DoubleExpression e, ClassGenerator<?> generator)
+ throws RuntimeException {
HoldingContainer out = generator.declare(e.getMajorType());
generator.getEvalBlock().assign(out.getValue(), JExpr.lit(e.getDouble()));
return out;
@@ -254,13 +259,13 @@ public class EvaluationVisitor {
return visitValueVectorWriteExpression((ValueVectorWriteExpression) e, generator);
} else if (e instanceof ReturnValueExpression) {
return visitReturnValueExpression((ReturnValueExpression) e, generator);
- }else if(e instanceof HoldingContainerExpression){
+ } else if (e instanceof HoldingContainerExpression) {
return ((HoldingContainerExpression) e).getContainer();
- }else if(e instanceof NullExpression){
+ } else if (e instanceof NullExpression) {
return generator.declare(Types.optional(MinorType.INT));
} else if (e instanceof TypedNullConstant) {
return generator.declare(e.getMajorType());
- } else {
+ } else {
return super.visitUnknown(e, generator);
}
@@ -271,27 +276,30 @@ public class EvaluationVisitor {
final LogicalExpression child = e.getChild();
final HoldingContainer inputContainer = child.accept(this, generator);
final boolean complex = Types.isComplex(inputContainer.getMajorType());
+ final boolean repeated = Types.isRepeated(inputContainer.getMajorType());
JBlock block = generator.getEvalBlock();
JExpression outIndex = generator.getMappingSet().getValueWriteIndex();
JVar vv = generator.declareVectorValueSetupAndMember(generator.getMappingSet().getOutgoing(), e.getFieldId());
- if(complex){
- JType writerImpl = generator.getModel()._ref(TypeHelper.getWriterImpl(inputContainer.getMinorType(), inputContainer.getMajorType().getMode()));
- JType writerIFace = generator.getModel()._ref(TypeHelper.getWriterInterface(inputContainer.getMinorType(), inputContainer.getMajorType().getMode()));
+ if (complex || repeated) {
+ JType writerImpl = generator.getModel()._ref(
+ TypeHelper.getWriterImpl(inputContainer.getMinorType(), inputContainer.getMajorType().getMode()));
+ JType writerIFace = generator.getModel()._ref(
+ TypeHelper.getWriterInterface(inputContainer.getMinorType(), inputContainer.getMajorType().getMode()));
JVar writer = generator.declareClassField("writer", writerIFace);
generator.getSetupBlock().assign(writer, JExpr._new(writerImpl).arg(vv).arg(JExpr._null()));
generator.getEvalBlock().add(writer.invoke("setPosition").arg(outIndex));
String copyMethod = inputContainer.isSingularRepeated() ? "copyAsValueSingle" : "copyAsValue";
generator.getEvalBlock().add(inputContainer.getHolder().invoke(copyMethod).arg(writer));
- if(e.isSafe()){
+ if (e.isSafe()) {
HoldingContainer outputContainer = generator.declare(Types.REQUIRED_BIT);
JConditional ifOut = generator.getEvalBlock()._if(writer.invoke("ok"));
ifOut._then().assign(outputContainer.getValue(), JExpr.lit(1));
ifOut._else().assign(outputContainer.getValue(), JExpr.lit(0));
return outputContainer;
}
- }else{
+ } else {
String setMethod = e.isSafe() ? "setSafe" : "set";
String isSafeMethod = "isSafe";
@@ -299,24 +307,26 @@ public class EvaluationVisitor {
JInvocation setMeth;
if (Types.usesHolderForGet(inputContainer.getMajorType())) {
setMeth = vv.invoke("getMutator").invoke(setMethod).arg(outIndex).arg(inputContainer.getHolder());
- }else{
+ } else {
setMeth = vv.invoke("getMutator").invoke(setMethod).arg(outIndex).arg(inputContainer.getValue());
}
- if(e.isSafe()){
+ if (e.isSafe()) {
HoldingContainer outputContainer = generator.declare(Types.REQUIRED_BIT);
block.assign(outputContainer.getValue(), JExpr.lit(1));
- if(inputContainer.isOptional()){
-// block._if(vv.invoke("getMutator").invoke(setMethod).arg(outIndex).not())._then().assign(outputContainer.getValue(), JExpr.lit(0));
+ if (inputContainer.isOptional()) {
+ // block._if(vv.invoke("getMutator").invoke(setMethod).arg(outIndex).not())._then().assign(outputContainer.getValue(),
+ // JExpr.lit(0));
JConditional jc = block._if(inputContainer.getIsSet().eq(JExpr.lit(0)).not());
block = jc._then();
- jc._else()._if(vv.invoke("getMutator").invoke(isSafeMethod).arg(outIndex).not())._then().assign(outputContainer.getValue(), JExpr.lit(0));
+ jc._else()._if(vv.invoke("getMutator").invoke(isSafeMethod).arg(outIndex).not())._then()
+ .assign(outputContainer.getValue(), JExpr.lit(0));
}
block._if(setMeth.not())._then().assign(outputContainer.getValue(), JExpr.lit(0));
return outputContainer;
- }else{
+ } else {
if (inputContainer.isOptional()) {
-// block.add(vv.invoke("getMutator").invoke(setMethod).arg(outIndex));
+ // block.add(vv.invoke("getMutator").invoke(setMethod).arg(outIndex));
JConditional jc = block._if(inputContainer.getIsSet().eq(JExpr.lit(0)).not());
block = jc._then();
}
@@ -325,7 +335,6 @@ public class EvaluationVisitor {
}
-
return null;
}
@@ -333,35 +342,37 @@ public class EvaluationVisitor {
throws RuntimeException {
// declare value vector
- JExpression vv1 = generator.declareVectorValueSetupAndMember(generator.getMappingSet().getIncoming(), e.getFieldId());
+ JExpression vv1 = generator.declareVectorValueSetupAndMember(generator.getMappingSet().getIncoming(),
+ e.getFieldId());
JExpression indexVariable = generator.getMappingSet().getValueReadIndex();
JExpression componentVariable = indexVariable.shrz(JExpr.lit(16));
if (e.isSuperReader()) {
- vv1 = (vv1.component(componentVariable));
+ vv1 = (vv1.component(componentVariable));
indexVariable = indexVariable.band(JExpr.lit((int) Character.MAX_VALUE));
}
// evaluation work.
HoldingContainer out = generator.declare(e.getMajorType());
+
final boolean primitive = !Types.usesHolderForGet(e.getMajorType());
final boolean hasReadPath = e.hasReadPath();
final boolean complex = Types.isComplex(e.getMajorType());
+ final boolean repeated = Types.isRepeated(e.getMajorType());
int[] fieldIds = e.getFieldId().getFieldIds();
- for(int i = 1; i < fieldIds.length; i++){
+ for (int i = 1; i < fieldIds.length; i++) {
}
- if(!hasReadPath && !complex){
-
+ if (!hasReadPath && !complex) {
JInvocation getValueAccessor = vv1.invoke("getAccessor").invoke("get");
JInvocation getValueAccessor2 = vv1.invoke("getAccessor");
JBlock eval = new JBlock();
- if(primitive){
+ if (primitive) {
eval.assign(out.getValue(), getValueAccessor.arg(indexVariable));
- }else{
+ } else {
eval.add(getValueAccessor.arg(indexVariable).arg(out.getHolder()));
}
@@ -370,13 +381,14 @@ public class EvaluationVisitor {
blk.assign(out.getIsSet(), getValueAccessor2.invoke("isSet").arg(indexVariable));
JConditional jc = blk._if(out.getIsSet().eq(JExpr.lit(1)));
jc._then().add(eval);
- }else{
+ } else {
generator.getEvalBlock().add(eval);
}
- }else{
+ } else {
JExpression vector = e.isSuperReader() ? vv1.component(componentVariable) : vv1;
JExpression expr = vector.invoke("getAccessor").invoke("getReader");
+ JVar isNull = generator.getEvalBlock().decl(generator.getModel().INT, "isNull", JExpr.lit(0));
JLabel label = generator.getEvalBlock().label("complex");
JBlock eval = generator.getEvalBlock().block();
@@ -387,65 +399,77 @@ public class EvaluationVisitor {
int listNum = 0;
boolean lastWasArray = false;
- while(seg != null){
- if(seg.isArray()){
+ while (seg != null) {
+ if (seg.isArray()) {
lastWasArray = true;
- if(seg.isLastPath() && !complex) break;
+ if (seg.isLastPath() && !complex && !repeated)
+ break;
JVar list = generator.declareClassField("list", generator.getModel()._ref(FieldReader.class));
- generator.getSetupBlock().assign(list, expr);
+ eval.assign(list, expr);
expr = list;
- // if this is an array, set a single position for the expression to allow us to read the right data lower down.
- JVar desiredIndex = eval.decl(generator.getModel().INT, "desiredIndex" + listNum, JExpr.lit(seg.getArraySegment().getIndex()));
- // start with negative one so that we are at zero after first call to next.
+ // if this is an array, set a single position for the expression to
+ // allow us to read the right data lower down.
+ JVar desiredIndex = eval.decl(generator.getModel().INT, "desiredIndex" + listNum,
+ JExpr.lit(seg.getArraySegment().getIndex()));
+ // start with negative one so that we are at zero after first call
+ // to next.
JVar currentIndex = eval.decl(generator.getModel().INT, "currentIndex" + listNum, JExpr.lit(-1));
eval._while( //
currentIndex.lt(desiredIndex) //
- .cand(expr.invoke("next")) ).body().assign(currentIndex, currentIndex.plus(JExpr.lit(1)));
+ .cand(list.invoke("next"))).body().assign(currentIndex, currentIndex.plus(JExpr.lit(1)));
+
+ expr = list.invoke("reader");
JBlock ifNoVal = eval._if(desiredIndex.ne(currentIndex))._then().block();
- if(!complex) ifNoVal.assign(out.getIsSet(), JExpr.lit(0));
+ if (out.isOptional()) {
+ ifNoVal.assign(out.getIsSet(), JExpr.lit(0));
+ }
+ ifNoVal.assign(isNull, JExpr.lit(1));
ifNoVal._break(label);
listNum++;
-
- }else{
+ } else {
lastWasArray = false;
JExpression fieldName = JExpr.lit(seg.getNameSegment().getPath());
expr = expr.invoke("reader").arg(fieldName);
}
seg = seg.getChild();
- // stop once we get to last column or when the segment is an array at the end of the reference.
- if(seg == null || seg.isLastPath() && seg.isArray()) break;
+ // stop once we get to last column or when the segment is an array at
+ // the end of the reference.
+ // if(seg == null || seg.isLastPath() && seg.isArray()) break;
}
- MajorType secondaryType = e.getFieldId().getSecondaryFinal();
- JType readerImpl = generator.getModel()._ref(TypeHelper.getReaderClassName(secondaryType.getMinorType(), secondaryType.getMode()));
- JVar complexReader = generator.declareClassField("reader", readerImpl);
- generator.getSetupBlock().assign(complexReader, JExpr.cast(readerImpl, expr));
- expr = complexReader;
-
- if(complex){
- HoldingContainer hc = new HoldingContainer(e.getMajorType(), (JVar) expr, null, null, lastWasArray);
+
+ if (complex || repeated) {
+ MajorType finalType = e.getFieldId().getFinalType();
+ // //
+ JVar complexReader = generator.declareClassField("reader", generator.getModel()._ref(FieldReader.class));
+
+ JConditional jc = generator.getEvalBlock()._if(isNull.eq(JExpr.lit(0)));
+
+ JClass nrClass = generator.getModel().ref(org.apache.drill.exec.vector.complex.impl.NullReader.class);
+ JExpression nullReader = nrClass.staticRef("INSTANCE");
+
+ jc._then().assign(complexReader, expr);
+ jc._else().assign(complexReader, nullReader);
+
+ HoldingContainer hc = new HoldingContainer(e.getMajorType(), complexReader, null, null, false);
return hc;
- //eval.assign(out.getHolder().ref("reader"), expr);
- }else{
- if(seg != null){
+ // //eval.assign(out.getHolder().ref("reader"), expr);
+ } else {
+ if (seg != null) {
eval.add(expr.invoke("read").arg(JExpr.lit(seg.getArraySegment().getIndex())).arg(out.getHolder()));
- }else{
-
+ } else {
eval.add(expr.invoke("read").arg(out.getHolder()));
}
}
}
-
-
-
return out;
}
@@ -453,9 +477,9 @@ public class EvaluationVisitor {
LogicalExpression child = e.getChild();
// Preconditions.checkArgument(child.getMajorType().equals(Types.REQUIRED_BOOLEAN));
HoldingContainer hc = child.accept(this, generator);
- if(e.isReturnTrueOnOne()){
+ if (e.isReturnTrueOnOne()) {
generator.getEvalBlock()._return(hc.getValue().eq(JExpr.lit(1)));
- }else{
+ } else {
generator.getEvalBlock()._return(hc.getValue());
}
@@ -470,7 +494,8 @@ public class EvaluationVisitor {
JType holderType = generator.getHolderType(majorType);
JVar var = generator.declareClassField("string", holderType);
JExpression stringLiteral = JExpr.lit(e.value);
- setup.assign(var, generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getVarCharHolder").arg(stringLiteral));
+ setup.assign(var,
+ generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getVarCharHolder").arg(stringLiteral));
return new HoldingContainer(majorType, var, null, null);
}
@@ -483,12 +508,16 @@ public class EvaluationVisitor {
JVar var = generator.declareClassField("intervalday", holderType);
JExpression dayLiteral = JExpr.lit(e.getIntervalDay());
JExpression millisLiteral = JExpr.lit(e.getIntervalMillis());
- setup.assign(var, generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getIntervalDayHolder").arg(dayLiteral).arg(millisLiteral));
+ setup.assign(
+ var,
+ generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getIntervalDayHolder").arg(dayLiteral)
+ .arg(millisLiteral));
return new HoldingContainer(majorType, var, null, null);
}
@Override
- public HoldingContainer visitDecimal9Constant(Decimal9Expression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitDecimal9Constant(Decimal9Expression e, ClassGenerator<?> generator)
+ throws RuntimeException {
MajorType majorType = e.getMajorType();
JBlock setup = generator.getBlock(BlockType.SETUP);
JType holderType = generator.getHolderType(majorType);
@@ -496,12 +525,16 @@ public class EvaluationVisitor {
JExpression valueLiteral = JExpr.lit(e.getIntFromDecimal());
JExpression scaleLiteral = JExpr.lit(e.getScale());
JExpression precisionLiteral = JExpr.lit(e.getPrecision());
- setup.assign(var, generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getDecimal9Holder").arg(valueLiteral).arg(scaleLiteral).arg(precisionLiteral));
+ setup.assign(
+ var,
+ generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getDecimal9Holder").arg(valueLiteral)
+ .arg(scaleLiteral).arg(precisionLiteral));
return new HoldingContainer(majorType, var, null, null);
}
@Override
- public HoldingContainer visitDecimal18Constant(Decimal18Expression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitDecimal18Constant(Decimal18Expression e, ClassGenerator<?> generator)
+ throws RuntimeException {
MajorType majorType = e.getMajorType();
JBlock setup = generator.getBlock(BlockType.SETUP);
JType holderType = generator.getHolderType(majorType);
@@ -509,7 +542,10 @@ public class EvaluationVisitor {
JExpression valueLiteral = JExpr.lit(e.getLongFromDecimal());
JExpression scaleLiteral = JExpr.lit(e.getScale());
JExpression precisionLiteral = JExpr.lit(e.getPrecision());
- setup.assign(var, generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getDecimal18Holder").arg(valueLiteral).arg(scaleLiteral).arg(precisionLiteral));
+ setup.assign(
+ var,
+ generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getDecimal18Holder").arg(valueLiteral)
+ .arg(scaleLiteral).arg(precisionLiteral));
return new HoldingContainer(majorType, var, null, null);
}
@@ -521,7 +557,8 @@ public class EvaluationVisitor {
JType holderType = generator.getHolderType(majorType);
JVar var = generator.declareClassField("dec28", holderType);
JExpression stringLiteral = JExpr.lit(e.getBigDecimal().toString());
- setup.assign(var, generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getDecimal28Holder").arg(stringLiteral));
+ setup.assign(var,
+ generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getDecimal28Holder").arg(stringLiteral));
return new HoldingContainer(majorType, var, null, null);
}
@@ -533,34 +570,34 @@ public class EvaluationVisitor {
JType holderType = generator.getHolderType(majorType);
JVar var = generator.declareClassField("dec38", holderType);
JExpression stringLiteral = JExpr.lit(e.getBigDecimal().toString());
- setup.assign(var, generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getVarCharHolder").arg(stringLiteral));
+ setup.assign(var,
+ generator.getModel().ref(ValueHolderHelper.class).staticInvoke("getVarCharHolder").arg(stringLiteral));
return new HoldingContainer(majorType, var, null, null);
}
@Override
public HoldingContainer visitCastExpression(CastExpression e, ClassGenerator<?> value) throws RuntimeException {
- throw new UnsupportedOperationException("CastExpression is not expected here. "+
- "It should have been converted to FunctionHolderExpression in materialization");
+ throw new UnsupportedOperationException("CastExpression is not expected here. "
+ + "It should have been converted to FunctionHolderExpression in materialization");
}
@Override
- public HoldingContainer visitConvertExpression(ConvertExpression e, ClassGenerator<?> value) throws RuntimeException {
+ public HoldingContainer visitConvertExpression(ConvertExpression e, ClassGenerator<?> value)
+ throws RuntimeException {
String convertFunctionName = e.getConvertFunction() + e.getEncodingType();
List<LogicalExpression> newArgs = Lists.newArrayList();
- newArgs.add(e.getInput()); //input_expr
+ newArgs.add(e.getInput()); // input_expr
FunctionCall fc = new FunctionCall(convertFunctionName, newArgs, e.getPosition());
return fc.accept(this, value);
}
}
-
private class ConstantFilter extends EvalVisitor {
private Set<LogicalExpression> constantBoundaries;
-
public ConstantFilter(Set<LogicalExpression> constantBoundaries) {
super();
this.constantBoundaries = constantBoundaries;
@@ -568,17 +605,18 @@ public class EvaluationVisitor {
@Override
public HoldingContainer visitFunctionCall(FunctionCall e, ClassGenerator<?> generator) throws RuntimeException {
- throw new UnsupportedOperationException("FunctionCall is not expected here. "+
- "It should have been converted to FunctionHolderExpression in materialization");
+ throw new UnsupportedOperationException("FunctionCall is not expected here. "
+ + "It should have been converted to FunctionHolderExpression in materialization");
}
@Override
- public HoldingContainer visitFunctionHolderExpression(FunctionHolderExpression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitFunctionHolderExpression(FunctionHolderExpression e, ClassGenerator<?> generator)
+ throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitFunctionHolderExpression(e, generator);
- //generator.getMappingSet().exitConstant();
- //return c;
+ // generator.getMappingSet().exitConstant();
+ // return c;
return renderConstantExpression(generator, c);
} else if (generator.getMappingSet().isWithinConstant()) {
return super.visitFunctionHolderExpression(e, generator).setConstant(true);
@@ -607,8 +645,8 @@ public class EvaluationVisitor {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitSchemaPath(e, generator);
- //generator.getMappingSet().exitConstant();
- //return c;
+ // generator.getMappingSet().exitConstant();
+ // return c;
return renderConstantExpression(generator, c);
} else if (generator.getMappingSet().isWithinConstant()) {
return super.visitSchemaPath(e, generator).setConstant(true);
@@ -622,8 +660,8 @@ public class EvaluationVisitor {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitLongConstant(e, generator);
- //generator.getMappingSet().exitConstant();
- //return c;
+ // generator.getMappingSet().exitConstant();
+ // return c;
return renderConstantExpression(generator, c);
} else if (generator.getMappingSet().isWithinConstant()) {
return super.visitLongConstant(e, generator).setConstant(true);
@@ -632,9 +670,9 @@ public class EvaluationVisitor {
}
}
-
@Override
- public HoldingContainer visitDecimal9Constant(Decimal9Expression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitDecimal9Constant(Decimal9Expression e, ClassGenerator<?> generator)
+ throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitDecimal9Constant(e, generator);
@@ -647,7 +685,8 @@ public class EvaluationVisitor {
}
@Override
- public HoldingContainer visitDecimal18Constant(Decimal18Expression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitDecimal18Constant(Decimal18Expression e, ClassGenerator<?> generator)
+ throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitDecimal18Constant(e, generator);
@@ -660,7 +699,8 @@ public class EvaluationVisitor {
}
@Override
- public HoldingContainer visitDecimal28Constant(Decimal28Expression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitDecimal28Constant(Decimal28Expression e, ClassGenerator<?> generator)
+ throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitDecimal28Constant(e, generator);
@@ -673,7 +713,8 @@ public class EvaluationVisitor {
}
@Override
- public HoldingContainer visitDecimal38Constant(Decimal38Expression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitDecimal38Constant(Decimal38Expression e, ClassGenerator<?> generator)
+ throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitDecimal38Constant(e, generator);
@@ -690,8 +731,8 @@ public class EvaluationVisitor {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitIntConstant(e, generator);
- //generator.getMappingSet().exitConstant();
- //return c;
+ // generator.getMappingSet().exitConstant();
+ // return c;
return renderConstantExpression(generator, c);
} else if (generator.getMappingSet().isWithinConstant()) {
return super.visitIntConstant(e, generator).setConstant(true);
@@ -714,7 +755,6 @@ public class EvaluationVisitor {
}
}
-
@Override
public HoldingContainer visitTimeConstant(TimeExpression e, ClassGenerator<?> generator) throws RuntimeException {
if (constantBoundaries.contains(e)) {
@@ -730,7 +770,8 @@ public class EvaluationVisitor {
}
@Override
- public HoldingContainer visitIntervalYearConstant(IntervalYearExpression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitIntervalYearConstant(IntervalYearExpression e, ClassGenerator<?> generator)
+ throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitIntervalYearConstant(e, generator);
@@ -744,7 +785,8 @@ public class EvaluationVisitor {
}
@Override
- public HoldingContainer visitTimeStampConstant(TimeStampExpression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitTimeStampConstant(TimeStampExpression e, ClassGenerator<?> generator)
+ throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitTimeStampConstant(e, generator);
@@ -758,12 +800,13 @@ public class EvaluationVisitor {
}
@Override
- public HoldingContainer visitDoubleConstant(DoubleExpression e, ClassGenerator<?> generator) throws RuntimeException {
+ public HoldingContainer visitDoubleConstant(DoubleExpression e, ClassGenerator<?> generator)
+ throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitDoubleConstant(e, generator);
- //generator.getMappingSet().exitConstant();
- //return c;
+ // generator.getMappingSet().exitConstant();
+ // return c;
return renderConstantExpression(generator, c);
} else if (generator.getMappingSet().isWithinConstant()) {
return super.visitDoubleConstant(e, generator).setConstant(true);
@@ -778,8 +821,8 @@ public class EvaluationVisitor {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitBooleanConstant(e, generator);
- //generator.getMappingSet().exitConstant();
- //return c;
+ // generator.getMappingSet().exitConstant();
+ // return c;
return renderConstantExpression(generator, c);
} else if (generator.getMappingSet().isWithinConstant()) {
return super.visitBooleanConstant(e, generator).setConstant(true);
@@ -788,14 +831,13 @@ public class EvaluationVisitor {
}
}
-
@Override
public HoldingContainer visitUnknown(LogicalExpression e, ClassGenerator<?> generator) throws RuntimeException {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitUnknown(e, generator);
- //generator.getMappingSet().exitConstant();
- //return c;
+ // generator.getMappingSet().exitConstant();
+ // return c;
return renderConstantExpression(generator, c);
} else if (generator.getMappingSet().isWithinConstant()) {
return super.visitUnknown(e, generator).setConstant(true);
@@ -810,8 +852,8 @@ public class EvaluationVisitor {
if (constantBoundaries.contains(e)) {
generator.getMappingSet().enterConstant();
HoldingContainer c = super.visitQuotedStringConstant(e, generator);
- //generator.getMappingSet().exitConstant();
- //return c;
+ // generator.getMappingSet().exitConstant();
+ // return c;
return renderConstantExpression(generator, c);
} else if (generator.getMappingSet().isWithinConstant()) {
return super.visitQuotedStringConstant(e, generator).setConstant(true);
@@ -820,7 +862,6 @@ public class EvaluationVisitor {
}
}
-
@Override
public HoldingContainer visitIntervalDayConstant(IntervalDayExpression e, ClassGenerator<?> generator)
throws RuntimeException {
@@ -836,14 +877,16 @@ public class EvaluationVisitor {
}
}
- /* Get a HoldingContainer for a constant expression. The returned HoldingContainder will indicate it's for
- * a constant expression.
- * */
- private HoldingContainer renderConstantExpression(ClassGenerator<?> generator, HoldingContainer input){
+ /*
+ * Get a HoldingContainer for a constant expression. The returned
+ * HoldingContainder will indicate it's for a constant expression.
+ */
+ private HoldingContainer renderConstantExpression(ClassGenerator<?> generator, HoldingContainer input) {
JVar fieldValue = generator.declareClassField("constant", generator.getHolderType(input.getMajorType()));
generator.getEvalBlock().assign(fieldValue, input.getHolder());
generator.getMappingSet().exitConstant();
- return new HoldingContainer(input.getMajorType(), fieldValue, fieldValue.ref("value"), fieldValue.ref("isSet")).setConstant(true);
+ return new HoldingContainer(input.getMajorType(), fieldValue, fieldValue.ref("value"), fieldValue.ref("isSet"))
+ .setConstant(true);
}
}
}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java
index fca743bb2..99d423f45 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/ExpressionTreeMaterializer.java
@@ -153,9 +153,9 @@ public class ExpressionTreeMaterializer {
( parmType.getMode().equals(TypeProtos.DataMode.OPTIONAL) ||
matchedFuncHolder.getNullHandling() == FunctionTemplate.NullHandling.NULL_IF_NULL)) {
argsWithCast.add(new TypedNullConstant(parmType));
- } else if (Types.softEquals(parmType, currentArg.getMajorType(), matchedFuncHolder.getNullHandling() ==
- FunctionTemplate.NullHandling.NULL_IF_NULL)) {
- //Case 2: argument and parameter matches. Do nothing.
+ } else if (Types.softEquals(parmType, currentArg.getMajorType(), matchedFuncHolder.getNullHandling() == FunctionTemplate.NullHandling.NULL_IF_NULL) ||
+ matchedFuncHolder.isFieldReader(i)) {
+ //Case 2: argument and parameter matches, or parameter is FieldReader. Do nothing.
argsWithCast.add(currentArg);
} else {
//Case 3: insert cast if param type is different from arg type.
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java
index ea4e9f65a..5d5acf0bc 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/DrillFuncHolder.java
@@ -24,19 +24,25 @@ import java.util.Map;
import org.apache.drill.common.expression.LogicalExpression;
import org.apache.drill.common.types.TypeProtos;
import org.apache.drill.common.types.TypeProtos.MajorType;
+import org.apache.drill.common.types.TypeProtos.MinorType;
import org.apache.drill.common.types.Types;
import org.apache.drill.exec.expr.ClassGenerator;
import org.apache.drill.exec.expr.ClassGenerator.BlockType;
import org.apache.drill.exec.expr.ClassGenerator.HoldingContainer;
+import org.apache.drill.exec.expr.TypeHelper;
import org.apache.drill.exec.expr.annotations.FunctionTemplate;
import org.apache.drill.exec.expr.annotations.FunctionTemplate.FunctionScope;
import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling;
+import org.apache.drill.exec.vector.complex.impl.NullableBigIntSingularReaderImpl;
+import org.apache.drill.exec.vector.complex.reader.FieldReader;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.sun.codemodel.JBlock;
+import com.sun.codemodel.JExpr;
+import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;
public abstract class DrillFuncHolder {
@@ -126,7 +132,14 @@ public abstract class DrillFuncHolder {
ValueReference parameter = parameters[i];
HoldingContainer inputVariable = inputVariables[i];
- sub.decl(inputVariable.getHolder().type(), parameter.name, inputVariable.getHolder());
+ if (parameter.isFieldReader && ! Types.isComplex(inputVariable.getMajorType()) && ! Types.isRepeated(inputVariable.getMajorType())) {
+ JType singularReaderClass = g.getModel()._ref(TypeHelper.getSingularReaderImpl(inputVariable.getMajorType().getMinorType(),
+ inputVariable.getMajorType().getMode()));
+ JType fieldReadClass = g.getModel()._ref(FieldReader.class);
+ sub.decl(fieldReadClass, parameter.name, JExpr._new(singularReaderClass).arg(inputVariable.getHolder()));
+ } else {
+ sub.decl(inputVariable.getHolder().type(), parameter.name, inputVariable.getHolder());
+ }
}
}
@@ -181,6 +194,10 @@ public abstract class DrillFuncHolder {
return this.parameters[i].isConstant;
}
+ public boolean isFieldReader(int i) {
+ return this.parameters[i].isFieldReader;
+ }
+
public MajorType getReturnType(List<LogicalExpression> args) {
if (nullHandling == NullHandling.NULL_IF_NULL) {
// if any one of the input types is nullable, then return nullable return type
@@ -220,6 +237,7 @@ public abstract class DrillFuncHolder {
MajorType type;
String name;
boolean isConstant;
+ boolean isFieldReader;
public ValueReference(MajorType type, String name) {
super();
@@ -228,6 +246,7 @@ public abstract class DrillFuncHolder {
this.type = type;
this.name = name;
isConstant = false;
+ this.isFieldReader = false;
}
public void setConstant(boolean isConstant) {
@@ -239,6 +258,13 @@ public abstract class DrillFuncHolder {
return "ValueReference [type=" + Types.toString(type) + ", name=" + name + "]";
}
+ public static ValueReference createFieldReaderRef(String name) {
+ MajorType type = Types.required(MinorType.LATE);
+ ValueReference ref = new ValueReference(type, name);
+ ref.isFieldReader = true;
+
+ return ref;
+ }
}
public static class WorkspaceReference {
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java
index 44210914d..7f5a33536 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionConverter.java
@@ -36,6 +36,7 @@ import org.apache.drill.exec.expr.annotations.Workspace;
import org.apache.drill.exec.expr.fn.DrillFuncHolder.ValueReference;
import org.apache.drill.exec.expr.fn.DrillFuncHolder.WorkspaceReference;
import org.apache.drill.exec.expr.holders.ValueHolder;
+import org.apache.drill.exec.vector.complex.reader.FieldReader;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.janino.Java.CompilationUnit;
import org.codehaus.janino.Parser;
@@ -52,9 +53,9 @@ import com.google.common.io.Resources;
*/
public class FunctionConverter {
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FunctionConverter.class);
-
+
private Map<String, CompilationUnit> functionUnits = Maps.newHashMap();
-
+
private CompilationUnit get(Class<?> c) throws IOException{
String path = c.getName();
path = path.replaceFirst("\\$.*", "");
@@ -70,7 +71,7 @@ public class FunctionConverter {
throw new IOException(String.format("Failure trying to located source code for Class %s, tried to read on classpath location %s", c.getName(), path));
}
String body = IO.toString(is);
-
+
//TODO: Hack to remove annotations so Janino doesn't choke. Need to reconsider this problem...
body = body.replaceAll("@\\w+(?:\\([^\\\\]*?\\))?", "");
try{
@@ -81,11 +82,11 @@ public class FunctionConverter {
logger.warn("Failure while parsing function class:\n{}", body, e);
return null;
}
-
+
}
-
+
}
-
+
public <T extends DrillFunc> DrillFuncHolder getHolder(Class<T> clazz){
FunctionTemplate template = clazz.getAnnotation(FunctionTemplate.class);
if(template == null){
@@ -100,16 +101,16 @@ public class FunctionConverter {
// start by getting field information.
List<ValueReference> params = Lists.newArrayList();
List<WorkspaceReference> workspaceFields = Lists.newArrayList();
-
+
ValueReference outputField = null;
-
-
+
+
for(Field field : clazz.getDeclaredFields()){
Param param = field.getAnnotation(Param.class);
Output output = field.getAnnotation(Output.class);
Workspace workspace = field.getAnnotation(Workspace.class);
-
+
int i =0;
if(param != null) i++;
if(output != null) i++;
@@ -121,12 +122,18 @@ public class FunctionConverter {
}
if(param != null || output != null){
-
+
+ // Special processing for @Param FieldReader
+ if (param != null && FieldReader.class.isAssignableFrom(field.getType())) {
+ params.add(ValueReference.createFieldReaderRef(field.getName()));
+ continue;
+ }
+
// check that param and output are value holders.
if(!ValueHolder.class.isAssignableFrom(field.getType())){
return failure(String.format("The field doesn't holds value of type %s which does not implement the ValueHolder interface. All fields of type @Param or @Output must extend this interface..", field.getType()), clazz, field);
}
-
+
// get the type field from the value holder.
MajorType type = null;
try{
@@ -134,34 +141,34 @@ public class FunctionConverter {
}catch(Exception e){
return failure("Failure while trying to access the ValueHolder's TYPE static variable. All ValueHolders must contain a static TYPE variable that defines their MajorType.", e, clazz, field.getName());
}
-
-
+
+
ValueReference p = new ValueReference(type, field.getName());
if(param != null){
if (param.constant()) {
p.setConstant(true);
}
params.add(p);
- }else{
+ }else{
if(outputField != null){
return failure("You've declared more than one @Output field. You must declare one and only @Output field per Function class.", clazz, field);
}else{
- outputField = p;
-
+ outputField = p;
+
}
-
+
}
-
+
}else{
// workspace work.
// logger.debug("Found workspace field {}:{}", field.getType(), field.getName());
//workspaceFields.add(new WorkspaceReference(field.getType(), field.getName()));
WorkspaceReference wsReference = new WorkspaceReference(field.getType(), field.getName());
-
+
if (template.scope() == FunctionScope.POINT_AGGREGATE && !ValueHolder.class.isAssignableFrom(field.getType()) ) {
- return failure(String.format("Aggregate function '%s' workspace variable '%s' is of type '%s'. Please change it to Holder type.", template.name(), field.getName(), field.getType()), clazz, field);
+ return failure(String.format("Aggregate function '%s' workspace variable '%s' is of type '%s'. Please change it to Holder type.", template.name(), field.getName(), field.getType()), clazz, field);
}
-
+
//If the workspace var is of Holder type, get its MajorType and assign to WorkspaceReference.
if(ValueHolder.class.isAssignableFrom(field.getType())){
MajorType majorType = null;
@@ -172,18 +179,18 @@ public class FunctionConverter {
}
wsReference.setMajorType(majorType);
}
-
+
workspaceFields.add(wsReference);
}
-
+
}
-
-
+
+
// if(!workspaceFields.isEmpty()) return failure("This function declares one or more workspace fields. However, those have not yet been implemented.", clazz);
if(outputField == null) return failure("This function declares zero output fields. A function must declare one output field.", clazz);
-
- // get function body.
-
+
+ // get function body.
+
CompilationUnit cu;
try {
cu = get(clazz);
@@ -191,8 +198,8 @@ public class FunctionConverter {
} catch (IOException e) {
return failure("Failure while getting class body.", e, clazz);
}
-
-
+
+
try{
Map<String, String> methods = MethodGrabbingVisitor.getMethods(cu, clazz);
List<String> imports = ImportGrabber.getMethods(cu);
@@ -238,11 +245,11 @@ public class FunctionConverter {
}catch(Exception | NoSuchFieldError | AbstractMethodError ex){
return failure("Failure while creating function holder.", ex, clazz);
}
-
+
}
-
-
-
+
+
+
private String getClassBody(Class<?> c) throws CompileException, IOException{
String path = c.getName();
path = path.replaceFirst("\\$.*", "");
@@ -255,28 +262,28 @@ public class FunctionConverter {
throw new IOException(String.format("Failure trying to located source code for Class %s, tried to read on classpath location %s", c.getName(), path));
}
String body = IO.toString(is);
-
+
//TODO: Hack to remove annotations so Janino doesn't choke. Need to reconsider this problem...
//return body.replaceAll("@(?:Output|Param|Workspace|Override|SuppressWarnings\\([^\\\\]*?\\)|FunctionTemplate\\([^\\\\]*?\\))", "");
return body.replaceAll("@(?:\\([^\\\\]*?\\))?", "");
}
-
+
}
-
-
-
+
+
+
@SuppressWarnings("unchecked")
private <T> T getStaticFieldValue(String fieldName, Class<?> valueType, Class<T> c) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
Field f = valueType.getDeclaredField(fieldName);
Object val = f.get(null);
return (T) val;
}
-
+
private static DrillFuncHolder failure(String message, Throwable t, Class<?> clazz, String fieldName){
logger.warn("Failure loading function class {}, field {}. " + message, clazz.getName(), fieldName, t);
return null;
- }
-
+ }
+
private DrillFuncHolder failure(String message, Class<?> clazz, String fieldName){
logger.warn("Failure loading function class {}, field {}. " + message, clazz.getName(), fieldName);
return null;
@@ -291,11 +298,11 @@ public class FunctionConverter {
logger.warn("Failure loading function class [{}]. Message: {}", clazz.getName(), message, t);
return null;
}
-
+
private DrillFuncHolder failure(String message, Class<?> clazz, Field field){
return failure(message, clazz, field.getName());
}
-
-
+
+
}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/conv/JsonConvertTo.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/conv/JsonConvertTo.java
new file mode 100644
index 000000000..ca1e01fe8
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/conv/JsonConvertTo.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.drill.exec.expr.fn.impl.conv;
+
+import java.io.ByteArrayOutputStream;
+
+import io.netty.buffer.ByteBuf;
+
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.annotations.Workspace;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate.FunctionScope;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate.NullHandling;
+import org.apache.drill.exec.expr.holders.VarBinaryHolder;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+import org.apache.drill.exec.record.RecordBatch;
+import org.apache.drill.exec.vector.complex.fn.JsonWriter;
+import org.apache.drill.exec.vector.complex.reader.FieldReader;
+
+import com.google.common.base.Charsets;
+
+public class JsonConvertTo {
+
+ static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(JsonConvertTo.class);
+
+ private JsonConvertTo(){}
+
+ @FunctionTemplate(name = "convert_toJSON", scope = FunctionScope.SIMPLE, nulls = NullHandling.NULL_IF_NULL)
+ public static class ConvertToJson implements DrillSimpleFunc{
+
+ @Param FieldReader input;
+ @Output VarBinaryHolder out;
+ @Workspace ByteBuf buffer;
+
+ public void setup(RecordBatch incoming){
+ buffer = org.apache.drill.exec.util.ConvertUtil.createBuffer(256);
+ }
+
+ public void eval(){
+ out.buffer = buffer;
+ out.start = 0;
+
+ java.io.ByteArrayOutputStream stream = new java.io.ByteArrayOutputStream();
+ try {
+ org.apache.drill.exec.vector.complex.fn.JsonWriter jsonWriter = new org.apache.drill.exec.vector.complex.fn.JsonWriter(stream, true);
+
+ jsonWriter.write(input);
+ } catch (Exception e) {
+ System.out.println(" msg = " + e.getMessage() + " trace : " + e.getStackTrace());
+ }
+
+ byte [] bytea = stream.toByteArray();
+
+ if (bytea.length > buffer.capacity()) {
+ buffer = org.apache.drill.exec.util.ConvertUtil.createBuffer(bytea.length);
+ out.buffer = buffer;
+ }
+
+ out.buffer.setBytes(out.start, bytea);
+ out.end = bytea.length;
+ }
+ }
+}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/record/SimpleVectorWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/record/SimpleVectorWrapper.java
index 692fe62f0..8a2312a93 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/record/SimpleVectorWrapper.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/record/SimpleVectorWrapper.java
@@ -19,6 +19,7 @@ package org.apache.drill.exec.record;
import org.apache.drill.common.expression.PathSegment;
import org.apache.drill.common.expression.SchemaPath;
+import org.apache.drill.common.types.TypeProtos.DataMode;
import org.apache.drill.exec.vector.ValueVector;
import org.apache.drill.exec.vector.complex.AbstractContainerVector;
import org.apache.drill.exec.vector.complex.MapVector;
@@ -115,6 +116,7 @@ public class SimpleVectorWrapper<T extends ValueVector> implements VectorWrapper
if(child.isArray() && child.isLastPath()){
builder.remainder(child);
builder.withIndex();
+ builder.finalType(v.getField().getType().toBuilder().setMode(DataMode.OPTIONAL).build());
return builder.build();
}else{
return null;
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/record/TypedFieldId.java b/exec/java-exec/src/main/java/org/apache/drill/exec/record/TypedFieldId.java
index 24a8251ac..22aa73141 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/record/TypedFieldId.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/record/TypedFieldId.java
@@ -121,6 +121,7 @@ public class TypedFieldId {
final IntArrayList ids = new IntArrayList();
MajorType finalType;
MajorType intermediateType;
+ MajorType secondaryFinal;
PathSegment remainder;
boolean hyperReader = false;
boolean withIndex = false;
@@ -150,6 +151,11 @@ public class TypedFieldId {
return this;
}
+ public Builder secondaryFinal(MajorType secondaryFinal) {
+ this.secondaryFinal = secondaryFinal;
+ return this;
+ }
+
public Builder intermediateType(MajorType intermediateType){
this.intermediateType = intermediateType;
return this;
@@ -160,15 +166,17 @@ public class TypedFieldId {
Preconditions.checkNotNull(finalType);
if(intermediateType == null) intermediateType = finalType;
+ if (secondaryFinal == null) secondaryFinal = finalType;
+
MajorType actualFinalType = finalType;
- MajorType secondaryFinal = finalType;
+ //MajorType secondaryFinal = finalType;
// if this has an index, switch to required type for output
- if(withIndex && intermediateType == finalType) actualFinalType = finalType.toBuilder().setMode(DataMode.REQUIRED).build();
+ //if(withIndex && intermediateType == finalType) actualFinalType = finalType.toBuilder().setMode(DataMode.REQUIRED).build();
// if this isn't a direct access, switch the final type to nullable as offsets may be null.
// TODO: there is a bug here with some things.
- if(intermediateType != finalType) actualFinalType = finalType.toBuilder().setMode(DataMode.OPTIONAL).build();
+ //if(intermediateType != finalType) actualFinalType = finalType.toBuilder().setMode(DataMode.OPTIONAL).build();
return new TypedFieldId(intermediateType, secondaryFinal, actualFinalType, hyperReader, remainder, ids.toArray());
}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java b/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java
index 2f6bf38a0..3c2055525 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/resolver/TypeCastRules.java
@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.drill.common.expression.FunctionCall;
+import org.apache.drill.common.types.Types;
import org.apache.drill.common.types.TypeProtos.DataMode;
import org.apache.drill.common.types.TypeProtos.MajorType;
import org.apache.drill.common.types.TypeProtos.MinorType;
@@ -796,6 +797,14 @@ public class TypeCastRules {
MajorType argType = call.args.get(i).getMajorType();
MajorType parmType = holder.getParmMajorType(i);
+ //@Param FieldReader will match any type
+ if (holder.isFieldReader(i)) {
+// if (Types.isComplex(call.args.get(i).getMajorType()) ||Types.isRepeated(call.args.get(i).getMajorType()) )
+ continue;
+// else
+// return -1;
+ }
+
if (!TypeCastRules.isCastable(argType, parmType, holder.getNullHandling())) {
return -1;
}
@@ -832,7 +841,7 @@ public class TypeCastRules {
}
// Check null vs non-null, using same logic as that in Types.softEqual()
// Only when the function uses NULL_IF_NULL, nullable and non-nullable are inter-changable.
- // Otherwise, the function implementation is not a match.
+ // Otherwise, the function implementation is not a match.
if (argType.getMode() != parmType.getMode()) {
// TODO - this does not seem to do what it is intended to
// if (!((holder.getNullHandling() == NullHandling.NULL_IF_NULL) &&
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/AbstractContainerVector.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/AbstractContainerVector.java
index ab1d2707d..4f7cf52cf 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/AbstractContainerVector.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/AbstractContainerVector.java
@@ -18,7 +18,9 @@
package org.apache.drill.exec.vector.complex;
import org.apache.drill.common.expression.PathSegment;
+import org.apache.drill.common.types.TypeProtos.DataMode;
import org.apache.drill.common.types.TypeProtos.MajorType;
+import org.apache.drill.common.types.TypeProtos.MinorType;
import org.apache.drill.exec.record.TypedFieldId;
import org.apache.drill.exec.vector.ValueVector;
@@ -49,11 +51,13 @@ public abstract class AbstractContainerVector implements ValueVector{
if(seg.isArray()){
if(seg.isLastPath()){
- if(addToBreadCrumb) builder.intermediateType(this.getField().getType());
+
+ //if(addToBreadCrumb) builder.intermediateType(this.getField().getType());
+
return builder //
.remainder(seg) //
- .finalType(this.getField().getType()) //
.withIndex() //
+ .finalType(getLastPathType()) //
.build();
}else{
if(addToBreadCrumb){
@@ -72,30 +76,50 @@ public abstract class AbstractContainerVector implements ValueVector{
VectorWithOrdinal vord = getVectorWithOrdinal(seg.isArray() ? null : seg.getNameSegment().getPath());
if(vord == null) return null;
+ ValueVector v = vord.vector;
if(addToBreadCrumb){
- builder.intermediateType(this.getField().getType());
+ //builder.intermediateType(this.getField().getType());
+ builder.intermediateType(v.getField().getType());
builder.addId(vord.ordinal);
}
- ValueVector v = vord.vector;
-
if(v instanceof AbstractContainerVector){
// we're looking for a multi path.
AbstractContainerVector c = (AbstractContainerVector) v;
return c.getFieldIdIfMatches(builder, addToBreadCrumb, seg.getChild());
}else{
- if(seg.isLastPath()){
+ if (seg != null && seg.isLastPath() && ! seg.isArray()) {
if(addToBreadCrumb) builder.intermediateType(v.getField().getType());
return builder.finalType(v.getField().getType()).build();
+ }else if(seg != null && seg.isLastPath() && seg.isArray()){
+ //if(addToBreadCrumb) builder.intermediateType(v.getField().getType());
+ return builder
+ .finalType(v.getField().getType().toBuilder().setMode(DataMode.OPTIONAL).build())
+ .build();
}else{
- logger.warn("You tried to request a complex type inside a scalar object.");
+ logger.warn("You tried to request a complex type inside a scalar object or path or type is wrong.");
return null;
}
}
}
+ private MajorType getLastPathType() {
+ if((this.getField().getType().getMinorType() == MinorType.LIST &&
+ this.getField().getType().getMode() == DataMode.REPEATED)) { // Use Repeated scalar type instead of Required List.
+ VectorWithOrdinal vord = getVectorWithOrdinal(null);
+ ValueVector v = vord.vector;
+ if (! (v instanceof AbstractContainerVector))
+ return v.getField().getType();
+ } else if (this.getField().getType().getMinorType() == MinorType.MAP &&
+ this.getField().getType().getMode() == DataMode.REPEATED) { // Use Required Map
+ return this.getField().getType().toBuilder().setMode(DataMode.REQUIRED).build();
+ }
+
+ return this.getField().getType();
+ }
+
protected boolean supportsDirectRead(){
return false;
}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/MapVector.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/MapVector.java
index 9a84ee871..8ea27961b 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/MapVector.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/MapVector.java
@@ -351,7 +351,8 @@ public class MapVector extends AbstractContainerVector {
@Override
public FieldReader getReader() {
- return new SingleMapReaderImpl(MapVector.this);
+ //return new SingleMapReaderImpl(MapVector.this);
+ return reader;
}
}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/RepeatedMapVector.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/RepeatedMapVector.java
index bcf8ad71f..f41cfdaa6 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/RepeatedMapVector.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/RepeatedMapVector.java
@@ -248,10 +248,10 @@ public class RepeatedMapVector extends AbstractContainerVector implements Repeat
//todo: make these bulk copies
for(int i = holder.start; i < holder.end; i++, newIndex++){
for(TransferPair p : pairs){
- if(!p.copyValueSafe(from, to)) return false;
+ if(!p.copyValueSafe(i, newIndex)) return false;
}
}
- if(!this.to.offsets.getMutator().setSafe(to, newIndex)) return false;
+ if(!this.to.offsets.getMutator().setSafe(to+1, newIndex)) return false;
return true;
}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/fn/JsonWriter.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/fn/JsonWriter.java
index 0624eceb1..de52b73e5 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/fn/JsonWriter.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/fn/JsonWriter.java
@@ -118,10 +118,13 @@ public class JsonWriter {
break;
case MAP:
gen.writeStartObject();
- for(String name : reader){
- if(reader.isSet()){
- gen.writeFieldName(name);
- writeValue(reader.reader(name));
+ if (reader.isSet()) {
+ for(String name : reader){
+ FieldReader childReader = reader.reader(name);
+ if(childReader.isSet()){
+ gen.writeFieldName(name);
+ writeValue(childReader);
+ }
}
}
gen.writeEndObject();
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedListReaderImpl.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedListReaderImpl.java
index c555f35ff..66f658dc8 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedListReaderImpl.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedListReaderImpl.java
@@ -98,7 +98,10 @@ public class RepeatedListReaderImpl extends AbstractFieldReader{
public FieldReader reader(){
if(reader == null){
reader = container.get(name, ValueVector.class).getAccessor().getReader();
- reader.setPosition(currentOffset);
+ if (currentOffset == NO_VALUES)
+ reader = NullReader.INSTANCE;
+ else
+ reader.setPosition(currentOffset);
}
return reader;
}
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedMapReaderImpl.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedMapReaderImpl.java
index ab778ff3f..8f788af43 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedMapReaderImpl.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/RepeatedMapReaderImpl.java
@@ -77,6 +77,7 @@ import org.apache.hadoop.io.Text;
+
import java.util.Map;
import java.util.Map.Entry;
@@ -117,6 +118,13 @@ public class RepeatedMapReaderImpl extends AbstractFieldReader{
return reader;
}
+ public FieldReader reader() {
+ if (currentOffset == NO_VALUES)
+ return NullReader.INSTANCE;
+
+ setChildrenPosition(currentOffset);
+ return new SingleLikeRepeatedMapReaderImpl(vector, this);
+ }
private int currentOffset;
private int maxOffset;
@@ -163,6 +171,10 @@ public class RepeatedMapReaderImpl extends AbstractFieldReader{
}
}
+ public boolean isNull() {
+ return currentOffset == NO_VALUES;
+ }
+
@Override
public Object readObject() {
return vector.getAccessor().getObject(idx());
@@ -178,7 +190,7 @@ public class RepeatedMapReaderImpl extends AbstractFieldReader{
@Override
public boolean isSet() {
- return false;
+ return true;
}
public void copyAsValue(MapWriter writer){
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/SingleLikeRepeatedMapReaderImpl.java b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/SingleLikeRepeatedMapReaderImpl.java
new file mode 100644
index 000000000..3f89a9f10
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/vector/complex/impl/SingleLikeRepeatedMapReaderImpl.java
@@ -0,0 +1,89 @@
+/**
+ * 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.drill.exec.vector.complex.impl;
+
+import java.util.Iterator;
+
+import org.apache.drill.common.types.TypeProtos.MajorType;
+import org.apache.drill.common.types.TypeProtos.MinorType;
+import org.apache.drill.common.types.Types;
+import org.apache.drill.exec.vector.complex.RepeatedMapVector;
+import org.apache.drill.exec.vector.complex.reader.FieldReader;
+import org.apache.drill.exec.vector.complex.writer.BaseWriter.MapWriter;
+
+public class SingleLikeRepeatedMapReaderImpl extends AbstractFieldReader{
+
+ private RepeatedMapReaderImpl delegate;
+
+ public SingleLikeRepeatedMapReaderImpl(RepeatedMapVector vector, FieldReader delegate) {
+ this.delegate = (RepeatedMapReaderImpl) delegate;
+ }
+
+ @Override
+ public int size() {
+ throw new UnsupportedOperationException("You can't call size on a single map reader.");
+ }
+
+ @Override
+ public boolean next() {
+ throw new UnsupportedOperationException("You can't call next on a single map reader.");
+ }
+
+ @Override
+ public MajorType getType() {
+ return Types.required(MinorType.MAP);
+ }
+
+
+ @Override
+ public void copyAsValue(MapWriter writer) {
+ delegate.copyAsValueSingle(writer);
+ }
+
+ public void copyAsValueSingle(MapWriter writer){
+ delegate.copyAsValueSingle(writer);
+ }
+
+ @Override
+ public FieldReader reader(String name) {
+ return delegate.reader(name);
+ }
+
+ @Override
+ public void setPosition(int index) {
+ delegate.setPosition(index);
+ }
+
+ @Override
+ public Object readObject() {
+ return delegate.readObject();
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ return delegate.iterator();
+ }
+
+ @Override
+ public boolean isSet() {
+ return ! delegate.isNull();
+ }
+
+
+}
diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/vector/complex/writer/TestComplexTypeReader.java b/exec/java-exec/src/test/java/org/apache/drill/exec/vector/complex/writer/TestComplexTypeReader.java
new file mode 100644
index 000000000..74c724d06
--- /dev/null
+++ b/exec/java-exec/src/test/java/org/apache/drill/exec/vector/complex/writer/TestComplexTypeReader.java
@@ -0,0 +1,167 @@
+/**
+ * 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.drill.exec.vector.complex.writer;
+
+import org.apache.drill.BaseTestQuery;
+import org.junit.Test;
+
+public class TestComplexTypeReader extends BaseTestQuery{
+ static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(TestComplexTypeReader.class);
+
+ @Test
+ // Repeated map (map) -> json.
+ public void testX() throws Exception{
+ test("select convert_to(z[0], 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //map -> json.
+ public void testX2() throws Exception{
+ test("select convert_to(x, 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //Map (mapfield) -> json.
+ public void testX3() throws Exception{
+ test("select convert_to(x['y'], 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //float value -> json
+ public void testX4() throws Exception{
+ test("select convert_to(`float`, 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //integer value -> json
+ public void testX5() throws Exception{
+ test("select convert_to(`integer`, 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ // repeated map -> json.
+ public void testX6() throws Exception{
+ test("select convert_to(z, 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //repeated list (Repeated BigInt) -> json
+ public void testX7() throws Exception{
+ test("select convert_to(rl[1], 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //repeated list (Repeated BigInt) -> json
+ public void testX8() throws Exception{
+ test("select convert_to(rl[0][1], 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //repeated list -> json
+ public void testX9() throws Exception{
+ test("select convert_to(rl, 'JSON') from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ public void testY() throws Exception{
+ test("select z[0] from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ public void testY2() throws Exception{
+ test("select x from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ public void testY3() throws Exception{
+ test("select x['y'] from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ public void testY6() throws Exception{
+ test("select z from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //repeated list (Repeated BigInt)
+ public void testZ() throws Exception{
+ test("select rl[1] from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //repeated list (Repeated BigInt ( BigInt) ) )
+ public void testZ1() throws Exception{
+ test("select rl[0][1] from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //repeated list (Repeated BigInt ( BigInt) ) ). The first index is out of boundary
+ public void testZ2() throws Exception{
+ test("select rl[1000][1] from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //repeated list (Repeated BigInt ( BigInt) ) ). The second index is out of boundary
+ public void testZ3() throws Exception{
+ test("select rl[0][1000] from cp.`jsoninput/input2.json`;");
+ }
+
+ @Test
+ //repeated map --> Json. It will go beyond the buffer of size 256 allocated in setup.
+ public void testA0() throws Exception{
+ test(" select convert_to(types, 'JSON') from cp.`jsoninput/vvtypes.json`;");
+ }
+
+ @Test
+ //repeated map (map) --> Json.
+ public void testA1() throws Exception{
+ test(" select convert_to(types[1], 'JSON') from cp.`jsoninput/vvtypes.json`;");
+ }
+
+ @Test
+ //repeated map (map (repeated map) ) --> Json.
+ public void testA2() throws Exception{
+ test(" select convert_to(types[1]['minor'], 'JSON') from cp.`jsoninput/vvtypes.json`;");
+ }
+
+ @Test
+ //repeated map (map( repeated map (map (varchar)))) --> Json.
+ public void testA3() throws Exception{
+ test(" select convert_to(types[1]['minor'][0]['valueHolder'], 'JSON') from cp.`jsoninput/vvtypes.json`;");
+ }
+
+ @Test
+ //repeated map (map) .
+ public void testB1() throws Exception{
+ test(" select types[1] from cp.`jsoninput/vvtypes.json`;");
+ }
+
+ @Test
+ //repeated map (map (repeated map) ).
+ public void testB2() throws Exception{
+ test(" select types[1]['minor'] from cp.`jsoninput/vvtypes.json`;");
+ }
+
+ @Test
+ //repeated map (map( repeated map (map (varchar)))).
+ public void testB3() throws Exception{
+ test(" select types[1]['minor'][0]['valueHolder'] from cp.`jsoninput/vvtypes.json`;");
+ }
+
+}
diff --git a/exec/java-exec/src/test/resources/jsoninput/vvtypes.json b/exec/java-exec/src/test/resources/jsoninput/vvtypes.json
new file mode 100644
index 000000000..60cd1ea1e
--- /dev/null
+++ b/exec/java-exec/src/test/resources/jsoninput/vvtypes.json
@@ -0,0 +1,140 @@
+{
+ modes: [
+ {name: "Optional", prefix: "Nullable"},
+ {name: "Required", prefix: ""},
+ {name: "Repeated", prefix: "Repeated"}
+ ],
+ types: [
+ {
+ major: "Fixed",
+ width: 1,
+ javaType: "byte",
+ boxedType: "Byte",
+ minor: [
+ { class: "TinyInt", valueHolder: "IntHolder"},
+ { class: "UInt1", valueHolder: "UInt1Holder"}
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 2,
+ javaType: "char",
+ boxedType: "Character",
+ minor: [
+ { class: "UInt2", valueHolder: "UInt2Holder"}
+ ]
+ }, {
+ major: "Fixed",
+ width: 2,
+ javaType: "short",
+ boxedType: "Short",
+ minor: [
+ { class: "SmallInt", valueHolder: "Int2Holder"}
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 4,
+ javaType: "int",
+ boxedType: "Integer",
+ minor: [
+ { class: "Int", valueHolder: "IntHolder" },
+ { class: "UInt4", valueHolder: "UInt4Holder" },
+ { class: "Float4", javaType: "float" , boxedType: "Float" },
+ { class: "Time", javaType: "int", friendlyType: "DateTime" },
+ { class: "IntervalYear", javaType: "int", friendlyType: "Period" },
+ { class: "Decimal9", maxPrecisionDigits: 9, friendlyType: "BigDecimal" }
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 8,
+ javaType: "long",
+ boxedType: "Long",
+ minor: [
+ { class: "BigInt" },
+ { class: "UInt8" },
+ { class: "Float8", javaType: "double" , boxedType: "Double" },
+ { class: "Date", javaType: "long", friendlyType: "DateTime" },
+ { class: "TimeStamp", javaType: "long", friendlyType: "DateTime" },
+ { class: "Decimal18", maxPrecisionDigits: 18, friendlyType: "BigDecimal" }
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 12,
+ javaType: "ByteBuf",
+ boxedType: "ByteBuf",
+ minor: [
+ { class: "TimeStampTZ", milliSecondsSize: 8, friendlyType: "DateTime" },
+ { class: "IntervalDay", milliSecondsOffset: 4, friendlyType: "Period" }
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 16,
+ javaType: "ByteBuf",
+ boxedType: "ByteBuf",
+ minor: [
+ { class: "Interval", daysOffset: 4, milliSecondsOffset: 8, friendlyType: "Period" }
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 12,
+ javaType: "ByteBuf",
+ boxedType: "ByteBuf",
+ minor: [
+ { class: "Decimal28Dense", maxPrecisionDigits: 28, nDecimalDigits: 3, friendlyType: "BigDecimal" }
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 16,
+ javaType: "ByteBuf",
+ boxedType: "ByteBuf",
+
+ minor: [
+ { class: "Decimal38Dense", maxPrecisionDigits: 38, nDecimalDigits: 4, friendlyType: "BigDecimal" }
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 24,
+ javaType: "ByteBuf",
+ boxedType: "ByteBuf",
+ minor: [
+ { class: "Decimal38Sparse", maxPrecisionDigits: 38, nDecimalDigits: 6, friendlyType: "BigDecimal" }
+ ]
+ },
+ {
+ major: "Fixed",
+ width: 20,
+ javaType: "ByteBuf",
+ boxedType: "ByteBuf",
+ minor: [
+ { class: "Decimal28Sparse", maxPrecisionDigits: 28, nDecimalDigits: 5, friendlyType: "BigDecimal" }
+ ]
+ },
+ {
+ major: "VarLen",
+ width: 4,
+ javaType: "int",
+ boxedType: "ByteBuf",
+ minor: [
+ { class: "VarBinary" , friendlyType: "byte[]" },
+ { class: "VarChar" , friendlyType: "Text" },
+ { class: "Var16Char" , friendlyType: "String" }
+ ]
+ },
+ {
+ major: "Bit",
+ width: 1,
+ javaType: "int",
+ boxedType: "ByteBuf",
+ minor: [
+ { class: "Bit" , friendlyType: "Boolean" }
+ ]
+ }
+ ]
+}