blob: bf4bd4a0cb5a11ac741e5dc2b71d16ad005d10b4 [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.sql.calcite.expression;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.calcite.avatica.util.TimeUnit;
import org.apache.calcite.avatica.util.TimeUnitRange;
import org.apache.calcite.sql.SqlFunction;
import org.apache.calcite.sql.SqlIntervalQualifier;
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
import org.apache.calcite.sql.fun.SqlTrimFunction;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.DateTimes;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.query.expression.TestExprMacroTable;
import org.apache.druid.query.extraction.RegexDimExtractionFn;
import org.apache.druid.query.filter.RegexDimFilter;
import org.apache.druid.query.filter.SearchQueryDimFilter;
import org.apache.druid.query.search.ContainsSearchQuerySpec;
import org.apache.druid.segment.column.RowSignature;
import org.apache.druid.segment.column.ValueType;
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
import org.apache.druid.sql.calcite.expression.builtin.ContainsOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.DateTruncOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.LPadOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.LeftOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.ParseLongOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.RPadOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.RegexpExtractOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.RegexpLikeOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.RepeatOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.ReverseOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.RightOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.RoundOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.StringFormatOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.StrposOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.TimeCeilOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.TimeExtractOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.TimeFloorOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.TimeFormatOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.TimeParseOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.TimeShiftOperatorConversion;
import org.apache.druid.sql.calcite.expression.builtin.TruncateOperatorConversion;
import org.joda.time.Period;
import org.junit.Before;
import org.junit.Test;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Map;
public class ExpressionsTest extends ExpressionTestBase
{
private static final RowSignature ROW_SIGNATURE = RowSignature
.builder()
.add("t", ValueType.LONG)
.add("a", ValueType.LONG)
.add("b", ValueType.LONG)
.add("x", ValueType.FLOAT)
.add("y", ValueType.LONG)
.add("z", ValueType.FLOAT)
.add("s", ValueType.STRING)
.add("nan", ValueType.DOUBLE)
.add("inf", ValueType.DOUBLE)
.add("-inf", ValueType.DOUBLE)
.add("fnan", ValueType.FLOAT)
.add("finf", ValueType.FLOAT)
.add("-finf", ValueType.FLOAT)
.add("hexstr", ValueType.STRING)
.add("intstr", ValueType.STRING)
.add("spacey", ValueType.STRING)
.add("newliney", ValueType.STRING)
.add("tstr", ValueType.STRING)
.add("dstr", ValueType.STRING)
.build();
private static final Map<String, Object> BINDINGS = ImmutableMap.<String, Object>builder()
.put("t", DateTimes.of("2000-02-03T04:05:06").getMillis())
.put("a", 10)
.put("b", 25)
.put("x", 2.25)
.put("y", 3.0)
.put("z", -2.25)
.put("o", 0)
.put("nan", Double.NaN)
.put("inf", Double.POSITIVE_INFINITY)
.put("-inf", Double.NEGATIVE_INFINITY)
.put("fnan", Float.NaN)
.put("finf", Float.POSITIVE_INFINITY)
.put("-finf", Float.NEGATIVE_INFINITY)
.put("s", "foo")
.put("hexstr", "EF")
.put("intstr", "-100")
.put("spacey", " hey there ")
.put("newliney", "beep\nboop")
.put("tstr", "2000-02-03 04:05:06")
.put("dstr", "2000-02-03")
.build();
private ExpressionTestHelper testHelper;
@Before
public void setUp()
{
testHelper = new ExpressionTestHelper(ROW_SIGNATURE, BINDINGS);
}
@Test
public void testConcat()
{
testHelper.testExpression(
SqlTypeName.VARCHAR,
SqlStdOperatorTable.CONCAT,
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("bar")
),
DruidExpression.fromExpression("concat(\"s\",'bar')"),
"foobar"
);
}
@Test
public void testCharacterLength()
{
testHelper.testExpression(
SqlStdOperatorTable.CHARACTER_LENGTH,
testHelper.makeInputRef("s"),
DruidExpression.fromExpression("strlen(\"s\")"),
3L
);
}
@Test
public void testRegexpExtract()
{
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("x(.)"),
testHelper.makeLiteral(1)
),
DruidExpression.of(
SimpleExtraction.of("s", new RegexDimExtractionFn("x(.)", 1, true, null)),
"regexp_extract(\"s\",'x(.)',1)"
),
null
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("(o)"),
testHelper.makeLiteral(1)
),
DruidExpression.of(
SimpleExtraction.of("s", new RegexDimExtractionFn("(o)", 1, true, null)),
"regexp_extract(\"s\",'(o)',1)"
),
// Column "s" contains an 'o', but not at the beginning; we do match this.
"o"
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("Z"),
testHelper.makeInputRef("s")
),
testHelper.makeLiteral("Zf(.)")
),
DruidExpression.fromExpression("regexp_extract(concat('Z',\"s\"),'Zf(.)')"),
"Zfo"
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("f(.)"),
testHelper.makeLiteral(1)
),
DruidExpression.of(
SimpleExtraction.of("s", new RegexDimExtractionFn("f(.)", 1, true, null)),
"regexp_extract(\"s\",'f(.)',1)"
),
"o"
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("f(.)")
),
DruidExpression.of(
SimpleExtraction.of("s", new RegexDimExtractionFn("f(.)", 0, true, null)),
"regexp_extract(\"s\",'f(.)')"
),
"fo"
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("")
),
DruidExpression.of(
SimpleExtraction.of("s", new RegexDimExtractionFn("", 0, true, null)),
"regexp_extract(\"s\",'')"
),
NullHandling.emptyToNullIfNeeded("")
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("")
),
DruidExpression.of(
SimpleExtraction.of("s", new RegexDimExtractionFn("", 0, true, null)),
"regexp_extract(\"s\",'')"
),
NullHandling.emptyToNullIfNeeded("")
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeNullLiteral(SqlTypeName.VARCHAR),
testHelper.makeLiteral("(.)")
),
DruidExpression.fromExpression("regexp_extract(null,'(.)')"),
null
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeNullLiteral(SqlTypeName.VARCHAR),
testHelper.makeLiteral("")
),
DruidExpression.fromExpression("regexp_extract(null,'')"),
null
);
testHelper.testExpression(
new RegexpExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeNullLiteral(SqlTypeName.VARCHAR),
testHelper.makeLiteral("null")
),
DruidExpression.fromExpression("regexp_extract(null,'null')"),
null
);
}
@Test
public void testRegexpLike()
{
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("f.")
),
DruidExpression.fromExpression("regexp_like(\"s\",'f.')"),
1L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("o")
),
DruidExpression.fromExpression("regexp_like(\"s\",'o')"),
// Column "s" contains an 'o', but not at the beginning; we do match this.
1L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("x.")
),
DruidExpression.fromExpression("regexp_like(\"s\",'x.')"),
0L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("")
),
DruidExpression.fromExpression("regexp_like(\"s\",'')"),
1L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral("beep\nboop"),
testHelper.makeLiteral("^beep$")
),
DruidExpression.fromExpression("regexp_like('beep\\u000Aboop','^beep$')"),
0L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral("beep\nboop"),
testHelper.makeLiteral("^beep\\nboop$")
),
DruidExpression.fromExpression("regexp_like('beep\\u000Aboop','^beep\\u005Cnboop$')"),
1L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("newliney"),
testHelper.makeLiteral("^beep$")
),
DruidExpression.fromExpression("regexp_like(\"newliney\",'^beep$')"),
0L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("newliney"),
testHelper.makeLiteral("^beep\\nboop$")
),
DruidExpression.fromExpression("regexp_like(\"newliney\",'^beep\\u005Cnboop$')"),
1L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("newliney"),
testHelper.makeLiteral("boo")
),
DruidExpression.fromExpression("regexp_like(\"newliney\",'boo')"),
1L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("newliney"),
testHelper.makeLiteral("^boo")
),
DruidExpression.fromExpression("regexp_like(\"newliney\",'^boo')"),
0L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("Z"),
testHelper.makeInputRef("s")
),
testHelper.makeLiteral("x(.)")
),
DruidExpression.fromExpression("regexp_like(concat('Z',\"s\"),'x(.)')"),
0L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeNullLiteral(SqlTypeName.VARCHAR),
testHelper.makeLiteral("(.)")
),
DruidExpression.fromExpression("regexp_like(null,'(.)')"),
0L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeNullLiteral(SqlTypeName.VARCHAR),
testHelper.makeLiteral("")
),
DruidExpression.fromExpression("regexp_like(null,'')"),
// In SQL-compatible mode, nulls don't match anything. Otherwise, they match like empty strings.
NullHandling.sqlCompatible() ? 0L : 1L
);
testHelper.testExpression(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeNullLiteral(SqlTypeName.VARCHAR),
testHelper.makeLiteral("null")
),
DruidExpression.fromExpression("regexp_like(null,'null')"),
0L
);
}
@Test
public void testRegexpLikeAsFilter()
{
testHelper.testFilter(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("f.")
),
Collections.emptyList(),
new RegexDimFilter("s", "f.", null),
true
);
testHelper.testFilter(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("o")
),
Collections.emptyList(),
// Column "s" contains an 'o', but not at the beginning, so we don't match
new RegexDimFilter("s", "o", null),
true
);
testHelper.testFilter(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("x.")
),
Collections.emptyList(),
new RegexDimFilter("s", "x.", null),
false
);
testHelper.testFilter(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("")
),
Collections.emptyList(),
new RegexDimFilter("s", "", null),
true
);
testHelper.testFilter(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("newliney"),
testHelper.makeLiteral("^beep$")
),
Collections.emptyList(),
new RegexDimFilter("newliney", "^beep$", null),
false
);
testHelper.testFilter(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("newliney"),
testHelper.makeLiteral("^beep\\nboop$")
),
Collections.emptyList(),
new RegexDimFilter("newliney", "^beep\\nboop$", null),
true
);
testHelper.testFilter(
new RegexpLikeOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("Z"),
testHelper.makeInputRef("s")
),
testHelper.makeLiteral("x(.)")
),
ImmutableList.of(
new ExpressionVirtualColumn(
"v0",
"concat('Z',\"s\")",
ValueType.STRING,
TestExprMacroTable.INSTANCE
)
),
new RegexDimFilter("v0", "x(.)", null),
false
);
}
@Test
public void testStringFormat()
{
testHelper.testExpression(
new StringFormatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral("%x"),
testHelper.makeInputRef("b")
),
DruidExpression.fromExpression("format('%x',\"b\")"),
"19"
);
testHelper.testExpression(
new StringFormatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral("%s %,d"),
testHelper.makeInputRef("s"),
testHelper.makeLiteral(1234)
),
DruidExpression.fromExpression("format('%s %,d',\"s\",1234)"),
"foo 1,234"
);
testHelper.testExpression(
new StringFormatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral("%s %,d"),
testHelper.makeInputRef("s")
),
DruidExpression.fromExpression("format('%s %,d',\"s\")"),
"%s %,d; foo"
);
testHelper.testExpression(
new StringFormatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral("%s %,d"),
testHelper.makeInputRef("s"),
testHelper.makeLiteral(1234),
testHelper.makeLiteral(6789)
),
DruidExpression.fromExpression("format('%s %,d',\"s\",1234,6789)"),
"foo 1,234"
);
}
@Test
public void testStrpos()
{
testHelper.testExpression(
new StrposOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("oo")
),
DruidExpression.fromExpression("(strpos(\"s\",'oo') + 1)"),
2L
);
testHelper.testExpression(
new StrposOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral("ax")
),
DruidExpression.fromExpression("(strpos(\"s\",'ax') + 1)"),
0L
);
testHelper.testExpression(
new StrposOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeNullLiteral(SqlTypeName.VARCHAR),
testHelper.makeLiteral("ax")
),
DruidExpression.fromExpression("(strpos(null,'ax') + 1)"),
NullHandling.replaceWithDefault() ? 0L : null
);
}
@Test
public void testParseLong()
{
testHelper.testExpression(
new ParseLongOperatorConversion().calciteOperator(),
testHelper.makeInputRef("intstr"),
DruidExpression.fromExpression("parse_long(\"intstr\")"),
-100L
);
testHelper.testExpression(
new ParseLongOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("hexstr"),
testHelper.makeLiteral(BigDecimal.valueOf(16))
),
DruidExpression.fromExpression("parse_long(\"hexstr\",16)"),
239L
);
testHelper.testExpression(
new ParseLongOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("0x"),
testHelper.makeInputRef("hexstr")
),
testHelper.makeLiteral(BigDecimal.valueOf(16))
),
DruidExpression.fromExpression("parse_long(concat('0x',\"hexstr\"),16)"),
239L
);
testHelper.testExpression(
new ParseLongOperatorConversion().calciteOperator(),
testHelper.makeInputRef("hexstr"),
DruidExpression.fromExpression("parse_long(\"hexstr\")"),
NullHandling.sqlCompatible() ? null : 0L
);
}
@Test
public void testPosition()
{
testHelper.testExpression(
SqlStdOperatorTable.POSITION,
ImmutableList.of(
testHelper.makeLiteral("oo"),
testHelper.makeInputRef("s")
),
DruidExpression.fromExpression("(strpos(\"s\",'oo',0) + 1)"),
2L
);
testHelper.testExpression(
SqlStdOperatorTable.POSITION,
ImmutableList.of(
testHelper.makeLiteral("oo"),
testHelper.makeInputRef("s"),
testHelper.makeLiteral(BigDecimal.valueOf(2))
),
DruidExpression.fromExpression("(strpos(\"s\",'oo',(2 - 1)) + 1)"),
2L
);
testHelper.testExpression(
SqlStdOperatorTable.POSITION,
ImmutableList.of(
testHelper.makeLiteral("oo"),
testHelper.makeInputRef("s"),
testHelper.makeLiteral(BigDecimal.valueOf(3))
),
DruidExpression.fromExpression("(strpos(\"s\",'oo',(3 - 1)) + 1)"),
0L
);
}
@Test
public void testPower()
{
testHelper.testExpression(
SqlStdOperatorTable.POWER,
ImmutableList.of(
testHelper.makeInputRef("a"),
testHelper.makeLiteral(2)
),
DruidExpression.fromExpression("pow(\"a\",2)"),
100.0
);
}
@Test
public void testFloor()
{
testHelper.testExpression(
SqlStdOperatorTable.FLOOR,
testHelper.makeInputRef("a"),
DruidExpression.fromExpression("floor(\"a\")"),
10.0
);
testHelper.testExpression(
SqlStdOperatorTable.FLOOR,
testHelper.makeInputRef("x"),
DruidExpression.fromExpression("floor(\"x\")"),
2.0
);
testHelper.testExpression(
SqlStdOperatorTable.FLOOR,
testHelper.makeInputRef("y"),
DruidExpression.fromExpression("floor(\"y\")"),
3.0
);
testHelper.testExpression(
SqlStdOperatorTable.FLOOR,
testHelper.makeInputRef("z"),
DruidExpression.fromExpression("floor(\"z\")"),
-3.0
);
}
@Test
public void testCeil()
{
testHelper.testExpression(
SqlStdOperatorTable.CEIL,
testHelper.makeInputRef("a"),
DruidExpression.fromExpression("ceil(\"a\")"),
10.0
);
testHelper.testExpression(
SqlStdOperatorTable.CEIL,
testHelper.makeInputRef("x"),
DruidExpression.fromExpression("ceil(\"x\")"),
3.0
);
testHelper.testExpression(
SqlStdOperatorTable.CEIL,
testHelper.makeInputRef("y"),
DruidExpression.fromExpression("ceil(\"y\")"),
3.0
);
testHelper.testExpression(
SqlStdOperatorTable.CEIL,
testHelper.makeInputRef("z"),
DruidExpression.fromExpression("ceil(\"z\")"),
-2.0
);
}
@Test
public void testTruncate()
{
final SqlFunction truncateFunction = new TruncateOperatorConversion().calciteOperator();
testHelper.testExpression(
truncateFunction,
testHelper.makeInputRef("a"),
DruidExpression.fromExpression("(cast(cast(\"a\" * 1,'long'),'double') / 1)"),
10.0
);
testHelper.testExpression(
truncateFunction,
testHelper.makeInputRef("x"),
DruidExpression.fromExpression("(cast(cast(\"x\" * 1,'long'),'double') / 1)"),
2.0
);
testHelper.testExpression(
truncateFunction,
testHelper.makeInputRef("y"),
DruidExpression.fromExpression("(cast(cast(\"y\" * 1,'long'),'double') / 1)"),
3.0
);
testHelper.testExpression(
truncateFunction,
testHelper.makeInputRef("z"),
DruidExpression.fromExpression("(cast(cast(\"z\" * 1,'long'),'double') / 1)"),
-2.0
);
testHelper.testExpression(
truncateFunction,
ImmutableList.of(
testHelper.makeInputRef("x"),
testHelper.makeLiteral(1)
),
DruidExpression.fromExpression("(cast(cast(\"x\" * 10.0,'long'),'double') / 10.0)"),
2.2
);
testHelper.testExpression(
truncateFunction,
ImmutableList.of(
testHelper.makeInputRef("z"),
testHelper.makeLiteral(1)
),
DruidExpression.fromExpression("(cast(cast(\"z\" * 10.0,'long'),'double') / 10.0)"),
-2.2
);
testHelper.testExpression(
truncateFunction,
ImmutableList.of(
testHelper.makeInputRef("b"),
testHelper.makeLiteral(-1)
),
DruidExpression.fromExpression("(cast(cast(\"b\" * 0.1,'long'),'double') / 0.1)"),
20.0
);
testHelper.testExpression(
truncateFunction,
ImmutableList.of(
testHelper.makeInputRef("z"),
testHelper.makeLiteral(-1)
),
DruidExpression.fromExpression("(cast(cast(\"z\" * 0.1,'long'),'double') / 0.1)"),
0.0
);
}
@Test
public void testRound()
{
final SqlFunction roundFunction = new RoundOperatorConversion().calciteOperator();
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("a"),
DruidExpression.fromExpression("round(\"a\")"),
10L
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("b"),
DruidExpression.fromExpression("round(\"b\")"),
25L
);
testHelper.testExpression(
roundFunction,
ImmutableList.of(
testHelper.makeInputRef("b"),
testHelper.makeLiteral(-1)
),
DruidExpression.fromExpression("round(\"b\",-1)"),
30L
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("x"),
DruidExpression.fromExpression("round(\"x\")"),
2.0
);
testHelper.testExpression(
roundFunction,
ImmutableList.of(
testHelper.makeInputRef("x"),
testHelper.makeLiteral(1)
),
DruidExpression.fromExpression("round(\"x\",1)"),
2.3
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("y"),
DruidExpression.fromExpression("round(\"y\")"),
3.0
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("z"),
DruidExpression.fromExpression("round(\"z\")"),
-2.0
);
}
@Test
public void testRoundWithInvalidArgument()
{
final SqlFunction roundFunction = new RoundOperatorConversion().calciteOperator();
expectException(
IAE.class,
"The first argument to the function[round] should be integer or double type but got the type: STRING"
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("s"),
DruidExpression.fromExpression("round(\"s\")"),
"IAE Exception"
);
}
@Test
public void testRoundWithInvalidSecondArgument()
{
final SqlFunction roundFunction = new RoundOperatorConversion().calciteOperator();
expectException(
IAE.class,
"The second argument to the function[round] should be integer type but got the type: STRING"
);
testHelper.testExpression(
roundFunction,
ImmutableList.of(
testHelper.makeInputRef("x"),
testHelper.makeLiteral("foo")
),
DruidExpression.fromExpression("round(\"x\",'foo')"),
"IAE Exception"
);
}
@Test
public void testRoundWithNanShouldRoundTo0()
{
final SqlFunction roundFunction = new RoundOperatorConversion().calciteOperator();
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("nan"),
DruidExpression.fromExpression("round(\"nan\")"),
0D
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("fnan"),
DruidExpression.fromExpression("round(\"fnan\")"),
0D
);
}
@Test
public void testRoundWithInfinityShouldRoundTo0()
{
final SqlFunction roundFunction = new RoundOperatorConversion().calciteOperator();
//CHECKSTYLE.OFF: Regexp
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("inf"),
DruidExpression.fromExpression("round(\"inf\")"),
Double.MAX_VALUE
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("-inf"),
DruidExpression.fromExpression("round(\"-inf\")"),
-1 * Double.MAX_VALUE
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("finf"),
DruidExpression.fromExpression("round(\"finf\")"),
Double.MAX_VALUE
);
testHelper.testExpression(
roundFunction,
testHelper.makeInputRef("-finf"),
DruidExpression.fromExpression("round(\"-finf\")"),
-1 * Double.MAX_VALUE
);
//CHECKSTYLE.ON: Regexp
}
@Test
public void testDateTrunc()
{
testHelper.testExpression(
new DateTruncOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral("hour"),
testHelper.makeLiteral(DateTimes.of("2000-02-03T04:05:06Z"))
),
DruidExpression.fromExpression("timestamp_floor(949550706000,'PT1H',null,'UTC')"),
DateTimes.of("2000-02-03T04:00:00").getMillis()
);
testHelper.testExpression(
new DateTruncOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral("DAY"),
testHelper.makeLiteral(DateTimes.of("2000-02-03T04:05:06Z"))
),
DruidExpression.fromExpression("timestamp_floor(949550706000,'P1D',null,'UTC')"),
DateTimes.of("2000-02-03T00:00:00").getMillis()
);
}
@Test
public void testTrim()
{
testHelper.testExpression(
SqlStdOperatorTable.TRIM,
ImmutableList.of(
testHelper.makeFlag(SqlTrimFunction.Flag.BOTH),
testHelper.makeLiteral(" "),
testHelper.makeInputRef("spacey")
),
DruidExpression.fromExpression("trim(\"spacey\",' ')"),
"hey there"
);
testHelper.testExpression(
SqlStdOperatorTable.TRIM,
ImmutableList.of(
testHelper.makeFlag(SqlTrimFunction.Flag.LEADING),
testHelper.makeLiteral(" h"),
testHelper.makeInputRef("spacey")
),
DruidExpression.fromExpression("ltrim(\"spacey\",' h')"),
"ey there "
);
testHelper.testExpression(
SqlStdOperatorTable.TRIM,
ImmutableList.of(
testHelper.makeFlag(SqlTrimFunction.Flag.TRAILING),
testHelper.makeLiteral(" e"),
testHelper.makeInputRef("spacey")
),
DruidExpression.fromExpression("rtrim(\"spacey\",' e')"),
" hey ther"
);
}
@Test
public void testPad()
{
testHelper.testExpression(
new LPadOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(5),
testHelper.makeLiteral("x")
),
DruidExpression.fromExpression("lpad(\"s\",5,'x')"),
"xxfoo"
);
testHelper.testExpression(
new RPadOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(5),
testHelper.makeLiteral("x")
),
DruidExpression.fromExpression("rpad(\"s\",5,'x')"),
"fooxx"
);
}
@Test
public void testContains()
{
testHelper.testExpression(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("there")
),
DruidExpression.fromExpression("contains_string(\"spacey\",'there')"),
1L
);
testHelper.testExpression(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("There")
),
DruidExpression.fromExpression("contains_string(\"spacey\",'There')"),
0L
);
testHelper.testExpression(
ContainsOperatorConversion.caseInsensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("There")
),
DruidExpression.fromExpression("icontains_string(\"spacey\",'There')"),
1L
);
testHelper.testExpression(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("what is"),
testHelper.makeInputRef("spacey")
),
testHelper.makeLiteral("what")
),
DruidExpression.fromExpression("contains_string(concat('what is',\"spacey\"),'what')"),
1L
);
testHelper.testExpression(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("what is"),
testHelper.makeInputRef("spacey")
),
testHelper.makeLiteral("there")
),
DruidExpression.fromExpression("contains_string(concat('what is',\"spacey\"),'there')"),
1L
);
testHelper.testExpression(
ContainsOperatorConversion.caseInsensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("what is"),
testHelper.makeInputRef("spacey")
),
testHelper.makeLiteral("There")
),
DruidExpression.fromExpression("icontains_string(concat('what is',\"spacey\"),'There')"),
1L
);
testHelper.testExpression(
SqlStdOperatorTable.AND,
ImmutableList.of(
testHelper.makeCall(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("there")
),
testHelper.makeCall(
SqlStdOperatorTable.EQUALS,
testHelper.makeLiteral("yes"),
testHelper.makeLiteral("yes")
)
),
DruidExpression.fromExpression("(contains_string(\"spacey\",'there') && ('yes' == 'yes'))"),
1L
);
testHelper.testExpression(
SqlStdOperatorTable.AND,
ImmutableList.of(
testHelper.makeCall(
ContainsOperatorConversion.caseInsensitive().calciteOperator(),
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("There")
),
testHelper.makeCall(
SqlStdOperatorTable.EQUALS,
testHelper.makeLiteral("yes"),
testHelper.makeLiteral("yes")
)
),
DruidExpression.fromExpression("(icontains_string(\"spacey\",'There') && ('yes' == 'yes'))"),
1L
);
}
@Test
public void testContainsAsFilter()
{
testHelper.testFilter(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("there")
),
Collections.emptyList(),
new SearchQueryDimFilter("spacey", new ContainsSearchQuerySpec("there", true), null),
true
);
testHelper.testFilter(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("There")
),
Collections.emptyList(),
new SearchQueryDimFilter("spacey", new ContainsSearchQuerySpec("There", true), null),
false
);
testHelper.testFilter(
ContainsOperatorConversion.caseInsensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("There")
),
Collections.emptyList(),
new SearchQueryDimFilter("spacey", new ContainsSearchQuerySpec("There", false), null),
true
);
testHelper.testFilter(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("what is"),
testHelper.makeInputRef("spacey")
),
testHelper.makeLiteral("what")
),
ImmutableList.of(
new ExpressionVirtualColumn(
"v0",
"concat('what is',\"spacey\")",
ValueType.STRING,
TestExprMacroTable.INSTANCE
)
),
new SearchQueryDimFilter("v0", new ContainsSearchQuerySpec("what", true), null),
true
);
testHelper.testFilter(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("what is"),
testHelper.makeInputRef("spacey")
),
testHelper.makeLiteral("there")
),
ImmutableList.of(
new ExpressionVirtualColumn(
"v0",
"concat('what is',\"spacey\")",
ValueType.STRING,
TestExprMacroTable.INSTANCE
)
),
new SearchQueryDimFilter("v0", new ContainsSearchQuerySpec("there", true), null),
true
);
testHelper.testFilter(
ContainsOperatorConversion.caseInsensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeCall(
SqlStdOperatorTable.CONCAT,
testHelper.makeLiteral("what is"),
testHelper.makeInputRef("spacey")
),
testHelper.makeLiteral("What")
),
ImmutableList.of(
new ExpressionVirtualColumn(
"v0",
"concat('what is',\"spacey\")",
ValueType.STRING,
TestExprMacroTable.INSTANCE
)
),
new SearchQueryDimFilter("v0", new ContainsSearchQuerySpec("What", false), null),
true
);
testHelper.testFilter(
ContainsOperatorConversion.caseSensitive().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("spacey"),
testHelper.makeLiteral("")
),
Collections.emptyList(),
new SearchQueryDimFilter("spacey", new ContainsSearchQuerySpec("", true), null),
true
);
}
@Test
public void testTimeFloor()
{
testHelper.testExpression(
new TimeFloorOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral(DateTimes.of("2000-02-03T04:05:06Z")),
testHelper.makeLiteral("PT1H")
),
DruidExpression.fromExpression("timestamp_floor(949550706000,'PT1H',null,'UTC')"),
DateTimes.of("2000-02-03T04:00:00").getMillis()
);
testHelper.testExpression(
new TimeFloorOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral("P1D"),
testHelper.makeNullLiteral(SqlTypeName.TIMESTAMP),
testHelper.makeLiteral("America/Los_Angeles")
),
DruidExpression.fromExpression("timestamp_floor(\"t\",'P1D',null,'America/Los_Angeles')"),
DateTimes.of("2000-02-02T08:00:00").getMillis()
);
}
@Test
public void testOtherTimeFloor()
{
// FLOOR(__time TO unit)
testHelper.testExpression(
SqlStdOperatorTable.FLOOR,
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeFlag(TimeUnitRange.YEAR)
),
DruidExpression.fromExpression("timestamp_floor(\"t\",'P1Y',null,'UTC')"),
DateTimes.of("2000").getMillis()
);
}
@Test
public void testTimeCeil()
{
testHelper.testExpression(
new TimeCeilOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeLiteral(DateTimes.of("2000-02-03T04:05:06Z")),
testHelper.makeLiteral("PT1H")
),
DruidExpression.fromExpression("timestamp_ceil(949550706000,'PT1H',null,'UTC')"),
DateTimes.of("2000-02-03T05:00:00").getMillis()
);
testHelper.testExpression(
new TimeCeilOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral("P1D"),
testHelper.makeNullLiteral(SqlTypeName.TIMESTAMP),
testHelper.makeLiteral("America/Los_Angeles")
),
DruidExpression.fromExpression("timestamp_ceil(\"t\",'P1D',null,'America/Los_Angeles')"),
DateTimes.of("2000-02-03T08:00:00").getMillis()
);
}
@Test
public void testOtherTimeCeil()
{
// CEIL(__time TO unit)
testHelper.testExpression(
SqlStdOperatorTable.CEIL,
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeFlag(TimeUnitRange.YEAR)
),
DruidExpression.fromExpression("timestamp_ceil(\"t\",'P1Y',null,'UTC')"),
DateTimes.of("2001").getMillis()
);
}
@Test
public void testTimeShift()
{
testHelper.testExpression(
new TimeShiftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral("PT2H"),
testHelper.makeLiteral(-3)
),
DruidExpression.fromExpression("timestamp_shift(\"t\",'PT2H',-3,'UTC')"),
DateTimes.of("2000-02-02T22:05:06").getMillis()
);
testHelper.testExpression(
new TimeShiftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral("PT2H"),
testHelper.makeLiteral(-3),
testHelper.makeLiteral("America/Los_Angeles")
),
DruidExpression.fromExpression("timestamp_shift(\"t\",'PT2H',-3,'America/Los_Angeles')"),
DateTimes.of("2000-02-02T22:05:06").getMillis()
);
}
@Test
public void testTimeExtract()
{
testHelper.testExpression(
new TimeExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral("QUARTER")
),
DruidExpression.fromExpression("timestamp_extract(\"t\",'QUARTER','UTC')"),
1L
);
testHelper.testExpression(
new TimeExtractOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral("DAY"),
testHelper.makeLiteral("America/Los_Angeles")
),
DruidExpression.fromExpression("timestamp_extract(\"t\",'DAY','America/Los_Angeles')"),
2L
);
}
@Test
public void testTimePlusDayTimeInterval()
{
final Period period = new Period("P1DT1H1M");
testHelper.testExpression(
SqlStdOperatorTable.DATETIME_PLUS,
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral(
new BigDecimal(period.toStandardDuration().getMillis()), // DAY-TIME literals value is millis
new SqlIntervalQualifier(TimeUnit.DAY, TimeUnit.MINUTE, SqlParserPos.ZERO)
)
),
DruidExpression.of(
null,
"(\"t\" + 90060000)"
),
DateTimes.of("2000-02-03T04:05:06").plus(period).getMillis()
);
}
@Test
public void testTimePlusYearMonthInterval()
{
final Period period = new Period("P1Y1M");
testHelper.testExpression(
SqlStdOperatorTable.DATETIME_PLUS,
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral(
new BigDecimal(13), // YEAR-MONTH literals value is months
new SqlIntervalQualifier(TimeUnit.YEAR, TimeUnit.MONTH, SqlParserPos.ZERO)
)
),
DruidExpression.of(
null,
"timestamp_shift(\"t\",concat('P', 13, 'M'),1,'UTC')"
),
DateTimes.of("2000-02-03T04:05:06").plus(period).getMillis()
);
}
@Test
public void testTimeMinusDayTimeInterval()
{
final Period period = new Period("P1DT1H1M");
testHelper.testExpression(
SqlTypeName.TIMESTAMP,
SqlStdOperatorTable.MINUS_DATE,
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral(
new BigDecimal(period.toStandardDuration().getMillis()), // DAY-TIME literals value is millis
new SqlIntervalQualifier(TimeUnit.DAY, TimeUnit.MINUTE, SqlParserPos.ZERO)
)
),
DruidExpression.of(
null,
"(\"t\" - 90060000)"
),
DateTimes.of("2000-02-03T04:05:06").minus(period).getMillis()
);
}
@Test
public void testTimeMinusYearMonthInterval()
{
final Period period = new Period("P1Y1M");
testHelper.testExpression(
SqlTypeName.TIMESTAMP,
SqlStdOperatorTable.MINUS_DATE,
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral(
new BigDecimal(13), // YEAR-MONTH literals value is months
new SqlIntervalQualifier(TimeUnit.YEAR, TimeUnit.MONTH, SqlParserPos.ZERO)
)
),
DruidExpression.of(
null,
"timestamp_shift(\"t\",concat('P', 13, 'M'),-1,'UTC')"
),
DateTimes.of("2000-02-03T04:05:06").minus(period).getMillis()
);
}
@Test
public void testTimeParse()
{
testHelper.testExpression(
new TimeParseOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("tstr"),
testHelper.makeLiteral("yyyy-MM-dd HH:mm:ss")
),
DruidExpression.fromExpression("timestamp_parse(\"tstr\",'yyyy-MM-dd HH:mm:ss','UTC')"),
DateTimes.of("2000-02-03T04:05:06").getMillis()
);
testHelper.testExpression(
new TimeParseOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("tstr"),
testHelper.makeLiteral("yyyy-MM-dd HH:mm:ss"),
testHelper.makeLiteral("America/Los_Angeles")
),
DruidExpression.fromExpression("timestamp_parse(\"tstr\",'yyyy-MM-dd HH:mm:ss','America/Los_Angeles')"),
DateTimes.of("2000-02-03T04:05:06-08:00").getMillis()
);
}
@Test
public void testTimeFormat()
{
testHelper.testExpression(
new TimeFormatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral("yyyy-MM-dd HH:mm:ss")
),
DruidExpression.fromExpression("timestamp_format(\"t\",'yyyy-MM-dd HH:mm:ss','UTC')"),
"2000-02-03 04:05:06"
);
testHelper.testExpression(
new TimeFormatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("t"),
testHelper.makeLiteral("yyyy-MM-dd HH:mm:ss"),
testHelper.makeLiteral("America/Los_Angeles")
),
DruidExpression.fromExpression("timestamp_format(\"t\",'yyyy-MM-dd HH:mm:ss','America/Los_Angeles')"),
"2000-02-02 20:05:06"
);
}
@Test
public void testExtract()
{
testHelper.testExpression(
SqlStdOperatorTable.EXTRACT,
ImmutableList.of(
testHelper.makeFlag(TimeUnitRange.QUARTER),
testHelper.makeInputRef("t")
),
DruidExpression.fromExpression("timestamp_extract(\"t\",'QUARTER','UTC')"),
1L
);
testHelper.testExpression(
SqlStdOperatorTable.EXTRACT,
ImmutableList.of(
testHelper.makeFlag(TimeUnitRange.DAY),
testHelper.makeInputRef("t")
),
DruidExpression.fromExpression("timestamp_extract(\"t\",'DAY','UTC')"),
3L
);
}
@Test
public void testCastAsTimestamp()
{
testHelper.testExpression(
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.TIMESTAMP),
testHelper.makeInputRef("t")
),
DruidExpression.of(
SimpleExtraction.of("t", null),
"\"t\""
),
DateTimes.of("2000-02-03T04:05:06Z").getMillis()
);
testHelper.testExpression(
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.TIMESTAMP),
testHelper.makeInputRef("tstr")
),
DruidExpression.of(
null,
"timestamp_parse(\"tstr\",null,'UTC')"
),
DateTimes.of("2000-02-03T04:05:06Z").getMillis()
);
}
@Test
public void testCastFromTimestamp()
{
testHelper.testExpression(
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.VARCHAR),
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.TIMESTAMP),
testHelper.makeInputRef("t")
)
),
DruidExpression.fromExpression(
"timestamp_format(\"t\",'yyyy-MM-dd HH:mm:ss','UTC')"
),
"2000-02-03 04:05:06"
);
testHelper.testExpression(
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.BIGINT),
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.TIMESTAMP),
testHelper.makeInputRef("t")
)
),
DruidExpression.of(
SimpleExtraction.of("t", null),
"\"t\""
),
DateTimes.of("2000-02-03T04:05:06").getMillis()
);
}
@Test
public void testCastAsDate()
{
testHelper.testExpression(
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.DATE),
testHelper.makeInputRef("t")
),
DruidExpression.fromExpression("timestamp_floor(\"t\",'P1D',null,'UTC')"),
DateTimes.of("2000-02-03").getMillis()
);
testHelper.testExpression(
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.DATE),
testHelper.makeInputRef("dstr")
),
DruidExpression.fromExpression(
"timestamp_floor(timestamp_parse(\"dstr\",null,'UTC'),'P1D',null,'UTC')"
),
DateTimes.of("2000-02-03").getMillis()
);
}
@Test
public void testCastFromDate()
{
testHelper.testExpression(
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.VARCHAR),
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.DATE),
testHelper.makeInputRef("t")
)
),
DruidExpression.fromExpression(
"timestamp_format(timestamp_floor(\"t\",'P1D',null,'UTC'),'yyyy-MM-dd','UTC')"
),
"2000-02-03"
);
testHelper.testExpression(
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.BIGINT),
testHelper.makeAbstractCast(
testHelper.createSqlType(SqlTypeName.DATE),
testHelper.makeInputRef("t")
)
),
DruidExpression.fromExpression("timestamp_floor(\"t\",'P1D',null,'UTC')"),
DateTimes.of("2000-02-03").getMillis()
);
}
@Test
public void testReverse()
{
testHelper.testExpression(
new ReverseOperatorConversion().calciteOperator(),
testHelper.makeInputRef("s"),
DruidExpression.fromExpression("reverse(\"s\")"),
"oof"
);
testHelper.testExpression(
new ReverseOperatorConversion().calciteOperator(),
testHelper.makeInputRef("spacey"),
DruidExpression.fromExpression("reverse(\"spacey\")"),
" ereht yeh "
);
testHelper.testExpression(
new ReverseOperatorConversion().calciteOperator(),
testHelper.makeInputRef("tstr"),
DruidExpression.fromExpression("reverse(\"tstr\")"),
"60:50:40 30-20-0002"
);
testHelper.testExpression(
new ReverseOperatorConversion().calciteOperator(),
testHelper.makeInputRef("dstr"),
DruidExpression.fromExpression("reverse(\"dstr\")"),
"30-20-0002"
);
}
@Test
public void testAbnormalReverseWithWrongType()
{
expectException(IAE.class, "Function[reverse] needs a string argument");
testHelper.testExpression(
new ReverseOperatorConversion().calciteOperator(),
testHelper.makeInputRef("a"),
DruidExpression.fromExpression("reverse(\"a\")"),
null
);
}
@Test
public void testRight()
{
testHelper.testExpression(
new RightOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(1)
),
DruidExpression.fromExpression("right(\"s\",1)"),
"o"
);
testHelper.testExpression(
new RightOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(2)
),
DruidExpression.fromExpression("right(\"s\",2)"),
"oo"
);
testHelper.testExpression(
new RightOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(3)
),
DruidExpression.fromExpression("right(\"s\",3)"),
"foo"
);
testHelper.testExpression(
new RightOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(4)
),
DruidExpression.fromExpression("right(\"s\",4)"),
"foo"
);
testHelper.testExpression(
new RightOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("tstr"),
testHelper.makeLiteral(5)
),
DruidExpression.fromExpression("right(\"tstr\",5)"),
"05:06"
);
}
@Test
public void testAbnormalRightWithNegativeNumber()
{
expectException(IAE.class, "Function[right] needs a postive integer as second argument");
testHelper.testExpression(
new RightOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(-1)
),
DruidExpression.fromExpression("right(\"s\",-1)"),
null
);
}
@Test
public void testAbnormalRightWithWrongType()
{
expectException(IAE.class, "Function[right] needs a string as first argument and an integer as second argument");
testHelper.testExpression(
new RightOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeInputRef("s")
),
DruidExpression.fromExpression("right(\"s\",\"s\")"),
null
);
}
@Test
public void testLeft()
{
testHelper.testExpression(
new LeftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(1)
),
DruidExpression.fromExpression("left(\"s\",1)"),
"f"
);
testHelper.testExpression(
new LeftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(2)
),
DruidExpression.fromExpression("left(\"s\",2)"),
"fo"
);
testHelper.testExpression(
new LeftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(3)
),
DruidExpression.fromExpression("left(\"s\",3)"),
"foo"
);
testHelper.testExpression(
new LeftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(4)
),
DruidExpression.fromExpression("left(\"s\",4)"),
"foo"
);
testHelper.testExpression(
new LeftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("tstr"),
testHelper.makeLiteral(10)
),
DruidExpression.fromExpression("left(\"tstr\",10)"),
"2000-02-03"
);
}
@Test
public void testAbnormalLeftWithNegativeNumber()
{
expectException(IAE.class, "Function[left] needs a postive integer as second argument");
testHelper.testExpression(
new LeftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(-1)
),
DruidExpression.fromExpression("left(\"s\",-1)"),
null
);
}
@Test
public void testAbnormalLeftWithWrongType()
{
expectException(IAE.class, "Function[left] needs a string as first argument and an integer as second argument");
testHelper.testExpression(
new LeftOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeInputRef("s")
),
DruidExpression.fromExpression("left(\"s\",\"s\")"),
null
);
}
@Test
public void testRepeat()
{
testHelper.testExpression(
new RepeatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(1)
),
DruidExpression.fromExpression("repeat(\"s\",1)"),
"foo"
);
testHelper.testExpression(
new RepeatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(3)
),
DruidExpression.fromExpression("repeat(\"s\",3)"),
"foofoofoo"
);
testHelper.testExpression(
new RepeatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeLiteral(-1)
),
DruidExpression.fromExpression("repeat(\"s\",-1)"),
null
);
}
@Test
public void testAbnormalRepeatWithWrongType()
{
expectException(IAE.class, "Function[repeat] needs a string as first argument and an integer as second argument");
testHelper.testExpression(
new RepeatOperatorConversion().calciteOperator(),
ImmutableList.of(
testHelper.makeInputRef("s"),
testHelper.makeInputRef("s")
),
DruidExpression.fromExpression("repeat(\"s\",\"s\")"),
null
);
}
}