SQL: Adds MONTHNAME, DAYNAME and QUARTER functions (#33411)

* Added monthname, dayname and quarter functions
* Updated docs tests with the new functions
This commit is contained in:
Andrei Stefan 2018-09-11 14:35:34 +03:00 committed by GitHub
parent f598297f55
commit a3e1f1e46f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 838 additions and 110 deletions

View File

@ -21,13 +21,16 @@ import org.elasticsearch.xpack.sql.expression.function.aggregate.Sum;
import org.elasticsearch.xpack.sql.expression.function.aggregate.SumOfSquares;
import org.elasticsearch.xpack.sql.expression.function.aggregate.VarPop;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.Mod;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayName;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfMonth;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfWeek;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfYear;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.HourOfDay;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MinuteOfDay;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MinuteOfHour;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MonthName;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MonthOfYear;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Quarter;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.SecondOfMinute;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.WeekOfYear;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Year;
@ -62,21 +65,21 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.string.Ascii;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BitLength;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Char;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.CharLength;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LCase;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LTrim;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Length;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.RTrim;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Space;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.UCase;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Concat;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Insert;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LCase;
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.Position;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.RTrim;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Repeat;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Replace;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Right;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Space;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.Substring;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.UCase;
import org.elasticsearch.xpack.sql.parser.ParsingException;
import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.util.StringUtils;
@ -123,6 +126,9 @@ public class FunctionRegistry {
def(MonthOfYear.class, MonthOfYear::new, "MONTH"),
def(Year.class, Year::new),
def(WeekOfYear.class, WeekOfYear::new, "WEEK"),
def(DayName.class, DayName::new, "DAYNAME"),
def(MonthName.class, MonthName::new, "MONTHNAME"),
def(Quarter.class, Quarter::new),
// Math
def(Abs.class, Abs::new),
def(ACos.class, ACos::new),

View File

@ -10,6 +10,8 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.BinaryArithmeticProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.UnaryArithmeticProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.BucketExtractorProcessor;
@ -17,13 +19,13 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.ConstantProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.HitExtractorProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringNumericProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringStringProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.ConcatFunctionProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.InsertFunctionProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.LocateFunctionProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.ReplaceFunctionProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.StringProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.SubstringFunctionProcessor;
import java.util.ArrayList;
@ -52,6 +54,8 @@ public final class Processors {
entries.add(new Entry(Processor.class, BinaryMathProcessor.NAME, BinaryMathProcessor::new));
// datetime
entries.add(new Entry(Processor.class, DateTimeProcessor.NAME, DateTimeProcessor::new));
entries.add(new Entry(Processor.class, NamedDateTimeProcessor.NAME, NamedDateTimeProcessor::new));
entries.add(new Entry(Processor.class, QuarterProcessor.NAME, QuarterProcessor::new));
// math
entries.add(new Entry(Processor.class, MathProcessor.NAME, MathProcessor::new));
// string

View File

@ -0,0 +1,70 @@
/*
* 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.datetime;
import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.Expressions;
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute;
import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction;
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate;
import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.tree.NodeInfo;
import org.elasticsearch.xpack.sql.type.DataType;
import java.util.TimeZone;
abstract class BaseDateTimeFunction extends UnaryScalarFunction {
private final TimeZone timeZone;
private final String name;
BaseDateTimeFunction(Location location, Expression field, TimeZone timeZone) {
super(location, field);
this.timeZone = timeZone;
StringBuilder sb = new StringBuilder(super.name());
// add timezone as last argument
sb.insert(sb.length() - 1, " [" + timeZone.getID() + "]");
this.name = sb.toString();
}
@Override
protected final NodeInfo<BaseDateTimeFunction> info() {
return NodeInfo.create(this, ctorForInfo(), field(), timeZone());
}
protected abstract NodeInfo.NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo();
@Override
protected TypeResolution resolveType() {
if (field().dataType() == DataType.DATE) {
return TypeResolution.TYPE_RESOLVED;
}
return new TypeResolution("Function [" + functionName() + "] cannot be applied on a non-date expression (["
+ Expressions.name(field()) + "] of type [" + field().dataType().esType + "])");
}
public TimeZone timeZone() {
return timeZone;
}
@Override
public String name() {
return name;
}
@Override
public boolean foldable() {
return field().foldable();
}
@Override
protected ScriptTemplate asScriptFrom(AggregateFunctionAttribute aggregate) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.datetime;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
import org.joda.time.ReadableInstant;
import java.io.IOException;
import java.util.TimeZone;
public abstract class BaseDateTimeProcessor implements Processor {
private final TimeZone timeZone;
BaseDateTimeProcessor(TimeZone timeZone) {
this.timeZone = timeZone;
}
BaseDateTimeProcessor(StreamInput in) throws IOException {
timeZone = TimeZone.getTimeZone(in.readString());
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(timeZone.getID());
}
TimeZone timeZone() {
return timeZone;
}
@Override
public Object process(Object l) {
if (l == null) {
return null;
}
long millis;
if (l instanceof String) {
// 6.4+
millis = Long.parseLong(l.toString());
} else if (l instanceof ReadableInstant) {
// 6.3-
millis = ((ReadableInstant) l).getMillis();
} else {
throw new SqlIllegalArgumentException("A string or a date is required; received {}", l);
}
return doProcess(millis);
}
abstract Object doProcess(long millis);
}

View File

@ -6,10 +6,7 @@
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.Expressions;
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
import org.elasticsearch.xpack.sql.expression.function.aggregate.AggregateFunctionAttribute;
import org.elasticsearch.xpack.sql.expression.function.scalar.UnaryScalarFunction;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinition;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinitions;
@ -17,7 +14,6 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definiti
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder;
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate;
import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.tree.NodeInfo;
import org.elasticsearch.xpack.sql.type.DataType;
import org.joda.time.DateTime;
@ -31,45 +27,10 @@ import java.util.TimeZone;
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate.formatTemplate;
public abstract class DateTimeFunction extends UnaryScalarFunction {
private final TimeZone timeZone;
private final String name;
public abstract class DateTimeFunction extends BaseDateTimeFunction {
DateTimeFunction(Location location, Expression field, TimeZone timeZone) {
super(location, field);
this.timeZone = timeZone;
StringBuilder sb = new StringBuilder(super.name());
// add timezone as last argument
sb.insert(sb.length() - 1, " [" + timeZone.getID() + "]");
this.name = sb.toString();
}
@Override
protected final NodeInfo<DateTimeFunction> info() {
return NodeInfo.create(this, ctorForInfo(), field(), timeZone());
}
protected abstract NodeInfo.NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo();
@Override
protected TypeResolution resolveType() {
if (field().dataType() == DataType.DATE) {
return TypeResolution.TYPE_RESOLVED;
}
return new TypeResolution("Function [" + functionName() + "] cannot be applied on a non-date expression (["
+ Expressions.name(field()) + "] of type [" + field().dataType().esType + "])");
}
public TimeZone timeZone() {
return timeZone;
}
@Override
public boolean foldable() {
return field().foldable();
super(location, field, timeZone);
}
@Override
@ -79,7 +40,7 @@ public abstract class DateTimeFunction extends UnaryScalarFunction {
return null;
}
return dateTimeChrono(folded.getMillis(), timeZone.getID(), chronoField().name());
return dateTimeChrono(folded.getMillis(), timeZone().getID(), chronoField().name());
}
public static Integer dateTimeChrono(long millis, String tzId, String chronoName) {
@ -94,27 +55,21 @@ public abstract class DateTimeFunction extends UnaryScalarFunction {
String template = null;
template = formatTemplate("{sql}.dateTimeChrono(doc[{}].value.millis, {}, {})");
params.variable(field.name())
.variable(timeZone.getID())
.variable(timeZone().getID())
.variable(chronoField().name());
return new ScriptTemplate(template, params.build(), dataType());
}
@Override
protected ScriptTemplate asScriptFrom(AggregateFunctionAttribute aggregate) {
throw new UnsupportedOperationException();
}
/**
* Used for generating the painless script version of this function when the time zone is not UTC
*/
protected abstract ChronoField chronoField();
@Override
protected final ProcessorDefinition makeProcessorDefinition() {
protected ProcessorDefinition makeProcessorDefinition() {
return new UnaryProcessorDefinition(location(), this, ProcessorDefinitions.toProcessorDefinition(field()),
new DateTimeProcessor(extractor(), timeZone));
new DateTimeProcessor(extractor(), timeZone()));
}
protected abstract DateTimeExtractor extractor();
@ -127,12 +82,6 @@ public abstract class DateTimeFunction extends UnaryScalarFunction {
// used for applying ranges
public abstract String dateTimeFormat();
// add tz along the rest of the params
@Override
public String name() {
return name;
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
@ -140,11 +89,11 @@ public abstract class DateTimeFunction extends UnaryScalarFunction {
}
DateTimeFunction other = (DateTimeFunction) obj;
return Objects.equals(other.field(), field())
&& Objects.equals(other.timeZone, timeZone);
&& Objects.equals(other.timeZone(), timeZone());
}
@Override
public int hashCode() {
return Objects.hash(field(), timeZone);
return Objects.hash(field(), timeZone());
}
}

View File

@ -7,19 +7,16 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
import org.joda.time.DateTime;
import org.joda.time.DateTimeFieldType;
import org.joda.time.DateTimeZone;
import org.joda.time.ReadableDateTime;
import org.joda.time.ReadableInstant;
import java.io.IOException;
import java.util.Objects;
import java.util.TimeZone;
public class DateTimeProcessor implements Processor {
public class DateTimeProcessor extends BaseDateTimeProcessor {
public enum DateTimeExtractor {
DAY_OF_MONTH(DateTimeFieldType.dayOfMonth()),
@ -45,24 +42,22 @@ public class DateTimeProcessor implements Processor {
}
public static final String NAME = "dt";
private final DateTimeExtractor extractor;
private final TimeZone timeZone;
public DateTimeProcessor(DateTimeExtractor extractor, TimeZone timeZone) {
super(timeZone);
this.extractor = extractor;
this.timeZone = timeZone;
}
public DateTimeProcessor(StreamInput in) throws IOException {
super(in);
extractor = in.readEnum(DateTimeExtractor.class);
timeZone = TimeZone.getTimeZone(in.readString());
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeEnum(extractor);
out.writeString(timeZone.getID());
}
@Override
@ -75,32 +70,15 @@ public class DateTimeProcessor implements Processor {
}
@Override
public Object process(Object l) {
if (l == null) {
return null;
}
ReadableDateTime dt;
if (l instanceof String) {
// 6.4+
final long millis = Long.parseLong(l.toString());
dt = new DateTime(millis, DateTimeZone.forTimeZone(timeZone));
} else if (l instanceof ReadableInstant) {
// 6.3-
dt = (ReadableDateTime) l;
if (!TimeZone.getTimeZone("UTC").equals(timeZone)) {
dt = dt.toDateTime().withZone(DateTimeZone.forTimeZone(timeZone));
}
} else {
throw new SqlIllegalArgumentException("A string or a date is required; received {}", l);
}
public Object doProcess(long millis) {
ReadableDateTime dt = new DateTime(millis, DateTimeZone.forTimeZone(timeZone()));
return extractor.extract(dt);
}
@Override
public int hashCode() {
return Objects.hash(extractor, timeZone);
return Objects.hash(extractor, timeZone());
}
@Override
@ -110,7 +88,7 @@ public class DateTimeProcessor implements Processor {
}
DateTimeProcessor other = (DateTimeProcessor) obj;
return Objects.equals(extractor, other.extractor)
&& Objects.equals(timeZone, other.timeZone);
&& Objects.equals(timeZone(), other.timeZone());
}
@Override

View File

@ -0,0 +1,49 @@
/*
* 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.datetime;
import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor.NameExtractor;
import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
import java.util.TimeZone;
/**
* Extract the day of the week from a datetime in text format (Monday, Tuesday etc.)
*/
public class DayName extends NamedDateTimeFunction {
protected static final String DAY_NAME_FORMAT = "EEEE";
public DayName(Location location, Expression field, TimeZone timeZone) {
super(location, field, timeZone);
}
@Override
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return DayName::new;
}
@Override
protected DayName replaceChild(Expression newChild) {
return new DayName(location(), newChild, timeZone());
}
@Override
protected String dateTimeFormat() {
return DAY_NAME_FORMAT;
}
@Override
protected NameExtractor nameExtractor() {
return NameExtractor.DAY_NAME;
}
@Override
public String extractName(long millis, String tzId) {
return nameExtractor().extract(millis, tzId);
}
}

View File

@ -22,7 +22,7 @@ public class DayOfMonth extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return DayOfMonth::new;
}

View File

@ -22,7 +22,7 @@ public class DayOfWeek extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return DayOfWeek::new;
}

View File

@ -23,7 +23,7 @@ public class DayOfYear extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return DayOfYear::new;
}

View File

@ -22,7 +22,7 @@ public class HourOfDay extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return HourOfDay::new;
}

View File

@ -23,7 +23,7 @@ public class MinuteOfDay extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return MinuteOfDay::new;
}

