Skip to content

Commit 6832248

Browse files
committed
SQL: Adds MONTHNAME, DAYNAME and QUARTER functions (#33411)
* Added monthname, dayname and quarter functions * Updated docs tests with the new functions
1 parent 0b1a7b9 commit 6832248

30 files changed

+838
-110
lines changed

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@
2121
import org.elasticsearch.xpack.sql.expression.function.aggregate.SumOfSquares;
2222
import org.elasticsearch.xpack.sql.expression.function.aggregate.VarPop;
2323
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Mod;
24+
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayName;
2425
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfMonth;
2526
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfWeek;
2627
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfYear;
2728
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.HourOfDay;
2829
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MinuteOfDay;
2930
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MinuteOfHour;
31+
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MonthName;
3032
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MonthOfYear;
33+
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Quarter;
3134
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.SecondOfMinute;
3235
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.WeekOfYear;
3336
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Year;
@@ -62,21 +65,21 @@
6265
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BitLength;
6366
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Char;
6467
import org.elasticsearch.xpack.sql.expression.function.scalar.string.CharLength;
65-
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LCase;
66-
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LTrim;
67-
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Length;
68-
import org.elasticsearch.xpack.sql.expression.function.scalar.string.RTrim;
69-
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Space;
70-
import org.elasticsearch.xpack.sql.expression.function.scalar.string.UCase;
7168
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Concat;
7269
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Insert;
70+
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LCase;
71+
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LTrim;
7372
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Left;
73+
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Length;
7474
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Locate;
7575
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Position;
76+
import org.elasticsearch.xpack.sql.expression.function.scalar.string.RTrim;
7677
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Repeat;
7778
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Replace;
7879
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Right;
80+
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Space;
7981
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Substring;
82+
import org.elasticsearch.xpack.sql.expression.function.scalar.string.UCase;
8083
import org.elasticsearch.xpack.sql.parser.ParsingException;
8184
import org.elasticsearch.xpack.sql.tree.Location;
8285
import org.elasticsearch.xpack.sql.util.StringUtils;
@@ -123,6 +126,9 @@ public class FunctionRegistry {
123126
def(MonthOfYear.class, MonthOfYear::new, "MONTH"),
124127
def(Year.class, Year::new),
125128
def(WeekOfYear.class, WeekOfYear::new, "WEEK"),
129+
def(DayName.class, DayName::new, "DAYNAME"),
130+
def(MonthName.class, MonthName::new, "MONTHNAME"),
131+
def(Quarter.class, Quarter::new),
126132
// Math
127133
def(Abs.class, Abs::new),
128134
def(ACos.class, ACos::new),

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/Processors.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@
1010
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.BinaryArithmeticProcessor;
1111
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.UnaryArithmeticProcessor;
1212
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor;
13+
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor;
14+
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor;
1315
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor;
1416
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor;
1517
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.BucketExtractorProcessor;
1618
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.ChainingProcessor;
1719
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.ConstantProcessor;
1820
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.HitExtractorProcessor;
1921
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
20-
import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor;
2122
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringNumericProcessor;
2223
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringStringProcessor;
2324
import org.elasticsearch.xpack.sql.expression.function.scalar.string.ConcatFunctionProcessor;
2425
import org.elasticsearch.xpack.sql.expression.function.scalar.string.InsertFunctionProcessor;
2526
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LocateFunctionProcessor;
2627
import org.elasticsearch.xpack.sql.expression.function.scalar.string.ReplaceFunctionProcessor;
28+
import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor;
2729
import org.elasticsearch.xpack.sql.expression.function.scalar.string.SubstringFunctionProcessor;
2830

2931
import java.util.ArrayList;
@@ -52,6 +54,8 @@ public static List<NamedWriteableRegistry.Entry> getNamedWriteables() {
5254
entries.add(new Entry(Processor.class, BinaryMathProcessor.NAME, BinaryMathProcessor::new));
5355
// datetime
5456
entries.add(new Entry(Processor.class, DateTimeProcessor.NAME, DateTimeProcessor::new));
57+
entries.add(new Entry(Processor.class, NamedDateTimeProcessor.NAME, NamedDateTimeProcessor::new));
58+
entries.add(new Entry(Processor.class, QuarterProcessor.NAME, QuarterProcessor::new));
5559
// math
5660
entries.add(new Entry(Processor.class, MathProcessor.NAME, MathProcessor::new));
5761
// string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
8+
9+
import org.elasticsearch.xpack.sql.expression.Expression;
10+
import org.elasticsearch.xpack.sql.expression.Expressions;
11+
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute;
12+
import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction;
13+
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate;
14+
import org.elasticsearch.xpack.sql.tree.Location;
15+
import org.elasticsearch.xpack.sql.tree.NodeInfo;
16+
import org.elasticsearch.xpack.sql.type.DataType;
17+
18+
import java.util.TimeZone;
19+
20+
abstract class BaseDateTimeFunction extends UnaryScalarFunction {
21+
22+
private final TimeZone timeZone;
23+
private final String name;
24+
25+
BaseDateTimeFunction(Location location, Expression field, TimeZone timeZone) {
26+
super(location, field);
27+
this.timeZone = timeZone;
28+
29+
StringBuilder sb = new StringBuilder(super.name());
30+
// add timezone as last argument
31+
sb.insert(sb.length() - 1, " [" + timeZone.getID() + "]");
32+
33+
this.name = sb.toString();
34+
}
35+
36+
@Override
37+
protected final NodeInfo<BaseDateTimeFunction> info() {
38+
return NodeInfo.create(this, ctorForInfo(), field(), timeZone());
39+
}
40+
41+
protected abstract NodeInfo.NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo();
42+
43+
@Override
44+
protected TypeResolution resolveType() {
45+
if (field().dataType() == DataType.DATE) {
46+
return TypeResolution.TYPE_RESOLVED;
47+
}
48+
return new TypeResolution("Function [" + functionName() + "] cannot be applied on a non-date expression (["
49+
+ Expressions.name(field()) + "] of type [" + field().dataType().esType + "])");
50+
}
51+
52+
public TimeZone timeZone() {
53+
return timeZone;
54+
}
55+
56+
@Override
57+
public String name() {
58+
return name;
59+
}
60+
61+
@Override
62+
public boolean foldable() {
63+
return field().foldable();
64+
}
65+
66+
@Override
67+
protected ScriptTemplate asScriptFrom(AggregateFunctionAttribute aggregate) {
68+
throw new UnsupportedOperationException();
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
8+
9+
import org.elasticsearch.common.io.stream.StreamInput;
10+
import org.elasticsearch.common.io.stream.StreamOutput;
11+
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
12+
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
13+
import org.joda.time.ReadableInstant;
14+
15+
import java.io.IOException;
16+
import java.util.TimeZone;
17+
18+
public abstract class BaseDateTimeProcessor implements Processor {
19+
20+
private final TimeZone timeZone;
21+
22+
BaseDateTimeProcessor(TimeZone timeZone) {
23+
this.timeZone = timeZone;
24+
}
25+
26+
BaseDateTimeProcessor(StreamInput in) throws IOException {
27+
timeZone = TimeZone.getTimeZone(in.readString());
28+
}
29+
30+
@Override
31+
public void writeTo(StreamOutput out) throws IOException {
32+
out.writeString(timeZone.getID());
33+
}
34+
35+
TimeZone timeZone() {
36+
return timeZone;
37+
}
38+
39+
@Override
40+
public Object process(Object l) {
41+
if (l == null) {
42+
return null;
43+
}
44+
long millis;
45+
if (l instanceof String) {
46+
// 6.4+
47+
millis = Long.parseLong(l.toString());
48+
} else if (l instanceof ReadableInstant) {
49+
// 6.3-
50+
millis = ((ReadableInstant) l).getMillis();
51+
} else {
52+
throw new SqlIllegalArgumentException("A string or a date is required; received {}", l);
53+
}
54+
55+
return doProcess(millis);
56+
}
57+
58+
abstract Object doProcess(long millis);
59+
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DateTimeFunction.java

Lines changed: 8 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,14 @@
66
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
77

88
import org.elasticsearch.xpack.sql.expression.Expression;
9-
import org.elasticsearch.xpack.sql.expression.Expressions;
109
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
11-
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute;
12-
import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction;
1310
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
1411
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinition;
1512
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinitions;
1613
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.UnaryProcessorDefinition;
1714
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder;
1815
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate;
1916
import org.elasticsearch.xpack.sql.tree.Location;
20-
import org.elasticsearch.xpack.sql.tree.NodeInfo;
2117
import org.elasticsearch.xpack.sql.type.DataType;
2218
import org.joda.time.DateTime;
2319

@@ -31,45 +27,10 @@
3127
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
3228
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate.formatTemplate;
3329

34-
public abstract class DateTimeFunction extends UnaryScalarFunction {
35-
36-
private final TimeZone timeZone;
37-
private final String name;
30+
public abstract class DateTimeFunction extends BaseDateTimeFunction {
3831

3932
DateTimeFunction(Location location, Expression field, TimeZone timeZone) {
40-
super(location, field);
41-
this.timeZone = timeZone;
42-
43-
StringBuilder sb = new StringBuilder(super.name());
44-
// add timezone as last argument
45-
sb.insert(sb.length() - 1, " [" + timeZone.getID() + "]");
46-
47-
this.name = sb.toString();
48-
}
49-
50-
@Override
51-
protected final NodeInfo<DateTimeFunction> info() {
52-
return NodeInfo.create(this, ctorForInfo(), field(), timeZone());
53-
}
54-
55-
protected abstract NodeInfo.NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo();
56-
57-
@Override
58-
protected TypeResolution resolveType() {
59-
if (field().dataType() == DataType.DATE) {
60-
return TypeResolution.TYPE_RESOLVED;
61-
}
62-
return new TypeResolution("Function [" + functionName() + "] cannot be applied on a non-date expression (["
63-
+ Expressions.name(field()) + "] of type [" + field().dataType().esType + "])");
64-
}
65-
66-
public TimeZone timeZone() {
67-
return timeZone;
68-
}
69-
70-
@Override
71-
public boolean foldable() {
72-
return field().foldable();
33+
super(location, field, timeZone);
7334
}
7435

7536
@Override
@@ -79,7 +40,7 @@ public Object fold() {
7940
return null;
8041
}
8142

82-
return dateTimeChrono(folded.getMillis(), timeZone.getID(), chronoField().name());
43+
return dateTimeChrono(folded.getMillis(), timeZone().getID(), chronoField().name());
8344
}
8445

8546
public static Integer dateTimeChrono(long millis, String tzId, String chronoName) {
@@ -94,27 +55,21 @@ protected ScriptTemplate asScriptFrom(FieldAttribute field) {
9455
String template = null;
9556
template = formatTemplate("{sql}.dateTimeChrono(doc[{}].value.millis, {}, {})");
9657
params.variable(field.name())
97-
.variable(timeZone.getID())
58+
.variable(timeZone().getID())
9859
.variable(chronoField().name());
9960

10061
return new ScriptTemplate(template, params.build(), dataType());
10162
}
10263

103-
104-
@Override
105-
protected ScriptTemplate asScriptFrom(AggregateFunctionAttribute aggregate) {
106-
throw new UnsupportedOperationException();
107-
}
108-
10964
/**
11065
* Used for generating the painless script version of this function when the time zone is not UTC
11166
*/
11267
protected abstract ChronoField chronoField();
11368

11469
@Override
115-
protected final ProcessorDefinition makeProcessorDefinition() {
70+
protected ProcessorDefinition makeProcessorDefinition() {
11671
return new UnaryProcessorDefinition(location(), this, ProcessorDefinitions.toProcessorDefinition(field()),
117-
new DateTimeProcessor(extractor(), timeZone));
72+
new DateTimeProcessor(extractor(), timeZone()));
11873
}
11974

12075
protected abstract DateTimeExtractor extractor();
@@ -127,24 +82,18 @@ public DataType dataType() {
12782
// used for applying ranges
12883
public abstract String dateTimeFormat();
12984

130-
// add tz along the rest of the params
131-
@Override
132-
public String name() {
133-
return name;
134-
}
135-
13685
@Override
13786
public boolean equals(Object obj) {
13887
if (obj == null || obj.getClass() != getClass()) {
13988
return false;
14089
}
14190
DateTimeFunction other = (DateTimeFunction) obj;
14291
return Objects.equals(other.field(), field())
143-
&& Objects.equals(other.timeZone, timeZone);
92+
&& Objects.equals(other.timeZone(), timeZone());
14493
}
14594

14695
@Override
14796
public int hashCode() {
148-
return Objects.hash(field(), timeZone);
97+
return Objects.hash(field(), timeZone());
14998
}
15099
}

0 commit comments

Comments
 (0)