Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Add Flow control function IF(expr1, expr2, expr3) #990

Merged
merged 9 commits into from
Jan 25, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,10 @@ public FunctionExpression nullif(Expression... expressions) {
return function(BuiltinFunctionName.NULLIF, expressions);
}

public FunctionExpression iffunction(Expression... expressions) {
return function(BuiltinFunctionName.IF, expressions);
}

public static Expression cases(Expression defaultResult,
WhenClause... whenClauses) {
return new CaseClause(Arrays.asList(whenClauses), defaultResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ public enum BuiltinFunctionName {
IS_NULL(FunctionName.of("is null")),
IS_NOT_NULL(FunctionName.of("is not null")),
IFNULL(FunctionName.of("ifnull")),
IF(FunctionName.of("if")),
NULLIF(FunctionName.of("nullif")),
ISNULL(FunctionName.of("isnull")),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public static void register(BuiltinFunctionRepository repository) {
repository.register(nullIf());
repository.register(isNull(BuiltinFunctionName.IS_NULL));
repository.register(isNull(BuiltinFunctionName.ISNULL));
repository.register(ifFunction());
}

private static FunctionResolver not() {
Expand Down Expand Up @@ -100,6 +101,19 @@ private static FunctionResolver isNotNull() {
Collectors.toList()));
}

private static FunctionResolver ifFunction() {
FunctionName functionName = BuiltinFunctionName.IF.getName();
List<ExprType> typeList = ExprCoreType.coreTypes();

List<SerializableFunction<FunctionName, org.apache.commons.lang3.tuple.Pair<FunctionSignature,
FunctionBuilder>>> functionsOne = typeList.stream().map(v ->
impl((UnaryPredicateOperator::exprIf), v, BOOLEAN, v, v))
.collect(Collectors.toList());

FunctionResolver functionResolver = FunctionDSL.define(functionName, functionsOne);
return functionResolver;
}

private static FunctionResolver ifNull() {
FunctionName functionName = BuiltinFunctionName.IFNULL.getName();
List<ExprType> typeList = ExprCoreType.coreTypes();
Expand Down Expand Up @@ -149,4 +163,8 @@ public static ExprValue exprNullIf(ExprValue v1, ExprValue v2) {
return v1.equals(v2) ? LITERAL_NULL : v1;
}

public static ExprValue exprIf(ExprValue v1, ExprValue v2, ExprValue v3) {
return v1.value().equals(LITERAL_TRUE.value()) ? v2 : v3;
harold-wang marked this conversation as resolved.
Show resolved Hide resolved
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,23 @@ private static Stream<Arguments> nullIfArguments() {
});
}

private static Stream<Arguments> ifArguments() {
ArrayList<Expression> exprValueArrayList = new ArrayList<>();
exprValueArrayList.add(DSL.literal(LITERAL_TRUE));
exprValueArrayList.add(DSL.literal(LITERAL_FALSE));

return Lists.cartesianProduct(exprValueArrayList, exprValueArrayList).stream()
.map(list -> {
Expression e1 = list.get(0);

if (e1.valueOf(valueEnv()).value() == LITERAL_TRUE.value()) {
return Arguments.of(e1, DSL.literal("123"), DSL.literal("321"), DSL.literal("123"));
} else {
return Arguments.of(e1, DSL.literal("123"), DSL.literal("321"), DSL.literal("321"));
}
});
}

private static Stream<Arguments> exprIfNullArguments() {
ArrayList<ExprValue> exprValues = new ArrayList<>();
exprValues.add(LITERAL_NULL);
Expand Down Expand Up @@ -200,18 +217,24 @@ public void test_ifnull_predicate(Expression v1, Expression v2, Expression expec
assertEquals(expected.valueOf(valueEnv()), dsl.ifnull(v1, v2).valueOf(valueEnv()));
}

@ParameterizedTest
@MethodSource("exprIfNullArguments")
public void test_exprIfNull_predicate(ExprValue v1, ExprValue v2, ExprValue expected) {
assertEquals(expected.value(), UnaryPredicateOperator.exprIfNull(v1, v2).value());
}

@ParameterizedTest
@MethodSource("nullIfArguments")
public void test_nullif_predicate(Expression v1, Expression v2, Expression expected) {
assertEquals(expected.valueOf(valueEnv()), dsl.nullif(v1, v2).valueOf(valueEnv()));
}

@ParameterizedTest
@MethodSource("ifArguments")
public void test_if_predicate(Expression v1, Expression v2, Expression v3, Expression expected) {
assertEquals(expected.valueOf(valueEnv()), dsl.iffunction(v1, v2, v3).valueOf(valueEnv()));
}

@ParameterizedTest
@MethodSource("exprIfNullArguments")
public void test_exprIfNull_predicate(ExprValue v1, ExprValue v2, ExprValue expected) {
assertEquals(expected.value(), UnaryPredicateOperator.exprIfNull(v1, v2).value());
}

@ParameterizedTest
@MethodSource("exprNullIfArguments")
public void test_exprNullIf_predicate(ExprValue v1, ExprValue v2, ExprValue expected) {
Expand Down
34 changes: 34 additions & 0 deletions docs/user/dql/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1982,6 +1982,40 @@ Example::
| True | False |
+---------------+---------------+

IF
------
harold-wang marked this conversation as resolved.
Show resolved Hide resolved

Description
>>>>>>>>>>>

Specifications:

1. IF(ES_TYPE0, ES_TYPE1, ES_TYPE2) -> ES_TYPE1 or ES_TYPE2
harold-wang marked this conversation as resolved.
Show resolved Hide resolved

Usage: return first parameter is true, return second parameter, otherwise return third one.
harold-wang marked this conversation as resolved.
Show resolved Hide resolved

Argument type: as same as second parameter

Return type: as same as second parameter

Example::

od> SELECT IF(100 > 200, '100', '200')
fetched rows / total rows = 1/1
+-------------------------------+
| IF(100 > 200, '100', '200') |
|-------------------------------|
| 200 |
+-------------------------------+

od> SELECT IF(200 > 100, '100', '200')
fetched rows / total rows = 1/1
+-------------------------------+
| IF(200 > 100, '100', '200') |
|-------------------------------|
| 100 |
+-------------------------------+

CASE
----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -714,12 +714,13 @@ public void right() throws IOException {

@Test
public void ifFuncShouldPassJDBC() {
Assume.assumeTrue(isNewQueryEngineEabled());
JSONObject response = executeJdbcRequest(
"SELECT IF(age > 30, 'True', 'False') AS Ages FROM " + TEST_INDEX_ACCOUNT
+ " WHERE age IS NOT NULL GROUP BY Ages");
assertEquals("Ages", response.query("/schema/0/name"));
assertEquals("IF(age > 30, \'True\', \'False\')", response.query("/schema/0/name"));
assertEquals("Ages", response.query("/schema/0/alias"));
assertEquals("double", response.query("/schema/0/type"));
assertEquals("keyword", response.query("/schema/0/type"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ public void nullifWithNotNullInputTestOne(){
Assume.assumeTrue(isNewQueryEngineEabled());
JSONObject response = new JSONObject(executeQuery(
"SELECT NULLIF(firstname, 'Amber JOHnny') as testnullif "
+ "FROM " + TEST_INDEX_BANK_WITH_NULL_VALUES
+ " limit 2 ", "jdbc"));
+ "FROM " + TEST_INDEX_BANK_WITH_NULL_VALUES
+ " limit 2 ", "jdbc"));
verifySchema(response,
schema("NULLIF(firstname, 'Amber JOHnny')", "testnullif", "keyword"));
verifyDataRows(response,
Expand Down Expand Up @@ -193,6 +193,39 @@ public void isnullWithMathExpr() throws IOException{
);
}

@Test
public void ifShouldPassJDBC() throws IOException {
Assume.assumeTrue(isNewQueryEngineEabled());
JSONObject response = executeJdbcRequest(
"SELECT IF(2 > 0, \'hello\', \'world\') AS name FROM " + TEST_INDEX_ACCOUNT);
assertEquals("IF(2 > 0, \'hello\', \'world\')", response.query("/schema/0/name"));
assertEquals("name", response.query("/schema/0/alias"));
assertEquals("keyword", response.query("/schema/0/type"));
}

@Test
public void ifWithTrueAndFalseCondition() throws IOException {
Assume.assumeTrue(isNewQueryEngineEabled());
JSONObject response = new JSONObject(executeQuery(
"SELECT IF(2 < 0, firstname, lastname) as IF0, "
+ " IF(2 > 0, firstname, lastname) as IF1, "
+ " firstname as IF2, "
+ " lastname as IF3 "
+ " FROM " + TEST_INDEX_BANK_WITH_NULL_VALUES
+ " limit 2 ", "jdbc" ));
verifySchema(response,
schema("IF(2 < 0, firstname, lastname)", "IF0", "keyword"),
schema("IF(2 > 0, firstname, lastname)", "IF1", "keyword"),
schema("firstname", "IF2", "text"),
schema("lastname", "IF3", "keyword")
);
verifyDataRows(response,
rows("Duke Willmington", "Amber JOHnny", "Amber JOHnny", "Duke Willmington"),
rows("Bond", "Hattie", "Hattie", "Bond")
);

}

private SearchHits query(String query) throws IOException {
final String rsp = executeQueryWithStringOutput(query);

Expand Down
2 changes: 1 addition & 1 deletion ppl/src/main/antlr/OpenDistroPPLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ dateAndTimeFunctionBase
/** condition function return boolean value */
conditionFunctionBase
: LIKE
| ISNULL | ISNOTNULL | IFNULL | NULLIF
| IF | ISNULL | ISNOTNULL | IFNULL | NULLIF
;

textFunctionBase
Expand Down
2 changes: 1 addition & 1 deletion sql/src/main/antlr/OpenDistroSQLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ textFunctionName
;

flowControlFunctionName
: IFNULL | NULLIF | ISNULL
: IF | IFNULL | NULLIF | ISNULL
;

functionArgs
Expand Down