Skip to content

Commit a90873f

Browse files
authored
Make dialect-specific clause words non-reserved (#2793)
CSV, FBV, FILE, SCRIPT and VERIFY (Exasol IMPORT/EXPORT), PREWHERE and SETTINGS (ClickHouse) and RETURNS (CREATE FUNCTION) were reserved for every dialect, so `SELECT settings, file FROM t` failed in PostgreSQL or DuckDB, where they are ordinary names. They are now non-reserved. PREWHERE and SETTINGS never start an implicit alias, so the ClickHouse clauses still follow a table name. TypeDdlName's SETTINGS special case and FILE's entry in the reserved-as-identifier list are no longer needed.
1 parent 19f12ea commit a90873f

3 files changed

Lines changed: 37 additions & 30 deletions

File tree

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

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
806806
case K_IIF: case K_IGNORE: case K_IN: case K_INTERVAL: case K_LEFT:
807807
case K_LIMIT: case K_NEXTVAL: case K_OFFSET: case K_ON: case K_OPTIMIZE:
808808
case K_ORDER: case K_PROCEDURE: case K_PUBLIC: case K_QUALIFY: case K_RIGHT:
809-
case K_FILE: case K_SET: case K_SOME: case K_START: case K_TABLES:
809+
case K_SET: case K_SOME: case K_START: case K_TABLES:
810810
case K_TOP: case K_VALUE: case K_VALUES:
811811
return true;
812812
default:
@@ -1595,6 +1595,11 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
15951595
return false;
15961596
}
15971597

1598+
// ClickHouse's PREWHERE and SETTINGS clauses, not aliases
1599+
if (kind == K_PREWHERE || kind == K_SETTINGS) {
1600+
return false;
1601+
}
1602+
15981603
// For reserved keywords in alias position, skip the structural-
15991604
// keyword whitelist and go directly to follower disambiguation.
16001605
// Only check keywords that are actually in RelObjectName's token
@@ -2564,6 +2569,7 @@ String NonReservedWord() :
25642569
| tk=<K_COSTS: "COSTS">
25652570
| tk=<K_COUNT: "COUNT">
25662571
| tk=<K_CREATED:"CREATED">
2572+
| tk=<K_CSV: "CSV">
25672573
| tk=<K_CYCLE:"CYCLE">
25682574
| tk=<K_DATABASE:"DATABASE">
25692575
| tk=<K_DATA:"DATA">
@@ -2623,6 +2629,8 @@ String NonReservedWord() :
26232629
| tk=<K_EXTENDED:"EXTENDED">
26242630
| tk=<K_EXTRACT:"EXTRACT">
26252631
| tk=<K_EXPORT:"EXPORT">
2632+
| tk=<K_FBV: "FBV">
2633+
| tk=<K_FILE: "FILE">
26262634
| tk=<K_ISOLATION:("UR" | "RS" | "RR" | "CS")>
26272635
| tk=<K_FILTER: "FILTER">
26282636
| tk=<K_FIELDS: "FIELDS">
@@ -2762,6 +2770,7 @@ String NonReservedWord() :
27622770
| tk=<K_PRAGMA: "PRAGMA">
27632771
| tk=<K_PREPARE: "PREPARE">
27642772
| tk=<K_PRECEDING: "PRECEDING">
2773+
| tk=<K_PREWHERE: "PREWHERE">
27652774
| tk=<K_PRIMARY:"PRIMARY">
27662775
| tk=<K_POLICY:"POLICY">
27672776
| tk=<K_PURGE:"PURGE">
@@ -2780,6 +2789,7 @@ String NonReservedWord() :
27802789
| tk=<K_REGEXP: "REGEXP">
27812790
| tk=<K_REJECT: "REJECT">
27822791
| tk=<K_RESPECT: "RESPECT">
2792+
| tk=<K_RETURNS: "RETURNS">
27832793
| tk=<K_RLIKE: "RLIKE">
27842794
| tk=<K_REGEXP_LIKE: "REGEXP_LIKE">
27852795
| tk=<K_REGISTER: "REGISTER">
@@ -2811,6 +2821,7 @@ String NonReservedWord() :
28112821
| tk=<K_SAVEPOINT: "SAVEPOINT">
28122822
| tk=<K_SCHEDULE: "SCHEDULE">
28132823
| tk=<K_SCHEMA: "SCHEMA">
2824+
| tk=<K_SCRIPT: "SCRIPT">
28142825
| tk=<K_SEARCH:"SEARCH">
28152826
| tk=<K_SECURE: "SECURE">
28162827
| tk=<K_SECURITY:"SECURITY">
@@ -2819,6 +2830,7 @@ String NonReservedWord() :
28192830
| tk=<K_SEPARATOR:"SEPARATOR">
28202831
| tk=<K_SESSION:"SESSION">
28212832
| tk=<K_SETS:"SETS">
2833+
| tk=<K_SETTINGS: "SETTINGS">
28222834
| tk=<K_SHOW : "SHOW">
28232835
| tk=<K_SHUTDOWN : "SHUTDOWN">
28242836
| tk=<K_SHARE : "SHARE">
@@ -2881,6 +2893,7 @@ String NonReservedWord() :
28812893
| tk=<K_VALIDATE : "VALIDATE">
28822894
| tk=<K_VALIDATION: "VALIDATION">
28832895
| tk=<K_VERBOSE: "VERBOSE">
2896+
| tk=<K_VERIFY: "VERIFY">
28842897
| tk=<K_VERSION: "VERSION">
28852898
| tk=<K_VIEW:"VIEW">
28862899
| tk=<K_VISIBLE: "VISIBLE">
@@ -2931,7 +2944,6 @@ TOKEN: /* Reserved SQL Keywords and structural tokens */
29312944
| <K_CONSTRAINT:"CONSTRAINT">
29322945
| <K_CREATE:"CREATE">
29332946
| <K_CROSS:"CROSS">
2934-
| <K_CSV:"CSV">
29352947
| <K_CURRENT: "CURRENT">
29362948
| <K_DATETIMELITERAL : "DATE" | "DATETIME" | "TIME" | "TIMESTAMP" | "TIMESTAMPTZ" >
29372949
| <K_DATE_LITERAL : "YEAR" | "MONTH" | "DAY" | "HOUR" | "MINUTE" | "SECOND" >
@@ -2943,9 +2955,7 @@ TOKEN: /* Reserved SQL Keywords and structural tokens */
29432955
| <K_EXCLUDES: "EXCLUDES"> /* Salesforce SOQL */
29442956
| <K_EXISTS:"EXISTS">
29452957
| <K_EXTEND:"EXTEND">
2946-
| <K_FBV:"FBV">
29472958
| <K_FETCH:"FETCH">
2948-
| <K_FILE: "FILE">
29492959
| <K_FINAL: "FINAL">
29502960
| <K_FALSE: "FALSE">
29512961
| <K_FOR:"FOR">
@@ -2992,20 +3002,16 @@ TOKEN: /* Reserved SQL Keywords and structural tokens */
29923002
| <K_OPTIMIZE: "OPTIMIZE" >
29933003
| <K_PIVOT:"PIVOT">
29943004
| <K_PREFERRING: "PREFERRING">
2995-
| <K_PREWHERE: "PREWHERE">
29963005
| <K_PRIOR:"PRIOR">
29973006
| <K_PROCEDURE:"PROCEDURE">
29983007
| <K_PUBLIC:"PUBLIC">
29993008
| <K_QUALIFY: "QUALIFY">
3000-
| <K_RETURNS: "RETURNS">
30013009
| <K_RETURNING: "RETURNING">
30023010
| <K_RIGHT:"RIGHT">
30033011
| <K_SAMPLE: "SAMPLE">
3004-
| <K_SCRIPT: "SCRIPT">
30053012
| <K_SELECT: ("SELECT" | "SEL")>
30063013
| <K_SEMI : "SEMI">
30073014
| <K_SET:"SET">
3008-
| <K_SETTINGS:"SETTINGS">
30093015
| <K_SOME:"SOME">
30103016
| <K_START:"START">
30113017
| <K_TABLES:"TABLES">
@@ -3025,7 +3031,6 @@ TOKEN: /* Reserved SQL Keywords and structural tokens */
30253031
| <K_USING:"USING">
30263032
| <K_VALUE:"VALUE">
30273033
| <K_VALUES:"VALUES">
3028-
| <K_VERIFY: "VERIFY">
30293034
| <K_WHEN:"WHEN">
30303035
| <K_WHERE:"WHERE">
30313036
| <K_WINDOW:"WINDOW">
@@ -6934,7 +6939,7 @@ String RelObjectName() :
69346939
| tk=<K_IIF> | tk=<K_IGNORE> | tk=<K_IN> | tk=<K_INTERVAL>
69356940
| tk=<K_LEFT> | tk=<K_LIMIT> | tk=<K_NEXTVAL> | tk=<K_OFFSET>
69366941
| tk=<K_ON> | tk=<K_OPTIMIZE> | tk=<K_ORDER> | tk=<K_PROCEDURE>
6937-
| tk=<K_PUBLIC> | tk=<K_QUALIFY> | tk=<K_RIGHT> | tk=<K_FILE>
6942+
| tk=<K_PUBLIC> | tk=<K_QUALIFY> | tk=<K_RIGHT>
69386943
| tk=<K_SET> | tk=<K_SOME> | tk=<K_START> | tk=<K_TABLES>
69396944
| tk=<K_TOP> | tk=<K_VALUE> | tk=<K_VALUES> )
69406945
)
@@ -20465,11 +20470,10 @@ Synonym Synonym() #Synonym :
2046520470