View File

@ -22,7 +22,7 @@ public class MinuteOfHour extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return MinuteOfHour::new;
}

View File

@ -0,0 +1,50 @@
/*
* 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.datetime;
import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor.NameExtractor;
import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
import java.util.TimeZone;
/**
* Extract the month from a datetime in text format (January, February etc.)
*/
public class MonthName extends NamedDateTimeFunction {
protected static final String MONTH_NAME_FORMAT = "MMMM";
public MonthName(Location location, Expression field, TimeZone timeZone) {
super(location, field, timeZone);
}
@Override
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return MonthName::new;
}
@Override
protected MonthName replaceChild(Expression newChild) {
return new MonthName(location(), newChild, timeZone());
}
@Override
protected String dateTimeFormat() {
return MONTH_NAME_FORMAT;
}
@Override
public String extractName(long millis, String tzId) {
return nameExtractor().extract(millis, tzId);
}
@Override
protected NameExtractor nameExtractor() {
return NameExtractor.MONTH_NAME;
}
}

View File

@ -22,7 +22,7 @@ public class MonthOfYear extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return MonthOfYear::new;
}

View File

@ -0,0 +1,94 @@
/*
* 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.datetime;
import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor.NameExtractor;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinition;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinitions;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.UnaryProcessorDefinition;
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder;
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate;
import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.type.DataType;
import org.elasticsearch.xpack.sql.util.StringUtils;
import org.joda.time.DateTime;
import java.util.Objects;
import java.util.TimeZone;
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate.formatTemplate;
/*
* Base class for "naming" date/time functions like month_name and day_name
*/
abstract class NamedDateTimeFunction extends BaseDateTimeFunction {
NamedDateTimeFunction(Location location, Expression field, TimeZone timeZone) {
super(location, field, timeZone);
}
@Override
public Object fold() {
DateTime folded = (DateTime) field().fold();
if (folded == null) {
return null;
}
return extractName(folded.getMillis(), timeZone().getID());
}
public abstract String extractName(long millis, String tzId);
@Override
protected ScriptTemplate asScriptFrom(FieldAttribute field) {
ParamsBuilder params = paramsBuilder();
String template = null;
template = formatTemplate(formatMethodName("{sql}.{method_name}(doc[{}].value.millis, {})"));
params.variable(field.name())
.variable(timeZone().getID());
return new ScriptTemplate(template, params.build(), dataType());
}
private String formatMethodName(String template) {
// the Painless method name will be the enum's lower camelcase name
return template.replace("{method_name}", StringUtils.underscoreToLowerCamelCase(nameExtractor().toString()));
}
@Override
protected final ProcessorDefinition makeProcessorDefinition() {
return new UnaryProcessorDefinition(location(), this, ProcessorDefinitions.toProcessorDefinition(field()),
new NamedDateTimeProcessor(nameExtractor(), timeZone()));
}
protected abstract NameExtractor nameExtractor();
protected abstract String dateTimeFormat();
@Override
public DataType dataType() {
return DataType.KEYWORD;
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
NamedDateTimeFunction other = (NamedDateTimeFunction) obj;
return Objects.equals(other.field(), field())
&& Objects.equals(other.timeZone(), timeZone());
}
@Override
public int hashCode() {
return Objects.hash(field(), timeZone());
}
}

