From eaf98847a4c69d01f8d665e093437632de792540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=98=E5=85=B8?= Date: Sun, 23 Aug 2026 14:59:22 +0800 Subject: [PATCH] fix(parser): support MySQL hash line comments A '#' followed by a blank now lexes as a line comment, the MySQL form from issue #2499. '#' without a following blank keeps its current lexing: identifier start (SQL Server #temp, ##global) and the JSON operators #> / #>> are unchanged. Signed-off-by: Fu Dian --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 6 +++- .../parser/CCJSqlParserUtilTest.java | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 381f3afc1..1f358b03b 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -1845,7 +1845,11 @@ TOKEN : /* Numeric Constants */ SPECIAL_TOKEN: { - < LINE_COMMENT: ("--" | "//") (~["\r","\n"])*> + // The `#` comment requires a following blank: `#` without one stays an + // identifier start (SQL Server `#temp`, `##global`) and `#>` / `#>>` + // JSON operators must keep their usual lexing (issue #1197, #1695). + < LINE_COMMENT: ("--" | "//") (~["\r","\n"])* + | "#" [" ", "\t"] (~["\r","\n"])*> } // Nested block comments: /* ... /* ... */ ... */ diff --git a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java index dd9b55732..c3a9563a6 100644 --- a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java @@ -221,6 +221,40 @@ public void accept(Statement statement) { assertEquals(3, list.size()); } + @Test + public void testLineCommentHashTrailing() throws Exception { + assertEquals("SELECT 1", CCJSqlParserUtil.parse("SELECT 1 # trailing comment").toString()); + } + + @Test + public void testLineCommentHashLeading() throws Exception { + assertEquals("SELECT 1", CCJSqlParserUtil.parse("# leading comment\nSELECT 1").toString()); + } + + @Test + public void testLineCommentHashWithinSelect() throws Exception { + assertEquals("SELECT 1 + 2, 3", + CCJSqlParserUtil.parse("SELECT 1 + 2 # note\n, 3").toString()); + } + + @Test + public void testHashWithoutBlankStaysIdentifier() throws Exception { + // without a following blank `#` is an identifier start, not a comment (#1197, #1695) + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT * FROM #temp"); + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT * FROM ##global"); + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT * FROM #$tab1#"); + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT * FROM $#tab1#"); + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT * FROM #$tab#tab1"); + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT a#b FROM t"); + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT 1 #note"); + } + + @Test + public void testHashJsonOperatorsStayOperators() throws Exception { + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT js #> '{a}' FROM t"); + TestUtils.assertSqlCanBeParsedAndDeparsed("SELECT js #>> '{a,b}' FROM t"); + } + @Test public void testParseStatementsFail() throws Exception { String sqlStr = "select * from dual;WHATEVER!!";