diff --git a/.travis.yml b/.travis.yml
index 3918b9bdb69..3c9f57ea4e5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,6 +33,15 @@ matrix:
- unset _JAVA_OPTIONS
script: echo "MAVEN_OPTS='-Xmx512m'" > ~/.mavenrc && mvn test -B -Pparallel-test -Dmaven.fork.count=2 -pl processing
+ # processing module tests with SQL Compatibility enabled
+ - sudo: false
+ env:
+ - NAME="processing module test with SQL Compatibility"
+ install: echo "MAVEN_OPTS='-Xmx3000m'" > ~/.mavenrc && mvn install -q -ff -DskipTests -B
+ before_script:
+ - unset _JAVA_OPTIONS
+ script: echo "MAVEN_OPTS='-Xmx512m'" > ~/.mavenrc && mvn test -B -Pparallel-test -Dmaven.fork.count=2 -Ddruid.generic.useDefaultValueForNull=false -pl processing
+
# server module test
- sudo: false
env:
@@ -43,6 +52,17 @@ matrix:
# Server module test is run without the parallel-test option because it's memory sensitive and often fails with that option.
script: echo "MAVEN_OPTS='-Xmx512m'" > ~/.mavenrc && mvn test -B -pl server
+ # server module test with SQL Compatibility enabled
+ - sudo: false
+ env:
+ - NAME="server module test with SQL Compatibility enabled"
+ install: echo "MAVEN_OPTS='-Xmx3000m'" > ~/.mavenrc && mvn install -q -ff -DskipTests -B
+ before_script:
+ - unset _JAVA_OPTIONS
+ # Server module test is run without the parallel-test option because it's memory sensitive and often fails with that option.
+ script: echo "MAVEN_OPTS='-Xmx512m'" > ~/.mavenrc && mvn test -B -pl server -Ddruid.generic.useDefaultValueForNull=false
+
+
# other modules test
- sudo: false
env:
@@ -53,6 +73,16 @@ matrix:
- unset _JAVA_OPTIONS
script: echo "MAVEN_OPTS='-Xmx512m'" > ~/.mavenrc && mvn test -B -Pparallel-test -Dmaven.fork.count=2 -pl '!processing,!server'
+ # other modules test with SQL Compatibility enabled
+ - sudo: false
+ env:
+ - NAME="other modules test with SQL Compatibility"
+ - AWS_REGION=us-east-1 # set a aws region for unit tests
+ install: echo "MAVEN_OPTS='-Xmx3000m'" > ~/.mavenrc && mvn install -q -ff -DskipTests -B
+ before_script:
+ - unset _JAVA_OPTIONS
+ script: echo "MAVEN_OPTS='-Xmx512m'" > ~/.mavenrc && mvn test -B -Pparallel-test -Dmaven.fork.count=2 -Ddruid.generic.useDefaultValueForNull=false -pl '!processing,!server'
+
# run integration tests
- sudo: required
services:
diff --git a/api/src/main/java/io/druid/data/input/Rows.java b/api/src/main/java/io/druid/data/input/Rows.java
index 2d52b5b355a..b511e7dfcab 100644
--- a/api/src/main/java/io/druid/data/input/Rows.java
+++ b/api/src/main/java/io/druid/data/input/Rows.java
@@ -23,9 +23,11 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
import com.google.common.primitives.Longs;
+import io.druid.common.config.NullHandling;
import io.druid.java.util.common.StringUtils;
import io.druid.java.util.common.parsers.ParseException;
+import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -92,10 +94,11 @@ public class Rows
* @throws NullPointerException if the string is null
* @throws ParseException if the column cannot be converted to a number
*/
+ @Nullable
public static Number objectToNumber(final String name, final Object inputValue)
{
if (inputValue == null) {
- return Rows.LONG_ZERO;
+ return NullHandling.defaultLongValue();
}
if (inputValue instanceof Number) {
diff --git a/benchmarks/src/main/java/io/druid/benchmark/FilterPartitionBenchmark.java b/benchmarks/src/main/java/io/druid/benchmark/FilterPartitionBenchmark.java
index bcf0f3627a9..29499d3b4db 100644
--- a/benchmarks/src/main/java/io/druid/benchmark/FilterPartitionBenchmark.java
+++ b/benchmarks/src/main/java/io/druid/benchmark/FilterPartitionBenchmark.java
@@ -21,12 +21,12 @@ package io.druid.benchmark;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.io.Files;
import io.druid.benchmark.datagen.BenchmarkDataGenerator;
import io.druid.benchmark.datagen.BenchmarkSchemaInfo;
import io.druid.benchmark.datagen.BenchmarkSchemas;
+import io.druid.common.config.NullHandling;
import io.druid.data.input.InputRow;
import io.druid.hll.HyperLogLogHash;
import io.druid.jackson.DefaultObjectMapper;
@@ -557,7 +557,7 @@ public class FilterPartitionBenchmark
if (extractionFn == null) {
return new NoBitmapSelectorFilter(dimension, value);
} else {
- final String valueOrNull = Strings.emptyToNull(value);
+ final String valueOrNull = NullHandling.emptyToNullIfNeeded(value);
final DruidPredicateFactory predicateFactory = new DruidPredicateFactory()
{
diff --git a/codestyle/checkstyle.xml b/codestyle/checkstyle.xml
index 1a41308439b..8ceab68a2a7 100644
--- a/codestyle/checkstyle.xml
+++ b/codestyle/checkstyle.xml
@@ -171,7 +171,6 @@
-
@@ -184,5 +183,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/common/src/main/java/io/druid/math/expr/Evals.java b/common/src/main/java/io/druid/math/expr/Evals.java
index cc218a0f35c..76669fdf24c 100644
--- a/common/src/main/java/io/druid/math/expr/Evals.java
+++ b/common/src/main/java/io/druid/math/expr/Evals.java
@@ -19,7 +19,7 @@
package io.druid.math.expr;
-import com.google.common.base.Strings;
+import io.druid.common.config.NullHandling;
import io.druid.java.util.common.logger.Logger;
import java.util.Arrays;
@@ -83,6 +83,6 @@ public class Evals
public static boolean asBoolean(String x)
{
- return !Strings.isNullOrEmpty(x) && Boolean.valueOf(x);
+ return !NullHandling.isNullOrEquivalent(x) && Boolean.valueOf(x);
}
}
diff --git a/common/src/main/java/io/druid/math/expr/Expr.java b/common/src/main/java/io/druid/math/expr/Expr.java
index c73d43d67c3..ddb6699b5fb 100644
--- a/common/src/main/java/io/druid/math/expr/Expr.java
+++ b/common/src/main/java/io/druid/math/expr/Expr.java
@@ -272,6 +272,9 @@ class UnaryMinusExpr extends UnaryExpr
public ExprEval eval(ObjectBinding bindings)
{
ExprEval ret = expr.eval(bindings);
+ if (NullHandling.sqlCompatible() && (ret.value() == null)) {
+ return ExprEval.of(null);
+ }
if (ret.type() == ExprType.LONG) {
return ExprEval.of(-ret.asLong());
}
@@ -307,6 +310,9 @@ class UnaryNotExpr extends UnaryExpr
public ExprEval eval(ObjectBinding bindings)
{
ExprEval ret = expr.eval(bindings);
+ if (NullHandling.sqlCompatible() && (ret.value() == null)) {
+ return ExprEval.of(null);
+ }
// conforming to other boolean-returning binary operators
ExprType retType = ret.type() == ExprType.DOUBLE ? ExprType.DOUBLE : ExprType.LONG;
return ExprEval.of(!ret.asBoolean(), retType);
@@ -365,15 +371,21 @@ abstract class BinaryEvalOpExprBase extends BinaryOpExprBase
// Result of any Binary expressions is null if any of the argument is null.
// e.g "select null * 2 as c;" or "select null + 1 as c;" will return null as per Standard SQL spec.
- if (NullHandling.sqlCompatible() && (leftVal.isNull() || rightVal.isNull())) {
+ if (NullHandling.sqlCompatible() && (leftVal.value() == null || rightVal.value() == null)) {
return ExprEval.of(null);
}
if (leftVal.type() == ExprType.STRING && rightVal.type() == ExprType.STRING) {
return evalString(leftVal.asString(), rightVal.asString());
} else if (leftVal.type() == ExprType.LONG && rightVal.type() == ExprType.LONG) {
+ if (NullHandling.sqlCompatible() && (leftVal.isNumericNull() || rightVal.isNumericNull())) {
+ return ExprEval.of(null);
+ }
return ExprEval.of(evalLong(leftVal.asLong(), rightVal.asLong()));
} else {
+ if (NullHandling.sqlCompatible() && (leftVal.isNumericNull() || rightVal.isNumericNull())) {
+ return ExprEval.of(null);
+ }
return ExprEval.of(evalDouble(leftVal.asDouble(), rightVal.asDouble()));
}
}
diff --git a/common/src/main/java/io/druid/math/expr/ExprEval.java b/common/src/main/java/io/druid/math/expr/ExprEval.java
index b87e29874c9..20c74d941f6 100644
--- a/common/src/main/java/io/druid/math/expr/ExprEval.java
+++ b/common/src/main/java/io/druid/math/expr/ExprEval.java
@@ -19,9 +19,7 @@
package io.druid.math.expr;
-import com.google.common.base.Preconditions;
import com.google.common.primitives.Doubles;
-import com.google.common.primitives.Ints;
import io.druid.common.config.NullHandling;
import io.druid.common.guava.GuavaUtils;
import io.druid.java.util.common.IAE;
@@ -32,7 +30,7 @@ import javax.annotation.Nullable;
*/
public abstract class ExprEval
{
- public static ExprEval ofLong(Number longValue)
+ public static ExprEval ofLong(@Nullable Number longValue)
{
return new LongExprEval(longValue);
}
@@ -42,7 +40,7 @@ public abstract class ExprEval
return new LongExprEval(longValue);
}
- public static ExprEval ofDouble(Number doubleValue)
+ public static ExprEval ofDouble(@Nullable Number doubleValue)
{
return new DoubleExprEval(doubleValue);
}
@@ -71,7 +69,7 @@ public abstract class ExprEval
}
}
- public static ExprEval bestEffortOf(Object val)
+ public static ExprEval bestEffortOf(@Nullable Object val)
{
if (val instanceof ExprEval) {
return (ExprEval) val;
@@ -85,6 +83,7 @@ public abstract class ExprEval
return new StringExprEval(val == null ? null : String.valueOf(val));
}
+ @Nullable
final T value;
private ExprEval(T value)
@@ -99,10 +98,10 @@ public abstract class ExprEval
return value;
}
- public boolean isNull()
- {
- return value == null;
- }
+ /**
+ * returns true if numeric primitive value for this ExprEval is null, otherwise false.
+ */
+ public abstract boolean isNumericNull();
public abstract int asInt();
@@ -125,7 +124,7 @@ public abstract class ExprEval
private abstract static class NumericExprEval extends ExprEval
{
- private NumericExprEval(Number value)
+ private NumericExprEval(@Nullable Number value)
{
super(value);
}
@@ -147,13 +146,19 @@ public abstract class ExprEval
{
return value.doubleValue();
}
+
+ @Override
+ public boolean isNumericNull()
+ {
+ return value == null;
+ }
}
private static class DoubleExprEval extends NumericExprEval
{
- private DoubleExprEval(Number value)
+ private DoubleExprEval(@Nullable Number value)
{
- super(Preconditions.checkNotNull(value, "value"));
+ super(value == null ? NullHandling.defaultDoubleValue() : value);
}
@Override
@@ -175,7 +180,7 @@ public abstract class ExprEval
case DOUBLE:
return this;
case LONG:
- return ExprEval.of(asLong());
+ return ExprEval.of(value == null ? null : asLong());
case STRING:
return ExprEval.of(asString());
}
@@ -191,9 +196,9 @@ public abstract class ExprEval
private static class LongExprEval extends NumericExprEval
{
- private LongExprEval(Number value)
+ private LongExprEval(@Nullable Number value)
{
- super(Preconditions.checkNotNull(value, "value"));
+ super(value == null ? NullHandling.defaultLongValue() : value);
}
@Override
@@ -213,7 +218,7 @@ public abstract class ExprEval
{
switch (castTo) {
case DOUBLE:
- return ExprEval.of(asDouble());
+ return ExprEval.of(value == null ? null : asDouble());
case LONG:
return this;
case STRING:
@@ -231,6 +236,8 @@ public abstract class ExprEval
private static class StringExprEval extends ExprEval
{
+ private Number numericVal;
+
private StringExprEval(@Nullable String value)
{
super(NullHandling.emptyToNullIfNeeded(value));
@@ -245,36 +252,63 @@ public abstract class ExprEval
@Override
public final int asInt()
{
- if (value == null) {
+ Number number = asNumber();
+ if (number == null) {
assert NullHandling.replaceWithDefault();
return 0;
}
-
- final Integer theInt = Ints.tryParse(value);
- assert NullHandling.replaceWithDefault() || theInt != null;
- return theInt == null ? 0 : theInt;
+ return number.intValue();
}
@Override
public final long asLong()
{
- // GuavaUtils.tryParseLong handles nulls, no need for special null handling here.
- final Long theLong = GuavaUtils.tryParseLong(value);
- assert NullHandling.replaceWithDefault() || theLong != null;
- return theLong == null ? 0L : theLong;
+ Number number = asNumber();
+ if (number == null) {
+ assert NullHandling.replaceWithDefault();
+ return 0L;
+ }
+ return number.longValue();
}
@Override
public final double asDouble()
{
- if (value == null) {
+ Number number = asNumber();
+ if (number == null) {
assert NullHandling.replaceWithDefault();
- return 0.0;
+ return 0.0d;
+ }
+ return number.doubleValue();
+ }
+
+ @Nullable
+ private Number asNumber()
+ {
+ if (value == null) {
+ return null;
+ }
+ if (numericVal != null) {
+ // Optimization for non-null case.
+ return numericVal;
+ }
+ Number rv;
+ Long v = GuavaUtils.tryParseLong(value);
+ // Do NOT use ternary operator here, because it makes Java to convert Long to Double
+ if (v != null) {
+ rv = v;
+ } else {
+ rv = Doubles.tryParse(value);
}
- final Double theDouble = Doubles.tryParse(value);
- assert NullHandling.replaceWithDefault() || theDouble != null;
- return theDouble == null ? 0.0 : theDouble;
+ numericVal = rv;
+ return rv;
+ }
+
+ @Override
+ public boolean isNumericNull()
+ {
+ return asNumber() == null;
}
@Override
@@ -288,9 +322,9 @@ public abstract class ExprEval
{
switch (castTo) {
case DOUBLE:
- return ExprEval.of(asDouble());
+ return ExprEval.ofDouble(asNumber());
case LONG:
- return ExprEval.of(asLong());
+ return ExprEval.ofLong(asNumber());
case STRING:
return this;
}
diff --git a/common/src/main/java/io/druid/math/expr/Function.java b/common/src/main/java/io/druid/math/expr/Function.java
index e7cc34f9a2b..a98b17ce2ff 100644
--- a/common/src/main/java/io/druid/math/expr/Function.java
+++ b/common/src/main/java/io/druid/math/expr/Function.java
@@ -74,7 +74,7 @@ interface Function
@Override
protected final ExprEval eval(ExprEval param)
{
- if (NullHandling.sqlCompatible() && param.isNull()) {
+ if (NullHandling.sqlCompatible() && param.isNumericNull()) {
return ExprEval.of(null);
}
if (param.type() == ExprType.LONG) {
@@ -796,6 +796,9 @@ interface Function
@Override
protected ExprEval eval(ExprEval x, ExprEval y)
{
+ if (NullHandling.sqlCompatible() && x.value() == null) {
+ return ExprEval.of(null);
+ }
ExprType castTo;
try {
castTo = ExprType.valueOf(StringUtils.toUpperCase(y.asString()));
@@ -880,7 +883,7 @@ interface Function
throw new IAE("Function[%s] needs 2 arguments", name());
}
final ExprEval eval = args.get(0).eval(bindings);
- return eval.isNull() ? args.get(1).eval(bindings) : eval;
+ return eval.value() == null ? args.get(1).eval(bindings) : eval;
}
}
@@ -937,7 +940,7 @@ interface Function
}
final String arg = args.get(0).eval(bindings).asString();
- return arg == null ? ExprEval.of(0) : ExprEval.of(arg.length());
+ return arg == null ? ExprEval.ofLong(NullHandling.defaultLongValue()) : ExprEval.of(arg.length());
}
}
@@ -1094,7 +1097,7 @@ interface Function
}
final ExprEval expr = args.get(0).eval(bindings);
- return ExprEval.of(expr.isNull(), ExprType.LONG);
+ return ExprEval.of(expr.value() == null, ExprType.LONG);
}
}
@@ -1114,7 +1117,7 @@ interface Function
}
final ExprEval expr = args.get(0).eval(bindings);
- return ExprEval.of(!expr.isNull(), ExprType.LONG);
+ return ExprEval.of(expr.value() != null, ExprType.LONG);
}
}
}
diff --git a/common/src/test/java/io/druid/math/expr/EvalTest.java b/common/src/test/java/io/druid/math/expr/EvalTest.java
index 6f334274305..4f9b6d9e956 100644
--- a/common/src/test/java/io/druid/math/expr/EvalTest.java
+++ b/common/src/test/java/io/druid/math/expr/EvalTest.java
@@ -140,11 +140,10 @@ public class EvalTest
Assert.assertEquals(1271055781L, evalLong("unix_timestamp('2010-04-12T07:03:01')", bindings));
Assert.assertEquals(1271023381L, evalLong("unix_timestamp('2010-04-12T07:03:01+09:00')", bindings));
Assert.assertEquals(1271023381L, evalLong("unix_timestamp('2010-04-12T07:03:01.419+09:00')", bindings));
- if (NullHandling.replaceWithDefault()) {
- Assert.assertEquals("NULL", eval("nvl(if(x == 9223372036854775807, '', 'x'), 'NULL')", bindings).asString());
- } else {
- Assert.assertEquals("", eval("nvl(if(x == 9223372036854775807, '', 'x'), 'NULL')", bindings).asString());
- }
+ Assert.assertEquals(
+ NullHandling.replaceWithDefault() ? "NULL" : "",
+ eval("nvl(if(x == 9223372036854775807, '', 'x'), 'NULL')", bindings).asString()
+ );
Assert.assertEquals("x", eval("nvl(if(x == 9223372036854775806, '', 'x'), 'NULL')", bindings).asString());
}
diff --git a/common/src/test/java/io/druid/math/expr/FunctionTest.java b/common/src/test/java/io/druid/math/expr/FunctionTest.java
index 27713832399..54540fc4f7b 100644
--- a/common/src/test/java/io/druid/math/expr/FunctionTest.java
+++ b/common/src/test/java/io/druid/math/expr/FunctionTest.java
@@ -88,7 +88,7 @@ public class FunctionTest
public void testStrlen()
{
assertExpr("strlen(x)", 3L);
- assertExpr("strlen(nonexistent)", 0L);
+ assertExpr("strlen(nonexistent)", NullHandling.defaultLongValue());
}
@Test
diff --git a/docs/content/configuration/auth.md b/docs/content/configuration/auth.md
index 9751ba6ddbd..e18703c3b54 100644
--- a/docs/content/configuration/auth.md
+++ b/docs/content/configuration/auth.md
@@ -12,7 +12,7 @@ layout: doc_page
|`druid.auth.unsecuredPaths`| List of Strings|List of paths for which security checks will not be performed. All requests to these paths will be allowed.|[]|no|
|`druid.auth.allowUnauthenticatedHttpOptions`|Boolean|If true, skip authentication checks for HTTP OPTIONS requests. This is needed for certain use cases, such as supporting CORS pre-flight requests. Note that disabling authentication checks for OPTIONS requests will allow unauthenticated users to determine what Druid endpoints are valid (by checking if the OPTIONS request returns a 200 instead of 404), so enabling this option may reveal information about server configuration, including information about what extensions are loaded (if those extensions add endpoints).|false|no|
-## Enabling Authentication/Authorization
+## Enabling Authentication/AuthorizationLoadingLookupTest
## Authenticator Chain
Authentication decisions are handled by a chain of Authenticator instances. A request will be checked by Authenticators in the sequence defined by the `druid.auth.authenticatorChain`.
diff --git a/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/quantiles/DoublesSketchAggregatorFactory.java b/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/quantiles/DoublesSketchAggregatorFactory.java
index e550720aa4d..e214a448bdf 100644
--- a/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/quantiles/DoublesSketchAggregatorFactory.java
+++ b/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/quantiles/DoublesSketchAggregatorFactory.java
@@ -106,13 +106,13 @@ public class DoublesSketchAggregatorFactory extends AggregatorFactory
if (selector instanceof NilColumnValueSelector) {
return new DoublesSketchNoOpBufferAggregator();
}
- return new DoublesSketchBuildBufferAggregator(selector, k, getMaxIntermediateSize());
+ return new DoublesSketchBuildBufferAggregator(selector, k, getMaxIntermediateSizeWithNulls());
}
final ColumnValueSelector selector = metricFactory.makeColumnValueSelector(fieldName);
if (selector instanceof NilColumnValueSelector) {
return new DoublesSketchNoOpBufferAggregator();
}
- return new DoublesSketchMergeBufferAggregator(selector, k, getMaxIntermediateSize());
+ return new DoublesSketchMergeBufferAggregator(selector, k, getMaxIntermediateSizeWithNulls());
}
@Override
diff --git a/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/quantiles/DoublesSketchMergeAggregatorFactory.java b/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/quantiles/DoublesSketchMergeAggregatorFactory.java
index b9cccb5d9c0..2ecc9907d58 100644
--- a/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/quantiles/DoublesSketchMergeAggregatorFactory.java
+++ b/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/quantiles/DoublesSketchMergeAggregatorFactory.java
@@ -57,7 +57,7 @@ public class DoublesSketchMergeAggregatorFactory extends DoublesSketchAggregator
if (selector instanceof NilColumnValueSelector) {
return new DoublesSketchNoOpBufferAggregator();
}
- return new DoublesSketchMergeBufferAggregator(selector, getK(), getMaxIntermediateSize());
+ return new DoublesSketchMergeBufferAggregator(selector, getK(), getMaxIntermediateSizeWithNulls());
}
}
diff --git a/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/theta/SketchAggregatorFactory.java b/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/theta/SketchAggregatorFactory.java
index 9fa7e3cb86a..2e6bc52e99a 100644
--- a/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/theta/SketchAggregatorFactory.java
+++ b/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/theta/SketchAggregatorFactory.java
@@ -74,7 +74,7 @@ public abstract class SketchAggregatorFactory extends AggregatorFactory
public BufferAggregator factorizeBuffered(ColumnSelectorFactory metricFactory)
{
BaseObjectColumnValueSelector selector = metricFactory.makeColumnValueSelector(fieldName);
- return new SketchBufferAggregator(selector, size, getMaxIntermediateSize());
+ return new SketchBufferAggregator(selector, size, getMaxIntermediateSizeWithNulls());
}
@Override
diff --git a/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/tuple/ArrayOfDoublesSketchAggregatorFactory.java b/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/tuple/ArrayOfDoublesSketchAggregatorFactory.java
index 2610084d7b8..58f5b2eb9b4 100644
--- a/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/tuple/ArrayOfDoublesSketchAggregatorFactory.java
+++ b/extensions-core/datasketches/src/main/java/io/druid/query/aggregation/datasketches/tuple/ArrayOfDoublesSketchAggregatorFactory.java
@@ -125,7 +125,7 @@ public class ArrayOfDoublesSketchAggregatorFactory extends AggregatorFactory
selector,
nominalEntries,
numberOfValues,
- getMaxIntermediateSize()
+ getMaxIntermediateSizeWithNulls()
);
}
// input is raw data (key and array of values), use build aggregator
@@ -143,7 +143,7 @@ public class ArrayOfDoublesSketchAggregatorFactory extends AggregatorFactory
keySelector,
valueSelectors,
nominalEntries,
- getMaxIntermediateSize()
+ getMaxIntermediateSizeWithNulls()
);
}
diff --git a/extensions-core/histogram/src/main/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregator.java b/extensions-core/histogram/src/main/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregator.java
index 7f4e724f7f8..ccd18cc9713 100644
--- a/extensions-core/histogram/src/main/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregator.java
+++ b/extensions-core/histogram/src/main/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregator.java
@@ -20,6 +20,7 @@
package io.druid.query.aggregation.histogram;
import com.google.common.primitives.Longs;
+import io.druid.common.config.NullHandling;
import io.druid.query.aggregation.Aggregator;
import io.druid.segment.BaseFloatColumnValueSelector;
@@ -59,7 +60,12 @@ public class ApproximateHistogramAggregator implements Aggregator
@Override
public void aggregate()
{
- histogram.offer(selector.getFloat());
+ // In case of ExpressionColumnValueSelector isNull will compute the expression and then give the result,
+ // the check for is NullHandling.replaceWithDefault is there to not have any performance impact of calling
+ // isNull for default case.
+ if (NullHandling.replaceWithDefault() || !selector.isNull()) {
+ histogram.offer(selector.getFloat());
+ }
}
@Override
diff --git a/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregationTest.java b/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregationTest.java
index 6f2b58ba7a0..261715dcc07 100644
--- a/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregationTest.java
+++ b/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregationTest.java
@@ -20,6 +20,7 @@
package io.druid.query.aggregation.histogram;
import com.google.common.collect.Lists;
+import io.druid.common.config.NullHandling;
import io.druid.data.input.MapBasedRow;
import io.druid.java.util.common.granularity.Granularities;
import io.druid.java.util.common.guava.Sequence;
@@ -79,10 +80,14 @@ public class ApproximateHistogramAggregationTest
@Test
public void testIngestWithNullsToZeroAndQuery() throws Exception
{
- MapBasedRow row = ingestAndQuery(false);
- Assert.assertEquals(0.0, row.getMetric("index_min").floatValue(), 0.0001);
- Assert.assertEquals(135.109191, row.getMetric("index_max").floatValue(), 0.0001);
- Assert.assertEquals(131.428176, row.getMetric("index_quantile").floatValue(), 0.0001);
+ // Nulls are ignored and not replaced with default for SQL compatible null handling.
+ // This is already tested in testIngestWithNullsIgnoredAndQuery()
+ if (NullHandling.replaceWithDefault()) {
+ MapBasedRow row = ingestAndQuery(false);
+ Assert.assertEquals(0.0F, row.getMetric("index_min"));
+ Assert.assertEquals(135.109191, row.getMetric("index_max").floatValue(), 0.0001);
+ Assert.assertEquals(131.428176, row.getMetric("index_quantile").floatValue(), 0.0001);
+ }
}
private MapBasedRow ingestAndQuery(boolean ignoreNulls) throws Exception
diff --git a/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregatorTest.java b/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregatorTest.java
index f99d3fdfdb9..c2569bf7bc2 100644
--- a/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregatorTest.java
+++ b/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/ApproximateHistogramAggregatorTest.java
@@ -48,7 +48,7 @@ public class ApproximateHistogramAggregatorTest
);
ApproximateHistogramBufferAggregator agg = new ApproximateHistogramBufferAggregator(selector, resolution);
- ByteBuffer buf = ByteBuffer.allocate(factory.getMaxIntermediateSize());
+ ByteBuffer buf = ByteBuffer.allocate(factory.getMaxIntermediateSizeWithNulls());
int position = 0;
agg.init(buf, position);
diff --git a/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/sql/QuantileSqlAggregatorTest.java b/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/sql/QuantileSqlAggregatorTest.java
index a61bd49709d..e4d6faa97a8 100644
--- a/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/sql/QuantileSqlAggregatorTest.java
+++ b/extensions-core/histogram/src/test/java/io/druid/query/aggregation/histogram/sql/QuantileSqlAggregatorTest.java
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import io.druid.common.config.NullHandling;
import io.druid.java.util.common.granularity.Granularities;
import io.druid.query.Druids;
import io.druid.query.QueryDataSource;
@@ -312,9 +313,12 @@ public class QuantileSqlAggregatorTest extends CalciteTestBase
// Verify results
final List