View File

@ -0,0 +1,98 @@
/*
* 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.datetime;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone;
import java.util.function.BiFunction;
public class NamedDateTimeProcessor extends BaseDateTimeProcessor {
public enum NameExtractor {
// for the moment we'll use no specific Locale, but we might consider introducing a Locale parameter, just like the timeZone one
DAY_NAME((Long millis, String tzId) -> {
ZonedDateTime time = ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of(tzId));
return time.format(DateTimeFormatter.ofPattern(DayName.DAY_NAME_FORMAT, Locale.ROOT));
}),
MONTH_NAME((Long millis, String tzId) -> {
ZonedDateTime time = ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of(tzId));
return time.format(DateTimeFormatter.ofPattern(MonthName.MONTH_NAME_FORMAT, Locale.ROOT));
});
private final BiFunction<Long,String,String> apply;
NameExtractor(BiFunction<Long,String,String> apply) {
this.apply = apply;
}
public final String extract(Long millis, String tzId) {
return apply.apply(millis, tzId);
}
}
public static final String NAME = "ndt";
private final NameExtractor extractor;
public NamedDateTimeProcessor(NameExtractor extractor, TimeZone timeZone) {
super(timeZone);
this.extractor = extractor;
}
public NamedDateTimeProcessor(StreamInput in) throws IOException {
super(in);
extractor = in.readEnum(NameExtractor.class);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeEnum(extractor);
}
@Override
public String getWriteableName() {
return NAME;
}
NameExtractor extractor() {
return extractor;
}
@Override
public Object doProcess(long millis) {
return extractor.extract(millis, timeZone().getID());
}
@Override
public int hashCode() {
return Objects.hash(extractor, timeZone());
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
NamedDateTimeProcessor other = (NamedDateTimeProcessor) obj;
return Objects.equals(extractor, other.extractor)
&& Objects.equals(timeZone(), other.timeZone());
}
@Override
public String toString() {
return extractor.toString();
}
}

View File

@ -0,0 +1,94 @@
/*
* 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.datetime;
import org.elasticsearch.xpack.sql.expression.Expression;
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinition;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinitions;
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.UnaryProcessorDefinition;
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder;
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate;
import org.elasticsearch.xpack.sql.tree.Location;
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
import org.elasticsearch.xpack.sql.type.DataType;
import org.joda.time.DateTime;
import java.util.Objects;
import java.util.TimeZone;
import static org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor.quarter;
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate.formatTemplate;
public class Quarter extends BaseDateTimeFunction {
protected static final String QUARTER_FORMAT = "q";
public Quarter(Location location, Expression field, TimeZone timeZone) {
super(location, field, timeZone);
}
@Override
public Object fold() {
DateTime folded = (DateTime) field().fold();
if (folded == null) {
return null;
}
return quarter(folded.getMillis(), timeZone().getID());
}
@Override
protected ScriptTemplate asScriptFrom(FieldAttribute field) {
ParamsBuilder params = paramsBuilder();
String template = null;
template = formatTemplate("{sql}.quarter(doc[{}].value.millis, {})");
params.variable(field.name())
.variable(timeZone().getID());
return new ScriptTemplate(template, params.build(), dataType());
}
@Override
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return Quarter::new;
}
@Override
protected Quarter replaceChild(Expression newChild) {
return new Quarter(location(), newChild, timeZone());
}
@Override
protected ProcessorDefinition makeProcessorDefinition() {
return new UnaryProcessorDefinition(location(), this, ProcessorDefinitions.toProcessorDefinition(field()),
new QuarterProcessor(timeZone()));
}
@Override
public DataType dataType() {
return DataType.INTEGER;
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
BaseDateTimeFunction other = (BaseDateTimeFunction) obj;
return Objects.equals(other.field(), field())
&& Objects.equals(other.timeZone(), timeZone());
}
@Override
public int hashCode() {
return Objects.hash(field(), timeZone());
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.datetime;
import org.elasticsearch.common.io.stream.StreamInput;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone;
public class QuarterProcessor extends BaseDateTimeProcessor {
public QuarterProcessor(TimeZone timeZone) {
super(timeZone);
}
public QuarterProcessor(StreamInput in) throws IOException {
super(in);
}
public static final String NAME = "q";
@Override
public String getWriteableName() {
return NAME;
}
@Override
public Object doProcess(long millis) {
return quarter(millis, timeZone().getID());
}
public static Integer quarter(long millis, String tzId) {
ZonedDateTime time = ZonedDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of(tzId));
return Integer.valueOf(time.format(DateTimeFormatter.ofPattern(Quarter.QUARTER_FORMAT, Locale.ROOT)));
}
@Override
public int hashCode() {
return Objects.hash(timeZone());
}
@Override
public boolean equals(Object obj) {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
DateTimeProcessor other = (DateTimeProcessor) obj;
return Objects.equals(timeZone(), other.timeZone());
}
}

View File

@ -22,7 +22,7 @@ public class SecondOfMinute extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return SecondOfMinute::new;
}

View File

@ -22,7 +22,7 @@ public class WeekOfYear extends DateTimeFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return WeekOfYear::new;
}

View File

@ -22,7 +22,7 @@ public class Year extends DateTimeHistogramFunction {
}
@Override
protected NodeCtor2<Expression, TimeZone, DateTimeFunction> ctorForInfo() {
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
return Year::new;
}

View File

@ -6,6 +6,8 @@
package org.elasticsearch.xpack.sql.expression.function.scalar.whitelist;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeFunction;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor.NameExtractor;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringNumericProcessor.BinaryStringNumericOperation;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.BinaryStringStringProcessor.BinaryStringStringOperation;
import org.elasticsearch.xpack.sql.expression.function.scalar.string.ConcatFunctionProcessor;
@ -28,6 +30,18 @@ public final class InternalSqlScriptUtils {
return DateTimeFunction.dateTimeChrono(millis, tzId, chronoName);
}
public static String dayName(long millis, String tzId) {
return NameExtractor.DAY_NAME.extract(millis, tzId);
}
public static String monthName(long millis, String tzId) {
return NameExtractor.MONTH_NAME.extract(millis, tzId);
}
public static Integer quarter(long millis, String tzId) {
return QuarterProcessor.quarter(millis, tzId);
}
public static Integer ascii(String s) {
return (Integer) StringOperation.ASCII.apply(s);
}

View File

@ -9,6 +9,9 @@
class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalSqlScriptUtils {
Integer dateTimeChrono(long, String, String)
String dayName(long, String)
String monthName(long, String)
Integer quarter(long, String)
Integer ascii(String)
Integer bitLength(String)
String character(Number)

View File

@ -0,0 +1,89 @@
/*
* 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.datetime;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.test.AbstractWireSerializingTestCase;
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor.NameExtractor;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.io.IOException;
import java.util.TimeZone;
public class NamedDateTimeProcessorTests extends AbstractWireSerializingTestCase<NamedDateTimeProcessor> {
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
public static NamedDateTimeProcessor randomNamedDateTimeProcessor() {
return new NamedDateTimeProcessor(randomFrom(NameExtractor.values()), UTC);
}
@Override
protected NamedDateTimeProcessor createTestInstance() {
return randomNamedDateTimeProcessor();
}
@Override
protected Reader<NamedDateTimeProcessor> instanceReader() {
return NamedDateTimeProcessor::new;
}
@Override
protected NamedDateTimeProcessor mutateInstance(NamedDateTimeProcessor instance) throws IOException {
NameExtractor replaced = randomValueOtherThan(instance.extractor(), () -> randomFrom(NameExtractor.values()));
return new NamedDateTimeProcessor(replaced, UTC);
}
public void testValidDayNamesInUTC() {
NamedDateTimeProcessor proc = new NamedDateTimeProcessor(NameExtractor.DAY_NAME, UTC);
assertEquals("Thursday", proc.process("0"));
assertEquals("Saturday", proc.process("-64164233612338"));
assertEquals("Monday", proc.process("64164233612338"));
assertEquals("Thursday", proc.process(new DateTime(0L, DateTimeZone.UTC)));
assertEquals("Thursday", proc.process(new DateTime(-5400, 12, 25, 2, 0, DateTimeZone.UTC)));
assertEquals("Friday", proc.process(new DateTime(30, 2, 1, 12, 13, DateTimeZone.UTC)));
assertEquals("Tuesday", proc.process(new DateTime(10902, 8, 22, 11, 11, DateTimeZone.UTC)));
}
public void testValidDayNamesWithNonUTCTimeZone() {
NamedDateTimeProcessor proc = new NamedDateTimeProcessor(NameExtractor.DAY_NAME, TimeZone.getTimeZone("GMT-10:00"));
assertEquals("Wednesday", proc.process("0"));
assertEquals("Friday", proc.process("-64164233612338"));
assertEquals("Monday", proc.process("64164233612338"));
assertEquals("Wednesday", proc.process(new DateTime(0L, DateTimeZone.UTC)));
assertEquals("Wednesday", proc.process(new DateTime(-5400, 12, 25, 2, 0, DateTimeZone.UTC)));
assertEquals("Friday", proc.process(new DateTime(30, 2, 1, 12, 13, DateTimeZone.UTC)));
assertEquals("Tuesday", proc.process(new DateTime(10902, 8, 22, 11, 11, DateTimeZone.UTC)));
assertEquals("Monday", proc.process(new DateTime(10902, 8, 22, 9, 59, DateTimeZone.UTC)));
}
public void testValidMonthNamesInUTC() {
NamedDateTimeProcessor proc = new NamedDateTimeProcessor(NameExtractor.MONTH_NAME, UTC);
assertEquals("January", proc.process("0"));
assertEquals("September", proc.process("-64164233612338"));
assertEquals("April", proc.process("64164233612338"));
assertEquals("January", proc.process(new DateTime(0L, DateTimeZone.UTC)));
assertEquals("December", proc.process(new DateTime(-5400, 12, 25, 10, 10, DateTimeZone.UTC)));
assertEquals("February", proc.process(new DateTime(30, 2, 1, 12, 13, DateTimeZone.UTC)));
assertEquals("August", proc.process(new DateTime(10902, 8, 22, 11, 11, DateTimeZone.UTC)));
}
public void testValidMonthNamesWithNonUTCTimeZone() {
NamedDateTimeProcessor proc = new NamedDateTimeProcessor(NameExtractor.MONTH_NAME, TimeZone.getTimeZone("GMT-3:00"));
assertEquals("December", proc.process("0"));
assertEquals("August", proc.process("-64165813612338")); // GMT: Tuesday, September 1, -0064 2:53:07.662 AM
assertEquals("April", proc.process("64164233612338")); // GMT: Monday, April 14, 4003 2:13:32.338 PM
assertEquals("December", proc.process(new DateTime(0L, DateTimeZone.UTC)));
assertEquals("November", proc.process(new DateTime(-5400, 12, 1, 1, 1, DateTimeZone.UTC)));
assertEquals("February", proc.process(new DateTime(30, 2, 1, 12, 13, DateTimeZone.UTC)));
assertEquals("July", proc.process(new DateTime(10902, 8, 1, 2, 59, DateTimeZone.UTC)));
assertEquals("August", proc.process(new DateTime(10902, 8, 1, 3, 00, DateTimeZone.UTC)));
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.datetime;
import org.elasticsearch.test.ESTestCase;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.util.TimeZone;
public class QuarterProcessorTests extends ESTestCase {
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
public void testQuarterWithUTCTimezone() {
QuarterProcessor proc = new QuarterProcessor(UTC);
assertEquals(1, proc.process(new DateTime(0L, DateTimeZone.UTC)));
assertEquals(4, proc.process(new DateTime(-5400, 12, 25, 10, 10, DateTimeZone.UTC)));
assertEquals(1, proc.process(new DateTime(30, 2, 1, 12, 13, DateTimeZone.UTC)));
assertEquals(3, proc.process(new DateTime(10902, 8, 22, 11, 11, DateTimeZone.UTC)));
assertEquals(1, proc.process("0"));
assertEquals(3, proc.process("-64164233612338"));
assertEquals(2, proc.process("64164233612338"));
}
public void testValidDayNamesWithNonUTCTimeZone() {
QuarterProcessor proc = new QuarterProcessor(TimeZone.getTimeZone("GMT-10:00"));
assertEquals(4, proc.process(new DateTime(0L, DateTimeZone.UTC)));
assertEquals(4, proc.process(new DateTime(-5400, 1, 1, 5, 0, DateTimeZone.UTC)));
assertEquals(1, proc.process(new DateTime(30, 4, 1, 9, 59, DateTimeZone.UTC)));
proc = new QuarterProcessor(TimeZone.getTimeZone("GMT+10:00"));
assertEquals(4, proc.process(new DateTime(10902, 9, 30, 14, 1, DateTimeZone.UTC)));
assertEquals(3, proc.process(new DateTime(10902, 9, 30, 13, 59, DateTimeZone.UTC)));
assertEquals(1, proc.process("0"));
assertEquals(3, proc.process("-64164233612338"));
assertEquals(2, proc.process("64164233612338"));
}
}

View File

@ -65,6 +65,8 @@ public abstract class ShowTestCase extends CliIntegrationTestCase {
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*"));
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_NAME\\s*\\|\\s*SCALAR\\s*"));
assertThat(readLine(), RegexMatcher.matches("\\s*DAYNAME\\s*\\|\\s*SCALAR\\s*"));
assertEquals("", readLine());
}
}

View File

@ -38,6 +38,11 @@ MONTH |SCALAR
YEAR |SCALAR
WEEK_OF_YEAR |SCALAR
WEEK |SCALAR
DAY_NAME |SCALAR
DAYNAME |SCALAR
MONTH_NAME |SCALAR
MONTHNAME |SCALAR
QUARTER |SCALAR
ABS |SCALAR
ACOS |SCALAR
ASIN |SCALAR
@ -130,6 +135,8 @@ DAY_OF_WEEK |SCALAR
DAY_OF_YEAR |SCALAR
HOUR_OF_DAY |SCALAR
MINUTE_OF_DAY |SCALAR
DAY_NAME |SCALAR
DAYNAME |SCALAR
;
showTables

View File

@ -12,34 +12,83 @@
dateTimeDay
SELECT DAY(birth_date) d, last_name l FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
dateTimeDayOfMonth
SELECT DAY_OF_MONTH(birth_date) d, last_name l FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
dateTimeMonth
SELECT MONTH(birth_date) d, last_name l FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
dateTimeYear
SELECT YEAR(birth_date) d, last_name l FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
monthNameFromStringDate
SELECT MONTHNAME(CAST('2018-09-03' AS TIMESTAMP)) month FROM "test_emp" limit 1;
dayNameFromStringDate
SELECT DAYNAME(CAST('2018-09-03' AS TIMESTAMP)) day FROM "test_emp" limit 1;
quarterSelect
SELECT QUARTER(hire_date) q, hire_date FROM test_emp ORDER BY hire_date LIMIT 15;
//
// Filter
//
dateTimeFilterDayOfMonth
SELECT DAY_OF_MONTH(birth_date) AS d, last_name l FROM "test_emp" WHERE DAY_OF_MONTH(birth_date) <= 10 ORDER BY emp_no LIMIT 5;
dateTimeFilterMonth
SELECT MONTH(birth_date) AS d, last_name l FROM "test_emp" WHERE MONTH(birth_date) <= 5 ORDER BY emp_no LIMIT 5;
dateTimeFilterYear
SELECT YEAR(birth_date) AS d, last_name l FROM "test_emp" WHERE YEAR(birth_date) <= 1960 ORDER BY emp_no LIMIT 5;
monthNameFilterWithFirstLetter
SELECT MONTHNAME(hire_date) AS m, hire_date FROM "test_emp" WHERE LEFT(MONTHNAME(hire_date), 1) = 'J' ORDER BY hire_date LIMIT 10;
monthNameFilterWithFullName
SELECT MONTHNAME(hire_date) AS m, hire_date FROM "test_emp" WHERE MONTHNAME(hire_date) = 'August' ORDER BY hire_date LIMIT 10;
dayNameFilterWithFullName
SELECT DAYNAME(hire_date) AS d, hire_date FROM "test_emp" WHERE DAYNAME(hire_date) = 'Sunday' ORDER BY hire_date LIMIT 10;
dayNameAndMonthNameAsFilter
SELECT first_name, last_name FROM "test_emp" WHERE DAYNAME(hire_date) = 'Sunday' AND MONTHNAME(hire_date) = 'January' ORDER BY hire_date LIMIT 10;
quarterWithFilter
SELECT QUARTER(hire_date) quarter, hire_date FROM test_emp WHERE QUARTER(hire_date) > 2 ORDER BY hire_date LIMIT 15;
//
// Aggregate
//
dateTimeAggByYear
SELECT YEAR(birth_date) AS d, CAST(SUM(emp_no) AS INT) s FROM "test_emp" GROUP BY YEAR(birth_date) ORDER BY YEAR(birth_date) LIMIT 13;
dateTimeAggByMonth
dateTimeAggByMonthWithOrderBy
SELECT MONTH(birth_date) AS d, COUNT(*) AS c, CAST(SUM(emp_no) AS INT) s FROM "test_emp" GROUP BY MONTH(birth_date) ORDER BY MONTH(birth_date) DESC;
dateTimeAggByDayOfMonth
dateTimeAggByDayOfMonthWithOrderBy
SELECT DAY_OF_MONTH(birth_date) AS d, COUNT(*) AS c, CAST(SUM(emp_no) AS INT) s FROM "test_emp" GROUP BY DAY_OF_MONTH(birth_date) ORDER BY DAY_OF_MONTH(birth_date) DESC;
monthNameWithGroupBy
SELECT MONTHNAME("hire_date") AS month, COUNT(*) AS count FROM "test_emp" GROUP BY MONTHNAME("hire_date"), MONTH("hire_date") ORDER BY MONTH("hire_date");
monthNameWithDoubleGroupByAndOrderBy
SELECT MONTHNAME("hire_date") AS month, COUNT(*) AS count FROM "test_emp" GROUP BY MONTHNAME("hire_date"), MONTH("hire_date") ORDER BY MONTHNAME("hire_date") DESC;
// AwaitsFix https://github.com/elastic/elasticsearch/issues/33519
// monthNameWithGroupByOrderByAndHaving
// SELECT CAST(MAX("salary") AS DOUBLE) max_salary, MONTHNAME("hire_date") month_name FROM "test_emp" GROUP BY MONTHNAME("hire_date") HAVING MAX("salary") > 50000 ORDER BY MONTHNAME(hire_date);
// dayNameWithHaving
// SELECT DAYNAME("hire_date") FROM "test_emp" GROUP BY DAYNAME("hire_date") HAVING MAX("emp_no") > ASCII(DAYNAME("hire_date"));
dayNameWithDoubleGroupByAndOrderBy
SELECT COUNT(*) c, DAYNAME(hire_date) day_name, DAY(hire_date) day FROM test_emp WHERE MONTHNAME(hire_date) = 'August' GROUP BY DAYNAME(hire_date), DAY(hire_date) ORDER BY DAYNAME(hire_date), DAY(hire_date);
dayNameWithGroupByOrderByAndHaving
SELECT CAST(MAX(salary) AS DOUBLE) max_salary, DAYNAME(hire_date) day_name FROM test_emp GROUP BY DAYNAME(hire_date) HAVING MAX(salary) > 50000 ORDER BY DAYNAME("hire_date");
quarterWithGroupByAndOrderBy
SELECT QUARTER(hire_date) quarter, COUNT(*) hires FROM test_emp GROUP BY QUARTER(hire_date) ORDER BY QUARTER(hire_date);

View File

@ -214,6 +214,11 @@ MONTH |SCALAR
YEAR |SCALAR
WEEK_OF_YEAR |SCALAR
WEEK |SCALAR
DAY_NAME |SCALAR
DAYNAME |SCALAR
MONTH_NAME |SCALAR
MONTHNAME |SCALAR
QUARTER |SCALAR
ABS |SCALAR
ACOS |SCALAR
ASIN |SCALAR
@ -319,6 +324,8 @@ DAY_OF_WEEK |SCALAR
DAY_OF_YEAR |SCALAR
HOUR_OF_DAY |SCALAR
MINUTE_OF_DAY |SCALAR
DAY_NAME |SCALAR
DAYNAME |SCALAR
// end::showFunctionsWithPattern
;