Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ public class ArrayOverlapOperatorConversion extends BaseExpressionDimFilterOpera
"'ARRAY_OVERLAP(array, array)'",
OperandTypes.or(
OperandTypes.family(SqlTypeFamily.ARRAY),
OperandTypes.family(SqlTypeFamily.STRING)
OperandTypes.family(SqlTypeFamily.STRING),
OperandTypes.family(SqlTypeFamily.NUMERIC)
Comment on lines +65 to +66
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like its possible to possible to specify operands with different types
could you add some tests like:

SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(l1||'.1', ARRAY[2.1, 7.1]) LIMIT 5
SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(l1||'.1', ARRAY[2.1, 7.1]) LIMIT 5
SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(ARRAY[l2], ARRAY[2, 7]) LIMIT 5
SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(ARRAY['x',l2||''], ARRAY['2', '7']) LIMIT 5
SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(ARRAY[2,7], ARRAY['2', '7']) LIMIT 5
SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(ARRAY[2,7], ARRAY[2.0,7.0]) LIMIT 5

it seems like type mismatch was already there in some cases (array<int>,array<string>) - would it be possible to reject invalid cases?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are being taken care of in this PR
But rather than rejecting them, we would cast them properly and return correct response

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't explicitly see these cases being covered in that PR (or I missed it).
Can we cover them somehow?

),
OperandTypes.or(
OperandTypes.family(SqlTypeFamily.ARRAY),
OperandTypes.family(SqlTypeFamily.STRING)
OperandTypes.family(SqlTypeFamily.STRING),
OperandTypes.family(SqlTypeFamily.NUMERIC)
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,17 @@ private SqlNode createArrayLiteral(Object value, int posn)
List<SqlNode> args = new ArrayList<>(list.size());
for (int i = 0, listSize = list.size(); i < listSize; i++) {
Object element = list.get(i);
if (element == null) {
throw InvalidSqlInput.exception("parameter [%d] is an array, with an illegal null at index [%d]", posn + 1, i);
}
SqlNode node;
if (element instanceof String) {
if (element == null) {
node = SqlLiteral.createNull(SqlParserPos.ZERO);
} else if (element instanceof String) {
node = SqlLiteral.createCharString((String) element, SqlParserPos.ZERO);
} else if (element instanceof Integer || element instanceof Long) {
// No direct way to create a literal from an Integer or Long, have
// to parse a string, sadly.
node = SqlLiteral.createExactNumeric(element.toString(), SqlParserPos.ZERO);
} else if (element instanceof Double || element instanceof Float) {
node = SqlLiteral.createApproxNumeric(element.toString(), SqlParserPos.ZERO);
} else if (element instanceof Boolean) {
node = SqlLiteral.createBoolean((Boolean) value, SqlParserPos.ZERO);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.apache.calcite.avatica.SqlType;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.guice.DruidInjectorBuilder;
import org.apache.druid.guice.NestedDataModule;
Expand Down Expand Up @@ -70,6 +71,7 @@
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
import org.apache.druid.sql.calcite.filtration.Filtration;
import org.apache.druid.sql.calcite.util.CalciteTests;
import org.apache.druid.sql.http.SqlParameter;
import org.junit.Assert;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -933,6 +935,94 @@ public void testArrayOverlapFilterArrayDoubleColumns()
);
}

@Test
public void testArrayOverlapFilterNumeric()
{
testQuery(
"SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(l1, ARRAY[1, 7]) LIMIT 5",
ImmutableList.of(
newScanQueryBuilder()
.dataSource(CalciteTests.DATASOURCE3)
.intervals(querySegmentSpec(Filtration.eternity()))
.filters(new InDimFilter("l1", ImmutableList.of("1", "7"), null))
.columns("dim3")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.limit(5)
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"[\"a\",\"b\"]"}
)
);
}

@Test
public void testArrayOverlapFilterWithDynamicParameter()
{
Druids.ScanQueryBuilder builder = newScanQueryBuilder()
.dataSource(CalciteTests.DATASOURCE3)
.intervals(querySegmentSpec(Filtration.eternity()))
.filters(new InDimFilter("d1", Arrays.asList("1.0", "1.7", null), null))
.columns("dim3")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.limit(5)
.context(QUERY_CONTEXT_DEFAULT);

testQuery(
PLANNER_CONFIG_DEFAULT,
QUERY_CONTEXT_DEFAULT,
ImmutableList.of(
new SqlParameter(SqlType.ARRAY, Arrays.asList(1.0, 1.7, null))
),
"SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(?, d1) LIMIT 5",
CalciteTests.REGULAR_USER_AUTH_RESULT,
ImmutableList.of(builder.build()),
NullHandling.sqlCompatible() ? ImmutableList.of(
new Object[]{"[\"a\",\"b\"]"},
new Object[]{"[\"b\",\"c\"]"},
new Object[]{""},
new Object[]{null},
new Object[]{null}
) : ImmutableList.of(
new Object[]{"[\"a\",\"b\"]"},
new Object[]{"[\"b\",\"c\"]"}
)
);
}

@Test
public void testArrayOverlapFilterWithDynamicParameterLong()
{
Druids.ScanQueryBuilder builder = newScanQueryBuilder()
.dataSource(CalciteTests.DATASOURCE3)
.intervals(querySegmentSpec(Filtration.eternity()))
.filters(new InDimFilter("l1", Arrays.asList("1", "7", null), null))
.columns("dim3")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.limit(5)
.context(QUERY_CONTEXT_DEFAULT);

testQuery(
PLANNER_CONFIG_DEFAULT,
QUERY_CONTEXT_DEFAULT,
ImmutableList.of(
new SqlParameter(SqlType.ARRAY, Arrays.asList(1, 7, null))
),
"SELECT dim3 FROM druid.numfoo WHERE ARRAY_OVERLAP(?, l1) LIMIT 5",
CalciteTests.REGULAR_USER_AUTH_RESULT,
ImmutableList.of(builder.build()),
NullHandling.sqlCompatible() ? ImmutableList.of(
new Object[]{"[\"a\",\"b\"]"},
new Object[]{""},
new Object[]{null},
new Object[]{null}
) : ImmutableList.of(
new Object[]{"[\"a\",\"b\"]"}
)
);
}

@Test
public void testArrayContainsFilter()
{
Expand Down Expand Up @@ -1231,6 +1321,48 @@ public void testArrayContainsFilterArrayDoubleColumns()
);
}

