Skip to content
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

feat: Support unknown keyword #2141

Merged
merged 1 commit into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -42,6 +42,7 @@
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression;
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.Matches;
Expand Down Expand Up @@ -267,6 +268,12 @@ default void visit(IsBooleanExpression isBooleanExpression) {
this.visit(isBooleanExpression, null);
}

<S> T visit(IsUnknownExpression isUnknownExpression, S context);

default void visit(IsUnknownExpression isUnknownExpression) {
this.visit(isUnknownExpression, null);
}

<S> T visit(LikeExpression likeExpression, S context);

default void visit(LikeExpression likeExpression) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression;
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.Matches;
Expand Down Expand Up @@ -263,6 +264,11 @@ public <S> T visit(IsBooleanExpression isBooleanExpression, S context) {
return isBooleanExpression.getLeftExpression().accept(this, context);
}

@Override
public <S> T visit(IsUnknownExpression isUnknownExpression, S context) {
return isUnknownExpression.getLeftExpression().accept(this, context);
}

@Override
public <S> T visit(LikeExpression likeExpression, S context) {
return visitBinaryExpression(likeExpression, context);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2025 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.expression.operators.relational;

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;

public class IsUnknownExpression extends ASTNodeAccessImpl implements Expression {

private Expression leftExpression;
private boolean isNot = false;

public Expression getLeftExpression() {
return leftExpression;
}

public void setLeftExpression(Expression expression) {
leftExpression = expression;
}

public boolean isNot() {
return isNot;
}

public void setNot(boolean isNot) {
this.isNot = isNot;
}

@Override
public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
return expressionVisitor.visit(this, context);
}

@Override
public String toString() {
return leftExpression + " IS" + (isNot ? " NOT" : "") + " UNKNOWN";
}

public IsUnknownExpression withLeftExpression(Expression leftExpression) {
this.setLeftExpression(leftExpression);
return this;
}

public IsUnknownExpression withNot(boolean isNot) {
this.setNot(isNot);
return this;
}

public <E extends Expression> E getLeftExpression(Class<E> type) {
return type.cast(getLeftExpression());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ public class ParserKeywordsUtils {
{"UNBOUNDED", RESTRICTED_JSQLPARSER},
{"UNION", RESTRICTED_SQL2016},
{"UNIQUE", RESTRICTED_SQL2016},
{"UNKNOWN", RESTRICTED_SQL2016},
{"UNPIVOT", RESTRICTED_JSQLPARSER},
{"USE", RESTRICTED_JSQLPARSER},
{"USING", RESTRICTED_SQL2016},
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression;
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.Matches;
Expand Down Expand Up @@ -530,6 +531,12 @@ public <S> Void visit(IsBooleanExpression isBooleanExpression, S context) {
return null;
}

@Override
public <S> Void visit(IsUnknownExpression isUnknownExpression, S context) {

return null;
}

@Override
public <S> Void visit(JdbcParameter jdbcParameter, S context) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression;
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.Matches;
Expand Down Expand Up @@ -428,6 +429,17 @@ public <S> StringBuilder visit(IsBooleanExpression isBooleanExpression, S contex
return buffer;
}

@Override
public <S> StringBuilder visit(IsUnknownExpression isUnknownExpression, S context) {
isUnknownExpression.getLeftExpression().accept(this, context);
if (isUnknownExpression.isNot()) {
buffer.append(" IS NOT UNKNOWN");
} else {
buffer.append(" IS UNKNOWN");
}
return buffer;
}

@Override
public <S> StringBuilder visit(JdbcParameter jdbcParameter, S context) {
buffer.append(jdbcParameter.getParameterCharacter());
Expand Down Expand Up @@ -514,6 +526,10 @@ public void visit(IsBooleanExpression isBooleanExpression) {
visit(isBooleanExpression, null);
}

public void visit(IsUnknownExpression isUnknownExpression) {
visit(isUnknownExpression, null);
}

public void visit(JdbcParameter jdbcParameter) {
visit(jdbcParameter, null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression;
import net.sf.jsqlparser.expression.operators.relational.IsDistinctExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression;
import net.sf.jsqlparser.expression.operators.relational.JsonOperator;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.Matches;
Expand Down Expand Up @@ -289,6 +290,12 @@ public <S> Void visit(IsBooleanExpression isBooleanExpression, S context) {
return null;
}

@Override
public <S> Void visit(IsUnknownExpression isUnknownExpression, S context) {
isUnknownExpression.getLeftExpression().accept(this, context);
return null;
}

@Override
public <S> Void visit(JdbcParameter jdbcParameter, S context) {
validateFeature(Feature.jdbcParameter);
Expand Down Expand Up @@ -383,6 +390,10 @@ public void visit(IsBooleanExpression isBooleanExpression) {
visit(isBooleanExpression, null); // Call the parametrized visit method with null context
}

public void visit(IsUnknownExpression isUnknownExpression) {
visit(isUnknownExpression, null); // Call the parametrized visit method with null context
}

public void visit(JdbcParameter jdbcParameter) {
visit(jdbcParameter, null); // Call the parametrized visit method with null context
}
Expand Down
18 changes: 18 additions & 0 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
| <K_UNBOUNDED: "UNBOUNDED">
| <K_UNION:"UNION">
| <K_UNIQUE:"UNIQUE">
| <K_UNKNOWN:"UNKNOWN">
| <K_UNLOGGED: "UNLOGGED">
| <K_UNPIVOT:"UNPIVOT">
| <K_UPDATE:"UPDATE">
Expand Down Expand Up @@ -4153,6 +4154,8 @@ Expression SQLCondition():
|
LOOKAHEAD(IsBooleanExpression()) result=IsBooleanExpression(left)
|
LOOKAHEAD(IsUnknownExpression()) result=IsUnknownExpression(left)
|
LOOKAHEAD(2) result=LikeExpression(left)
|
LOOKAHEAD(IsDistinctExpression()) result=IsDistinctExpression(left)
Expand Down Expand Up @@ -4366,6 +4369,21 @@ Expression IsBooleanExpression(Expression leftExpression):
}
}

Expression IsUnknownExpression(Expression leftExpression):
{
IsUnknownExpression result = new IsUnknownExpression();
}
{
(
<K_IS> [<K_NOT> { result.setNot(true); } ] <K_UNKNOWN>
)

{
result.setLeftExpression(leftExpression);
return result;
}
}

Expression ExistsExpression():
{
ExistsExpression result = new ExistsExpression();
Expand Down
12 changes: 8 additions & 4 deletions src/site/sphinx/keywords.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and
+----------------------+-------------+-----------+
| QUALIFY | Yes | |
+----------------------+-------------+-----------+
| HAVING | Yes | Yes |
| HAVING | Yes | Yes |
+----------------------+-------------+-----------+
| IF | Yes | Yes |
+----------------------+-------------+-----------+
Expand All @@ -97,7 +97,7 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and
+----------------------+-------------+-----------+
| INTERVAL | Yes | Yes |
+----------------------+-------------+-----------+
| INTO | Yes | Yes |
| INTO | Yes | Yes |
+----------------------+-------------+-----------+
| IS | Yes | Yes |
+----------------------+-------------+-----------+
Expand All @@ -109,7 +109,7 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and
+----------------------+-------------+-----------+
| LIKE | Yes | Yes |
+----------------------+-------------+-----------+
| LIMIT | Yes | Yes |
| LIMIT | Yes | Yes |
+----------------------+-------------+-----------+
| MINUS | Yes | Yes |
+----------------------+-------------+-----------+
Expand Down Expand Up @@ -139,7 +139,9 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and
+----------------------+-------------+-----------+
| OPTIMIZE | Yes | Yes |
+----------------------+-------------+-----------+
| PIVOT | Yes | Yes |
| OVERWRITE | Yes | Yes |
+----------------------+-------------+-----------+
| PIVOT | Yes | Yes |
+----------------------+-------------+-----------+
| PREFERRING | Yes | Yes |
+----------------------+-------------+-----------+
Expand Down Expand Up @@ -181,6 +183,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and
+----------------------+-------------+-----------+
| UNIQUE | Yes | Yes |
+----------------------+-------------+-----------+
| UNKNOWN | Yes | Yes |
+----------------------+-------------+-----------+
| UNPIVOT | Yes | Yes |
+----------------------+-------------+-----------+
| USE | Yes | Yes |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2023 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.expression.operators.relational;

import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.test.TestUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

class IsUnknownExpressionTest {

@ParameterizedTest
@ValueSource(strings = {
"SELECT * FROM mytable WHERE 1 IS UNKNOWN",
"SELECT * FROM mytable WHERE 1 IS NOT UNKNOWN",
})
public void testIsUnknownExpression(String sqlStr) {
assertDoesNotThrow(() -> TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr));
}

@Test
void testStringConstructor() {
Column column = new Column("x");

IsUnknownExpression defaultIsUnknownExpression =
new IsUnknownExpression().withLeftExpression(column);
TestUtils.assertExpressionCanBeDeparsedAs(defaultIsUnknownExpression, "x IS UNKNOWN");

IsUnknownExpression isUnknownExpression =
new IsUnknownExpression().withLeftExpression(column).withNot(false);
TestUtils.assertExpressionCanBeDeparsedAs(isUnknownExpression, "x IS UNKNOWN");

IsUnknownExpression isNotUnknownExpression =
new IsUnknownExpression().withLeftExpression(column).withNot(true);
TestUtils.assertExpressionCanBeDeparsedAs(isNotUnknownExpression, "x IS NOT UNKNOWN");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public class ReflectionModelTest {
new net.sf.jsqlparser.expression.operators.relational.InExpression(),
new net.sf.jsqlparser.expression.operators.relational.IsBooleanExpression(),
new net.sf.jsqlparser.expression.operators.relational.IsNullExpression(),
new net.sf.jsqlparser.expression.operators.relational.IsUnknownExpression(),
new net.sf.jsqlparser.expression.operators.relational.JsonOperator("@>"),
new net.sf.jsqlparser.expression.operators.relational.LikeExpression(),
new net.sf.jsqlparser.expression.operators.relational.Matches(),
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2271,6 +2271,18 @@ public void testIsNotFalse() throws JSQLParserException {
assertSqlCanBeParsedAndDeparsed(statement);
}

@Test
public void testIsUnknown() throws JSQLParserException {
String statement = "SELECT col FROM tbl WHERE col IS UNKNOWN";
assertSqlCanBeParsedAndDeparsed(statement);
}

@Test
public void testIsNotUnknown() throws JSQLParserException {
String statement = "SELECT col FROM tbl WHERE col IS NOT UNKNOWN";
assertSqlCanBeParsedAndDeparsed(statement);
}

@Test
public void testTSQLJoin() throws JSQLParserException {
String stmt = "SELECT * FROM tabelle1, tabelle2 WHERE tabelle1.a *= tabelle2.b";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,12 @@ public void testIsNull() {
validateNoErrors("SELECT * FROM tab t WHERE t.col IS NOT NULL", 1, EXPRESSIONS);
}

@Test
public void testIsUnknown() {
validateNoErrors("SELECT * FROM tab t WHERE t.col IS UNKNOWN", 1, EXPRESSIONS);
validateNoErrors("SELECT * FROM tab t WHERE t.col IS NOT UNKNOWN", 1, EXPRESSIONS);
}

@Test
public void testLike() {
validateNoErrors("SELECT * FROM tab t WHERE t.col LIKE '%search for%'", 1, EXPRESSIONS);
Expand Down
Loading