blob: fa3699d22afcda66f06e13f6d2250df4bd425093 [file] [log] [blame]
/*
* 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.druid.math.expr;
import com.google.common.collect.ImmutableList;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.testing.InitializedNullHandlingTest;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class ExprEvalTest extends InitializedNullHandlingTest
{
private static int MAX_SIZE_BYTES = 1 << 13;
@Rule
public ExpectedException expectedException = ExpectedException.none();
ByteBuffer buffer = ByteBuffer.allocate(1 << 16);
@Test
public void testStringSerde()
{
assertExpr(0, "hello");
assertExpr(1234, "hello");
assertExpr(0, ExprEval.bestEffortOf(null));
}
@Test
public void testStringSerdeTooBig()
{
expectedException.expect(ISE.class);
expectedException.expectMessage(StringUtils.format(
"Unable to serialize [%s], size [%s] is larger than max [%s]",
ExprType.STRING,
16,
10
));
assertExpr(0, ExprEval.of("hello world"), 10);
}
@Test
public void testLongSerde()
{
assertExpr(0, 1L);
assertExpr(1234, 1L);
assertExpr(1234, ExprEval.ofLong(null));
}
@Test
public void testDoubleSerde()
{
assertExpr(0, 1.123);
assertExpr(1234, 1.123);
assertExpr(1234, ExprEval.ofDouble(null));
}
@Test
public void testStringArraySerde()
{
assertExpr(0, new String[]{"hello", "hi", "hey"});
assertExpr(1024, new String[]{"hello", null, "hi", "hey"});
assertExpr(2048, new String[]{});
}
@Test
public void testStringArraySerdeToBig()
{
expectedException.expect(ISE.class);
expectedException.expectMessage(StringUtils.format(
"Unable to serialize [%s], size [%s] is larger than max [%s]",
ExprType.STRING_ARRAY,
14,
10
));
assertExpr(0, ExprEval.ofStringArray(new String[]{"hello", "hi", "hey"}), 10);
}
@Test
public void testStringArrayEvalToBig()
{
expectedException.expect(ISE.class);
// this has a different failure size than string serde because it doesn't check incrementally
expectedException.expectMessage(StringUtils.format(
"Unable to serialize [%s], size [%s] is larger than max [%s]",
ExprType.STRING_ARRAY,
27,
10
));
assertEstimatedBytes(ExprEval.ofStringArray(new String[]{"hello", "hi", "hey"}), 10);
}
@Test
public void testLongArraySerde()
{
assertExpr(0, new Long[]{1L, 2L, 3L});
assertExpr(1234, new Long[]{1L, 2L, null, 3L});
assertExpr(1234, new Long[]{});
}
@Test
public void testLongArraySerdeTooBig()
{
expectedException.expect(ISE.class);
expectedException.expectMessage(StringUtils.format(
"Unable to serialize [%s], size [%s] is larger than max [%s]",
ExprType.LONG_ARRAY,
29,
10
));
assertExpr(0, ExprEval.ofLongArray(new Long[]{1L, 2L, 3L}), 10);
}
@Test
public void testLongArrayEvalTooBig()
{
expectedException.expect(ISE.class);
expectedException.expectMessage(StringUtils.format(
"Unable to serialize [%s], size [%s] is larger than max [%s]",
ExprType.LONG_ARRAY,
NullHandling.sqlCompatible() ? 32 : 29,
10
));
assertEstimatedBytes(ExprEval.ofLongArray(new Long[]{1L, 2L, 3L}), 10);
}
@Test
public void testDoubleArraySerde()
{
assertExpr(0, new Double[]{1.1, 2.2, 3.3});
assertExpr(1234, new Double[]{1.1, 2.2, null, 3.3});
assertExpr(1234, new Double[]{});
}
@Test
public void testDoubleArraySerdeTooBig()
{
expectedException.expect(ISE.class);
expectedException.expectMessage(StringUtils.format(
"Unable to serialize [%s], size [%s] is larger than max [%s]",
ExprType.DOUBLE_ARRAY,
29,
10
));
assertExpr(0, ExprEval.ofDoubleArray(new Double[]{1.1, 2.2, 3.3}), 10);
}
@Test
public void testDoubleArrayEvalTooBig()
{
expectedException.expect(ISE.class);
expectedException.expectMessage(StringUtils.format(
"Unable to serialize [%s], size [%s] is larger than max [%s]",
ExprType.DOUBLE_ARRAY,
NullHandling.sqlCompatible() ? 32 : 29,
10
));
assertEstimatedBytes(ExprEval.ofDoubleArray(new Double[]{1.1, 2.2, 3.3}), 10);
}
@Test
public void test_coerceListToArray()
{
Assert.assertNull(ExprEval.coerceListToArray(null, false));
Assert.assertArrayEquals(new Object[0], (Object[]) ExprEval.coerceListToArray(ImmutableList.of(), false));
Assert.assertArrayEquals(new String[]{null}, (String[]) ExprEval.coerceListToArray(null, true));
Assert.assertArrayEquals(new String[]{null}, (String[]) ExprEval.coerceListToArray(ImmutableList.of(), true));
List<Long> longList = ImmutableList.of(1L, 2L, 3L);
Assert.assertArrayEquals(new Long[]{1L, 2L, 3L}, (Long[]) ExprEval.coerceListToArray(longList, false));
List<Integer> intList = ImmutableList.of(1, 2, 3);
Assert.assertArrayEquals(new Long[]{1L, 2L, 3L}, (Long[]) ExprEval.coerceListToArray(intList, false));
List<Float> floatList = ImmutableList.of(1.0f, 2.0f, 3.0f);
Assert.assertArrayEquals(new Double[]{1.0, 2.0, 3.0}, (Double[]) ExprEval.coerceListToArray(floatList, false));
List<Double> doubleList = ImmutableList.of(1.0, 2.0, 3.0);
Assert.assertArrayEquals(new Double[]{1.0, 2.0, 3.0}, (Double[]) ExprEval.coerceListToArray(doubleList, false));
List<String> stringList = ImmutableList.of("a", "b", "c");
Assert.assertArrayEquals(new String[]{"a", "b", "c"}, (String[]) ExprEval.coerceListToArray(stringList, false));
List<String> withNulls = new ArrayList<>();
withNulls.add("a");
withNulls.add(null);
withNulls.add("c");
Assert.assertArrayEquals(new String[]{"a", null, "c"}, (String[]) ExprEval.coerceListToArray(withNulls, false));
List<Long> withNumberNulls = new ArrayList<>();
withNumberNulls.add(1L);
withNumberNulls.add(null);
withNumberNulls.add(3L);
Assert.assertArrayEquals(new Long[]{1L, null, 3L}, (Long[]) ExprEval.coerceListToArray(withNumberNulls, false));
List<Object> withStringMix = ImmutableList.of(1L, "b", 3L);
Assert.assertArrayEquals(
new String[]{"1", "b", "3"},
(String[]) ExprEval.coerceListToArray(withStringMix, false)
);
List<Number> withIntsAndLongs = ImmutableList.of(1, 2L, 3);
Assert.assertArrayEquals(
new Long[]{1L, 2L, 3L},
(Long[]) ExprEval.coerceListToArray(withIntsAndLongs, false)
);
List<Number> withFloatsAndLongs = ImmutableList.of(1, 2L, 3.0f);
Assert.assertArrayEquals(
new Double[]{1.0, 2.0, 3.0},
(Double[]) ExprEval.coerceListToArray(withFloatsAndLongs, false)
);
List<Number> withDoublesAndLongs = ImmutableList.of(1, 2L, 3.0);
Assert.assertArrayEquals(
new Double[]{1.0, 2.0, 3.0},
(Double[]) ExprEval.coerceListToArray(withDoublesAndLongs, false)
);
List<Number> withFloatsAndDoubles = ImmutableList.of(1L, 2.0f, 3.0);
Assert.assertArrayEquals(
new Double[]{1.0, 2.0, 3.0},
(Double[]) ExprEval.coerceListToArray(withFloatsAndDoubles, false)
);
List<String> withAllNulls = new ArrayList<>();
withAllNulls.add(null);
withAllNulls.add(null);
withAllNulls.add(null);
Assert.assertArrayEquals(
new String[]{null, null, null},
(String[]) ExprEval.coerceListToArray(withAllNulls, false)
);
}
@Test
public void testStringArrayToNumberArray()
{
ExprEval someStringArray = ExprEval.ofStringArray(new String[]{"1", "2", "foo", null, "3.3"});
Assert.assertArrayEquals(
new Long[]{1L, 2L, null, null, 3L},
someStringArray.asLongArray()
);
Assert.assertArrayEquals(
new Double[]{1.0, 2.0, null, null, 3.3},
someStringArray.asDoubleArray()
);
}
@Test
public void testEmptyArrayFromList()
{
// empty arrays will materialize from JSON into an empty list, which coerce list to array will make into Object[]
// make sure we can handle it
ExprEval someEmptyArray = ExprEval.bestEffortOf(new ArrayList<>());
Assert.assertTrue(someEmptyArray.isArray());
Assert.assertEquals(0, someEmptyArray.asArray().length);
}
private void assertExpr(int position, Object expected)
{
assertExpr(position, ExprEval.bestEffortOf(expected));
}
private void assertExpr(int position, ExprEval expected)
{
assertExpr(position, expected, MAX_SIZE_BYTES);
}
private void assertExpr(int position, ExprEval expected, int maxSizeBytes)
{
ExprEval.serialize(buffer, position, expected, maxSizeBytes);
if (ExprType.isArray(expected.type())) {
Assert.assertArrayEquals(
expected.asArray(),
ExprEval.deserialize(buffer, position + 1, ExprType.fromByte(buffer.get(position))).asArray()
);
Assert.assertArrayEquals(
expected.asArray(),
ExprEval.deserialize(buffer, position).asArray()
);
} else {
Assert.assertEquals(
expected.value(),
ExprEval.deserialize(buffer, position + 1, ExprType.fromByte(buffer.get(position))).value()
);
Assert.assertEquals(
expected.value(),
ExprEval.deserialize(buffer, position).value()
);
}
assertEstimatedBytes(expected, maxSizeBytes);
}
private void assertEstimatedBytes(ExprEval eval, int maxSizeBytes)
{
ExprEval.estimateAndCheckMaxBytes(eval, maxSizeBytes);
}
}