Skip to content

Commit

Permalink
Merged opensearch-project#754 with dev-add-UTC-DateTime.
Browse files Browse the repository at this point in the history
Signed-off-by: MitchellGale-BitQuill <[email protected]>
  • Loading branch information
MitchellGale committed Sep 19, 2022
2 parents 3e3930c + 425a998 commit 7f5dcf8
Show file tree
Hide file tree
Showing 26 changed files with 1,559 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@

package org.opensearch.sql.common.utils;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.apache.logging.log4j.ThreadContext;

/**
* Utility class for recording and accessing context for the query being executed.
* Implementation Details: context variables is being persisted statically in the thread context
* @see: @ThreadContext
*/
public class QueryContext {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
package org.opensearch.sql.analysis;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.Getter;
import org.opensearch.sql.expression.Expression;
import org.opensearch.sql.expression.NamedExpression;

/**
Expand All @@ -23,13 +26,26 @@ public class AnalysisContext {
@Getter
private final List<NamedExpression> namedParseExpressions;

/**
* Storage for values of functions which return a constant value.
* We are storing the values there to use it in sequential calls to those functions.
* For example, `now` function should the same value during processing a query.
*/
@Getter
private final Map<String, Expression> constantFunctionValues;

public AnalysisContext() {
this(new TypeEnvironment(null));
}

/**
* Class CTOR.
* @param environment Env to set to a new instance.
*/
public AnalysisContext(TypeEnvironment environment) {
this.environment = environment;
this.namedParseExpressions = new ArrayList<>();
this.constantFunctionValues = new HashMap<>();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.opensearch.sql.ast.expression.Case;
import org.opensearch.sql.ast.expression.Cast;
import org.opensearch.sql.ast.expression.Compare;
import org.opensearch.sql.ast.expression.ConstantFunction;
import org.opensearch.sql.ast.expression.EqualTo;
import org.opensearch.sql.ast.expression.Field;
import org.opensearch.sql.ast.expression.Function;
Expand Down Expand Up @@ -169,6 +170,19 @@ public Expression visitRelevanceFieldList(RelevanceFieldList node, AnalysisConte
ImmutableMap.copyOf(node.getFieldList())));
}

@Override
public Expression visitConstantFunction(ConstantFunction node, AnalysisContext context) {
var valueName = node.getFuncName();
if (context.getConstantFunctionValues().containsKey(valueName)) {
return context.getConstantFunctionValues().get(valueName);
}

var value = visitFunction(node, context);
value = DSL.literal(value.valueOf(null));
context.getConstantFunctionValues().put(valueName, value);
return value;
}

