Skip to content

Commit 10efba1

Browse files
committed
Add ES|QL copy_sign function
1 parent 6e4cb81 commit 10efba1

File tree

3 files changed

+293
-0
lines changed

3 files changed

+293
-0
lines changed

x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/math/CopySignEvaluator.java

Lines changed: 158 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import org.elasticsearch.xpack.esql.expression.function.scalar.math.Atan2;
7878
import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cbrt;
7979
import org.elasticsearch.xpack.esql.expression.function.scalar.math.Ceil;
80+
import org.elasticsearch.xpack.esql.expression.function.scalar.math.CopySign;
8081
import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cos;
8182
import org.elasticsearch.xpack.esql.expression.function.scalar.math.Cosh;
8283
import org.elasticsearch.xpack.esql.expression.function.scalar.math.E;
@@ -298,6 +299,7 @@ private static FunctionDefinition[][] functions() {
298299
def(Atan2.class, Atan2::new, "atan2"),
299300
def(Cbrt.class, Cbrt::new, "cbrt"),
300301
def(Ceil.class, Ceil::new, "ceil"),
302+
def(CopySign.class, CopySign::new, "copy_sign"),
301303
def(Cos.class, Cos::new, "cos"),
302304
def(Cosh.class, Cosh::new, "cosh"),
303305
def(E.class, E::new, "e"),
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.esql.expression.function.scalar.math;
9+
10+
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
11+
import org.elasticsearch.common.io.stream.StreamInput;
12+
import org.elasticsearch.common.io.stream.StreamOutput;
13+
import org.elasticsearch.compute.ann.Evaluator;
14+
import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
15+
import org.elasticsearch.xpack.esql.core.expression.Expression;
16+
import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
17+
import org.elasticsearch.xpack.esql.core.tree.Source;
18+
import org.elasticsearch.xpack.esql.core.type.DataType;
19+
import org.elasticsearch.xpack.esql.core.util.NumericUtils;
20+
import org.elasticsearch.xpack.esql.expression.function.Example;
21+
import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
22+
import org.elasticsearch.xpack.esql.expression.function.Param;
23+
import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlScalarFunction;
24+
import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
25+
26+
import java.io.IOException;
27+
import java.util.Arrays;
28+
import java.util.List;
29+
30+
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST;
31+
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND;
32+
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNumeric;
33+
34+
public class CopySign extends EsqlScalarFunction {
35+
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "CopySign", CopySign::new);
36+
37+
private final Expression magnitude;
38+
private final Expression sign;
39+
40+
@FunctionInfo(
41+
returnType = { "double" },
42+
description = "Returns the first argument with the sign of the second argument.",
43+
examples = @Example(file = "math", tag = "CopySign")
44+
)
45+
public CopySign(
46+
Source source,
47+
@Param(
48+
name = "magnitude",
49+
type = { "double", "integer", "long", "unsigned_long" },
50+
description = "Numeric expression. If `null`, the function returns `null`."
51+
) Expression magnitude,
52+
@Param(
53+
name = "sign",
54+
type = { "double", "integer", "long", "unsigned_long" },
55+
description = "Numeric expression. If `null`, the function returns `null`."
56+
) Expression sign
57+
) {
58+
super(source, Arrays.asList(magnitude, sign));
59+
this.magnitude = magnitude;
60+
this.sign = sign;
61+
}
62+
63+
private CopySign(StreamInput in) throws IOException {
64+
this(Source.readFrom((PlanStreamInput) in), in.readNamedWriteable(Expression.class), in.readNamedWriteable(Expression.class));
65+
}
66+
67+
@Override
68+
public void writeTo(StreamOutput out) throws IOException {
69+
source().writeTo(out);
70+
out.writeNamedWriteable(magnitude);
71+
out.writeNamedWriteable(sign);
72+
}
73+
74+
@Override
75+
public String getWriteableName() {
76+
return ENTRY.name;
77+
}
78+
79+
@Override
80+
protected TypeResolution resolveType() {
81+
if (childrenResolved() == false) {
82+
return new TypeResolution("Unresolved children");
83+
}
84+
85+
TypeResolution resolution = isNumeric(magnitude, sourceText(), FIRST);
86+
if (resolution.unresolved()) {
87+
return resolution;
88+
}
89+
90+
return isNumeric(sign, sourceText(), SECOND);
91+
}
92+
93+
@Override
94+
public boolean foldable() {
95+
return magnitude.foldable() && sign.foldable();
96+
}
97+
98+
@Evaluator(warnExceptions = { ArithmeticException.class })
99+
static double process(double magnitude, double sign) {
100+
return NumericUtils.asFiniteNumber(Math.copySign(magnitude, sign));
101+
}
102+
103+
@Override
104+
public Expression replaceChildren(List<Expression> newChildren) {
105+
return new CopySign(source(), newChildren.get(0), newChildren.get(1));
106+
}
107+
108+
@Override
109+
protected NodeInfo<? extends Expression> info() {
110+
return NodeInfo.create(this, CopySign::new, magnitude(), sign());
111+
}
112+
113+
public Expression magnitude() {
114+
return magnitude;
115+
}
116+
117+
public Expression sign() {
118+
return sign;
119+
}
120+
121+
@Override
122+
public DataType dataType() {
123+
return DataType.DOUBLE;
124+
}
125+
126+
127+
@Override
128+
public ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
129+
var magnitudeEval = Cast.cast(source(), magnitude.dataType(), DataType.DOUBLE, toEvaluator.apply(magnitude));
130+
var signEval = Cast.cast(source(), sign.dataType(), DataType.DOUBLE, toEvaluator.apply(sign));
131+
return new CopySignEvaluator.Factory(source(), magnitudeEval, signEval);
132+
}
133+
}

0 commit comments

Comments
 (0)