mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-25 09:28:27 +00:00
SQL: Functions enhancements (OCTET_LENGTH function, order functions alphabetically, RANDOM function docs) (#34101)
* New OCTET_LENGTH function * Changed the way the FunctionRegistry stores functions, considering the alphabetic ordering by name * Added documentation for the RANDOM function
This commit is contained in:
parent
9e522d5d97
commit
d7a94fb6aa
@ -276,6 +276,30 @@ include-tagged::{sql-specs}/docs.csv-spec[mathInlinePowerPositive]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[mathInlinePowerNegative]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-math-random]]
|
||||
===== `RANDOM`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
RANDOM(seed<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> numeric expression
|
||||
|
||||
*Output*: double numeric value
|
||||
|
||||
.Description:
|
||||
|
||||
Returns a random double using the given seed.
|
||||
|
||||
["source","sql",subs="attributes,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/docs.csv-spec[mathRandom]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-math-round]]
|
||||
===== `ROUND`
|
||||
|
||||
|
@ -271,6 +271,29 @@ Returns the characters of `string_exp`, with leading blanks removed.
|
||||
include-tagged::{sql-specs}/docs.csv-spec[stringLTrim]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-string-octet-length]]
|
||||
==== `OCTET_LENGTH`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
OCTET_LENGTH(string_exp<1>)
|
||||
--------------------------------------------------
|
||||
*Input*:
|
||||
|
||||
<1> string expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Returns the length in bytes of the `string_exp` input expression.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/docs.csv-spec[stringOctetLength]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-string-position]]
|
||||
==== `POSITION`
|
||||
|
||||
|
@ -202,8 +202,7 @@ class JdbcDatabaseMetaData implements DatabaseMetaData, JdbcWrapper {
|
||||
+ "CHAR,CHAR_LENGTH,CHARACTER_LENGTH,CONCAT,"
|
||||
+ "INSERT,"
|
||||
+ "LCASE,LEFT,LENGTH,LOCATE,LTRIM,"
|
||||
// waiting on https://github.com/elastic/elasticsearch/issues/33477
|
||||
//+ "OCTET_LENGTH,"
|
||||
+ "OCTET_LENGTH,"
|
||||
+ "POSITION,"
|
||||
+ "REPEAT,REPLACE,RIGHT,RTRIM,"
|
||||
+ "SPACE,SUBSTRING,"
|
||||
|
@ -72,6 +72,7 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.string.LTrim;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Left;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Length;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Locate;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.OctetLength;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Position;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.RTrim;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Repeat;
|
||||
@ -92,124 +93,143 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class FunctionRegistry {
|
||||
private static final List<FunctionDefinition> DEFAULT_FUNCTIONS = unmodifiableList(Arrays.asList(
|
||||
// Aggregate functions
|
||||
def(Avg.class, Avg::new),
|
||||
def(Count.class, Count::new),
|
||||
def(Max.class, Max::new),
|
||||
def(Min.class, Min::new),
|
||||
def(Sum.class, Sum::new),
|
||||
// Statistics
|
||||
def(StddevPop.class, StddevPop::new),
|
||||
def(VarPop.class, VarPop::new),
|
||||
def(Percentile.class, Percentile::new),
|
||||
def(PercentileRank.class, PercentileRank::new),
|
||||
def(SumOfSquares.class, SumOfSquares::new),
|
||||
def(Skewness.class, Skewness::new),
|
||||
def(Kurtosis.class, Kurtosis::new),
|
||||
// Scalar functions
|
||||
// Date
|
||||
def(DayName.class, DayName::new, "DAYNAME"),
|
||||
def(DayOfMonth.class, DayOfMonth::new, "DAYOFMONTH", "DAY", "DOM"),
|
||||
def(DayOfWeek.class, DayOfWeek::new, "DAYOFWEEK", "DOW"),
|
||||
def(DayOfYear.class, DayOfYear::new, "DAYOFYEAR", "DOY"),
|
||||
def(HourOfDay.class, HourOfDay::new, "HOUR"),
|
||||
def(MinuteOfDay.class, MinuteOfDay::new),
|
||||
def(MinuteOfHour.class, MinuteOfHour::new, "MINUTE"),
|
||||
def(MonthName.class, MonthName::new, "MONTHNAME"),
|
||||
def(MonthOfYear.class, MonthOfYear::new, "MONTH"),
|
||||
def(SecondOfMinute.class, SecondOfMinute::new, "SECOND"),
|
||||
def(Quarter.class, Quarter::new),
|
||||
def(Year.class, Year::new),
|
||||
def(WeekOfYear.class, WeekOfYear::new, "WEEK"),
|
||||
// Math
|
||||
def(Abs.class, Abs::new),
|
||||
def(ACos.class, ACos::new),
|
||||
def(ASin.class, ASin::new),
|
||||
def(ATan.class, ATan::new),
|
||||
def(ATan2.class, ATan2::new),
|
||||
def(Cbrt.class, Cbrt::new),
|
||||
def(Ceil.class, Ceil::new, "CEILING"),
|
||||
def(Cos.class, Cos::new),
|
||||
def(Cosh.class, Cosh::new),
|
||||
def(Cot.class, Cot::new),
|
||||
def(Degrees.class, Degrees::new),
|
||||
def(E.class, E::new),
|
||||
def(Exp.class, Exp::new),
|
||||
def(Expm1.class, Expm1::new),
|
||||
def(Floor.class, Floor::new),
|
||||
def(Log.class, Log::new),
|
||||
def(Log10.class, Log10::new),
|
||||
// SQL and ODBC require MOD as a _function_
|
||||
def(Mod.class, Mod::new),
|
||||
def(Pi.class, Pi::new),
|
||||
def(Power.class, Power::new),
|
||||
def(Radians.class, Radians::new),
|
||||
def(Random.class, Random::new, "RAND"),
|
||||
def(Round.class, Round::new),
|
||||
def(Sign.class, Sign::new, "SIGNUM"),
|
||||
def(Sin.class, Sin::new),
|
||||
def(Sinh.class, Sinh::new),
|
||||
def(Sqrt.class, Sqrt::new),
|
||||
def(Tan.class, Tan::new),
|
||||
def(Truncate.class, Truncate::new),
|
||||
// String
|
||||
def(Ascii.class, Ascii::new),
|
||||
def(BitLength.class, BitLength::new),
|
||||
def(Char.class, Char::new),
|
||||
def(CharLength.class, CharLength::new, "CHARACTER_LENGTH"),
|
||||
def(Concat.class, Concat::new),
|
||||
def(Insert.class, Insert::new),
|
||||
def(LCase.class, LCase::new),
|
||||
def(Left.class, Left::new),
|
||||
def(Length.class, Length::new),
|
||||
def(Locate.class, Locate::new),
|
||||
def(LTrim.class, LTrim::new),
|
||||
def(Position.class, Position::new),
|
||||
def(Repeat.class, Repeat::new),
|
||||
def(Replace.class, Replace::new),
|
||||
def(Right.class, Right::new),
|
||||
def(RTrim.class, RTrim::new),
|
||||
def(Space.class, Space::new),
|
||||
def(Substring.class, Substring::new),
|
||||
def(UCase.class, UCase::new),
|
||||
// Special
|
||||
def(Score.class, Score::new)));
|
||||
|
||||
// list of functions grouped by type of functions (aggregate, statistics, math etc) and ordered alphabetically inside each group
|
||||
// a single function will have one entry for itself with its name associated to its instance and, also, one entry for each alias
|
||||
// it has with the alias name associated to the FunctionDefinition instance
|
||||
private final Map<String, FunctionDefinition> defs = new LinkedHashMap<>();
|
||||
private final Map<String, String> aliases;
|
||||
private final Map<String, String> aliases = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructor to build with the default list of functions.
|
||||
*/
|
||||
public FunctionRegistry() {
|
||||
this(DEFAULT_FUNCTIONS);
|
||||
defineDefaultFunctions();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor specifying alternate functions for testing.
|
||||
*/
|
||||
FunctionRegistry(List<FunctionDefinition> functions) {
|
||||
this.aliases = new HashMap<>();
|
||||
FunctionRegistry(FunctionDefinition... functions) {
|
||||
addToMap(functions);
|
||||
}
|
||||
|
||||
private void defineDefaultFunctions() {
|
||||
// Aggregate functions
|
||||
addToMap(def(Avg.class, Avg::new),
|
||||
def(Count.class, Count::new),
|
||||
def(Max.class, Max::new),
|
||||
def(Min.class, Min::new),
|
||||
def(Sum.class, Sum::new));
|
||||
// Statistics
|
||||
addToMap(def(StddevPop.class, StddevPop::new),
|
||||
def(VarPop.class, VarPop::new),
|
||||
def(Percentile.class, Percentile::new),
|
||||
def(PercentileRank.class, PercentileRank::new),
|
||||
def(SumOfSquares.class, SumOfSquares::new),
|
||||
def(Skewness.class, Skewness::new),
|
||||
def(Kurtosis.class, Kurtosis::new));
|
||||
// Scalar functions
|
||||
// Date
|
||||
addToMap(def(DayName.class, DayName::new, "DAYNAME"),
|
||||
def(DayOfMonth.class, DayOfMonth::new, "DAYOFMONTH", "DAY", "DOM"),
|
||||
def(DayOfWeek.class, DayOfWeek::new, "DAYOFWEEK", "DOW"),
|
||||
def(DayOfYear.class, DayOfYear::new, "DAYOFYEAR", "DOY"),
|
||||
def(HourOfDay.class, HourOfDay::new, "HOUR"),
|
||||
def(MinuteOfDay.class, MinuteOfDay::new),
|
||||
def(MinuteOfHour.class, MinuteOfHour::new, "MINUTE"),
|
||||
def(MonthName.class, MonthName::new, "MONTHNAME"),
|
||||
def(MonthOfYear.class, MonthOfYear::new, "MONTH"),
|
||||
def(SecondOfMinute.class, SecondOfMinute::new, "SECOND"),
|
||||
def(Quarter.class, Quarter::new),
|
||||
def(Year.class, Year::new),
|
||||
def(WeekOfYear.class, WeekOfYear::new, "WEEK"));
|
||||
// Math
|
||||
addToMap(def(Abs.class, Abs::new),
|
||||
def(ACos.class, ACos::new),
|
||||
def(ASin.class, ASin::new),
|
||||
def(ATan.class, ATan::new),
|
||||
def(ATan2.class, ATan2::new),
|
||||
def(Cbrt.class, Cbrt::new),
|
||||
def(Ceil.class, Ceil::new, "CEILING"),
|
||||
def(Cos.class, Cos::new),
|
||||
def(Cosh.class, Cosh::new),
|
||||
def(Cot.class, Cot::new),
|
||||
def(Degrees.class, Degrees::new),
|
||||
def(E.class, E::new),
|
||||
def(Exp.class, Exp::new),
|
||||
def(Expm1.class, Expm1::new),
|
||||
def(Floor.class, Floor::new),
|
||||
def(Log.class, Log::new),
|
||||
def(Log10.class, Log10::new),
|
||||
// SQL and ODBC require MOD as a _function_
|
||||
def(Mod.class, Mod::new),
|
||||
def(Pi.class, Pi::new),
|
||||
def(Power.class, Power::new),
|
||||
def(Radians.class, Radians::new),
|
||||
def(Random.class, Random::new, "RAND"),
|
||||
def(Round.class, Round::new),
|
||||
def(Sign.class, Sign::new, "SIGNUM"),
|
||||
def(Sin.class, Sin::new),
|
||||
def(Sinh.class, Sinh::new),
|
||||
def(Sqrt.class, Sqrt::new),
|
||||
def(Tan.class, Tan::new),
|
||||
def(Truncate.class, Truncate::new));
|
||||
// String
|
||||
addToMap(def(Ascii.class, Ascii::new),
|
||||
def(BitLength.class, BitLength::new),
|
||||
def(Char.class, Char::new),
|
||||
def(CharLength.class, CharLength::new, "CHARACTER_LENGTH"),
|
||||
def(Concat.class, Concat::new),
|
||||
def(Insert.class, Insert::new),
|
||||
def(LCase.class, LCase::new),
|
||||
def(Left.class, Left::new),
|
||||
def(Length.class, Length::new),
|
||||
def(Locate.class, Locate::new),
|
||||
def(LTrim.class, LTrim::new),
|
||||
def(OctetLength.class, OctetLength::new),
|
||||
def(Position.class, Position::new),
|
||||
def(Repeat.class, Repeat::new),
|
||||
def(Replace.class, Replace::new),
|
||||
def(Right.class, Right::new),
|
||||
def(RTrim.class, RTrim::new),
|
||||
def(Space.class, Space::new),
|
||||
def(Substring.class, Substring::new),
|
||||
def(UCase.class, UCase::new));
|
||||
// Special
|
||||
addToMap(def(Score.class, Score::new));
|
||||
}
|
||||
|
||||
protected void addToMap(FunctionDefinition...functions) {
|
||||
// temporary map to hold [function_name/alias_name : function instance]
|
||||
Map<String, FunctionDefinition> batchMap = new HashMap<>();
|
||||
for (FunctionDefinition f : functions) {
|
||||
defs.put(f.name(), f);
|
||||
batchMap.put(f.name(), f);
|
||||
for (String alias : f.aliases()) {
|
||||
Object old = aliases.put(alias, f.name());
|
||||
if (old != null) {
|
||||
throw new IllegalArgumentException("alias [" + alias + "] is used by [" + old + "] and [" + f.name() + "]");
|
||||
Object old = batchMap.put(alias, f);
|
||||
if (old != null || defs.containsKey(alias)) {
|
||||
throw new IllegalArgumentException("alias [" + alias + "] is used by "
|
||||
+ "[" + (old != null ? old : defs.get(alias).name()) + "] and [" + f.name() + "]");
|
||||
}
|
||||
defs.put(alias, f);
|
||||
aliases.put(alias, f.name());
|
||||
}
|
||||
}
|
||||
// sort the temporary map by key name and add it to the global map of functions
|
||||
defs.putAll(batchMap.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.collect(Collectors.<Entry<String, FunctionDefinition>, String,
|
||||
FunctionDefinition, LinkedHashMap<String, FunctionDefinition>> toMap(Map.Entry::getKey, Map.Entry::getValue,
|
||||
(oldValue, newValue) -> oldValue, LinkedHashMap::new)));
|
||||
}
|
||||
|
||||
public FunctionDefinition resolveFunction(String functionName) {
|
||||
|
@ -12,7 +12,7 @@ import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
/**
|
||||
* Returns returns the number of bits contained within the value expression.
|
||||
* Returns the number of bits contained within the value expression.
|
||||
*/
|
||||
public class BitLength extends UnaryStringFunction {
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.string;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor.StringOperation;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
/**
|
||||
* Returns the number of bytes contained within the value expression.
|
||||
*/
|
||||
public class OctetLength extends UnaryStringFunction {
|
||||
|
||||
public OctetLength(Location location, Expression field) {
|
||||
super(location, field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeInfo<OctetLength> info() {
|
||||
return NodeInfo.create(this, OctetLength::new, field());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OctetLength replaceChild(Expression newChild) {
|
||||
return new OctetLength(location(), newChild);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StringOperation operation() {
|
||||
return StringOperation.OCTET_LENGTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
return DataType.INTEGER;
|
||||
}
|
||||
}
|
@ -65,6 +65,7 @@ public class StringProcessor implements Processor {
|
||||
return new String(spaces);
|
||||
}),
|
||||
BIT_LENGTH((String s) -> UnicodeUtil.calcUTF16toUTF8Length(s, 0, s.length()) * 8),
|
||||
OCTET_LENGTH((String s) -> UnicodeUtil.calcUTF16toUTF8Length(s, 0, s.length())),
|
||||
CHAR_LENGTH(String::length);
|
||||
|
||||
private final Function<Object, Object> apply;
|
||||
|
@ -43,6 +43,14 @@ public final class InternalSqlScriptUtils {
|
||||
return QuarterProcessor.quarter(millis, tzId);
|
||||
}
|
||||
|
||||
public static Number round(Number v, Number s) {
|
||||
return BinaryMathOperation.ROUND.apply(v, s);
|
||||
}
|
||||
|
||||
public static Number truncate(Number v, Number s) {
|
||||
return BinaryMathOperation.TRUNCATE.apply(v, s);
|
||||
}
|
||||
|
||||
public static Integer ascii(String s) {
|
||||
return (Integer) StringOperation.ASCII.apply(s);
|
||||
}
|
||||
@ -59,75 +67,71 @@ public final class InternalSqlScriptUtils {
|
||||
return (Integer) StringOperation.CHAR_LENGTH.apply(s);
|
||||
}
|
||||
|
||||
public static String lcase(String s) {
|
||||
return (String) StringOperation.LCASE.apply(s);
|
||||
}
|
||||
|
||||
public static String ucase(String s) {
|
||||
return (String) StringOperation.UCASE.apply(s);
|
||||
}
|
||||
|
||||
public static Integer length(String s) {
|
||||
return (Integer) StringOperation.LENGTH.apply(s);
|
||||
}
|
||||
|
||||
public static String rtrim(String s) {
|
||||
return (String) StringOperation.RTRIM.apply(s);
|
||||
}
|
||||
|
||||
public static String ltrim(String s) {
|
||||
return (String) StringOperation.LTRIM.apply(s);
|
||||
}
|
||||
|
||||
public static String space(Number n) {
|
||||
return (String) StringOperation.SPACE.apply(n);
|
||||
}
|
||||
|
||||
public static String left(String s, int count) {
|
||||
return BinaryStringNumericOperation.LEFT.apply(s, count);
|
||||
}
|
||||
|
||||
public static String right(String s, int count) {
|
||||
return BinaryStringNumericOperation.RIGHT.apply(s, count);
|
||||
}
|
||||
|
||||
public static String concat(String s1, String s2) {
|
||||
return ConcatFunctionProcessor.doProcessInScripts(s1, s2).toString();
|
||||
}
|
||||
|
||||
public static String repeat(String s, int count) {
|
||||
return BinaryStringNumericOperation.REPEAT.apply(s, count);
|
||||
}
|
||||
|
||||
public static Integer position(String s1, String s2) {
|
||||
return (Integer) BinaryStringStringOperation.POSITION.apply(s1, s2);
|
||||
}
|
||||
|
||||
public static String insert(String s, int start, int length, String r) {
|
||||
return InsertFunctionProcessor.doProcess(s, start, length, r).toString();
|
||||
}
|
||||
|
||||
public static String substring(String s, int start, int length) {
|
||||
return SubstringFunctionProcessor.doProcess(s, start, length).toString();
|
||||
public static String lcase(String s) {
|
||||
return (String) StringOperation.LCASE.apply(s);
|
||||
}
|
||||
|
||||
public static String replace(String s1, String s2, String s3) {
|
||||
return ReplaceFunctionProcessor.doProcess(s1, s2, s3).toString();
|
||||
public static String left(String s, int count) {
|
||||
return BinaryStringNumericOperation.LEFT.apply(s, count);
|
||||
}
|
||||
|
||||
public static Integer locate(String s1, String s2, Integer pos) {
|
||||
return (Integer) LocateFunctionProcessor.doProcess(s1, s2, pos);
|
||||
public static Integer length(String s) {
|
||||
return (Integer) StringOperation.LENGTH.apply(s);
|
||||
}
|
||||
|
||||
public static Integer locate(String s1, String s2) {
|
||||
return locate(s1, s2, null);
|
||||
}
|
||||
|
||||
public static Number round(Number v, Number s) {
|
||||
return BinaryMathOperation.ROUND.apply(v, s);
|
||||
public static Integer locate(String s1, String s2, Integer pos) {
|
||||
return (Integer) LocateFunctionProcessor.doProcess(s1, s2, pos);
|
||||
}
|
||||
|
||||
public static Number truncate(Number v, Number s) {
|
||||
return BinaryMathOperation.TRUNCATE.apply(v, s);
|
||||
public static String ltrim(String s) {
|
||||
return (String) StringOperation.LTRIM.apply(s);
|
||||
}
|
||||
|
||||
public static Integer octetLength(String s) {
|
||||
return (Integer) StringOperation.OCTET_LENGTH.apply(s);
|
||||
}
|
||||
|
||||
public static Integer position(String s1, String s2) {
|
||||
return (Integer) BinaryStringStringOperation.POSITION.apply(s1, s2);
|
||||
}
|
||||
|
||||
public static String repeat(String s, int count) {
|
||||
return BinaryStringNumericOperation.REPEAT.apply(s, count);
|
||||
}
|
||||
|
||||
public static String replace(String s1, String s2, String s3) {
|
||||
return ReplaceFunctionProcessor.doProcess(s1, s2, s3).toString();
|
||||
}
|
||||
|
||||
public static String right(String s, int count) {
|
||||
return BinaryStringNumericOperation.RIGHT.apply(s, count);
|
||||
}
|
||||
|
||||
public static String rtrim(String s) {
|
||||
return (String) StringOperation.RTRIM.apply(s);
|
||||
}
|
||||
|
||||
public static String space(Number n) {
|
||||
return (String) StringOperation.SPACE.apply(n);
|
||||
}
|
||||
|
||||
public static String substring(String s, int start, int length) {
|
||||
return SubstringFunctionProcessor.doProcess(s, start, length).toString();
|
||||
}
|
||||
|
||||
public static String ucase(String s) {
|
||||
return (String) StringOperation.UCASE.apply(s);
|
||||
}
|
||||
}
|
@ -16,8 +16,8 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS
|
||||
Number truncate(Number, Number)
|
||||
Integer ascii(String)
|
||||
Integer bitLength(String)
|
||||
Integer charLength(String)
|
||||
String character(Number)
|
||||
Integer charLength(String)
|
||||
String concat(String, String)
|
||||
String insert(String, int, int, String)
|
||||
String lcase(String)
|
||||
@ -26,6 +26,7 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS
|
||||
Integer locate(String, String)
|
||||
Integer locate(String, String, Integer)
|
||||
String ltrim(String)
|
||||
Integer octetLength(String)
|
||||
Integer position(String, String)
|
||||
String repeat(String, int)
|
||||
String replace(String, String, String)
|
||||
|
@ -18,7 +18,6 @@ import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@ -34,7 +33,7 @@ import static org.mockito.Mockito.mock;
|
||||
public class FunctionRegistryTests extends ESTestCase {
|
||||
public void testNoArgFunction() {
|
||||
UnresolvedFunction ur = uf(STANDARD);
|
||||
FunctionRegistry r = new FunctionRegistry(Collections.singletonList(def(DummyFunction.class, DummyFunction::new)));
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new));
|
||||
FunctionDefinition def = r.resolveFunction(ur.name());
|
||||
assertEquals(ur.location(), ur.buildResolved(randomTimeZone(), def).location());
|
||||
|
||||
@ -51,11 +50,10 @@ public class FunctionRegistryTests extends ESTestCase {
|
||||
|
||||
public void testUnaryFunction() {
|
||||
UnresolvedFunction ur = uf(STANDARD, mock(Expression.class));
|
||||
FunctionRegistry r = new FunctionRegistry(Collections.singletonList(
|
||||
def(DummyFunction.class, (Location l, Expression e) -> {
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Location l, Expression e) -> {
|
||||
assertSame(e, ur.children().get(0));
|
||||
return new DummyFunction(l);
|
||||
})));
|
||||
}));
|
||||
FunctionDefinition def = r.resolveFunction(ur.name());
|
||||
assertFalse(def.datetime());
|
||||
assertEquals(ur.location(), ur.buildResolved(randomTimeZone(), def).location());
|
||||
@ -79,12 +77,11 @@ public class FunctionRegistryTests extends ESTestCase {
|
||||
public void testUnaryDistinctAwareFunction() {
|
||||
boolean urIsDistinct = randomBoolean();
|
||||
UnresolvedFunction ur = uf(urIsDistinct ? DISTINCT : STANDARD, mock(Expression.class));
|
||||
FunctionRegistry r = new FunctionRegistry(Collections.singletonList(
|
||||
def(DummyFunction.class, (Location l, Expression e, boolean distinct) -> {
|
||||
assertEquals(urIsDistinct, distinct);
|
||||
assertSame(e, ur.children().get(0));
|
||||
return new DummyFunction(l);
|
||||
})));
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Location l, Expression e, boolean distinct) -> {
|
||||
assertEquals(urIsDistinct, distinct);
|
||||
assertSame(e, ur.children().get(0));
|
||||
return new DummyFunction(l);
|
||||
}));
|
||||
FunctionDefinition def = r.resolveFunction(ur.name());
|
||||
assertEquals(ur.location(), ur.buildResolved(randomTimeZone(), def).location());
|
||||
assertFalse(def.datetime());
|
||||
@ -104,12 +101,11 @@ public class FunctionRegistryTests extends ESTestCase {
|
||||
boolean urIsExtract = randomBoolean();
|
||||
UnresolvedFunction ur = uf(urIsExtract ? EXTRACT : STANDARD, mock(Expression.class));
|
||||
TimeZone providedTimeZone = randomTimeZone();
|
||||
FunctionRegistry r = new FunctionRegistry(Collections.singletonList(
|
||||
def(DummyFunction.class, (Location l, Expression e, TimeZone tz) -> {
|
||||
assertEquals(providedTimeZone, tz);
|
||||
assertSame(e, ur.children().get(0));
|
||||
return new DummyFunction(l);
|
||||
})));
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Location l, Expression e, TimeZone tz) -> {
|
||||
assertEquals(providedTimeZone, tz);
|
||||
assertSame(e, ur.children().get(0));
|
||||
return new DummyFunction(l);
|
||||
}));
|
||||
FunctionDefinition def = r.resolveFunction(ur.name());
|
||||
assertEquals(ur.location(), ur.buildResolved(providedTimeZone, def).location());
|
||||
assertTrue(def.datetime());
|
||||
@ -132,12 +128,11 @@ public class FunctionRegistryTests extends ESTestCase {
|
||||
|
||||
public void testBinaryFunction() {
|
||||
UnresolvedFunction ur = uf(STANDARD, mock(Expression.class), mock(Expression.class));
|
||||
FunctionRegistry r = new FunctionRegistry(Collections.singletonList(
|
||||
def(DummyFunction.class, (Location l, Expression lhs, Expression rhs) -> {
|
||||
assertSame(lhs, ur.children().get(0));
|
||||
assertSame(rhs, ur.children().get(1));
|
||||
return new DummyFunction(l);
|
||||
})));
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Location l, Expression lhs, Expression rhs) -> {
|
||||
assertSame(lhs, ur.children().get(0));
|
||||
assertSame(rhs, ur.children().get(1));
|
||||
return new DummyFunction(l);
|
||||
}));
|
||||
FunctionDefinition def = r.resolveFunction(ur.name());
|
||||
assertEquals(ur.location(), ur.buildResolved(randomTimeZone(), def).location());
|
||||
assertFalse(def.datetime());
|
||||
@ -163,14 +158,34 @@ public class FunctionRegistryTests extends ESTestCase {
|
||||
.buildResolved(randomTimeZone(), def));
|
||||
assertThat(e.getMessage(), endsWith("expects exactly two arguments"));
|
||||
}
|
||||
|
||||
public void testAliasNameIsTheSameAsAFunctionName() {
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "ALIAS"));
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
|
||||
r.addToMap(def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION")));
|
||||
assertEquals(iae.getMessage(), "alias [DUMMY_FUNCTION] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]");
|
||||
}
|
||||
|
||||
public void testDuplicateAliasInTwoDifferentFunctionsFromTheSameBatch() {
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
|
||||
new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "ALIAS"),
|
||||
def(DummyFunction2.class, DummyFunction2::new, "ALIAS")));
|
||||
assertEquals(iae.getMessage(), "alias [ALIAS] is used by [DUMMY_FUNCTION(ALIAS)] and [DUMMY_FUNCTION2]");
|
||||
}
|
||||
|
||||
public void testDuplicateAliasInTwoDifferentFunctionsFromTwoDifferentBatches() {
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "ALIAS"));
|
||||
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () ->
|
||||
r.addToMap(def(DummyFunction2.class, DummyFunction2::new, "ALIAS")));
|
||||
assertEquals(iae.getMessage(), "alias [ALIAS] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]");
|
||||
}
|
||||
|
||||
public void testFunctionResolving() {
|
||||
UnresolvedFunction ur = uf(STANDARD, mock(Expression.class));
|
||||
FunctionRegistry r = new FunctionRegistry(
|
||||
Collections.singletonList(def(DummyFunction.class, (Location l, Expression e) -> {
|
||||
FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Location l, Expression e) -> {
|
||||
assertSame(e, ur.children().get(0));
|
||||
return new DummyFunction(l);
|
||||
}, "DUMMY_FUNC")));
|
||||
}, "DUMMY_FUNC"));
|
||||
|
||||
// Resolve by primary name
|
||||
FunctionDefinition def = r.resolveFunction(r.resolveAlias("DuMMy_FuncTIon"));
|
||||
@ -241,4 +256,10 @@ public class FunctionRegistryTests extends ESTestCase {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DummyFunction2 extends DummyFunction {
|
||||
public DummyFunction2(Location location) {
|
||||
super(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -202,4 +202,17 @@ public class StringFunctionProcessorTests extends AbstractWireSerializingTestCas
|
||||
|
||||
stringCharInputValidation(proc);
|
||||
}
|
||||
|
||||
public void testOctetLength() {
|
||||
StringProcessor proc = new StringProcessor(StringOperation.OCTET_LENGTH);
|
||||
assertNull(proc.process(null));
|
||||
assertEquals(7, proc.process("foo bar"));
|
||||
assertEquals(0, proc.process(""));
|
||||
assertEquals(1, proc.process('f'));
|
||||
assertEquals(3, proc.process('\u20ac')); // euro symbol
|
||||
// euro (3), lamda (2), theta (2), 'white sun with rays' (3), math 'A' (4) symbols
|
||||
assertEquals(14, proc.process("\u20ac\u039B\u03F4\u263C\u1D400"));
|
||||
|
||||
stringCharInputValidation(proc);
|
||||
}
|
||||
}
|
||||
|
@ -59,15 +59,15 @@ public abstract class ShowTestCase extends CliIntegrationTestCase {
|
||||
public void testShowFunctionsLikeInfix() throws IOException {
|
||||
assertThat(command("SHOW FUNCTIONS LIKE '%DAY%'"), RegexMatcher.matches("\\s*name\\s*\\|\\s*type\\s*"));
|
||||
assertThat(readLine(), containsString("----------"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_NAME\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAYNAME\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_OF_MONTH\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAYOFMONTH\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_OF_WEEK\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAYNAME\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAYOFMONTH\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAYOFWEEK\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_OF_YEAR\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAYOFYEAR\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_NAME\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_OF_MONTH\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_OF_WEEK\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_OF_YEAR\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*HOUR_OF_DAY\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*MINUTE_OF_DAY\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertEquals("", readLine());
|
||||
|
@ -12,40 +12,40 @@ COUNT |AGGREGATE
|
||||
MAX |AGGREGATE
|
||||
MIN |AGGREGATE
|
||||
SUM |AGGREGATE
|
||||
STDDEV_POP |AGGREGATE
|
||||
VAR_POP |AGGREGATE
|
||||
KURTOSIS |AGGREGATE
|
||||
PERCENTILE |AGGREGATE
|
||||
PERCENTILE_RANK |AGGREGATE
|
||||
SUM_OF_SQUARES |AGGREGATE
|
||||
SKEWNESS |AGGREGATE
|
||||
KURTOSIS |AGGREGATE
|
||||
DAY_NAME |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAY_OF_MONTH |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
STDDEV_POP |AGGREGATE
|
||||
SUM_OF_SQUARES |AGGREGATE
|
||||
VAR_POP |AGGREGATE
|
||||
DAY |SCALAR
|
||||
DOM |SCALAR
|
||||
DAY_OF_WEEK |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
DAYOFWEEK |SCALAR
|
||||
DOW |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
DAYOFYEAR |SCALAR
|
||||
DAY_NAME |SCALAR
|
||||
DAY_OF_MONTH |SCALAR
|
||||
DAY_OF_WEEK |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
DOM |SCALAR
|
||||
DOW |SCALAR
|
||||
DOY |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
HOUR |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
MINUTE |SCALAR
|
||||
MINUTE_OF_DAY |SCALAR
|
||||
MINUTE_OF_HOUR |SCALAR
|
||||
MINUTE |SCALAR
|
||||
MONTH_NAME |SCALAR
|
||||
MONTHNAME |SCALAR
|
||||
MONTH_OF_YEAR |SCALAR
|
||||
MONTH |SCALAR
|
||||
SECOND_OF_MINUTE|SCALAR
|
||||
SECOND |SCALAR
|
||||
MONTHNAME |SCALAR
|
||||
MONTH_NAME |SCALAR
|
||||
MONTH_OF_YEAR |SCALAR
|
||||
QUARTER |SCALAR
|
||||
YEAR |SCALAR
|
||||
SECOND |SCALAR
|
||||
SECOND_OF_MINUTE|SCALAR
|
||||
WEEK |SCALAR
|
||||
WEEK_OF_YEAR |SCALAR
|
||||
WEEK |SCALAR
|
||||
YEAR |SCALAR
|
||||
ABS |SCALAR
|
||||
ACOS |SCALAR
|
||||
ASIN |SCALAR
|
||||
@ -68,8 +68,8 @@ MOD |SCALAR
|
||||
PI |SCALAR
|
||||
POWER |SCALAR
|
||||
RADIANS |SCALAR
|
||||
RANDOM |SCALAR
|
||||
RAND |SCALAR
|
||||
RANDOM |SCALAR
|
||||
ROUND |SCALAR
|
||||
SIGN |SCALAR
|
||||
SIGNUM |SCALAR
|
||||
@ -81,21 +81,22 @@ TRUNCATE |SCALAR
|
||||
ASCII |SCALAR
|
||||
BIT_LENGTH |SCALAR
|
||||
CHAR |SCALAR
|
||||
CHAR_LENGTH |SCALAR
|
||||
CHARACTER_LENGTH|SCALAR
|
||||
CONCAT |SCALAR
|
||||
INSERT |SCALAR
|
||||
CHAR_LENGTH |SCALAR
|
||||
CONCAT |SCALAR
|
||||
INSERT |SCALAR
|
||||
LCASE |SCALAR
|
||||
LEFT |SCALAR
|
||||
LENGTH |SCALAR
|
||||
LOCATE |SCALAR
|
||||
LTRIM |SCALAR
|
||||
OCTET_LENGTH |SCALAR
|
||||
POSITION |SCALAR
|
||||
REPEAT |SCALAR
|
||||
REPLACE |SCALAR
|
||||
RIGHT |SCALAR
|
||||
RIGHT |SCALAR
|
||||
RTRIM |SCALAR
|
||||
SPACE |SCALAR
|
||||
SPACE |SCALAR
|
||||
SUBSTRING |SCALAR
|
||||
UCASE |SCALAR
|
||||
SCORE |SCORE
|
||||
@ -134,15 +135,15 @@ showFunctionsWithLeadingPattern
|
||||
SHOW FUNCTIONS LIKE '%DAY%';
|
||||
|
||||
name:s | type:s
|
||||
DAY_NAME |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAY_OF_MONTH |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
DAY |SCALAR
|
||||
DAY_OF_WEEK |SCALAR
|
||||
DAYOFWEEK |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
DAYOFYEAR |SCALAR
|
||||
DAY |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
DAYOFWEEK |SCALAR
|
||||
DAYOFYEAR |SCALAR
|
||||
DAY_NAME |SCALAR
|
||||
DAY_OF_MONTH |SCALAR
|
||||
DAY_OF_WEEK |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
MINUTE_OF_DAY |SCALAR
|
||||
;
|
||||
|
@ -188,40 +188,40 @@ COUNT |AGGREGATE
|
||||
MAX |AGGREGATE
|
||||
MIN |AGGREGATE
|
||||
SUM |AGGREGATE
|
||||
STDDEV_POP |AGGREGATE
|
||||
VAR_POP |AGGREGATE
|
||||
KURTOSIS |AGGREGATE
|
||||
PERCENTILE |AGGREGATE
|
||||
PERCENTILE_RANK |AGGREGATE
|
||||
SUM_OF_SQUARES |AGGREGATE
|
||||
SKEWNESS |AGGREGATE
|
||||
KURTOSIS |AGGREGATE
|
||||
DAY_NAME |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAY_OF_MONTH |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
STDDEV_POP |AGGREGATE
|
||||
SUM_OF_SQUARES |AGGREGATE
|
||||
VAR_POP |AGGREGATE
|
||||
DAY |SCALAR
|
||||
DOM |SCALAR
|
||||
DAY_OF_WEEK |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
DAYOFWEEK |SCALAR
|
||||
DOW |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
DAYOFYEAR |SCALAR
|
||||
DAY_NAME |SCALAR
|
||||
DAY_OF_MONTH |SCALAR
|
||||
DAY_OF_WEEK |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
DOM |SCALAR
|
||||
DOW |SCALAR
|
||||
DOY |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
HOUR |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
MINUTE |SCALAR
|
||||
MINUTE_OF_DAY |SCALAR
|
||||
MINUTE_OF_HOUR |SCALAR
|
||||
MINUTE |SCALAR
|
||||
MONTH_NAME |SCALAR
|
||||
MONTHNAME |SCALAR
|
||||
MONTH_OF_YEAR |SCALAR
|
||||
MONTH |SCALAR
|
||||
SECOND_OF_MINUTE|SCALAR
|
||||
SECOND |SCALAR
|
||||
MONTHNAME |SCALAR
|
||||
MONTH_NAME |SCALAR
|
||||
MONTH_OF_YEAR |SCALAR
|
||||
QUARTER |SCALAR
|
||||
YEAR |SCALAR
|
||||
SECOND |SCALAR
|
||||
SECOND_OF_MINUTE|SCALAR
|
||||
WEEK |SCALAR
|
||||
WEEK_OF_YEAR |SCALAR
|
||||
WEEK |SCALAR
|
||||
YEAR |SCALAR
|
||||
ABS |SCALAR
|
||||
ACOS |SCALAR
|
||||
ASIN |SCALAR
|
||||
@ -244,8 +244,8 @@ MOD |SCALAR
|
||||
PI |SCALAR
|
||||
POWER |SCALAR
|
||||
RADIANS |SCALAR
|
||||
RANDOM |SCALAR
|
||||
RAND |SCALAR
|
||||
RANDOM |SCALAR
|
||||
ROUND |SCALAR
|
||||
SIGN |SCALAR
|
||||
SIGNUM |SCALAR
|
||||
@ -257,24 +257,25 @@ TRUNCATE |SCALAR
|
||||
ASCII |SCALAR
|
||||
BIT_LENGTH |SCALAR
|
||||
CHAR |SCALAR
|
||||
CHAR_LENGTH |SCALAR
|
||||
CHARACTER_LENGTH|SCALAR
|
||||
CONCAT |SCALAR
|
||||
INSERT |SCALAR
|
||||
CHAR_LENGTH |SCALAR
|
||||
CONCAT |SCALAR
|
||||
INSERT |SCALAR
|
||||
LCASE |SCALAR
|
||||
LEFT |SCALAR
|
||||
LENGTH |SCALAR
|
||||
LOCATE |SCALAR
|
||||
LTRIM |SCALAR
|
||||
OCTET_LENGTH |SCALAR
|
||||
POSITION |SCALAR
|
||||
REPEAT |SCALAR
|
||||
REPLACE |SCALAR
|
||||
RIGHT |SCALAR
|
||||
RIGHT |SCALAR
|
||||
RTRIM |SCALAR
|
||||
SPACE |SCALAR
|
||||
SPACE |SCALAR
|
||||
SUBSTRING |SCALAR
|
||||
UCASE |SCALAR
|
||||
SCORE |SCORE
|
||||
SCORE |SCORE
|
||||
// end::showFunctions
|
||||
;
|
||||
|
||||
@ -322,15 +323,15 @@ SHOW FUNCTIONS LIKE '%DAY%';
|
||||
|
||||
name | type
|
||||
---------------+---------------
|
||||
DAY_NAME |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAY_OF_MONTH |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
DAY |SCALAR
|
||||
DAY_OF_WEEK |SCALAR
|
||||
DAYOFWEEK |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
DAYOFYEAR |SCALAR
|
||||
DAY |SCALAR
|
||||
DAYNAME |SCALAR
|
||||
DAYOFMONTH |SCALAR
|
||||
DAYOFWEEK |SCALAR
|
||||
DAYOFYEAR |SCALAR
|
||||
DAY_NAME |SCALAR
|
||||
DAY_OF_MONTH |SCALAR
|
||||
DAY_OF_WEEK |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
MINUTE_OF_DAY |SCALAR
|
||||
|
||||
@ -1007,6 +1008,16 @@ Elastic
|
||||
// end::stringLTrim
|
||||
;
|
||||
|
||||
stringOctetLength
|
||||
// tag::stringOctetLength
|
||||
SELECT OCTET_LENGTH('Elastic');
|
||||
|
||||
OCTET_LENGTH(Elastic)
|
||||
-------------------
|
||||
7
|
||||
// end::stringOctetLength
|
||||
;
|
||||
|
||||
stringPosition
|
||||
// tag::stringPosition
|
||||
SELECT POSITION('Elastic', 'Elasticsearch');
|
||||
@ -1342,6 +1353,16 @@ SELECT RADIANS(90), PI()/2;
|
||||
// end::mathInlineRadians
|
||||
;
|
||||
|
||||
mathRandom
|
||||
// tag::mathRandom
|
||||
SELECT RANDOM(123);
|
||||
|
||||
RANDOM(123)
|
||||
------------------
|
||||
0.7231742029971469
|
||||
// end::mathRandom
|
||||
;
|
||||
|
||||
mathRoundWithNegativeParameter
|
||||
// tag::mathRoundWithNegativeParameter
|
||||
SELECT ROUND(-345.153, -1) AS rounded;
|
||||
|
@ -366,6 +366,37 @@ bu |1
|
||||
by |1
|
||||
;
|
||||
|
||||
octetLengthGroupByAndOrderBy
|
||||
SELECT OCTET_LENGTH(first_name), COUNT(*) count FROM "test_emp" GROUP BY OCTET_LENGTH(first_name) ORDER BY OCTET_LENGTH(first_name) LIMIT 10;
|
||||
|
||||
OCTET_LENGTH(first_name):i| count:l
|
||||
3 |4
|
||||
4 |11
|
||||
5 |16
|
||||
6 |24
|
||||
7 |19
|
||||
8 |14
|
||||
9 |10
|
||||
10 |1
|
||||
11 |1
|
||||
;
|
||||
|
||||
octetLengthOrderByFieldWithWhere
|
||||
SELECT OCTET_LENGTH(first_name) len, first_name FROM "test_emp" WHERE OCTET_LENGTH(first_name) > 8 ORDER BY first_name LIMIT 10;
|
||||
|
||||
len:i | first_name:s
|
||||
10 |Adamantios
|
||||
9 |Alejandro
|
||||
9 |Alejandro
|
||||
9 |Chirstian
|
||||
9 |Cristinel
|
||||
9 |Duangkaew
|
||||
9 |Eberhardt
|
||||
9 |Margareta
|
||||
9 |Prasadram
|
||||
11 |Sreekrishna
|
||||
;
|
||||
|
||||
upperCasingTheSecondLetterFromTheRightFromFirstName
|
||||
SELECT CONCAT(CONCAT(SUBSTRING("first_name",1,LENGTH("first_name")-2),UCASE(LEFT(RIGHT("first_name",2),1))),RIGHT("first_name",1)) f FROM "test_emp" ORDER BY "first_name" LIMIT 10;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user