Skip to content

Commit f5d3cd8

Browse files
committed
[CALCITE-5612] Babel parser should support PostgreSQL's SET TRANSACTION command
1 parent 9b4eff0 commit f5d3cd8

File tree

28 files changed

+1010
-429
lines changed

28 files changed

+1010
-429
lines changed

babel/src/main/codegen/config.fmpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ data: {
3030
"org.apache.calcite.sql.SqlCreate",
3131
"org.apache.calcite.sql.babel.SqlBabelCreateTable",
3232
"org.apache.calcite.sql.babel.TableCollectionType",
33-
"org.apache.calcite.sql.babel.postgresql.AndChain",
34-
"org.apache.calcite.sql.babel.postgresql.SqlBegin",
35-
"org.apache.calcite.sql.babel.postgresql.SqlCommit",
36-
"org.apache.calcite.sql.babel.postgresql.SqlDiscard",
37-
"org.apache.calcite.sql.babel.postgresql.SqlRollback",
38-
"org.apache.calcite.sql.babel.postgresql.SqlShow",
33+
"org.apache.calcite.sql.babel.postgres.TransactionMode",
34+
"org.apache.calcite.sql.babel.postgres.TransactionChainingMode",
35+
"org.apache.calcite.sql.babel.postgres.SqlBegin",
36+
"org.apache.calcite.sql.babel.postgres.SqlCommit",
37+
"org.apache.calcite.sql.babel.postgres.SqlDiscard",
38+
"org.apache.calcite.sql.babel.postgres.SqlRollback",
39+
"org.apache.calcite.sql.babel.postgres.SqlShow",
40+
"org.apache.calcite.sql.babel.postgres.SqlSetOptions",
3941
"org.apache.calcite.sql.ddl.SqlDdlNodes",
4042
]
4143

@@ -49,6 +51,7 @@ data: {
4951
"SEED"
5052
"SEMI"
5153
"SEQUENCES"
54+
"SNAPSHOT"
5255
"TEMP"
5356
"VOLATILE"
5457
]
@@ -567,12 +570,11 @@ data: {
567570
]
568571

569572
statementParserMethods: [
570-
"PostgresqlSqlShow()",
571-
"PostgresqlSqlSetOption()",
572-
"PostgresqlSqlBegin()",
573-
"PostgresqlSqlDiscard()",
574-
"PostgresqlSqlCommit()",
575-
"PostgresqlSqlRollback()"
573+
"PostgresSqlBegin()"
574+
"PostgresSqlCommit()"
575+
"PostgresSqlDiscard()"
576+
"PostgresSqlRollback()"
577+
"PostgresSqlShow()"
576578
]
577579

578580
# Binary operators tokens.
@@ -608,9 +610,10 @@ data: {
608610
# Example: "parserImpls.ftl".
609611
implementationFiles: [
610612
"parserImpls.ftl"
611-
"parserPostgresqlImpls.ftl"
613+
"parserPostgresImpls.ftl"
612614
]
613615

616+
setOptionParserMethod: "PostgresSqlSetOption"
614617
includePosixOperators: true
615618
includeParsingStringLiteralAsArrayLiteral: true
616619
}
Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
<#--
2+
// Licensed to the Apache Software Foundation (ASF) under one or more
3+
// contributor license agreements. See the NOTICE file distributed with
4+
// this work for additional information regarding copyright ownership.
5+
// The ASF licenses this file to you under the Apache License, Version 2.0
6+
// (the "License"); you may not use this file except in compliance with
7+
// the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
-->
17+
18+
/**
19+
* <blockquote><pre>
20+
* SHOW ALL
21+
* SHOW TIME ZONE
22+
* SHOW TRANSACTION ISOLATION LEVEL
23+
* SHOW SESSION AUTHORIZATION
24+
* SHOW Identifier()
25+
* </pre></blockquote>
26+
*
27+
* @see <a href="https://www.postgresql.org/docs/current/sql-show.html">
28+
* PostgreSQL SHOW documentation</a>
29+
* @see <a href="https://github.com/postgres/postgres/blob/master/src/backend/parser/gram.y">
30+
* PostgreSQL grammar file (VariableShowStmt) </a>
31+
*/
32+
SqlNode PostgresSqlShow() :
33+
{
34+
final String name;
35+
final Span s;
36+
}
37+
{
38+
<SHOW> { s = span(); }
39+
( <ALL> { name = "all"; }
40+
| <TIME> <ZONE> { name = "timezone"; }
41+
| <TRANSACTION> <ISOLATION> <LEVEL> { name = "transaction_isolation"; }
42+
| <SESSION> <AUTHORIZATION> { name = "session_authorization"; }
43+
| name = Identifier()
44+
) {
45+
return SqlShow.OPERATOR.createCall(null, s.end(this), new SqlIdentifier(name, getPos()));
46+
}
47+
}
48+
49+
/**
50+
* <blockquote><pre>
51+
* SET { SESSION | LOCAL } configuration_parameter { TO | = } { value | DEFAULT }
52+
* SET { SESSION | LOCAL } TIME ZONE { value | LOCAL | DEFAULT }
53+
* SET { SESSION | LOCAL } (SCHEMA | NAMES | SEED) value
54+
* SET { SESSION | LOCAL } TRANSACTION transaction_mode [, ...]
55+
* SET { SESSION | LOCAL } TRANSACTION SNAPSHOT snapshot_id
56+
* SET { SESSION | LOCAL } SESSION CHARACTERISTICS AS TRANSACTION transaction_mode [, ...]
57+
* SET { SESSION | LOCAL } SESSION AUTHORIZATION
58+
* SET { SESSION | LOCAL } ROLE role_name
59+
* SET { SESSION | LOCAL } ROLE NONE
60+
* RESET ALL
61+
* RESET SESSION AUTHORIZATION
62+
* RESET TIME ZONE
63+
* RESET TRANSACTION ISOLATION LEVEL
64+
* RESET CompoundIdentifier()
65+
*
66+
* value - Values can be specified as string constants, identifiers, numbers, or
67+
* comma-separated lists of these
68+
*
69+
* transaction_mode is one of:
70+
* ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }
71+
* READ WRITE | READ ONLY
72+
* [ NOT ] DEFERRABLE
73+
* </blockquote></pre>
74+
*
75+
* @see <a href="https://www.postgresql.org/docs/current/sql-set.html">
76+
* PostgreSQL SET documentation</a>
77+
* @see <a href="https://www.postgresql.org/docs/current/sql-reset.html">
78+
* PostgreSQL RESET documentation</a>
79+
* @see <a href="https://www.postgresql.org/docs/current/sql-set-role.html">
80+
* PostgreSQL SET ROLE documentation</a>
81+
* @see <a href="https://www.postgresql.org/docs/current/sql-set-transaction.html">
82+
* PostgreSQL SET TRANSACTION documentation</a>
83+
* @see <a href="https://www.postgresql.org/docs/current/sql-set-session-authorization.html">
84+
* PostgreSQL SET SESSION AUTHORIZATION documentation</a>
85+
* @see <a href="https://github.com/postgres/postgres/blob/master/src/backend/parser/gram.y">
86+
* PostgreSQL grammar file (VariableSetStmt, VariableResetStmt) </a>
87+
*/
88+
SqlAlter PostgresSqlSetOption(Span s, String scope) :
89+
{
90+
final SqlAlter node;
91+
}
92+
{
93+
94+
{ s.add(this); }
95+
(
96+
<SET>
97+
( LOOKAHEAD(2) node = PostgresSqlSetParameter(s, scope)
98+
| <SESSION> { scope = token.image.toUpperCase(Locale.ROOT); } node = PostgresSqlSetParameter(s, scope)
99+
| <LOCAL> { scope = token.image.toUpperCase(Locale.ROOT); } node = PostgresSqlSetParameter(s, scope)
100+
)
101+
| node = PostgresSqlResetParameter(s, scope)
102+
) {
103+
return node;
104+
}
105+
}
106+
107+
SqlAlter PostgresSqlSetParameter(Span s, String scope) :
108+
{
109+
SqlNode name;
110+
final SqlNode val;
111+
}
112+
{
113+
(
114+
<SESSION>
115+
(
116+
<CHARACTERISTICS> <AS> <TRANSACTION> {
117+
name = SqlSetOptions.Names.SESSION_CHARACTERISTICS_AS_TRANSACTION.symbol(getPos());
118+
} val = PostgresSqlTransactionModeList()
119+
|
120+
<AUTHORIZATION> {
121+
name = new SqlIdentifier("session_authorization", getPos());
122+
} val = PostgresSqlOptionValue()
123+
)
124+
|
125+
<TRANSACTION>
126+
(
127+
<SNAPSHOT> val = PostgresSqlOptionValues() {
128+
name = SqlSetOptions.Names.TRANSACTION_SNAPSHOT.symbol(getPos());
129+
}
130+
|
131+
val = PostgresSqlTransactionModeList() {
132+
name = SqlSetOptions.Names.TRANSACTION.symbol(getPos());
133+
}
134+
)
135+
|
136+
<TIME> <ZONE> { name = SqlSetOptions.Names.TIME_ZONE.symbol(getPos()); }
137+
( val = Default()
138+
| <LOCAL> { val = SqlSetOptions.Values.LOCAL.symbol(getPos()); }
139+
| val = Literal()
140+
)
141+
|
142+
<ROLE> { name = SqlSetOptions.Names.ROLE.symbol(getPos()); }
143+
( <NONE> { val = SqlSetOptions.Values.NONE.symbol(getPos()); }
144+
| val = PostgresSqlOptionValue()
145+
)
146+
|
147+
( name = CompoundIdentifier() ( <EQ> | <TO> )
148+
| <SCHEMA> { name = new SqlIdentifier("search_path", getPos()); }
149+
| <NAMES> { name = new SqlIdentifier("client_encoding", getPos()); }
150+
| <SEED> { name = new SqlIdentifier("seed", getPos()); }
151+
) val = PostgresSqlOptionValues()
152+
) {
153+
return new SqlSetOption(s.end(val), scope, name, val);
154+
}
155+
}
156+
157+
SqlAlter PostgresSqlResetParameter(Span s, String scope) :
158+
{
159+
SqlNode name;
160+
SqlNode value;
161+
}
162+
{
163+
<RESET> { s.add(this); }
164+
( <ALL> { name = SqlSetOptions.Names.ALL.symbol(getPos()); }
165+
| <SESSION> <AUTHORIZATION> { name = new SqlIdentifier("session_authorization", getPos()); }
166+
| <TIME> <ZONE> { name = new SqlIdentifier("timezone", getPos()); }
167+
| <TRANSACTION> <ISOLATION> <LEVEL> { name = new SqlIdentifier("transaction_isolation", getPos()); }
168+
| name = CompoundIdentifier()
169+
) {
170+
return new SqlSetOption(s.end(name), scope, name, null);
171+
}
172+
}
173+
174+
SqlNode PostgresSqlOptionValues() :
175+
{
176+
final List<SqlNode> list;
177+
Span s;
178+
SqlNode e;
179+
}
180+
{
181+
e = PostgresSqlOptionValue() { s = span(); list = startList(e); }
182+
( <COMMA> e = PostgresSqlOptionValue() { list.add(e); } )*
183+
{ return list.size() > 1 ? new SqlNodeList(list, s.end(this)) : e; }
184+
}
185+
186+
SqlNode PostgresSqlOptionValue() :
187+
{
188+
final SqlNode val;
189+
}
190+
{
191+
( val = Default()
192+
| val = Literal()
193+
| val = SimpleIdentifier()
194+
| <ON> {
195+
// OFF is handled by SimpleIdentifier, ON handled here.
196+
val = new SqlIdentifier(token.image.toUpperCase(Locale.ROOT), getPos());
197+
}
198+
) {
199+
return val;
200+
}
201+
}
202+
203+
/**
204+
* <blockquote><pre>
205+
* DISCARD { ALL | PLANS | SEQUENCES | TEMPORARY | TEMP }
206+
* </blockquote></pre>
207+
*
208+
* @see <a href="https://www.postgresql.org/docs/current/sql-discard.html">
209+
* PostgreSQL DISCARD documentation</a>
210+
*/
211+
SqlNode PostgresSqlDiscard() :
212+
{
213+
final Span s;
214+
}
215+
{
216+
{ s = span(); }
217+
<DISCARD> ( <ALL> | <PLANS> | <SEQUENCES> | <TEMPORARY> | <TEMP> ) {
218+
return SqlDiscard.OPERATOR.createCall(s.end(this), new SqlIdentifier(
219+
token.image.toUpperCase(Locale.ROOT), getPos()));
220+
}
221+
}
222+
223+
/**
224+
* <blockquote><pre>
225+
* BEGIN [ WORK | TRANSACTION ] [ transaction_mode [, ...] ]
226+
* where transaction_mode is one of:
227+
* ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }
228+
* READ WRITE | READ ONLY
229+
* [ NOT ] DEFERRABLE
230+
* </blockquote></pre>
231+
*
232+
* @see <a href="https://www.postgresql.org/docs/current/sql-begin.html">
233+
* PostgreSQL BEGIN documentation</a>
234+
*/
235+
SqlNode PostgresSqlBegin() :
236+
{
237+
final Span s;
238+
SqlNodeList transactionModeList = SqlNodeList.EMPTY;
239+
}
240+
{
241+
{ s = span(); }
242+
<BEGIN> [ ( <WORK> | <TRANSACTION> ) ] [ transactionModeList = PostgresSqlTransactionModeList() ] {
243+
return SqlBegin.OPERATOR.createCall(s.end(this), (SqlNode) transactionModeList);
244+
}
245+
}
246+
247+
SqlNodeList PostgresSqlTransactionModeList() :
248+
{
249+
final List<SqlNode> list;
250+
Span s;
251+
SqlNode e;
252+
}
253+
{
254+
{ s = span(); }
255+
e = PostgresSqlTransactionMode() { s = span(); list = startList(e); }
256+
( <COMMA> e = PostgresSqlTransactionMode() { list.add(e); } )*
257+
{ return new SqlNodeList(list, s.end(this)); }
258+
}
259+
260+
SqlNode PostgresSqlTransactionMode() :
261+
{
262+
final Span s;
263+
TransactionMode m;
264+
}
265+
{
266+
{ s = span(); }
267+
( <READ>
268+
( <WRITE> { m = TransactionMode.READ_WRITE; }
269+
| <ONLY> { m = TransactionMode.READ_ONLY; }
270+
)
271+
| <DEFERRABLE> { m = TransactionMode.DEFERRABLE; }
272+
| <NOT> <DEFERRABLE> { m = TransactionMode.NOT_DEFERRABLE; }
273+
| <ISOLATION> <LEVEL>
274+
( <SERIALIZABLE> { m = TransactionMode.ISOLATION_LEVEL_SERIALIZABLE; }
275+
| <REPEATABLE> <READ> { m = TransactionMode.ISOLATION_LEVEL_REPEATABLE_READ; }
276+
| <READ>
277+
( <COMMITTED> { m = TransactionMode.ISOLATION_LEVEL_READ_COMMITTED; }
278+
| <UNCOMMITTED> { m = TransactionMode.ISOLATION_LEVEL_READ_UNCOMMITTED; }
279+
)
280+
)
281+
) {
282+
return m.symbol(s.end(this));
283+
}
284+
}
285+
286+
/**
287+
* <blockquote><pre>
288+
* COMMIT [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ]
289+
* </blockquote></pre>
290+
*
291+
* @see <a href="https://www.postgresql.org/docs/current/sql-commit.html">
292+
* PostgreSQL COMMIT documentation</a>
293+
*/
294+
SqlNode PostgresSqlCommit() :
295+
{
296+
final Span s;
297+
TransactionChainingMode chainingMode = TransactionChainingMode.AND_NO_CHAIN;
298+
}
299+
{
300+
{ s = span(); }
301+
<COMMIT> [ <WORK> | <TRANSACTION> ] [ chainingMode = PostgresTransactionChainingMode() ] {
302+
final SqlParserPos pos = s.end(this);
303+
return SqlCommit.OPERATOR.createCall(pos, chainingMode.symbol(pos));
304+
}
305+
}
306+
307+
/**
308+
* <blockquote><pre>
309+
* ROLLBACK [ WORK | TRANSACTION ] [ AND [ NO ] CHAIN ]
310+
* </blockquote></pre>
311+
*
312+
* @see <a href="https://www.postgresql.org/docs/current/sql-rollback.html">
313+
* PostgreSQL ROLLBACK documentation</a>
314+
*/
315+
SqlNode PostgresSqlRollback() :
316+
{
317+
final Span s;
318+
TransactionChainingMode chainingMode = TransactionChainingMode.AND_NO_CHAIN;
319+
}
320+
{
321+
{ s = span(); }
322+
<ROLLBACK> [ <WORK> | <TRANSACTION> ] [ chainingMode = PostgresTransactionChainingMode() ] {
323+
final SqlParserPos pos = s.end(this);
324+
return SqlRollback.OPERATOR.createCall(pos, chainingMode.symbol(pos));
325+
}
326+
}
327+
328+
TransactionChainingMode PostgresTransactionChainingMode() :
329+
{
330+
TransactionChainingMode chainingMode = TransactionChainingMode.AND_NO_CHAIN;
331+
}
332+
{
333+
( <AND> <CHAIN> { chainingMode = TransactionChainingMode.AND_CHAIN; }
334+
| <AND> <NO> <CHAIN>
335+
)
336+
{ return chainingMode; }
337+
}

0 commit comments

Comments
 (0)