Skip to content

Commit 0ecc7f1

Browse files
Add isnotempty PPL function
Adds `isnotempty(field)` function to PPL that returns true when a field is not null and not an empty string — the logical negation of `isempty(field)`. Implementation: NOT(IS_NULL(arg) OR IS_EMPTY(arg)) - ANTLR grammar: added ISNOTEMPTY token and parser rules in all three grammar modules (ppl, language-grammar, async-query-core) - BuiltinFunctionName: added IS_NOT_EMPTY enum constant - PPLFuncImpTable: registered Calcite implementation - Integration test: testIsNotEmpty in CalcitePPLConditionBuiltinFunctionIT - Documentation: added ISNOTEMPTY section to condition functions docs Resolves #5182 Signed-off-by: Luca Cavenaghi <lucacavenaghics97@gmail.com>
1 parent acf5fcb commit 0ecc7f1

11 files changed

Lines changed: 82 additions & 2 deletions

File tree

async-query-core/src/main/antlr/OpenSearchPPLLexer.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ REPLACE: 'REPLACE';
373373
REVERSE: 'REVERSE';
374374
CAST: 'CAST';
375375
ISEMPTY: 'ISEMPTY';
376+
ISNOTEMPTY: 'ISNOTEMPTY';
376377
ISBLANK: 'ISBLANK';
377378

378379
// JSON TEXT FUNCTIONS

async-query-core/src/main/antlr/OpenSearchPPLParser.g4

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ positionFunction
468468
booleanExpression
469469
: booleanFunctionCall # booleanFunctionCallExpr
470470
| isEmptyExpression # isEmptyExpr
471+
| isNotEmptyExpression # isNotEmptyExpr
471472
| valueExpressionList NOT? IN LT_SQR_PRTHS subSearch RT_SQR_PRTHS # inSubqueryExpr
472473
| EXISTS LT_SQR_PRTHS subSearch RT_SQR_PRTHS # existsSubqueryExpr
473474
| cidrMatchFunctionCall # cidrFunctionCallExpr
@@ -477,6 +478,10 @@ booleanExpression
477478
: (ISEMPTY | ISBLANK) LT_PRTHS functionArg RT_PRTHS
478479
;
479480

481+
isNotEmptyExpression
482+
: ISNOTEMPTY LT_PRTHS functionArg RT_PRTHS
483+
;
484+
480485
caseFunction
481486
: CASE LT_PRTHS logicalExpression COMMA valueExpression (COMMA logicalExpression COMMA valueExpression)* (ELSE valueExpression)? RT_PRTHS
482487
;
@@ -860,6 +865,7 @@ textFunctionName
860865
| REPLACE
861866
| REVERSE
862867
| ISEMPTY
868+
| ISNOTEMPTY
863869
| ISBLANK
864870
;
865871

