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
|
||||
{
|
||||
private static final double PI = Math.PI;
|
||||
|
|
|
@ -69,6 +69,7 @@ The following built-in functions are available.
|
|||
|concat|concatenate a list of strings|
|
||||
|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)|
|
||||
|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.|
|
||||
|replace|replace(expr, pattern, replacement) replaces pattern with replacement|
|
||||
|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`.|
|
||||
|`LOOKUP(expr, lookupName)`|Look up expr in a registered [query-time lookup table](lookups.html).|
|
||||
|`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.|
|
||||
|`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.|
|
||||
|
|
|
@ -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.LikeOperatorConversion;
|
||||
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.RTrimOperatorConversion;
|
||||
import org.apache.druid.sql.calcite.expression.builtin.RegexpExtractOperatorConversion;
|
||||
|
@ -172,6 +173,7 @@ public class DruidOperatorTable implements SqlOperatorTable
|
|||
.add(new PositionOperatorConversion())
|
||||
.add(new RegexpExtractOperatorConversion())
|
||||
.add(new RTrimOperatorConversion())
|
||||
.add(new ParseLongOperatorConversion())
|
||||
.add(new StrposOperatorConversion())
|
||||
.add(new SubstringOperatorConversion())
|
||||
.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.segment.column.ValueType;
|
||||
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.StrposOperatorConversion;
|
||||
import org.apache.druid.sql.calcite.expression.builtin.TimeExtractOperatorConversion;
|
||||
|
@ -83,6 +84,8 @@ public class ExpressionsTest extends CalciteTestBase
|
|||
.add("y", ValueType.LONG)
|
||||
.add("z", ValueType.FLOAT)
|
||||
.add("s", ValueType.STRING)
|
||||
.add("hexstr", ValueType.STRING)
|
||||
.add("intstr", ValueType.STRING)
|
||||
.add("spacey", ValueType.STRING)
|
||||
.add("tstr", ValueType.STRING)
|
||||
.add("dstr", ValueType.STRING)
|
||||
|
@ -95,6 +98,8 @@ public class ExpressionsTest extends CalciteTestBase
|
|||
.put("y", 3.0)
|
||||
.put("z", -2.25)
|
||||
.put("s", "foo")
|
||||
.put("hexstr", "EF")
|
||||
.put("intstr", "-100")
|
||||
.put("spacey", " hey there ")
|
||||
.put("tstr", "2000-02-03 04:05:06")
|
||||
.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
|
||||
public void testPosition()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue