diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 2a28d21ba..9f8150309 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -1601,8 +1601,9 @@ TOKEN : /* Numeric Constants */ )> | < S_LONG: ( )+ > | < #DIGIT: ["0" - "9"] > - | < S_HEX: ("X" ("'" ( )* "'" (" ")*)+ | "0x" ( )+ ) > + | < S_HEX: ("X" ("'" ( )* "'" (" ")*)+ | "0x" ( )+ ) > | < #HEX_VALUE: ["0"-"9","A"-"F", " "] > + | < #HEX_DIGIT: ["0"-"9","A"-"F"] > } SPECIAL_TOKEN: diff --git a/src/test/java/net/sf/jsqlparser/expression/HexValueTest.java b/src/test/java/net/sf/jsqlparser/expression/HexValueTest.java index 736c82cca..2e1c2e78a 100644 --- a/src/test/java/net/sf/jsqlparser/expression/HexValueTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/HexValueTest.java @@ -9,6 +9,8 @@ */ package net.sf.jsqlparser.expression; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; + import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.statement.select.PlainSelect; @@ -39,4 +41,23 @@ void testHexCode() throws JSQLParserException { Assertions.assertEquals("'\\xC3\\xBC'", hex3.getBlob().toString()); } + + @Test + void testHexLiteralFollowedByPrimaryKeyword() throws JSQLParserException { + // Issue #2435: a "0x"-prefixed hex literal must not greedily consume the + // following whitespace nor adjacent hex letters (e.g. the "F" of FROM), + // which previously made "SELECT 0xFF FROM t" fail to parse. + assertHexSelectItem("SELECT 0xFF FROM t", "FF"); + assertHexSelectItem("SELECT 0xff FROM t", "ff"); + assertHexSelectItem("SELECT 0xDEADBEEF FROM t", "DEADBEEF"); + assertHexSelectItem("SELECT 0xab FROM dual", "ab"); + } + + private static void assertHexSelectItem(String sql, String expectedDigits) + throws JSQLParserException { + PlainSelect select = (PlainSelect) assertSqlCanBeParsedAndDeparsed(sql, true); + Expression expr = select.getSelectItem(0).getExpression(); + Assertions.assertTrue(expr instanceof HexValue, () -> "Expected HexValue for: " + sql); + Assertions.assertEquals(expectedDigits, ((HexValue) expr).getDigits()); + } }