core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ public enum BuiltinFunctionName {
289289

290290
IS_PRESENT(FunctionName.of("ispresent")),
291291
IS_EMPTY(FunctionName.of("isempty")),
292+
IS_NOT_EMPTY(FunctionName.of("isnotempty")),
292293
IS_BLANK(FunctionName.of("isblank")),
293294

294295
ROW_NUMBER(FunctionName.of("row_number")),

core/src/main/java/org/opensearch/sql/expression/function/PPLFuncImpTable.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
import static org.opensearch.sql.expression.function.BuiltinFunctionName.INTERNAL_TRANSLATE3;
9292
import static org.opensearch.sql.expression.function.BuiltinFunctionName.IS_BLANK;
9393
import static org.opensearch.sql.expression.function.BuiltinFunctionName.IS_EMPTY;
94+
import static org.opensearch.sql.expression.function.BuiltinFunctionName.IS_NOT_EMPTY;
9495
import static org.opensearch.sql.expression.function.BuiltinFunctionName.IS_NOT_NULL;
9596
import static org.opensearch.sql.expression.function.BuiltinFunctionName.IS_NULL;
9697
import static org.opensearch.sql.expression.function.BuiltinFunctionName.IS_PRESENT;
@@ -1252,6 +1253,17 @@ void populate() {
12521253
builder.makeCall(SqlStdOperatorTable.IS_NULL, arg),
12531254
builder.makeCall(SqlStdOperatorTable.IS_EMPTY, arg)),
12541255
PPLTypeChecker.family(SqlTypeFamily.ANY));
1256+
register(
1257+
IS_NOT_EMPTY,
1258+
(FunctionImp1)
1259+
(builder, arg) ->
1260+
builder.makeCall(
1261+
SqlStdOperatorTable.NOT,
1262+
builder.makeCall(
1263+
SqlStdOperatorTable.OR,
1264+
builder.makeCall(SqlStdOperatorTable.IS_NULL, arg),
1265+
builder.makeCall(SqlStdOperatorTable.IS_EMPTY, arg))),
1266+
PPLTypeChecker.family(SqlTypeFamily.ANY));
12551267
register(
12561268
IS_BLANK,
12571269
(FunctionImp1)

docs/user/ppl/functions/condition.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,8 +642,40 @@ fetched rows / total rows = 4/4
642642
| False | | True | null |
643643
+---------------+---------+-------------------+----------+
644644
```
645-
646-
## EARLIEST
645+
646+
## ISNOTEMPTY
647+
648+
### Description
649+
650+
Usage: `isnotempty(field)` returns true if the field is not null and is not an empty string.
651+
652+
**Argument type:** All supported data types.
653+
**Return type:** `BOOLEAN`
654+
655+
### Example
656+
657+
```ppl
658+
source=accounts
659+
| eval temp = ifnull(employer, ' ')
660+
| eval `isnotempty(employer)` = isnotempty(employer), `isnotempty(temp)` = isnotempty(temp)
661+
| fields `isnotempty(temp)`, temp, `isnotempty(employer)`, employer
662+
```
663+
664+
Expected output:
665+
666+
```text
667+
fetched rows / total rows = 4/4
668+
+------------------+---------+----------------------+----------+
669+
| isnotempty(temp) | temp | isnotempty(employer) | employer |
670+
|------------------+---------+----------------------+----------|
671+
| True | Pyrami | True | Pyrami |
672+
| True | Netagy | True | Netagy |
673+
| True | Quility | True | Quility |
674+
| True | | False | null |
675+
+------------------+---------+----------------------+----------|
676+
```
677+
678+
## EARLIEST
647679

648680
### Description
649681

docs/user/ppl/functions/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ PPL supports a wide range of built-in functions for data processing and analysis
5454
- [ISPRESENT](condition.md/#ispresent)
5555
- [ISBLANK](condition.md/#isblank)
5656
- [ISEMPTY](condition.md/#isempty)
57+
- [ISNOTEMPTY](condition.md/#isnotempty)
5758
- [EARLIEST](condition.md/#earliest)
5859
- [LATEST](condition.md/#latest)
5960
- [REGEXP_MATCH](condition.md/#regexp_match)

integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLConditionBuiltinFunctionIT.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,28 @@ public void testIsEmpty() throws IOException {
282282
verifyDataRows(actual, rows(null, 10), rows("", 57));
283283
}
284284

285+
@Test
286+
public void testIsNotEmpty() throws IOException {
287+
JSONObject actual =
288+
executeQuery(
289+
String.format(
290+
"source=%s | where isnotempty(name) | fields name, age",
291+
TEST_INDEX_STATE_COUNTRY_WITH_NULL));
292+
293+
verifySchema(actual, schema("name", "string"), schema("age", "int"));
294+
295+
// isnotempty = NOT isempty. isempty returns (null,10) and ("",57).
296+
// So isnotempty returns everything else: Jake, Hello, John, Jane, Kevin, whitespace.
297+
verifyDataRows(
298+
actual,
299+
rows("Jake", 70),
300+
rows("Hello", 30),
301+
rows("John", 25),
302+
rows("Jane", 20),
303+
rows("Kevin", null),
304+
rows(" ", 27));
305+
}
306+
285307
@Test
286308
public void testIsBlank() throws IOException {
287309
JSONObject actual =

language-grammar/src/main/antlr4/OpenSearchPPLLexer.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ BETWEEN: 'BETWEEN';
419419
CIDRMATCH: 'CIDRMATCH';
420420
ISPRESENT: 'ISPRESENT';
421421
ISEMPTY: 'ISEMPTY';
422+
ISNOTEMPTY: 'ISNOTEMPTY';
422423
ISBLANK: 'ISBLANK';
423424

424425
// FLOWCONTROL FUNCTIONS

language-grammar/src/main/antlr4/OpenSearchPPLParser.g4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,7 @@ conditionFunctionBase
851851
| EARLIEST
852852
| LATEST
853853
| ISEMPTY
854+
| ISNOTEMPTY
854855
| ISBLANK
855856
;
856857

@@ -877,6 +878,7 @@ textFunctionName
877878
| REPLACE
878879
| REVERSE
879880
| ISEMPTY
881+
| ISNOTEMPTY
880882
| ISBLANK
881883
;
882884

ppl/src/main/antlr/OpenSearchPPLLexer.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ CIDRMATCH: 'CIDRMATCH';
463463
BETWEEN: 'BETWEEN';
464464
ISPRESENT: 'ISPRESENT';
465465
ISEMPTY: 'ISEMPTY';
466+
ISNOTEMPTY: 'ISNOTEMPTY';
466467
ISBLANK: 'ISBLANK';
467468

468469
// COLLECTION FUNCTIONS

0 commit comments

Comments
 (0)