Skip to content

Commit

Permalink
DRILL-7237: Fix single_value aggregate function for variable length t…
Browse files Browse the repository at this point in the history
…ypes

- Add implementations of single_value for complex data types

closes #1782
  • Loading branch information
vvysotskyi authored and Ben-Zvi committed May 10, 2019
1 parent 0fa2967 commit 0195d1f
Show file tree
Hide file tree
Showing 13 changed files with 442 additions and 475 deletions.
1 change: 0 additions & 1 deletion exec/java-exec/src/main/codegen/config.fmpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ data: {
intervalNumericTypes: tdd(../data/IntervalNumericTypes.tdd),
extract: tdd(../data/ExtractTypes.tdd),
sumzero: tdd(../data/SumZero.tdd),
singleValue: tdd(../data/SingleValue.tdd),
numericTypes: tdd(../data/NumericTypes.tdd),
casthigh: tdd(../data/CastHigh.tdd),
countAggrTypes: tdd(../data/CountAggrTypes.tdd)
Expand Down
148 changes: 98 additions & 50 deletions exec/java-exec/src/main/codegen/data/AggrTypes1.tdd

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion exec/java-exec/src/main/codegen/data/DecimalAggrTypes1.tdd
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
{className: "AnyValue", funcName: "any_value", types: [
{inputType: "VarDecimal", outputType: "NullableVarDecimal"},
{inputType: "NullableVarDecimal", outputType: "NullableVarDecimal"}
{inputType: "RepeatedVarDecimal", outputType: "RepeatedVarDecimal"}
]
},
{className: "SingleValue", funcName: "single_value", types: [
{inputType: "VarDecimal", outputType: "NullableVarDecimal"},
{inputType: "NullableVarDecimal", outputType: "NullableVarDecimal"}
]
}
]
Expand Down
62 changes: 0 additions & 62 deletions exec/java-exec/src/main/codegen/data/SingleValue.tdd

This file was deleted.

237 changes: 120 additions & 117 deletions exec/java-exec/src/main/codegen/templates/AggrTypeFunctions1.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,134 +44,137 @@
@SuppressWarnings("unused")

