From 7acf9d548edc854ddca5a9de0de151f5080ef590 Mon Sep 17 00:00:00 2001 From: lucarota Date: Fri, 15 Nov 2024 00:33:59 +0100 Subject: [PATCH 1/2] fix: Issue #2109 true and false value parsed as column instead of BooleanValue (#2110) Co-authored-by: Luca Rota --- .../jsqlparser/expression/BooleanValue.java | 74 +++++++++++++++++++ .../expression/ExpressionVisitor.java | 6 ++ .../expression/ExpressionVisitorAdapter.java | 5 ++ .../parser/ParserKeywordsUtils.java | 2 + .../sf/jsqlparser/util/TablesNamesFinder.java | 7 ++ .../util/deparser/ExpressionDeParser.java | 12 +++ .../validator/ExpressionValidator.java | 11 +++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 8 +- src/site/sphinx/keywords.rst | 4 + .../expression/BooleanValueTest.java | 49 ++++++++++++ .../statement/update/UpdateTest.java | 16 ++++ 11 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/expression/BooleanValue.java create mode 100644 src/test/java/net/sf/jsqlparser/expression/BooleanValueTest.java diff --git a/src/main/java/net/sf/jsqlparser/expression/BooleanValue.java b/src/main/java/net/sf/jsqlparser/expression/BooleanValue.java new file mode 100644 index 000000000..258a89e16 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/expression/BooleanValue.java @@ -0,0 +1,74 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +import java.util.Objects; + +/** + * A boolean value true/false + */ +public final class BooleanValue extends ASTNodeAccessImpl implements Expression { + + private boolean value = false; + + public BooleanValue() { + // empty constructor + } + + public BooleanValue(String value) { + this(Boolean.parseBoolean(value)); + } + + public BooleanValue(boolean bool) { + value = bool; + } + + public boolean getValue() { + return value; + } + + public void setValue(boolean bool) { + value = bool; + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public String toString() { + return Boolean.toString(value); + } + + public BooleanValue withValue(boolean bool) { + this.setValue(bool); + return this; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + BooleanValue that = (BooleanValue) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index a6a0992b0..19067bf47 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -147,6 +147,12 @@ default void visit(StringValue stringValue) { this.visit(stringValue, null); } + T visit(BooleanValue booleanValue, S context); + + default void visit(BooleanValue booleanValue) { + this.visit(booleanValue, null); + } + T visit(Addition addition, S context); default void visit(Addition addition) { diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index 6a54e3851..89bacff48 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -156,6 +156,11 @@ public T visit(StringValue stringValue, S context) { return visitExpression(stringValue, context); } + @Override + public T visit(BooleanValue booleanValue, S context) { + return visitExpression(booleanValue, context); + } + @Override public T visit(Addition addition, S context) { return visitBinaryExpression(addition, context); diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java index 80bc71779..2ac33fbd3 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -68,6 +68,7 @@ public class ParserKeywordsUtils { {"EXCEPT", RESTRICTED_SQL2016}, {"EXCLUDES", RESTRICTED_JSQLPARSER}, {"EXISTS", RESTRICTED_SQL2016}, + {"FALSE", RESTRICTED_SQL2016}, {"FETCH", RESTRICTED_SQL2016}, {"FINAL", RESTRICTED_JSQLPARSER}, {"FOR", RESTRICTED_SQL2016}, @@ -131,6 +132,7 @@ public class ParserKeywordsUtils { {"TABLES", RESTRICTED_ALIAS}, {"TOP", RESTRICTED_SQL2016}, {"TRAILING", RESTRICTED_SQL2016}, + {"TRUE", RESTRICTED_SQL2016}, {"UNBOUNDED", RESTRICTED_JSQLPARSER}, {"UNION", RESTRICTED_SQL2016}, {"UNIQUE", RESTRICTED_SQL2016}, diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index ee4601e75..122d5cf2e 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -16,6 +16,7 @@ import net.sf.jsqlparser.expression.ArrayConstructor; import net.sf.jsqlparser.expression.ArrayExpression; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.BooleanValue; import net.sf.jsqlparser.expression.CaseExpression; import net.sf.jsqlparser.expression.CastExpression; import net.sf.jsqlparser.expression.CollateExpression; @@ -626,6 +627,12 @@ public Void visit(StringValue stringValue, S context) { return null; } + @Override + public Void visit(BooleanValue booleanValue, S context) { + + return null; + } + @Override public Void visit(Subtraction subtraction, S context) { visitBinaryExpression(subtraction); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index 3b0e7281e..dc0c2b21f 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -16,6 +16,7 @@ import net.sf.jsqlparser.expression.ArrayConstructor; import net.sf.jsqlparser.expression.ArrayExpression; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.BooleanValue; import net.sf.jsqlparser.expression.CaseExpression; import net.sf.jsqlparser.expression.CastExpression; import net.sf.jsqlparser.expression.CollateExpression; @@ -621,6 +622,13 @@ public StringBuilder visit(StringValue stringValue, S context) { return buffer; } + @Override + public StringBuilder visit(BooleanValue booleanValue, S context) { + buffer.append(booleanValue.getValue()); + + return buffer; + } + @Override public StringBuilder visit(Subtraction subtraction, S context) { deparse(subtraction, " - ", null); @@ -749,6 +757,10 @@ public void visit(StringValue stringValue) { visit(stringValue, null); } + public void visit(BooleanValue booleanValue) { + visit(booleanValue, null); + } + public void visit(Subtraction subtraction) { visit(subtraction, null); } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java index 8c3a36066..c4fc26a94 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java @@ -15,6 +15,7 @@ import net.sf.jsqlparser.expression.ArrayConstructor; import net.sf.jsqlparser.expression.ArrayExpression; import net.sf.jsqlparser.expression.BinaryExpression; +import net.sf.jsqlparser.expression.BooleanValue; import net.sf.jsqlparser.expression.CaseExpression; import net.sf.jsqlparser.expression.CastExpression; import net.sf.jsqlparser.expression.CollateExpression; @@ -486,6 +487,12 @@ public Void visit(StringValue stringValue, S context) { return null; } + @Override + public Void visit(BooleanValue booleanValue, S context) { + // nothing to validate + return null; + } + @Override public Void visit(Subtraction subtraction, S context) { visitBinaryExpression(subtraction, " - "); @@ -620,6 +627,10 @@ public void visit(StringValue stringValue) { visit(stringValue, null); } + public void visit(BooleanValue booleanValue) { + visit(booleanValue, null); + } + public void visit(Subtraction subtraction) { visit(subtraction, null); } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 51b111cfb..a612e7f9f 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2022,7 +2022,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="END" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FALSE" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="PARALLEL" | tk="PARENT" | tk="PARTITION" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="RENAME" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAFE_CAST" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="STORED" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUE" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VERBOSE" | tk="VIEW" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="END" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="PARALLEL" | tk="PARENT" | tk="PARTITION" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="RENAME" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAFE_CAST" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="STORED" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VERBOSE" | tk="VIEW" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) { return tk.image; } } @@ -4786,7 +4786,7 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(2, {!interrupted}) retval=DateTimeLiteralExpression() - | LOOKAHEAD( 3 , {!interrupted}) retval=StructType() + | LOOKAHEAD(3 , {!interrupted}) retval=StructType() | LOOKAHEAD(3, {!interrupted}) retval=ArrayConstructor(true) @@ -4800,6 +4800,8 @@ Expression PrimaryExpression() #PrimaryExpression: | LOOKAHEAD(2, {!interrupted}) retval=Column() + | LOOKAHEAD(2, {!interrupted}) (token= | token=) { retval = new BooleanValue(token.image); } + | token= { retval = new StringValue(token.image); linkAST(retval,jjtThis); } | "{d" token= "}" { retval = new DateValue(token.image); } @@ -6750,7 +6752,7 @@ String AList(): "(" ( - ( (tk= | tk= | tk=) { retval.append(tk.image); } + ( (tk= | tk= | tk= | tk= | tk=) { retval.append(tk.image); } | (name=RelObjectNameWithoutValue()) { retval.append(name); }) [("," {retval.append(",");} | "=" {retval.append("=");})] )* diff --git a/src/site/sphinx/keywords.rst b/src/site/sphinx/keywords.rst index 159c2fb85..8e890215e 100644 --- a/src/site/sphinx/keywords.rst +++ b/src/site/sphinx/keywords.rst @@ -53,6 +53,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | EXISTS | Yes | Yes | +----------------------+-------------+-----------+ +| FALSE | Yes | Yes | ++----------------------+-------------+-----------+ | FETCH | Yes | Yes | +----------------------+-------------+-----------+ | FINAL | Yes | Yes | @@ -179,6 +181,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | TRAILING | Yes | Yes | +----------------------+-------------+-----------+ +| TRUE | Yes | Yes | ++----------------------+-------------+-----------+ | UNBOUNDED | Yes | Yes | +----------------------+-------------+-----------+ | UNION | Yes | Yes | diff --git a/src/test/java/net/sf/jsqlparser/expression/BooleanValueTest.java b/src/test/java/net/sf/jsqlparser/expression/BooleanValueTest.java new file mode 100644 index 000000000..93c936188 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/expression/BooleanValueTest.java @@ -0,0 +1,49 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2024 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.expression; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * + * @author tw + */ +public class BooleanValueTest { + + @Test + public void testTrueValue() { + BooleanValue value = new BooleanValue("true"); + + assertTrue(value.getValue()); + } + + @Test + public void testFalseValue() { + BooleanValue value = new BooleanValue("false"); + + assertFalse(value.getValue()); + } + + @Test + public void testWrongValueAsFalseLargeNumber() { + BooleanValue value = new BooleanValue("test"); + + assertFalse(value.getValue()); + } + + @Test + public void testNullStringValue() { + BooleanValue value = new BooleanValue(null); + + assertFalse(value.getValue()); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java b/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java index 75ff452b0..127b4cfb7 100644 --- a/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/update/UpdateTest.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.update; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.BooleanValue; import net.sf.jsqlparser.expression.DoubleValue; import net.sf.jsqlparser.expression.JdbcParameter; import net.sf.jsqlparser.expression.LongValue; @@ -36,6 +37,7 @@ import static net.sf.jsqlparser.test.TestUtils.assertUpdateMysqlHintExists; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -550,4 +552,18 @@ public void testPreferringClause(String sqlStr) throws JSQLParserException { assertSqlCanBeParsedAndDeparsed(sqlStr); } + @Test + public void testUpdateWithBoolean() throws JSQLParserException { + String statement = "UPDATE mytable set col1='as', col2=true Where o >= 3"; + Update update = (Update) PARSER_MANAGER.parse(new StringReader(statement)); + assertEquals("mytable", update.getTable().toString()); + assertEquals(2, update.getUpdateSets().size()); + assertEquals("col1", update.getUpdateSets().get(0).getColumns().get(0).getColumnName()); + assertEquals("col2", update.getUpdateSets().get(1).getColumns().get(0).getColumnName()); + assertEquals("as", + ((StringValue) update.getUpdateSets().get(0).getValues().get(0)).getValue()); + assertInstanceOf(BooleanValue.class, update.getUpdateSets().get(1).getValues().get(0)); + assertTrue(((BooleanValue) update.getUpdateSets().get(1).getValues().get(0)).getValue()); + assertInstanceOf(GreaterThanEquals.class, update.getWhere()); + } } From f80800ca5294e89b618998c527d67992da88aa8a Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sat, 16 Nov 2024 10:50:23 +0700 Subject: [PATCH 2/2] feat: proper `:` JSon operator - `:` is allowed as delimiter in table names (for INFORMIX) - otherwise `:` will return a JSON expression and can't be used as column delimiter - see #1134 and #2001 Signed-off-by: Andreas Reichel --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 20 +++++++++++++++++-- .../expression/JsonExpressionTest.java | 12 ++++++++++- .../select/ExpressionDelimiterTest.java | 10 +++++++--- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index a612e7f9f..3356c2066 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -1969,6 +1969,7 @@ MergeOperation MergeWhenNotMatched() : { { return mi; } } +// table names seem to allow ":" delimiters, e.g. for Informix see #1134 ObjectNames RelObjectNames() : { String token = null; Token delimiter = null; @@ -1984,8 +1985,23 @@ ObjectNames RelObjectNames() : { { return new ObjectNames(data, delimiters); } } -// See: http://technet.microsoft.com/en-us/library/ms187879%28v=sql.105%29.aspx +// column names do not allow ":" delimeters as those represent JSON `GET` operators +ObjectNames ColumnIdentifier() : { + String token = null; + Token delimiter = null; + List data = new ArrayList(); + List delimiters = new ArrayList(); +} { + token = RelObjectNameExt() { data.add(token); } + ( + LOOKAHEAD (2) ( delimiter = "." ) { delimiters.add(delimiter.image); } (( delimiter = "." ) { data.add(null); delimiters.add(delimiter.image); })* + token = RelObjectNameExt2() { data.add(token); } + ) * + { return new ObjectNames(data, delimiters); } +} + +// See: http://technet.microsoft.com/en-us/library/ms187879%28v=sql.105%29.aspx Column Column() #Column : { ObjectNames data = null; @@ -1993,7 +2009,7 @@ Column Column() #Column : Token tk = null; } { - data = RelObjectNames() + data = ColumnIdentifier() [ LOOKAHEAD(2) tk= ] // @todo: we better should return a SEQUENCE instead of a COLUMN [ LOOKAHEAD(2) "." { data.getNames().add("nextval"); } ] diff --git a/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java b/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java index 1a02dbcc2..cb4e92ac6 100644 --- a/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/JsonExpressionTest.java @@ -10,6 +10,8 @@ package net.sf.jsqlparser.expression; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.statement.select.PlainSelect; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -40,7 +42,15 @@ void testIssue1792() throws JSQLParserException { @Test void testSnowflakeGetOperator() throws JSQLParserException { String sqlStr = "SELECT v:'attr[0].name' FROM vartab;"; - assertSqlCanBeParsedAndDeparsed(sqlStr, true); + PlainSelect st = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertInstanceOf(JsonExpression.class, st.getSelectItem(0).getExpression()); + } + + @Test + void testDataBricksExtractPathOperator() throws JSQLParserException { + String sqlStr = "SELECT C1:PRICE J FROM VALUES('{\"price\":5}')AS T(C1)"; + PlainSelect st = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertInstanceOf(JsonExpression.class, st.getSelectItem(0).getExpression()); } @Test diff --git a/src/test/java/net/sf/jsqlparser/statement/select/ExpressionDelimiterTest.java b/src/test/java/net/sf/jsqlparser/statement/select/ExpressionDelimiterTest.java index cb4a63c97..6c14a331f 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/ExpressionDelimiterTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/ExpressionDelimiterTest.java @@ -10,7 +10,10 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.JsonExpression; import net.sf.jsqlparser.schema.Column; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.List; @@ -24,12 +27,13 @@ public class ExpressionDelimiterTest { public void testColumnWithDifferentDelimiters() throws JSQLParserException { String statement = "SELECT mytable.mycolumn:parent:child FROM mytable"; PlainSelect parsed = (PlainSelect) assertSqlCanBeParsedAndDeparsed(statement); - Column column = parsed.getSelectItem(0).getExpression(Column.class); - assertEquals(":", column.getTableDelimiter()); - assertEquals(List.of(":", "."), column.getTable().getNamePartDelimiters()); + Assertions.assertInstanceOf(JsonExpression.class, parsed.getSelectItem(0).getExpression()); } + // I don't know what kind of Operator ".:." shall present + // please rework @Test + @Disabled public void testColumnWithEmptyNameParts() throws JSQLParserException { String statement = "SELECT mytable.:.child FROM mytable"; PlainSelect parsed = (PlainSelect) assertSqlCanBeParsedAndDeparsed(statement);