@Override
public Expression visitFunction(Function node, AnalysisContext context) {
FunctionName functionName = FunctionName.of(node.getFuncName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.opensearch.sql.ast.expression.Case;
import org.opensearch.sql.ast.expression.Cast;
import org.opensearch.sql.ast.expression.Compare;
import org.opensearch.sql.ast.expression.ConstantFunction;
import org.opensearch.sql.ast.expression.EqualTo;
import org.opensearch.sql.ast.expression.Field;
import org.opensearch.sql.ast.expression.Function;
Expand Down Expand Up @@ -116,6 +117,10 @@ public T visitRelevanceFieldList(RelevanceFieldList node, C context) {
return visitChildren(node, context);
}

public T visitConstantFunction(ConstantFunction node, C context) {
return visitChildren(node, context);
}

public T visitUnresolvedAttribute(UnresolvedAttribute node, C context) {
return visitChildren(node, context);
}
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/org/opensearch/sql/ast/dsl/AstDSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.opensearch.sql.ast.expression.Case;
import org.opensearch.sql.ast.expression.Cast;
import org.opensearch.sql.ast.expression.Compare;
import org.opensearch.sql.ast.expression.ConstantFunction;
import org.opensearch.sql.ast.expression.DataType;
import org.opensearch.sql.ast.expression.EqualTo;
import org.opensearch.sql.ast.expression.Field;
Expand Down Expand Up @@ -234,6 +235,10 @@ public static Function function(String funcName, UnresolvedExpression... funcArg
return new Function(funcName, Arrays.asList(funcArgs));
}

public static Function constantFunction(String funcName, UnresolvedExpression... funcArgs) {
return new ConstantFunction(funcName, Arrays.asList(funcArgs));
}

/**
* CASE
* WHEN search_condition THEN result_expr
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/


package org.opensearch.sql.ast.expression;

import java.util.List;
import lombok.EqualsAndHashCode;
import org.opensearch.sql.ast.AbstractNodeVisitor;

/**
* Expression node that holds a function which should be replaced by its constant[1] value.
* [1] Constant at execution time.
*/
@EqualsAndHashCode(callSuper = false)
public class ConstantFunction extends Function {

public ConstantFunction(String funcName, List<UnresolvedExpression> funcArgs) {
super(funcName, funcArgs);
}

@Override
public <R, C> R accept(AbstractNodeVisitor<R, C> nodeVisitor, C context) {
return nodeVisitor.visitConstantFunction(this, context);
}
}
36 changes: 36 additions & 0 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,42 @@ public FunctionExpression match_bool_prefix(Expression... args) {
return compile(BuiltinFunctionName.MATCH_BOOL_PREFIX, args);
}

public FunctionExpression now(Expression... args) {
return compile(BuiltinFunctionName.NOW, args);
}

public FunctionExpression current_timestamp(Expression... args) {
return compile(BuiltinFunctionName.CURRENT_TIMESTAMP, args);
}

public FunctionExpression localtimestamp(Expression... args) {
return compile(BuiltinFunctionName.LOCALTIMESTAMP, args);
}

public FunctionExpression localtime(Expression... args) {
return compile(BuiltinFunctionName.LOCALTIME, args);
}

public FunctionExpression sysdate(Expression... args) {
return compile(BuiltinFunctionName.SYSDATE, args);
}

public FunctionExpression curtime(Expression... args) {
return compile(BuiltinFunctionName.CURTIME, args);
}

public FunctionExpression current_time(Expression... args) {
return compile(BuiltinFunctionName.CURRENT_TIME, args);
}

public FunctionExpression curdate(Expression... args) {
return compile(BuiltinFunctionName.CURDATE, args);
}

public FunctionExpression current_date(Expression... args) {
return compile(BuiltinFunctionName.CURRENT_DATE, args);
}

private FunctionExpression compile(BuiltinFunctionName bfn, Expression... args) {
return (FunctionExpression) repository.compile(bfn.getName(), Arrays.asList(args.clone()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@
import static org.opensearch.sql.expression.function.FunctionDSL.impl;
import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandling;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import lombok.experimental.UtilityClass;
import org.opensearch.sql.data.model.ExprDateValue;
import org.opensearch.sql.data.model.ExprDatetimeValue;
Expand Down Expand Up @@ -88,6 +92,84 @@ public void register(BuiltinFunctionRepository repository) {
repository.register(to_days());
repository.register(week());
repository.register(year());

repository.register(now());
repository.register(current_timestamp());
repository.register(localtimestamp());
repository.register(localtime());
repository.register(sysdate());
repository.register(curtime());
repository.register(current_time());
repository.register(curdate());
repository.register(current_date());
}

/**
* NOW() returns a constant time that indicates the time at which the statement began to execute.
* `fsp` argument support is removed until refactoring to avoid bug where `now()`, `now(x)` and
* `now(y) return different values.
*/
private FunctionResolver now(FunctionName functionName) {
return define(functionName,
impl(() -> new ExprDatetimeValue(formatNow(null)), DATETIME)
);
}

private FunctionResolver now() {
return now(BuiltinFunctionName.NOW.getName());
}

private FunctionResolver current_timestamp() {
return now(BuiltinFunctionName.CURRENT_TIMESTAMP.getName());
}

private FunctionResolver localtimestamp() {
return now(BuiltinFunctionName.LOCALTIMESTAMP.getName());
}

private FunctionResolver localtime() {
return now(BuiltinFunctionName.LOCALTIME.getName());
}

/**
* SYSDATE() returns the time at which it executes.
*/
private FunctionResolver sysdate() {
return define(BuiltinFunctionName.SYSDATE.getName(),
impl(() -> new ExprDatetimeValue(formatNow(null)), DATETIME),
impl((v) -> new ExprDatetimeValue(formatNow(v.integerValue())), DATETIME, INTEGER)
);
}

/**
* Synonym for @see `now`.
*/
private FunctionResolver curtime(FunctionName functionName) {
return define(functionName,
impl(() -> new ExprTimeValue(formatNow(null).toLocalTime()), TIME)
);
}

private FunctionResolver curtime() {
return curtime(BuiltinFunctionName.CURTIME.getName());
}

private FunctionResolver current_time() {
return curtime(BuiltinFunctionName.CURRENT_TIME.getName());
}

private FunctionResolver curdate(FunctionName functionName) {
return define(functionName,
impl(() -> new ExprDateValue(formatNow(null).toLocalDate()), DATE)
);
}

private FunctionResolver curdate() {
return curdate(BuiltinFunctionName.CURDATE.getName());
}

private FunctionResolver current_date() {
return curdate(BuiltinFunctionName.CURRENT_DATE.getName());
}

/**
Expand Down Expand Up @@ -796,4 +878,24 @@ private ExprValue exprYear(ExprValue date) {
return new ExprIntegerValue(date.dateValue().getYear());
}

/**
* Prepare LocalDateTime value. Truncate fractional second part according to the argument.
* @param fsp argument is given to specify a fractional seconds precision from 0 to 6,
* the return value includes a fractional seconds part of that many digits.
* @return LocalDateTime object.
*/
private LocalDateTime formatNow(@Nullable Integer fsp) {
var res = LocalDateTime.now();
if (fsp == null) {
fsp = 0;
}
var defaultPrecision = 9; // There are 10^9 nanoseconds in one second
if (fsp < 0 || fsp > 6) { // Check that the argument is in the allowed range [0, 6]
throw new IllegalArgumentException(
String.format("Invalid `fsp` value: %d, allowed 0 to 6", fsp));
}
var nano = new BigDecimal(res.getNano())
.setScale(fsp - defaultPrecision, RoundingMode.DOWN).intValue();
return res.withNano(nano);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,16 @@ public enum BuiltinFunctionName {
UTC_TIMESTAMP(FunctionName.of("utc_timestamp")),
WEEK(FunctionName.of("week")),
YEAR(FunctionName.of("year")),

// `now`-like functions
NOW(FunctionName.of("now")),
CURDATE(FunctionName.of("curdate")),
CURRENT_DATE(FunctionName.of("current_date")),
CURTIME(FunctionName.of("curtime")),
CURRENT_TIME(FunctionName.of("current_time")),
LOCALTIME(FunctionName.of("localtime")),
CURRENT_TIMESTAMP(FunctionName.of("current_timestamp")),
LOCALTIMESTAMP(FunctionName.of("localtimestamp")),
SYSDATE(FunctionName.of("sysdate")),
/**
* Text Functions.
*/
Expand Down
Loading

0 comments on commit 7f5dcf8

Please sign in to comment.