public class ${aggrtype.className}Functions {
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(${aggrtype.className}Functions.class);

<#list aggrtype.types as type>
<#if type.major == "Numeric">

@FunctionTemplate(name = "${aggrtype.funcName}", scope = FunctionTemplate.FunctionScope.POINT_AGGREGATE)
public static class ${type.inputType}${aggrtype.className} implements DrillAggFunc{

@Param ${type.inputType}Holder in;
@Workspace ${type.runningType}Holder value;
@Workspace BigIntHolder nonNullCount;
@Output ${type.outputType}Holder out;

public void setup() {
value = new ${type.runningType}Holder();
nonNullCount = new BigIntHolder();
nonNullCount.value = 0;
<#if aggrtype.funcName == "sum" || aggrtype.funcName == "any_value">
value.value = 0;
<#elseif aggrtype.funcName == "min">
<#if type.runningType?starts_with("Bit")>
@FunctionTemplate(name = "${aggrtype.funcName}",
scope = FunctionTemplate.FunctionScope.POINT_AGGREGATE)
public static class ${type.inputType}${aggrtype.className} implements DrillAggFunc {
@Param ${type.inputType}Holder in;
@Workspace ${type.runningType}Holder value;
@Workspace BigIntHolder nonNullCount;
@Output ${type.outputType}Holder out;

public void setup() {
value = new ${type.runningType}Holder();
nonNullCount = new BigIntHolder();
nonNullCount.value = 0;
<#if aggrtype.funcName == "sum" || aggrtype.funcName == "any_value" || aggrtype.funcName == "single_value">
value.value = 0;
<#elseif aggrtype.funcName == "min">
<#if type.runningType?starts_with("Bit")>
value.value = 1;
<#elseif type.runningType?starts_with("Int")>
value.value = Integer.MAX_VALUE;
<#elseif type.runningType?starts_with("BigInt")>
value.value = Long.MAX_VALUE;
<#elseif type.runningType?starts_with("Float4")>
value.value = Float.NaN;
<#elseif type.runningType?starts_with("Float8")>
value.value = Double.NaN;
</#if>
<#elseif aggrtype.funcName == "max">
<#if type.runningType?starts_with("Bit")>
<#elseif type.runningType?starts_with("Int")>
value.value = Integer.MAX_VALUE;
<#elseif type.runningType?starts_with("BigInt")>
value.value = Long.MAX_VALUE;
<#elseif type.runningType?starts_with("Float4")>
value.value = Float.NaN;
<#elseif type.runningType?starts_with("Float8")>
value.value = Double.NaN;
</#if>
<#elseif aggrtype.funcName == "max">
<#if type.runningType?starts_with("Bit")>
value.value = 0;
<#elseif type.runningType?starts_with("Int")>
value.value = Integer.MIN_VALUE;
<#elseif type.runningType?starts_with("BigInt")>
value.value = Long.MIN_VALUE;
<#elseif type.runningType?starts_with("Float4")>
value.value = -Float.MAX_VALUE;
<#elseif type.runningType?starts_with("Float8")>
value.value = -Double.MAX_VALUE;
</#if>
</#if>

}

@Override
public void add() {
<#if type.inputType?starts_with("Nullable")>
sout: {
if (in.isSet == 0) {
// processing nullable input and the value is null, so don't do anything...
break sout;
}
</#if>
nonNullCount.value = 1;
// For min/max functions: NaN is the biggest value,
// Infinity is the second biggest value
// -Infinity is the smallest value
<#if aggrtype.funcName == "min">
<#if type.inputType?contains("Float4")>
if(!Float.isNaN(in.value)) {
value.value = Float.isNaN(value.value) ? in.value : Math.min(value.value, in.value);
}
<#elseif type.inputType?contains("Float8")>
if(!Double.isNaN(in.value)) {
value.value = Double.isNaN(value.value) ? in.value : Math.min(value.value, in.value);
}
<#elseif type.runningType?starts_with("Int")>
value.value = Integer.MIN_VALUE;
<#elseif type.runningType?starts_with("BigInt")>
value.value = Long.MIN_VALUE;
<#elseif type.runningType?starts_with("Float4")>
value.value = -Float.MAX_VALUE;
<#elseif type.runningType?starts_with("Float8")>
value.value = -Double.MAX_VALUE;
</#if>
</#if>
}

@Override
public void add() {
<#if type.inputType?starts_with("Nullable")>
sout: {
if (in.isSet == 0) {
// processing nullable input and the value is null, so don't do anything...
break sout;
}
</#if>
<#if aggrtype.funcName == "single_value">
if (nonNullCount.value > 0) {
throw org.apache.drill.common.exceptions.UserException.functionError()
.message("Input for single_value function has more than one row")
.build();
}
</#if>
nonNullCount.value = 1;
// For min/max functions: NaN is the biggest value,
// Infinity is the second biggest value
// -Infinity is the smallest value
<#if aggrtype.funcName == "min">
<#if type.inputType?contains("Float4")>
if(!Float.isNaN(in.value)) {
value.value = Float.isNaN(value.value) ? in.value : Math.min(value.value, in.value);
}
<#elseif type.inputType?contains("Float8")>
if(!Double.isNaN(in.value)) {
value.value = Double.isNaN(value.value) ? in.value : Math.min(value.value, in.value);
}
<#else>
value.value = Math.min(value.value, in.value);
</#if>
<#elseif aggrtype.funcName == "max">
value.value = Math.max(value.value, in.value);
<#elseif aggrtype.funcName == "sum">
value.value += in.value;
<#elseif aggrtype.funcName == "count">
value.value++;
<#elseif aggrtype.funcName == "any_value" || aggrtype.funcName == "single_value">
value.value = in.value;
<#else>
value.value = Math.min(value.value, in.value);
</#if>
<#elseif aggrtype.funcName == "max">
value.value = Math.max(value.value, in.value);
<#elseif aggrtype.funcName == "sum">
value.value += in.value;
<#elseif aggrtype.funcName == "count">
value.value++;
<#elseif aggrtype.funcName == "any_value">
value.value = in.value;
<#else>
// TODO: throw an error ?
</#if>
<#if type.inputType?starts_with("Nullable")>
} // end of sout block
</#if>
}
// TODO: throw an error ?
</#if>
<#if type.inputType?starts_with("Nullable")>
} // end of sout block
</#if>
}

@Override
public void output() {
if (nonNullCount.value > 0) {
out.value = value.value;
out.isSet = 1;
} else {
out.isSet = 0;
@Override
public void output() {
if (nonNullCount.value > 0) {
out.value = value.value;
out.isSet = 1;
} else {
out.isSet = 0;
}
}
}

@Override
public void reset() {
nonNullCount.value = 0;
<#if aggrtype.funcName == "sum" || aggrtype.funcName == "count" || aggrtype.funcName == "any_value">
value.value = 0;
<#elseif aggrtype.funcName == "min">
<#if type.runningType?starts_with("Int")>
value.value = Integer.MAX_VALUE;
<#elseif type.runningType?starts_with("BigInt")>
value.value = Long.MAX_VALUE;
<#elseif type.runningType?starts_with("Float4")>
value.value = Float.NaN;
<#elseif type.runningType?starts_with("Float8")>
value.value = Double.NaN;
</#if>
<#elseif aggrtype.funcName == "max">
<#if type.runningType?starts_with("Int")>
value.value = Integer.MIN_VALUE;
<#elseif type.runningType?starts_with("BigInt")>
value.value = Long.MIN_VALUE;
<#elseif type.runningType?starts_with("Float4")>
value.value = -Float.MAX_VALUE;
<#elseif type.runningType?starts_with("Float8")>
value.value = -Double.MAX_VALUE;
</#if>
</#if>
@Override
public void reset() {
nonNullCount.value = 0;
<#if aggrtype.funcName == "sum" || aggrtype.funcName == "count" || aggrtype.funcName == "any_value" || aggrtype.funcName == "single_value">
value.value = 0;
<#elseif aggrtype.funcName == "min">
<#if type.runningType?starts_with("Int")>
value.value = Integer.MAX_VALUE;
<#elseif type.runningType?starts_with("BigInt")>
value.value = Long.MAX_VALUE;
<#elseif type.runningType?starts_with("Float4")>
value.value = Float.NaN;
<#elseif type.runningType?starts_with("Float8")>
value.value = Double.NaN;
</#if>
<#elseif aggrtype.funcName == "max">
<#if type.runningType?starts_with("Int")>
value.value = Integer.MIN_VALUE;
<#elseif type.runningType?starts_with("BigInt")>
value.value = Long.MIN_VALUE;
<#elseif type.runningType?starts_with("Float4")>
value.value = -Float.MAX_VALUE;
<#elseif type.runningType?starts_with("Float8")>
value.value = -Double.MAX_VALUE;
</#if>
</#if>
}
}

}

</#if>
</#list>
Expand Down
Loading

0 comments on commit 0195d1f

Please sign in to comment.