Skip to content

Commit 2927bad

Browse files
authored
fix: preserve token boundaries in DDL parameter lists (#2857)
1 parent d8b308d commit 2927bad

2 files changed

Lines changed: 69 additions & 3 deletions

File tree

‎src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19822,14 +19822,23 @@ String AList():
1982219822
StringBuilder retval = new StringBuilder("(");
1982319823
Token tk = null;
1982419824
String name = null;
19825+
boolean needsSeparator = false;
1982519826
}
1982619827
{
1982719828
"("
1982819829

1982919830
(
19830-
( (tk=<S_LONG> | tk=<S_DOUBLE> | tk=<S_CHAR_LITERAL> | tk=<K_TRUE> | tk=<K_FALSE>) { retval.append(tk.image); }
19831-
| (name=RelObjectName()) { retval.append(name); })
19832-
[("," {retval.append(",");} | "=" {retval.append("=");})] )*
19831+
( (tk=<S_LONG> | tk=<S_DOUBLE> | tk=<S_CHAR_LITERAL> | tk=<K_TRUE> | tk=<K_FALSE>) { name = tk.image; }
19832+
| name=RelObjectName() )
19833+
{
19834+
if (needsSeparator) {
19835+
retval.append(' ');
19836+
}
19837+
retval.append(name);
19838+
needsSeparator = true;
19839+
}
19840+
[("," { retval.append(','); needsSeparator = false; }
19841+
| "=" { retval.append('='); needsSeparator = false; })] )*
1983319842

1983419843
")"
1983519844
{
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.create;
11+
12+
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
14+
import net.sf.jsqlparser.JSQLParserException;
15+
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
16+
import net.sf.jsqlparser.parser.CCJSqlParser;
17+
import net.sf.jsqlparser.parser.CCJSqlParserConstants;
18+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
19+
import net.sf.jsqlparser.parser.ParseException;
20+
import net.sf.jsqlparser.statement.Statement;
21+
import net.sf.jsqlparser.util.deparser.StatementDeParser;
22+
import org.junit.jupiter.params.ParameterizedTest;
23+
import org.junit.jupiter.params.provider.ValueSource;
24+
25+
class DdlParameterListTest {
26+
@ParameterizedTest
27+
@ValueSource(strings = {
28+
"CREATE VECTOR INDEX items_hnsw ON items (embedding) ORGANIZATION INMEMORY NEIGHBOR GRAPH DISTANCE COSINE WITH TARGET ACCURACY 95 PARAMETERS (TYPE HNSW,NEIGHBORS 32,EFCONSTRUCTION 500)",
29+
"CREATE VECTOR INDEX items_ivf ON items (embedding) ORGANIZATION NEIGHBOR PARTITIONS DISTANCE COSINE WITH TARGET ACCURACY 95 PARAMETERS (TYPE IVF,NEIGHBOR PARTITIONS 10)",
30+
"CREATE TABLE samples (id INT) STORAGE (INITIAL 65536,NEXT 131072)"})
31+
void ddlParametersKeepSeparateWordsAndNumbers(String sql) throws JSQLParserException {
32+
for (Dialect dialect : new Dialect[] {null, Dialect.ORACLE}) {
33+
Statement statement = CCJSqlParserUtil.parse(sql, parser -> {
34+
if (dialect != null) {
35+
parser.withDialect(dialect);
36+
}
37+
});
38+
assertEquals(sql, statement.toString());
39+
StringBuilder output = new StringBuilder();
40+
statement.accept(new StatementDeParser(output), null);
41+
assertEquals(sql, output.toString());
42+
assertEquals(sql, CCJSqlParserUtil.parse(output.toString()).toString());
43+
}
44+
}
45+
46+
@ParameterizedTest
47+
@ValueSource(strings = {"()", "(1,2,3)", "(name=value,count=32)",
48+
"(TYPE HNSW,NEIGHBORS 32,EFCONSTRUCTION 500)",
49+
"(enabled TRUE,ratio 0.5,disabled FALSE)",
50+
"('keep two spaces','comma,equals=','it''s fine')",
51+
"(\"Quoted Name\" 10,\"dotted.name\" 20)"})
52+
void preservesLiteralsQuotedNamesAndExplicitDelimiters(String list) throws ParseException {
53+
CCJSqlParser parser = CCJSqlParserUtil.newParser(list);
54+
assertEquals(list, parser.AList());
55+
assertEquals(CCJSqlParserConstants.EOF, parser.getNextToken().kind);
56+
}
57+
}

0 commit comments

Comments
 (0)