SQL: Add Atan2 and Power functions (elastic/x-pack-elasticsearch#4412)
Add missing Atan2 & Power(and introduce BinaryMath operations), similar to MathOperation. Also align arithmetic package with binary math for code reuse. Original commit: elastic/x-pack-elasticsearch@311961815e
This commit is contained in:
parent
e6f69ee269
commit
bc2ef139a8
|
@ -20,6 +20,7 @@ import org.elasticsearch.xpack.sql.expression.function.aggregate.StddevPop;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.Sum;
|
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.SumOfSquares;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.aggregate.VarPop;
|
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.DayOfMonth;
|
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.DayOfWeek;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfYear;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfYear;
|
||||||
|
@ -33,6 +34,7 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Year;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ACos;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ACos;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ASin;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ASin;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ATan;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ATan;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ATan2;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Abs;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Abs;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Cbrt;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Cbrt;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Ceil;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Ceil;
|
||||||
|
@ -46,6 +48,7 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.math.Floor;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Log;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Log;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Log10;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Log10;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Pi;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Pi;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Power;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Radians;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Radians;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Round;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Round;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Sin;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.Sin;
|
||||||
|
@ -104,6 +107,7 @@ public class FunctionRegistry {
|
||||||
def(ACos.class, ACos::new),
|
def(ACos.class, ACos::new),
|
||||||
def(ASin.class, ASin::new),
|
def(ASin.class, ASin::new),
|
||||||
def(ATan.class, ATan::new),
|
def(ATan.class, ATan::new),
|
||||||
|
def(ATan2.class, ATan2::new),
|
||||||
def(Cbrt.class, Cbrt::new),
|
def(Cbrt.class, Cbrt::new),
|
||||||
def(Ceil.class, Ceil::new),
|
def(Ceil.class, Ceil::new),
|
||||||
def(Cos.class, Cos::new),
|
def(Cos.class, Cos::new),
|
||||||
|
@ -115,7 +119,10 @@ public class FunctionRegistry {
|
||||||
def(Floor.class, Floor::new),
|
def(Floor.class, Floor::new),
|
||||||
def(Log.class, Log::new),
|
def(Log.class, Log::new),
|
||||||
def(Log10.class, Log10::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(Pi.class, Pi::new),
|
||||||
|
def(Power.class, Power::new),
|
||||||
def(Radians.class, Radians::new),
|
def(Radians.class, Radians::new),
|
||||||
def(Round.class, Round::new),
|
def(Round.class, Round::new),
|
||||||
def(Sin.class, Sin::new),
|
def(Sin.class, Sin::new),
|
||||||
|
|
|
@ -7,8 +7,9 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic;
|
||||||
|
|
||||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
import org.elasticsearch.xpack.sql.expression.Literal;
|
import org.elasticsearch.xpack.sql.expression.Literal;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.BinaryScalarFunction;
|
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryNumericFunction;
|
||||||
|
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.ProcessorDefinitions;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.script.ScriptTemplate;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
@ -16,20 +17,20 @@ import org.elasticsearch.xpack.sql.type.DataType;
|
||||||
import org.elasticsearch.xpack.sql.type.DataTypeConversion;
|
import org.elasticsearch.xpack.sql.type.DataTypeConversion;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static java.lang.String.format;
|
import static java.lang.String.format;
|
||||||
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
|
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
|
||||||
|
|
||||||
public abstract class ArithmeticFunction extends BinaryScalarFunction {
|
public abstract class ArithmeticFunction extends BinaryNumericFunction {
|
||||||
|
|
||||||
private BinaryArithmeticOperation operation;
|
private final BinaryArithmeticOperation operation;
|
||||||
|
|
||||||
ArithmeticFunction(Location location, Expression left, Expression right, BinaryArithmeticOperation operation) {
|
ArithmeticFunction(Location location, Expression left, Expression right, BinaryArithmeticOperation operation) {
|
||||||
super(location, left, right);
|
super(location, left, right);
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public BinaryArithmeticOperation operation() {
|
public BinaryArithmeticOperation operation() {
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
@ -39,32 +40,6 @@ public abstract class ArithmeticFunction extends BinaryScalarFunction {
|
||||||
return DataTypeConversion.commonType(left().dataType(), right().dataType());
|
return DataTypeConversion.commonType(left().dataType(), right().dataType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TypeResolution resolveType() {
|
|
||||||
if (!childrenResolved()) {
|
|
||||||
return new TypeResolution("Unresolved children");
|
|
||||||
}
|
|
||||||
DataType l = left().dataType();
|
|
||||||
DataType r = right().dataType();
|
|
||||||
|
|
||||||
TypeResolution resolution = resolveInputType(l);
|
|
||||||
|
|
||||||
if (resolution == TypeResolution.TYPE_RESOLVED) {
|
|
||||||
return resolveInputType(r);
|
|
||||||
}
|
|
||||||
return resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TypeResolution resolveInputType(DataType inputType) {
|
|
||||||
return inputType.isNumeric() ? TypeResolution.TYPE_RESOLVED
|
|
||||||
: new TypeResolution("'%s' requires a numeric type, not %s", operation, inputType.sqlName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object fold() {
|
|
||||||
return operation.apply((Number) left().fold(), (Number) right().fold());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||||
String op = operation.symbol();
|
String op = operation.symbol();
|
||||||
|
@ -79,10 +54,11 @@ public abstract class ArithmeticFunction extends BinaryScalarFunction {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final BinaryArithmeticProcessorDefinition makeProcessorDefinition() {
|
protected ProcessorDefinition makeProcessorDefinition() {
|
||||||
return new BinaryArithmeticProcessorDefinition(location(), this,
|
return new BinaryArithmeticProcessorDefinition(location(), this,
|
||||||
ProcessorDefinitions.toProcessorDefinition(left()),
|
ProcessorDefinitions.toProcessorDefinition(left()),
|
||||||
ProcessorDefinitions.toProcessorDefinition(right()), operation);
|
ProcessorDefinitions.toProcessorDefinition(right()),
|
||||||
|
operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -115,20 +91,4 @@ public abstract class ArithmeticFunction extends BinaryScalarFunction {
|
||||||
protected boolean useParanthesis() {
|
protected boolean useParanthesis() {
|
||||||
return !(left() instanceof Literal) || !(right() instanceof Literal);
|
return !(left() instanceof Literal) || !(right() instanceof Literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == null || obj.getClass() != getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ArithmeticFunction other = (ArithmeticFunction) obj;
|
|
||||||
return Objects.equals(other.left(), left())
|
|
||||||
&& Objects.equals(other.right(), right())
|
|
||||||
&& Objects.equals(other.operation, operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(left(), right(), operation);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -7,18 +7,16 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic;
|
||||||
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.arithmetic.BinaryArithmeticProcessor.BinaryArithmeticOperation;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.BinaryProcessor;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryNumericProcessor;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
public class BinaryArithmeticProcessor extends BinaryProcessor {
|
public class BinaryArithmeticProcessor extends BinaryNumericProcessor<BinaryArithmeticOperation> {
|
||||||
|
|
||||||
public enum BinaryArithmeticOperation {
|
public enum BinaryArithmeticOperation implements BiFunction<Number, Number, Number> {
|
||||||
|
|
||||||
ADD(Arithmetics::add, "+"),
|
ADD(Arithmetics::add, "+"),
|
||||||
SUB(Arithmetics::sub, "-"),
|
SUB(Arithmetics::sub, "-"),
|
||||||
|
@ -38,6 +36,7 @@ public class BinaryArithmeticProcessor extends BinaryProcessor {
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final Number apply(Number left, Number right) {
|
public final Number apply(Number left, Number right) {
|
||||||
return process.apply(left, right);
|
return process.apply(left, right);
|
||||||
}
|
}
|
||||||
|
@ -50,66 +49,21 @@ public class BinaryArithmeticProcessor extends BinaryProcessor {
|
||||||
|
|
||||||
public static final String NAME = "ab";
|
public static final String NAME = "ab";
|
||||||
|
|
||||||
private final BinaryArithmeticOperation operation;
|
|
||||||
|
|
||||||
public BinaryArithmeticProcessor(Processor left, Processor right, BinaryArithmeticOperation operation) {
|
public BinaryArithmeticProcessor(Processor left, Processor right, BinaryArithmeticOperation operation) {
|
||||||
super(left, right);
|
super(left, right, operation);
|
||||||
this.operation = operation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BinaryArithmeticProcessor(StreamInput in) throws IOException {
|
public BinaryArithmeticProcessor(StreamInput in) throws IOException {
|
||||||
super(in);
|
super(in, i -> i.readEnum(BinaryArithmeticOperation.class));
|
||||||
operation = in.readEnum(BinaryArithmeticOperation.class);
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWrite(StreamOutput out) throws IOException {
|
||||||
|
out.writeEnum(operation());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWriteableName() {
|
public String getWriteableName() {
|
||||||
return NAME;
|
return NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doWrite(StreamOutput out) throws IOException {
|
|
||||||
out.writeEnum(operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object doProcess(Object left, Object right) {
|
|
||||||
if (left == null || right == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!(left instanceof Number)) {
|
|
||||||
throw new SqlIllegalArgumentException("A number is required; received {}", left);
|
|
||||||
}
|
|
||||||
if (!(right instanceof Number)) {
|
|
||||||
throw new SqlIllegalArgumentException("A number is required; received {}", right);
|
|
||||||
}
|
|
||||||
|
|
||||||
return operation.apply((Number) left, (Number) right);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return operation.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj == null || getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryArithmeticProcessor other = (BinaryArithmeticProcessor) obj;
|
|
||||||
return Objects.equals(operation, other.operation)
|
|
||||||
&& Objects.equals(left(), other.left())
|
|
||||||
&& Objects.equals(right(), other.right());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format(Locale.ROOT, "(%s %s %s)", left(), operation, right());
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@ import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a href="https://en.wikipedia.org/wiki/Inverse_trigonometric_functions">Arc cosine</a>
|
* <a href="https://en.wikipedia.org/wiki/Inverse_trigonometric_functions">Arc cosine</a>
|
||||||
* fuction.
|
* function.
|
||||||
*/
|
*/
|
||||||
public class ACos extends MathFunction {
|
public class ACos extends MathFunction {
|
||||||
public ACos(Location location, Expression field) {
|
public ACos(Location location, Expression field) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a href="https://en.wikipedia.org/wiki/Inverse_trigonometric_functions">Arc sine</a>
|
* <a href="https://en.wikipedia.org/wiki/Inverse_trigonometric_functions">Arc sine</a>
|
||||||
* fuction.
|
* function.
|
||||||
*/
|
*/
|
||||||
public class ASin extends MathFunction {
|
public class ASin extends MathFunction {
|
||||||
public ASin(Location location, Expression field) {
|
public ASin(Location location, Expression field) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a href="https://en.wikipedia.org/wiki/Inverse_trigonometric_functions">Arc tangent</a>
|
* <a href="https://en.wikipedia.org/wiki/Inverse_trigonometric_functions">Arc tangent</a>
|
||||||
* fuction.
|
* function.
|
||||||
*/
|
*/
|
||||||
public class ATan extends MathFunction {
|
public class ATan extends MathFunction {
|
||||||
public ATan(Location location, Expression field) {
|
public ATan(Location location, Expression field) {
|
||||||
|
|
|
@ -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.math;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||||
|
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.tree.Location;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="https://en.wikipedia.org/wiki/Atan2">Multi-valued inverse tangent</a>
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
public class ATan2 extends BinaryNumericFunction {
|
||||||
|
|
||||||
|
public ATan2(Location location, Expression left, Expression right) {
|
||||||
|
super(location, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BiFunction<Number, Number, Number> operation() {
|
||||||
|
return BinaryMathOperation.ATAN2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NodeInfo<? extends Expression> info() {
|
||||||
|
return NodeInfo.create(this, ATan2::new, left(), right());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ATan2 replaceChildren(Expression newLeft, Expression newRight) {
|
||||||
|
return new ATan2(location(), newLeft, newRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ProcessorDefinition makeProcessorDefinition() {
|
||||||
|
return new BinaryMathProcessorDefinition(location(), this,
|
||||||
|
ProcessorDefinitions.toProcessorDefinition(left()),
|
||||||
|
ProcessorDefinitions.toProcessorDefinition(right()),
|
||||||
|
BinaryMathOperation.ATAN2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.math;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binary math operations. Sister class to {@link MathOperation}.
|
||||||
|
*/
|
||||||
|
public class BinaryMathProcessor extends BinaryNumericProcessor<BinaryMathOperation> {
|
||||||
|
|
||||||
|
public enum BinaryMathOperation implements BiFunction<Number, Number, Number> {
|
||||||
|
|
||||||
|
ATAN2((l, r) -> Math.atan2(l.doubleValue(), r.doubleValue())),
|
||||||
|
POWER((l, r) -> Math.pow(l.doubleValue(), r.doubleValue()));
|
||||||
|
|
||||||
|
private final BiFunction<Number, Number, Number> process;
|
||||||
|
|
||||||
|
BinaryMathOperation(BiFunction<Number, Number, Number> process) {
|
||||||
|
this.process = process;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Number apply(Number left, Number right) {
|
||||||
|
return process.apply(left, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String NAME = "mb";
|
||||||
|
|
||||||
|
public BinaryMathProcessor(Processor left, Processor right, BinaryMathOperation operation) {
|
||||||
|
super(left, right, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BinaryMathProcessor(StreamInput in) throws IOException {
|
||||||
|
super(in, i -> i.readEnum(BinaryMathOperation.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWrite(StreamOutput out) throws IOException {
|
||||||
|
out.writeEnum(operation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWriteableName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.math;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.BinaryProcessorDefinition;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.definition.ProcessorDefinition;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processor definition for math operations requiring two arguments.
|
||||||
|
*/
|
||||||
|
public class BinaryMathProcessorDefinition extends BinaryProcessorDefinition {
|
||||||
|
|
||||||
|
private final BinaryMathOperation operation;
|
||||||
|
|
||||||
|
public BinaryMathProcessorDefinition(Location location, Expression expression, ProcessorDefinition left,
|
||||||
|
ProcessorDefinition right, BinaryMathOperation operation) {
|
||||||
|
super(location, expression, left, right);
|
||||||
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NodeInfo<BinaryMathProcessorDefinition> info() {
|
||||||
|
return NodeInfo.create(this, BinaryMathProcessorDefinition::new, expression(), left(), right(), operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BinaryMathOperation operation() {
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BinaryProcessorDefinition replaceChildren(ProcessorDefinition left, ProcessorDefinition right) {
|
||||||
|
return new BinaryMathProcessorDefinition(location(), expression(), left, right, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BinaryMathProcessor asProcessor() {
|
||||||
|
return new BinaryMathProcessor(left().asProcessor(), right().asProcessor(), operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(left(), right(), operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryMathProcessorDefinition other = (BinaryMathProcessorDefinition) obj;
|
||||||
|
return Objects.equals(operation, other.operation)
|
||||||
|
&& Objects.equals(left(), other.left())
|
||||||
|
&& Objects.equals(right(), other.right());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* 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.math;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.BinaryScalarFunction;
|
||||||
|
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 java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
import static org.elasticsearch.xpack.sql.expression.function.scalar.script.ParamsBuilder.paramsBuilder;
|
||||||
|
|
||||||
|
public abstract class BinaryNumericFunction extends BinaryScalarFunction {
|
||||||
|
|
||||||
|
protected BinaryNumericFunction(Location location, Expression left, Expression right) {
|
||||||
|
super(location, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract BiFunction<Number, Number, Number> operation();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType dataType() {
|
||||||
|
return DataType.DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TypeResolution resolveType() {
|
||||||
|
if (!childrenResolved()) {
|
||||||
|
return new TypeResolution("Unresolved children");
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeResolution resolution = resolveInputType(left().dataType());
|
||||||
|
|
||||||
|
if (resolution == TypeResolution.TYPE_RESOLVED) {
|
||||||
|
return resolveInputType(right().dataType());
|
||||||
|
}
|
||||||
|
return resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TypeResolution resolveInputType(DataType inputType) {
|
||||||
|
return inputType.isNumeric() ?
|
||||||
|
TypeResolution.TYPE_RESOLVED :
|
||||||
|
new TypeResolution("'%s' requires a numeric type, received %s", mathFunction(), inputType.esType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object fold() {
|
||||||
|
return operation().apply((Number) left().fold(), (Number) right().fold());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate rightScript) {
|
||||||
|
return new ScriptTemplate(format(Locale.ROOT, "Math.%s(%s,%s)", mathFunction(), leftScript.template(), rightScript.template()),
|
||||||
|
paramsBuilder()
|
||||||
|
.script(leftScript.params()).script(rightScript.params())
|
||||||
|
.build(), dataType());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String mathFunction() {
|
||||||
|
return getClass().getSimpleName().toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(left(), right(), operation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null || obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BinaryNumericFunction other = (BinaryNumericFunction) obj;
|
||||||
|
return Objects.equals(other.left(), left())
|
||||||
|
&& Objects.equals(other.right(), right())
|
||||||
|
&& Objects.equals(other.operation(), operation());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* 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.math;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.BinaryProcessor;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
public abstract class BinaryNumericProcessor<O extends Enum<?> & BiFunction<Number, Number, Number>> extends BinaryProcessor {
|
||||||
|
|
||||||
|
private final O operation;
|
||||||
|
|
||||||
|
protected BinaryNumericProcessor(Processor left, Processor right, O operation) {
|
||||||
|
super(left, right);
|
||||||
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BinaryNumericProcessor(StreamInput in, Reader<O> reader) throws IOException {
|
||||||
|
super(in);
|
||||||
|
operation = reader.read(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected O operation() {
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object doProcess(Object left, Object right) {
|
||||||
|
if (left == null || right == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!(left instanceof Number)) {
|
||||||
|
throw new SqlIllegalArgumentException("A number is required; received {}", left);
|
||||||
|
}
|
||||||
|
if (!(right instanceof Number)) {
|
||||||
|
throw new SqlIllegalArgumentException("A number is required; received {}", right);
|
||||||
|
}
|
||||||
|
|
||||||
|
return operation.apply((Number) left, (Number) right);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryNumericProcessor<?> other = (BinaryNumericProcessor<?>) obj;
|
||||||
|
return Objects.equals(operation, other.operation)
|
||||||
|
&& Objects.equals(left(), other.left())
|
||||||
|
&& Objects.equals(right(), other.right());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(Locale.ROOT, "(%s %s %s)", left(), operation, right());
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,11 @@ public class Ceil extends MathFunction {
|
||||||
return new Ceil(location(), newChild);
|
return new Ceil(location(), newChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Number fold() {
|
||||||
|
return DataTypeConversion.toInteger((double) super.fold(), dataType());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MathOperation operation() {
|
protected MathOperation operation() {
|
||||||
return MathOperation.CEIL;
|
return MathOperation.CEIL;
|
||||||
|
|
|
@ -31,6 +31,11 @@ public class Floor extends MathFunction {
|
||||||
return new Floor(location(), newChild);
|
return new Floor(location(), newChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object fold() {
|
||||||
|
return DataTypeConversion.toInteger((double) super.fold(), dataType());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MathOperation operation() {
|
protected MathOperation operation() {
|
||||||
return MathOperation.FLOOR;
|
return MathOperation.FLOOR;
|
||||||
|
|
|
@ -53,6 +53,16 @@ public abstract class MathFunction extends UnaryScalarFunction {
|
||||||
return DataType.DOUBLE;
|
return DataType.DOUBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TypeResolution resolveType() {
|
||||||
|
if (!childrenResolved()) {
|
||||||
|
return new TypeResolution("Unresolved children");
|
||||||
|
}
|
||||||
|
|
||||||
|
return field().dataType().isNumeric() ? TypeResolution.TYPE_RESOLVED
|
||||||
|
: new TypeResolution("'%s' requires a numeric type, received %s", operation(), field().dataType().esType);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final ProcessorDefinition makeProcessorDefinition() {
|
protected final ProcessorDefinition makeProcessorDefinition() {
|
||||||
return new UnaryProcessorDefinition(location(), this,
|
return new UnaryProcessorDefinition(location(), this,
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.math;
|
||||||
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
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.elasticsearch.xpack.sql.expression.function.scalar.processor.runtime.Processor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -93,6 +94,10 @@ public class MathProcessor implements Processor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object process(Object input) {
|
public Object process(Object input) {
|
||||||
|
if (input != null && !(input instanceof Number)) {
|
||||||
|
throw new SqlIllegalArgumentException("A number is required; received [{}]", input);
|
||||||
|
}
|
||||||
|
|
||||||
return processor.apply(input);
|
return processor.apply(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.math;
|
||||||
|
|
||||||
|
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||||
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||||
|
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.tree.Location;
|
||||||
|
import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
public class Power extends BinaryNumericFunction {
|
||||||
|
|
||||||
|
public Power(Location location, Expression left, Expression right) {
|
||||||
|
super(location, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BiFunction<Number, Number, Number> operation() {
|
||||||
|
return BinaryMathOperation.POWER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NodeInfo<? extends Expression> info() {
|
||||||
|
return NodeInfo.create(this, Power::new, left(), right());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Power replaceChildren(Expression newLeft, Expression newRight) {
|
||||||
|
return new Power(location(), newLeft, newRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ProcessorDefinition makeProcessorDefinition() {
|
||||||
|
return new BinaryMathProcessorDefinition(location(), this,
|
||||||
|
ProcessorDefinitions.toProcessorDefinition(left()),
|
||||||
|
ProcessorDefinitions.toProcessorDefinition(right()),
|
||||||
|
BinaryMathOperation.POWER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String mathFunction() {
|
||||||
|
return "pow";
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import org.elasticsearch.xpack.sql.tree.NodeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a href="https://en.wikipedia.org/wiki/Trigonometric_functions#sine">Tangent</a>
|
* <a href="https://en.wikipedia.org/wiki/Trigonometric_functions#sine">Tangent</a>
|
||||||
* fuction.
|
* function.
|
||||||
*/
|
*/
|
||||||
public class Tan extends MathFunction {
|
public class Tan extends MathFunction {
|
||||||
public Tan(Location location, Expression field) {
|
public Tan(Location location, Expression field) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import static org.elasticsearch.xpack.sql.type.DataType.BOOLEAN;
|
||||||
import static org.elasticsearch.xpack.sql.type.DataType.DATE;
|
import static org.elasticsearch.xpack.sql.type.DataType.DATE;
|
||||||
import static org.elasticsearch.xpack.sql.type.DataType.LONG;
|
import static org.elasticsearch.xpack.sql.type.DataType.LONG;
|
||||||
import static org.elasticsearch.xpack.sql.type.DataType.NULL;
|
import static org.elasticsearch.xpack.sql.type.DataType.NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conversions from one Elasticsearch data type to another Elasticsearch data types.
|
* Conversions from one Elasticsearch data type to another Elasticsearch data types.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -316,6 +317,21 @@ public abstract class DataTypeConversion {
|
||||||
return Math.round(x);
|
return Math.round(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Number toInteger(double x, DataType dataType) {
|
||||||
|
long l = safeToLong(x);
|
||||||
|
|
||||||
|
switch (dataType) {
|
||||||
|
case BYTE:
|
||||||
|
return safeToByte(l);
|
||||||
|
case SHORT:
|
||||||
|
return safeToShort(l);
|
||||||
|
case INTEGER:
|
||||||
|
return safeToInt(l);
|
||||||
|
default:
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean convertToBoolean(String val) {
|
public static boolean convertToBoolean(String val) {
|
||||||
String lowVal = val.toLowerCase(Locale.ROOT);
|
String lowVal = val.toLowerCase(Locale.ROOT);
|
||||||
if (Booleans.isBoolean(lowVal) == false) {
|
if (Booleans.isBoolean(lowVal) == false) {
|
||||||
|
|
|
@ -111,8 +111,8 @@ public class VerifierErrorMessagesTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGroupByOrderByScalarOverNonGrouped() {
|
public void testGroupByOrderByScalarOverNonGrouped() {
|
||||||
assertEquals("1:50: Cannot order by non-grouped column [bool], expected [text]",
|
assertEquals("1:50: Cannot order by non-grouped column [date], expected [text]",
|
||||||
verify("SELECT MAX(int) FROM test GROUP BY text ORDER BY ABS(bool)"));
|
verify("SELECT MAX(int) FROM test GROUP BY text ORDER BY YEAR(date)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGroupByHavingNonGrouped() {
|
public void testGroupByHavingNonGrouped() {
|
||||||
|
|
|
@ -40,29 +40,29 @@ public class BinaryArithmeticProcessorTests extends AbstractWireSerializingTestC
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAdd() {
|
public void testAdd() {
|
||||||
BinaryArithmeticProcessor ba = new Add(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
Processor ba = new Add(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
||||||
assertEquals(10, ba.process(null));
|
assertEquals(10, ba.process(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSub() {
|
public void testSub() {
|
||||||
BinaryArithmeticProcessor ba = new Sub(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
Processor ba = new Sub(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
||||||
assertEquals(4, ba.process(null));
|
assertEquals(4, ba.process(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMul() {
|
public void testMul() {
|
||||||
BinaryArithmeticProcessor ba = new Mul(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
Processor ba = new Mul(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
||||||
assertEquals(21, ba.process(null));
|
assertEquals(21, ba.process(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testDiv() {
|
public void testDiv() {
|
||||||
BinaryArithmeticProcessor ba = new Div(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
Processor ba = new Div(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
||||||
assertEquals(2, ((Number) ba.process(null)).longValue());
|
assertEquals(2, ((Number) ba.process(null)).longValue());
|
||||||
ba = new Div(EMPTY, l((double) 7), l(3)).makeProcessorDefinition().asProcessor();
|
ba = new Div(EMPTY, l((double) 7), l(3)).makeProcessorDefinition().asProcessor();
|
||||||
assertEquals(2.33, ((Number) ba.process(null)).doubleValue(), 0.01d);
|
assertEquals(2.33, ((Number) ba.process(null)).doubleValue(), 0.01d);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMod() {
|
public void testMod() {
|
||||||
BinaryArithmeticProcessor ba = new Mod(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
Processor ba = new Mod(EMPTY, l(7), l(3)).makeProcessorDefinition().asProcessor();
|
||||||
assertEquals(1, ba.process(null));
|
assertEquals(1, ba.process(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.sql.expression.function.scalar.math;
|
||||||
|
|
||||||
import org.elasticsearch.common.io.stream.Writeable.Reader;
|
import org.elasticsearch.common.io.stream.Writeable.Reader;
|
||||||
import org.elasticsearch.test.AbstractWireSerializingTestCase;
|
import org.elasticsearch.test.AbstractWireSerializingTestCase;
|
||||||
|
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation;
|
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -34,7 +35,6 @@ public class MathFunctionProcessorTests extends AbstractWireSerializingTestCase<
|
||||||
public void testApply() {
|
public void testApply() {
|
||||||
MathProcessor proc = new MathProcessor(MathOperation.E);
|
MathProcessor proc = new MathProcessor(MathOperation.E);
|
||||||
assertEquals(Math.E, proc.process(null));
|
assertEquals(Math.E, proc.process(null));
|
||||||
assertEquals(Math.E, proc.process("cat"));
|
|
||||||
assertEquals(Math.E, proc.process(Math.PI));
|
assertEquals(Math.E, proc.process(Math.PI));
|
||||||
|
|
||||||
proc = new MathProcessor(MathOperation.SQRT);
|
proc = new MathProcessor(MathOperation.SQRT);
|
||||||
|
@ -42,4 +42,11 @@ public class MathFunctionProcessorTests extends AbstractWireSerializingTestCase<
|
||||||
assertEquals(3.0, (double) proc.process(9d), 0);
|
assertEquals(3.0, (double) proc.process(9d), 0);
|
||||||
assertEquals(1.77, (double) proc.process(3.14), 0.01);
|
assertEquals(1.77, (double) proc.process(3.14), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testNumberCheck() {
|
||||||
|
MathProcessor proc = new MathProcessor(MathOperation.E);
|
||||||
|
SqlIllegalArgumentException siae = expectThrows(SqlIllegalArgumentException.class, () -> proc.process("string"));
|
||||||
|
assertEquals("A number is required; received [string]", siae.getMessage());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ ABS |SCALAR
|
||||||
ACOS |SCALAR
|
ACOS |SCALAR
|
||||||
ASIN |SCALAR
|
ASIN |SCALAR
|
||||||
ATAN |SCALAR
|
ATAN |SCALAR
|
||||||
|
ATAN2 |SCALAR
|
||||||
CBRT |SCALAR
|
CBRT |SCALAR
|
||||||
CEIL |SCALAR
|
CEIL |SCALAR
|
||||||
COS |SCALAR
|
COS |SCALAR
|
||||||
|
@ -53,7 +54,9 @@ EXPM1 |SCALAR
|
||||||
FLOOR |SCALAR
|
FLOOR |SCALAR
|
||||||
LOG |SCALAR
|
LOG |SCALAR
|
||||||
LOG10 |SCALAR
|
LOG10 |SCALAR
|
||||||
|
MOD |SCALAR
|
||||||
PI |SCALAR
|
PI |SCALAR
|
||||||
|
POWER |SCALAR
|
||||||
RADIANS |SCALAR
|
RADIANS |SCALAR
|
||||||
ROUND |SCALAR
|
ROUND |SCALAR
|
||||||
SIN |SCALAR
|
SIN |SCALAR
|
||||||
|
@ -80,6 +83,7 @@ ABS |SCALAR
|
||||||
ACOS |SCALAR
|
ACOS |SCALAR
|
||||||
ASIN |SCALAR
|
ASIN |SCALAR
|
||||||
ATAN |SCALAR
|
ATAN |SCALAR
|
||||||
|
ATAN2 |SCALAR
|
||||||
;
|
;
|
||||||
|
|
||||||
showFunctionsWithPatternChar
|
showFunctionsWithPatternChar
|
||||||
|
|
|
@ -112,3 +112,15 @@ mathConstantPI
|
||||||
SELECT ABS(emp_no) m, PI() as pi, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
|
SELECT ABS(emp_no) m, PI() as pi, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
|
||||||
mathConstant
|
mathConstant
|
||||||
SELECT 5 + 2 * 3 / 2 % 2 AS c, PI() as e, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
|
SELECT 5 + 2 * 3 / 2 % 2 AS c, PI() as e, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
|
||||||
|
|
||||||
|
//
|
||||||
|
// binary functions
|
||||||
|
//
|
||||||
|
mathATan2
|
||||||
|
// tag::atan2
|
||||||
|
SELECT ATAN2(emp_no, emp_no) m, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
|
||||||
|
// end::atan2
|
||||||
|
mathPower
|
||||||
|
// tag::power
|
||||||
|
SELECT POWER(emp_no, 2) m, first_name FROM "test_emp" WHERE emp_no < 10010 ORDER BY emp_no;
|
||||||
|
// end::power
|
||||||
|
|
Loading…
Reference in New Issue