@Test
public void testArrayContainsFilterWithDynamicParameter()
{
Druids.ScanQueryBuilder builder = newScanQueryBuilder()
.dataSource(CalciteTests.DATASOURCE3)
.intervals(querySegmentSpec(Filtration.eternity()))
.columns("dim3")
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
.limit(5)
.context(QUERY_CONTEXT_DEFAULT);

if (NullHandling.sqlCompatible()) {
builder = builder.filters(
and(
equality("dim3", "a", ColumnType.STRING),
equality("dim3", "b", ColumnType.STRING)
)
);
} else {
builder = builder.filters(
and(
selector("dim3", "a"),
selector("dim3", "b")
)
);
}

testQuery(
PLANNER_CONFIG_DEFAULT,
QUERY_CONTEXT_DEFAULT,
ImmutableList.of(
new SqlParameter(SqlType.ARRAY, Arrays.asList("a", "b"))
),
"SELECT dim3 FROM druid.numfoo WHERE ARRAY_CONTAINS(dim3, ?) LIMIT 5",
CalciteTests.REGULAR_USER_AUTH_RESULT,
ImmutableList.of(builder.build()),
ImmutableList.of(
new Object[]{"[\"a\",\"b\"]"}
)
);
}

@Test
public void testArrayContainsConstantNull()
{
Expand Down