mirror of https://github.com/apache/druid.git
SQL: Add PARSE_LONG function. (#7326)
* SQL: Add PARSE_LONG function. * Fix test.
This commit is contained in:
parent
01c021e6da
commit
4ca5fe0f60
|
@ -122,6 +122,48 @@ interface Function
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ParseLong implements Function
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String name()
|
||||||
|
{
|
||||||
|
return "parse_long";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
|
||||||
|
{
|
||||||
|
final int radix;
|
||||||
|
if (args.size() == 1) {
|
||||||
|
radix = 10;
|
||||||
|
} else if (args.size() == 2) {
|
||||||
|
radix = args.get(1).eval(bindings).asInt();
|
||||||
|
} else {
|
||||||
|
throw new IAE("Function[%s] needs 1 or 2 arguments", name());
|
||||||
|
}
|
||||||
|
|
||||||
|
final String input = NullHandling.nullToEmptyIfNeeded(args.get(0).eval(bindings).asString());
|
||||||
|
if (input == null) {
|
||||||
|
return ExprEval.ofLong(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
final long retVal;
|
||||||
|
try {
|
||||||
|
if (radix == 16 && (input.startsWith("0x") || input.startsWith("0X"))) {
|
||||||
|
// Strip leading 0x from hex strings.
|
||||||
|
retVal = Long.parseLong(input.substring(2), radix);
|
||||||
|
} else {
|
||||||
|
retVal = Long.parseLong(input, radix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
return ExprEval.ofLong(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExprEval.of(retVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Pi implements Function
|
class Pi implements Function
|
||||||
{
|
{
|
||||||
private static final double PI = Math.PI;
|
private static final double PI = Math.PI;
|
||||||
|
|
|
@ -69,6 +69,7 @@ The following built-in functions are available.
|
||||||
|concat|concatenate a list of strings|
|
|concat|concatenate a list of strings|
|
||||||
|like|like(expr, pattern[, escape]) is equivalent to SQL `expr LIKE pattern`|
|
|like|like(expr, pattern[, escape]) is equivalent to SQL `expr LIKE pattern`|
|
||||||
|lookup|lookup(expr, lookup-name) looks up expr in a registered [query-time lookup](../querying/lookups.html)|
|
|lookup|lookup(expr, lookup-name) looks up expr in a registered [query-time lookup](../querying/lookups.html)|
|
||||||
|
|parse_long|parse_long(string[, radix]) parses a string as a long with the given radix, or 10 (decimal) if a radix is not provided.|
|
||||||
|regexp_extract|regexp_extract(expr, pattern[, index]) applies a regular expression pattern and extracts a capture group index, or null if there is no match. If index is unspecified or zero, returns the substring that matched the pattern.|
|
|regexp_extract|regexp_extract(expr, pattern[, index]) applies a regular expression pattern and extracts a capture group index, or null if there is no match. If index is unspecified or zero, returns the substring that matched the pattern.|
|
||||||
|replace|replace(expr, pattern, replacement) replaces pattern with replacement|
|
|replace|replace(expr, pattern, replacement) replaces pattern with replacement|
|
||||||
|substring|substring(expr, index, length) behaves like java.lang.String's substring|
|
|substring|substring(expr, index, length) behaves like java.lang.String's substring|
|
||||||
|
|
|
@ -178,6 +178,7 @@ String functions accept strings, and return a type appropriate to the function.
|
||||||
|`STRLEN(expr)`|Synonym for `LENGTH`.|
|
|`STRLEN(expr)`|Synonym for `LENGTH`.|
|
||||||
|`LOOKUP(expr, lookupName)`|Look up expr in a registered [query-time lookup table](lookups.html).|
|
|`LOOKUP(expr, lookupName)`|Look up expr in a registered [query-time lookup table](lookups.html).|
|
||||||
|`LOWER(expr)`|Returns expr in all lowercase.|
|
|`LOWER(expr)`|Returns expr in all lowercase.|
|
||||||
|
|`PARSE_LONG(string[, radix])`|Parses a string into a long (BIGINT) with the given radix, or 10 (decimal) if a radix is not provided.|
|
||||||
|`POSITION(needle IN haystack [FROM fromIndex])`|Returns the index of needle within haystack, with indexes starting from 1. The search will begin at fromIndex, or 1 if fromIndex is not specified. If the needle is not found, returns 0.|
|
|`POSITION(needle IN haystack [FROM fromIndex])`|Returns the index of needle within haystack, with indexes starting from 1. The search will begin at fromIndex, or 1 if fromIndex is not specified. If the needle is not found, returns 0.|
|
||||||
|`REGEXP_EXTRACT(expr, pattern, [index])`|Apply regular expression pattern and extract a capture group, or null if there is no match. If index is unspecified or zero, returns the substring that matched the pattern.|
|
|`REGEXP_EXTRACT(expr, pattern, [index])`|Apply regular expression pattern and extract a capture group, or null if there is no match. If index is unspecified or zero, returns the substring that matched the pattern.|
|
||||||
|`REPLACE(expr, pattern, replacement)`|Replaces pattern with replacement in expr, and returns the result.|
|
|`REPLACE(expr, pattern, replacement)`|Replaces pattern with replacement in expr, and returns the result.|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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.builtin;
|
||||||
|
|
||||||
|
import org.apache.calcite.rex.RexNode;
|
||||||
|
import org.apache.calcite.sql.SqlFunction;
|
||||||
|
import org.apache.calcite.sql.SqlFunctionCategory;
|
||||||
|
import org.apache.calcite.sql.SqlOperator;
|
||||||
|
import org.apache.calcite.sql.type.SqlTypeFamily;
|
||||||
|
import org.apache.calcite.sql.type.SqlTypeName;
|
||||||
|
import org.apache.druid.sql.calcite.expression.DruidExpression;
|
||||||
|
import org.apache.druid.sql.calcite.expression.OperatorConversions;
|
||||||
|
import org.apache.druid.sql.calcite.expression.SqlOperatorConversion;
|
||||||
|
import org.apache.druid.sql.calcite.planner.PlannerContext;
|
||||||
|
import org.apache.druid.sql.calcite.table.RowSignature;
|
||||||
|
|
||||||
|
public class ParseLongOperatorConversion implements SqlOperatorConversion
|
||||||
|
{
|
||||||
|
private static final String NAME = "PARSE_LONG";
|
||||||
|
|
||||||
|
private static final SqlFunction SQL_FUNCTION = OperatorConversions
|
||||||
|
.operatorBuilder(NAME)
|
||||||
|
.operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER)
|
||||||
|
.returnType(SqlTypeName.BIGINT)
|
||||||
|
.functionCategory(SqlFunctionCategory.STRING)
|
||||||
|
.requiredOperands(1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqlOperator calciteOperator()
|
||||||
|
{
|
||||||
|
return SQL_FUNCTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DruidExpression toDruidExpression(
|
||||||
|
final PlannerContext plannerContext,
|
||||||
|
final RowSignature rowSignature,
|
||||||
|
final RexNode rexNode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return OperatorConversions.convertCall(plannerContext, rowSignature, rexNode, "parse_long");
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,6 +56,7 @@ import org.apache.druid.sql.calcite.expression.builtin.FloorOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.LTrimOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.LTrimOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.LikeOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.LikeOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.MillisToTimestampOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.MillisToTimestampOperatorConversion;
|
||||||
|
import org.apache.druid.sql.calcite.expression.builtin.ParseLongOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.PositionOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.PositionOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.RTrimOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.RTrimOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.RegexpExtractOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.RegexpExtractOperatorConversion;
|
||||||
|
@ -172,6 +173,7 @@ public class DruidOperatorTable implements SqlOperatorTable
|
||||||
.add(new PositionOperatorConversion())
|
.add(new PositionOperatorConversion())
|
||||||
.add(new RegexpExtractOperatorConversion())
|
.add(new RegexpExtractOperatorConversion())
|
||||||
.add(new RTrimOperatorConversion())
|
.add(new RTrimOperatorConversion())
|
||||||
|
.add(new ParseLongOperatorConversion())
|
||||||
.add(new StrposOperatorConversion())
|
.add(new StrposOperatorConversion())
|
||||||
.add(new SubstringOperatorConversion())
|
.add(new SubstringOperatorConversion())
|
||||||
.add(new AliasedOperatorConversion(new SubstringOperatorConversion(), "SUBSTR"))
|
.add(new AliasedOperatorConversion(new SubstringOperatorConversion(), "SUBSTR"))
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.apache.druid.math.expr.Parser;
|
||||||
import org.apache.druid.query.extraction.RegexDimExtractionFn;
|
import org.apache.druid.query.extraction.RegexDimExtractionFn;
|
||||||
import org.apache.druid.segment.column.ValueType;
|
import org.apache.druid.segment.column.ValueType;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.DateTruncOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.DateTruncOperatorConversion;
|
||||||
|
import org.apache.druid.sql.calcite.expression.builtin.ParseLongOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.RegexpExtractOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.RegexpExtractOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.StrposOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.StrposOperatorConversion;
|
||||||
import org.apache.druid.sql.calcite.expression.builtin.TimeExtractOperatorConversion;
|
import org.apache.druid.sql.calcite.expression.builtin.TimeExtractOperatorConversion;
|
||||||
|
@ -83,6 +84,8 @@ public class ExpressionsTest extends CalciteTestBase
|
||||||
.add("y", ValueType.LONG)
|
.add("y", ValueType.LONG)
|
||||||
.add("z", ValueType.FLOAT)
|
.add("z", ValueType.FLOAT)
|
||||||
.add("s", ValueType.STRING)
|
.add("s", ValueType.STRING)
|
||||||
|
.add("hexstr", ValueType.STRING)
|
||||||
|
.add("intstr", ValueType.STRING)
|
||||||
.add("spacey", ValueType.STRING)
|
.add("spacey", ValueType.STRING)
|
||||||
.add("tstr", ValueType.STRING)
|
.add("tstr", ValueType.STRING)
|
||||||
.add("dstr", ValueType.STRING)
|
.add("dstr", ValueType.STRING)
|
||||||
|
@ -95,6 +98,8 @@ public class ExpressionsTest extends CalciteTestBase
|
||||||
.put("y", 3.0)
|
.put("y", 3.0)
|
||||||
.put("z", -2.25)
|
.put("z", -2.25)
|
||||||
.put("s", "foo")
|
.put("s", "foo")
|
||||||
|
.put("hexstr", "EF")
|
||||||
|
.put("intstr", "-100")
|
||||||
.put("spacey", " hey there ")
|
.put("spacey", " hey there ")
|
||||||
.put("tstr", "2000-02-03 04:05:06")
|
.put("tstr", "2000-02-03 04:05:06")
|
||||||
.put("dstr", "2000-02-03")
|
.put("dstr", "2000-02-03")
|
||||||
|
@ -198,6 +203,52 @@ public class ExpressionsTest extends CalciteTestBase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseLong()
|
||||||
|
{
|
||||||
|
testExpression(
|
||||||
|
rexBuilder.makeCall(
|
||||||
|
new ParseLongOperatorConversion().calciteOperator(),
|
||||||
|
inputRef("intstr")
|
||||||
|
),
|
||||||
|
DruidExpression.fromExpression("parse_long(\"intstr\")"),
|
||||||
|
-100L
|
||||||
|
);
|
||||||
|
|
||||||
|
testExpression(
|
||||||
|
rexBuilder.makeCall(
|
||||||
|
new ParseLongOperatorConversion().calciteOperator(),
|
||||||
|
inputRef("hexstr"),
|
||||||
|
rexBuilder.makeExactLiteral(BigDecimal.valueOf(16))
|
||||||
|
),
|
||||||
|
DruidExpression.fromExpression("parse_long(\"hexstr\",16)"),
|
||||||
|
239L
|
||||||
|
);
|
||||||
|
|
||||||
|
testExpression(
|
||||||
|
rexBuilder.makeCall(
|
||||||
|
new ParseLongOperatorConversion().calciteOperator(),
|
||||||
|
rexBuilder.makeCall(
|
||||||
|
SqlStdOperatorTable.CONCAT,
|
||||||
|
rexBuilder.makeLiteral("0x"),
|
||||||
|
inputRef("hexstr")
|
||||||
|
),
|
||||||
|
rexBuilder.makeExactLiteral(BigDecimal.valueOf(16))
|
||||||
|
),
|
||||||
|
DruidExpression.fromExpression("parse_long(concat('0x',\"hexstr\"),16)"),
|
||||||
|
239L
|
||||||
|
);
|
||||||
|
|
||||||
|
testExpression(
|
||||||
|
rexBuilder.makeCall(
|
||||||
|
new ParseLongOperatorConversion().calciteOperator(),
|
||||||
|
inputRef("hexstr")
|
||||||
|
),
|
||||||
|
DruidExpression.fromExpression("parse_long(\"hexstr\")"),
|
||||||
|
NullHandling.sqlCompatible() ? null : 0L
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPosition()
|
public void testPosition()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue