-
Notifications
You must be signed in to change notification settings - Fork 25k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SQL: Introduce Coalesce function #35253
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// | ||
// Null expressions | ||
// | ||
|
||
dateTimeOverNull | ||
SELECT YEAR(CAST(NULL AS DATE)) d; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @matriv notice that now |
||
|
||
d:i | ||
null | ||
; | ||
|
||
addOfNull | ||
SELECT CAST(NULL AS INT) + CAST(NULL AS FLOAT) AS n; | ||
|
||
n:d | ||
null | ||
; | ||
|
||
|
||
divOfCastedNull | ||
SELECT 5 / CAST(NULL AS FLOAT) + 10 AS n; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because I want to check that the a cast preserve the null value and its associated type. I've renamed the test and added a basic one without cast. |
||
|
||
n:d | ||
null | ||
; | ||
|
||
divNoNull | ||
SELECT 5 / null + 1 AS n; | ||
|
||
n:i | ||
null | ||
; | ||
|
||
coalesceJustWithNull | ||
SELECT COALESCE(null, null, null) AS c; | ||
|
||
c | ||
null | ||
; | ||
|
||
coalesceFirstNotNull | ||
SELECT COALESCE(123) AS c; | ||
|
||
c | ||
123 | ||
; | ||
|
||
|
||
coalesceWithFirstNullOfString | ||
SELECT COALESCE(null, 'first') AS c; | ||
|
||
c:s | ||
first | ||
; | ||
|
||
coalesceWithFirstNullOfNumber | ||
SELECT COALESCE(null, 123) AS c; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also add a test where all values are There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm... my bad, not sure why I haven't seen that. |
||
c:i | ||
123 | ||
; | ||
|
||
coalesceMixed | ||
SELECT COALESCE(null, 123, null, 321) AS c; | ||
|
||
c:i | ||
123 | ||
; | ||
|
||
coalesceScalar | ||
SELECT COALESCE(null, ABS(123) + 1) AS c; | ||
|
||
c:i | ||
124 | ||
; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a test where the first value is non-null? (all tests with COALESCE assume there is at least one null value before the first non-null) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added (there's an optimization test that tries that but anyway). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// | ||
// Null expressions | ||
// | ||
|
||
coalesceField | ||
SELECT COALESCE(null, ABS(emp_no) + 1) AS c FROM test_emp ORDER BY emp_no LIMIT 5; | ||
|
||
coalesceHaving | ||
SELECT COALESCE(null, ABS(MAX(emp_no)) + 1, 123) AS c FROM test_emp GROUP BY languages HAVING c > 100 ORDER BY languages LIMIT 5; | ||
|
||
coalesceWhere | ||
SELECT COALESCE(null, ABS(emp_no) + 1, 123) AS c FROM test_emp WHERE COALESCE(null, ABS(emp_no) + 1, 123, 321) > 100 ORDER BY emp_no NULLS FIRST LIMIT 5; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,6 +82,7 @@ | |
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.expression.predicate.conditional.Coalesce; | ||
import org.elasticsearch.xpack.sql.expression.predicate.operator.arithmetic.Mod; | ||
import org.elasticsearch.xpack.sql.parser.ParsingException; | ||
import org.elasticsearch.xpack.sql.tree.Location; | ||
|
@@ -142,6 +143,8 @@ private void defineDefaultFunctions() { | |
def(Skewness.class, Skewness::new), | ||
def(Kurtosis.class, Kurtosis::new)); | ||
// Scalar functions | ||
// conditional | ||
addToMap(def(Coalesce.class, Coalesce::new)); | ||
// Date | ||
addToMap(def(DayName.class, DayName::new, "DAYNAME"), | ||
def(DayOfMonth.class, DayOfMonth::new, "DAYOFMONTH", "DAY", "DOM"), | ||
|
@@ -310,6 +313,26 @@ static <T extends Function> FunctionDefinition def(Class<T> function, | |
return def(function, builder, false, aliases); | ||
} | ||
|
||
/** | ||
* Build a {@linkplain FunctionDefinition} for multi-arg function that | ||
* is not aware of time zone and does not support {@code DISTINCT}. | ||
*/ | ||
@SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do | ||
static <T extends Function> FunctionDefinition def(Class<T> function, | ||
MultiFunctionBuilder<T> ctorRef, String... aliases) { | ||
FunctionBuilder builder = (location, children, distinct, tz) -> { | ||
if (distinct) { | ||
throw new IllegalArgumentException("does not support DISTINCT yet it was specified"); | ||
} | ||
return ctorRef.build(location, children); | ||
}; | ||
return def(function, builder, false, aliases); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Really really minor: can you remove the empty line or add it to the other places between the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I've added it to the rest (the source wasn't consistent). |
||
interface MultiFunctionBuilder<T> { | ||
T build(Location location, List<Expression> children); | ||
} | ||
|
||
/** | ||
* Build a {@linkplain FunctionDefinition} for a unary function that is not | ||
* aware of time zone but does support {@code DISTINCT}. | ||
|
@@ -325,6 +348,7 @@ static <T extends Function> FunctionDefinition def(Class<T> function, | |
}; | ||
return def(function, builder, false, aliases); | ||
} | ||
|
||
interface DistinctAwareUnaryFunctionBuilder<T> { | ||
T build(Location location, Expression target, boolean distinct); | ||
} | ||
|
@@ -347,6 +371,7 @@ static <T extends Function> FunctionDefinition def(Class<T> function, | |
}; | ||
return def(function, builder, true, aliases); | ||
} | ||
|
||
interface DatetimeUnaryFunctionBuilder<T> { | ||
T build(Location location, Expression target, TimeZone tz); | ||
} | ||
|
@@ -373,6 +398,7 @@ static <T extends Function> FunctionDefinition def(Class<T> function, | |
}; | ||
return def(function, builder, false, aliases); | ||
} | ||
|
||
interface BinaryFunctionBuilder<T> { | ||
T build(Location location, Expression lhs, Expression rhs); | ||
} | ||
|
@@ -391,6 +417,7 @@ private static FunctionDefinition def(Class<? extends Function> function, Functi | |
}; | ||
return new FunctionDefinition(primaryName, unmodifiableList(Arrays.asList(aliases)), function, datetime, realBuilder); | ||
} | ||
|
||
private interface FunctionBuilder { | ||
Function build(Location location, List<Expression> children, boolean distinct, TimeZone tz); | ||
} | ||
|
@@ -450,6 +477,7 @@ private static <T extends Function> FunctionDefinition def(Class<T> function, | |
ctorRef.build(location, children.get(0), children.get(0).dataType()); | ||
return def(function, builder, false, aliases); | ||
} | ||
|
||
private interface CastFunctionBuilder<T> { | ||
T build(Location location, Expression expression, DataType dataType); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hack to get jdbc-csv to support null. /cc @matriv