SQL: Fix assumption that AND, OR have two arguments. (#5470)

Calcite can deliver an AND or OR operator with > 2 arguments.
Fixes #5468.
This commit is contained in:
Gian Merlino 2018-03-05 21:56:35 -05:00 committed by Fangjin Yang
parent c9b12e7813
commit ff0de21fc5
2 changed files with 45 additions and 7 deletions

View File

@ -19,6 +19,7 @@
package io.druid.sql.calcite.expression; package io.druid.sql.calcite.expression;
import com.google.common.base.Joiner;
import io.druid.java.util.common.ISE; import io.druid.java.util.common.ISE;
import io.druid.java.util.common.StringUtils; import io.druid.java.util.common.StringUtils;
import io.druid.sql.calcite.planner.PlannerContext; import io.druid.sql.calcite.planner.PlannerContext;
@ -26,15 +27,17 @@ import io.druid.sql.calcite.table.RowSignature;
import org.apache.calcite.rex.RexNode; import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.SqlOperator;
import java.util.stream.Collectors;
public class BinaryOperatorConversion implements SqlOperatorConversion public class BinaryOperatorConversion implements SqlOperatorConversion
{ {
private final SqlOperator operator; private final SqlOperator operator;
private final String druidOperator; private final Joiner joiner;
public BinaryOperatorConversion(final SqlOperator operator, final String druidOperator) public BinaryOperatorConversion(final SqlOperator operator, final String druidOperator)
{ {
this.operator = operator; this.operator = operator;
this.druidOperator = druidOperator; this.joiner = Joiner.on(" " + druidOperator + " ");
} }
@Override @Override
@ -55,16 +58,18 @@ public class BinaryOperatorConversion implements SqlOperatorConversion
rowSignature, rowSignature,
rexNode, rexNode,
operands -> { operands -> {
if (operands.size() != 2) { if (operands.size() < 2) {
throw new ISE("WTF?! Got binary operator[%s] with %s args?", operator.getName(), operands.size()); throw new ISE("WTF?! Got binary operator[%s] with %s args?", operator.getName(), operands.size());
} }
return DruidExpression.fromExpression( return DruidExpression.fromExpression(
StringUtils.format( StringUtils.format(
"(%s %s %s)", "(%s)",
operands.get(0).getExpression(), joiner.join(
druidOperator, operands.stream()
operands.get(1).getExpression() .map(DruidExpression::getExpression)
.collect(Collectors.toList())
)
) )
); );
} }

View File

@ -1597,6 +1597,39 @@ public class CalciteQueryTest extends CalciteTestBase
); );
} }
@Test
public void testGroupByCaseWhenOfTripleAnd() throws Exception
{
testQuery(
"SELECT\n"
+ " CASE WHEN m1 > 1 AND m1 < 5 AND cnt = 1 THEN 'x' ELSE NULL END,"
+ " COUNT(*)\n"
+ "FROM druid.foo\n"
+ "GROUP BY 1",
ImmutableList.of(
GroupByQuery.builder()
.setDataSource(CalciteTests.DATASOURCE1)
.setInterval(QSS(Filtration.eternity()))
.setGranularity(Granularities.ALL)
.setVirtualColumns(
EXPRESSION_VIRTUAL_COLUMN(
"d0:v",
"case_searched(((\"m1\" > 1) && (\"m1\" < 5) && (\"cnt\" == 1)),'x','')",
ValueType.STRING
)
)
.setDimensions(DIMS(new DefaultDimensionSpec("d0:v", "d0")))
.setAggregatorSpecs(AGGS(new CountAggregatorFactory("a0")))
.setContext(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{"", 3L},
new Object[]{"x", 3L}
)
);
}
@Test @Test
public void testNullEmptyStringEquality() throws Exception public void testNullEmptyStringEquality() throws Exception
{ {