2046620471

2046720472
String TypeDdlName():
20468-
{ String name; String part; Token keyword; }
20473+
{ String name; String part; }
2046920474
{
20470-
( name=RelObjectName() | keyword=<K_SETTINGS> { name = keyword.image; } )
20471-
( LOOKAHEAD(2) "." ( part=RelObjectNameExt() | keyword=<K_SETTINGS> { part = keyword.image; } )
20472-
{ name += "." + part; } )*
20475+
name=RelObjectName()
20476+
( LOOKAHEAD(2) "." part=RelObjectNameExt() { name += "." + part; } )*
2047320477
{ return name; }
2047420478
}
2047520479

‎src/site/sphinx/keywords.rst‎

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ The following Keywords are **reserved** in JSQLParser-|JSQLPARSER_VERSION| and m
3737
+---------------------------+
3838
| CROSS |
3939
+---------------------------+
40-
| CSV |
41-
+---------------------------+
4240
| CURRENT |
4341
+---------------------------+
4442
| DISTINCT |
@@ -57,12 +55,8 @@ The following Keywords are **reserved** in JSQLParser-|JSQLPARSER_VERSION| and m
5755
+---------------------------+
5856
| FALSE |
5957
+---------------------------+
60-
| FBV |
61-
+---------------------------+
6258
| FETCH |
6359
+---------------------------+
64-
| FILE |
65-
+---------------------------+
6660
| FINAL |
6761
+---------------------------+
6862
| FOR |
@@ -143,8 +137,6 @@ The following Keywords are **reserved** in JSQLParser-|JSQLPARSER_VERSION| and m
143137
+---------------------------+
144138
| PREFERRING |
145139
+---------------------------+
146-
| PREWHERE |
147-
+---------------------------+
148140
| PRIOR |
149141
+---------------------------+
150142
| PROCEDURE |
@@ -155,18 +147,12 @@ The following Keywords are **reserved** in JSQLParser-|JSQLPARSER_VERSION| and m
155147
+---------------------------+
156148
| RETURNING |
157149
+---------------------------+
158-
| RETURNS |
159-
+---------------------------+
160150
| RIGHT |
161151
+---------------------------+
162152
| SAMPLE |
163153
+---------------------------+
164-
| SCRIPT |
165-
+---------------------------+
166154
| SET |
167155
+---------------------------+
168-
| SETTINGS |
169-
+---------------------------+
170156
| SOME |
171157
+---------------------------+
172158
| SQL_CACHE |
@@ -209,8 +195,6 @@ The following Keywords are **reserved** in JSQLParser-|JSQLPARSER_VERSION| and m
209195
+---------------------------+
210196
| VALUES |
211197
+---------------------------+
212-
| VERIFY |
213-
+---------------------------+
214198
| WHEN |
215199
+---------------------------+
216200
| WHERE |

‎src/test/java/net/sf/jsqlparser/statement/KeywordsTest.java‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,23 @@ public void testErrorsAsIdentifier() throws JSQLParserException {
7272
assertSqlCanBeParsedAndDeparsed("WITH errors AS (SELECT 1) SELECT * FROM errors", true);
7373
assertSqlCanBeParsedAndDeparsed("CREATE TABLE mytable (errors VARCHAR)", true);
7474
}
75+
76+
// Dialect-specific clause words (Exasol IMPORT/EXPORT, ClickHouse PREWHERE/SETTINGS, CREATE
77+
// FUNCTION ... RETURNS) are ordinary names in other dialects, e.g. PostgreSQL or DuckDB.
78+
@Test
79+
public void testDialectClauseWordsAsIdentifiers() throws JSQLParserException {
80+
assertSqlCanBeParsedAndDeparsed(
81+
"SELECT csv, fbv, file, prewhere, returns, script, settings, verify FROM mytable",
82+
true);
83+
assertSqlCanBeParsedAndDeparsed("SELECT t.file, t.settings FROM mytable t", true);
84+
assertSqlCanBeParsedAndDeparsed("SELECT * FROM settings", true);
85+
assertSqlCanBeParsedAndDeparsed("WITH file AS (SELECT 1) SELECT * FROM file", true);
86+
assertSqlCanBeParsedAndDeparsed("CREATE TABLE mytable (csv VARCHAR, settings JSON)", true);
87+
}
88+
89+
@Test
90+
public void testClickHouseClausesAfterTable() throws JSQLParserException {
91+
assertSqlCanBeParsedAndDeparsed("SELECT a FROM mytable PREWHERE b = 1 WHERE c = 2", true);
92+
assertSqlCanBeParsedAndDeparsed("SELECT a FROM mytable SETTINGS max_threads = 8", true);
93+
}
7594
}

0 commit comments

Comments
 (0)