Skip to content

Commit 8805d37

Browse files
feat: guard INSERT OR conflict clauses by the SQLITE dialect
Add Dialect.SQLITE. INSERT OR ABORT, FAIL, IGNORE and ROLLBACK need it. INSERT OR REPLACE keeps parsing in every dialect.
1 parent b57a924 commit 8805d37

57 files changed

Lines changed: 1406 additions & 1327 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public enum Dialect {
4848
AdjacentStringLiterals.WHITESPACE,
4949
Feature.allowDoubleQuotedStrings,
5050
Feature.allowBackslashEscapeCharacter), SNOWFLAKE(
51-
Feature.allowBackslashEscapeCharacter), INFORMIX, SPANNER, DORIS, COCKROACHDB, TERADATA;
51+
Feature.allowBackslashEscapeCharacter), INFORMIX, SPANNER, DORIS, COCKROACHDB, TERADATA, SQLITE;
5252

5353
private final Set<Feature> lexerFeatures;
5454
private final AdjacentStringLiterals adjacentStringLiterals;

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,6 +3039,11 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
30393039
}
30403040
}
30413041

3042+
private void requireSqliteSyntax(String syntax) throws ParseException {
3043+
requireDdlSyntax(Dialect.SQLITE.name().equals(getAsString(Feature.dialect)),
3044+
syntax + " needs Dialect.SQLITE");
3045+
}
3046+
30423047
private void requireDdlSyntax(boolean valid, String message) throws ParseException {
30433048
if (!valid) {
30443049
throw new ParseException(message);
@@ -7970,12 +7975,20 @@ Upsert Upsert():
79707975
(
79717976
<K_REPLACE> { upsert.setUpsertType(UpsertType.INSERT_OR_REPLACE); }
79727977
|
7973-
<K_IGNORE> { upsert.setUpsertType(UpsertType.INSERT_OR_IGNORE); }
7978+
// the other conflict resolution algorithms are SQLite syntax
7979+
<K_IGNORE> {
7980+
requireSqliteSyntax("INSERT OR IGNORE");
7981+
upsert.setUpsertType(UpsertType.INSERT_OR_IGNORE);
7982+
}
79747983
|
7975-
<K_ROLLBACK> { upsert.setUpsertType(UpsertType.INSERT_OR_ROLLBACK); }
7984+
<K_ROLLBACK> {
7985+
requireSqliteSyntax("INSERT OR ROLLBACK");
7986+
upsert.setUpsertType(UpsertType.INSERT_OR_ROLLBACK);
7987+
}
79767988
|
7977-
// SQLite conflict resolution algorithms that are not keywords of the parser
7989+
// ABORT and FAIL are not keywords of the parser
79787990
tk=<S_IDENTIFIER> {
7991+
requireSqliteSyntax("INSERT OR " + tk.image);
79797992
requireDdlSyntax("ABORT".equalsIgnoreCase(tk.image) || "FAIL".equalsIgnoreCase(tk.image),
79807993
"Expected ABORT, FAIL, IGNORE, REPLACE or ROLLBACK");
79817994
upsert.setUpsertType("ABORT".equalsIgnoreCase(tk.image)

‎src/site/sphinx/usage.rst‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,8 @@ One grammar covers every supported RDBMS, but a few pieces of syntax mean differ
15921592
- ``ALTER TABLE ... ALTER PRIMARY KEY USING COLUMNS (...)`` with optional hash sharding and storage parameters
15931593
* - ``TERADATA``
15941594
- ``UPDATE target FROM sources SET ...`` with the FROM clause before SET
1595+
* - ``SQLITE``
1596+
- ``INSERT OR ABORT``, ``INSERT OR FAIL``, ``INSERT OR IGNORE`` and ``INSERT OR ROLLBACK`` conflict clauses
15951597

15961598
Features set explicitly *after* the preset win over it.
15971599

‎src/test/java/net/sf/jsqlparser/statement/select/SQLiteTest.java‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package net.sf.jsqlparser.statement.select;
1111

1212
import net.sf.jsqlparser.JSQLParserException;
13+
import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect;
1314
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
1415
import net.sf.jsqlparser.test.TestUtils;
1516
import org.junit.jupiter.api.Test;
@@ -31,14 +32,24 @@ void testInsertOrReplaceUpsert() throws JSQLParserException {
3132
@ValueSource(strings = {"ABORT", "FAIL", "IGNORE", "REPLACE", "ROLLBACK"})
3233
void testInsertOrConflictAlgorithm(String algorithm) throws JSQLParserException {
3334
TestUtils.assertSqlCanBeParsedAndDeparsed(
34-
"INSERT OR " + algorithm + " INTO t (a, b) VALUES (1, 2)", true);
35+
"INSERT OR " + algorithm + " INTO t (a, b) VALUES (1, 2)", true,
36+
parser -> parser.withDialect(Dialect.SQLITE));
3537
TestUtils.assertSqlCanBeParsedAndDeparsed(
36-
"insert or " + algorithm.toLowerCase(Locale.ROOT) + " into t select * from s", true);
38+
"insert or " + algorithm.toLowerCase(Locale.ROOT) + " into t select * from s", true,
39+
parser -> parser.withDialect(Dialect.SQLITE));
40+
}
41+
42+
@ParameterizedTest
43+
@ValueSource(strings = {"ABORT", "FAIL", "IGNORE", "ROLLBACK"})
44+
void testInsertOrConflictAlgorithmNeedsSqliteDialect(String algorithm) {
45+
assertThrows(JSQLParserException.class,
46+
() -> CCJSqlParserUtil.parse("INSERT OR " + algorithm + " INTO t VALUES (1)"));
3747
}
3848

3949
@Test
4050
void testInsertOrUnknownAlgorithm() {
4151
assertThrows(JSQLParserException.class,
42-
() -> CCJSqlParserUtil.parse("INSERT OR NOTHING INTO t VALUES (1)"));
52+
() -> CCJSqlParserUtil.parse("INSERT OR NOTHING INTO t VALUES (1)",
53+
parser -> parser.withDialect(Dialect.SQLITE)));
4354
}
4455
}

‎src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query02.sql‎

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
---
2-
-- #%L
3-
-- JSQLParser library
4-
-- %%
5-
-- Copyright (C) 2004 - 2019 JSQLParser
6-
-- %%
7-
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8-
-- #L%
9-
---
10-
select time_id, product
11-
, last_value(quantity ignore nulls) over (partition by product order by time_id) quantity
12-
, last_value(quantity respect nulls) over (partition by product order by time_id) quantity
13-
from ( select times.time_id, product, quantity
14-
from inventory partition by (product)
15-
right outer join times on (times.time_id = inventory.time_id)
16-
where times.time_id between to_date('01/04/01', 'dd/mm/yy')
17-
and to_date('06/04/01', 'dd/mm/yy'))
18-
order by 2,1
19-
20-
21-
22-
--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:07 AM
23-
--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Apr 6, 2024, 7:38:53 AM
24-
--@FAILURE: Encountered: <K_BY> / "by", at line 14, column 39, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
25-
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
1+
---
2+
-- #%L
3+
-- JSQLParser library
4+
-- %%
5+
-- Copyright (C) 2004 - 2019 JSQLParser
6+
-- %%
7+
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
-- #L%
9+
---
10+
select time_id, product
11+
, last_value(quantity ignore nulls) over (partition by product order by time_id) quantity
12+
, last_value(quantity respect nulls) over (partition by product order by time_id) quantity
13+
from ( select times.time_id, product, quantity
14+
from inventory partition by (product)
15+
right outer join times on (times.time_id = inventory.time_id)
16+
where times.time_id between to_date('01/04/01', 'dd/mm/yy')
17+
and to_date('06/04/01', 'dd/mm/yy'))
18+
order by 2,1
19+
20+
21+
22+
--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:07 AM
23+
--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Apr 6, 2024, 7:38:53 AM
24+
--@FAILURE: Encountered: <K_BY> / "by", at line 14, column 39, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
25+
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
26+
--@FAILURE: --- recorded first on 23-Oct-2026, 4:26:44 pm

‎src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/analytic_query03.sql‎

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
---
2-
-- #%L
3-
-- JSQLParser library
4-
-- %%
5-
-- Copyright (C) 2004 - 2019 JSQLParser
6-
-- %%
7-
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8-
-- #L%
9-
---
10-
select times.time_id, product, quantity from inventory
11-
partition by (product)
12-
right outer join times on (times.time_id = inventory.time_id)
13-
where times.time_id between to_date('01/04/01', 'dd/mm/yy')
14-
and to_date('06/04/01', 'dd/mm/yy')
15-
order by 2,1
16-
17-
18-
19-
--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM
20-
--@FAILURE: Encountered: <K_BY> / "by", at line 11, column 14, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
21-
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
1+
---
2+
-- #%L
3+
-- JSQLParser library
4+
-- %%
5+
-- Copyright (C) 2004 - 2019 JSQLParser
6+
-- %%
7+
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
-- #L%
9+
---
10+
select times.time_id, product, quantity from inventory
11+
partition by (product)
12+
right outer join times on (times.time_id = inventory.time_id)
13+
where times.time_id between to_date('01/04/01', 'dd/mm/yy')
14+
and to_date('06/04/01', 'dd/mm/yy')
15+
order by 2,1
16+
17+
18+
19+
--@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM
20+
--@FAILURE: Encountered: <K_BY> / "by", at line 11, column 14, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
21+
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
22+
--@FAILURE: --- recorded first on 23-Oct-2026, 4:26:44 pm

‎src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar03.sql‎

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
1-
---
2-
-- #%L
3-
-- JSQLParser library
4-
-- %%
5-
-- Copyright (C) 2004 - 2019 JSQLParser
6-
-- %%
7-
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8-
-- #L%
9-
---
10-
select count(*), max(scn)
11-
from
12-
(
13-
(select sp.bo#, sp.pmoptype, sp.scn, sp.flags
14-
from sumpartlog$ sp, sumdep$ sd
15-
where sd.sumobj# = :1 and sd.p_obj# = sp.bo#
16-
group by sp.bo#, sp.pmoptype, sp.scn, sp.flags)
17-
minus
18-
(select sp.bo#, sp.pmoptype, sp.scn, sp.flags
19-
from sumpartlog$ sp
20-
where sp.bo# not in
21-
(
22-
select sk.detailobj# from sumkey$ sk where sk.sumobj# = :1 and sk.detailcolfunction in (2,3)
23-
)
24-
and bitand(sp.flags, 2) != 2 and sp.pmoptype in (2,3,5,7))
25-
group by sp.bo#, sp.pmoptype, sp.scn, sp.flags
26-
)
27-
where scn > :2
28-
29-
--@FAILURE: Encountered unexpected token: "group" "GROUP" recorded first on Aug 3, 2021, 7:20:08 AM
30-
--@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Mar 25, 2023, 9:30:55 AM
31-
--@FAILURE: Encountered: <K_GROUP> / "group", at line 25, column 2, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
32-
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
1+
---
2+
-- #%L
3+
-- JSQLParser library
4+
-- %%
5+
-- Copyright (C) 2004 - 2019 JSQLParser
6+
-- %%
7+
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
-- #L%
9+
---
10+
select count(*), max(scn)
11+
from
12+
(
13+
(select sp.bo#, sp.pmoptype, sp.scn, sp.flags
14+
from sumpartlog$ sp, sumdep$ sd
15+
where sd.sumobj# = :1 and sd.p_obj# = sp.bo#
16+
group by sp.bo#, sp.pmoptype, sp.scn, sp.flags)
17+
minus
18+
(select sp.bo#, sp.pmoptype, sp.scn, sp.flags
19+
from sumpartlog$ sp
20+
where sp.bo# not in
21+
(
22+
select sk.detailobj# from sumkey$ sk where sk.sumobj# = :1 and sk.detailcolfunction in (2,3)
23+
)
24+
and bitand(sp.flags, 2) != 2 and sp.pmoptype in (2,3,5,7))
25+
group by sp.bo#, sp.pmoptype, sp.scn, sp.flags
26+
)
27+
where scn > :2
28+
29+
--@FAILURE: Encountered unexpected token: "group" "GROUP" recorded first on Aug 3, 2021, 7:20:08 AM
30+
--@FAILURE: Encountered unexpected token: "minus" "MINUS" recorded first on Mar 25, 2023, 9:30:55 AM
31+
--@FAILURE: Encountered: <K_GROUP> / "group", at line 25, column 2, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
32+
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
33+
--@FAILURE: --- recorded first on 23-Oct-2026, 4:26:44 pm

‎src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/bindvar04.sql‎

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
---
2-
-- #%L
3-
-- JSQLParser library
4-
-- %%
5-
-- Copyright (C) 2004 - 2019 JSQLParser
6-
-- %%
7-
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8-
-- #L%
9-
---
10-
select *
11-
from
12-
(
13-
select *
14-
from "rme" "rm"
15-
where "rm".a-interval:"sys_b_07" day(:"sys_b_08") to second(:"sys_b_09")
16-
)
17-
18-
--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM
19-
--@FAILURE: Encountered: "(" / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
20-
--@FAILURE: Encountered: <OPENING_BRACKET> / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17
21-
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
1+
---
2+
-- #%L
3+
-- JSQLParser library
4+
-- %%
5+
-- Copyright (C) 2004 - 2019 JSQLParser
6+
-- %%
7+
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
-- #L%
9+
---
10+
select *
11+
from
12+
(
13+
select *
14+
from "rme" "rm"
15+
where "rm".a-interval:"sys_b_07" day(:"sys_b_08") to second(:"sys_b_09")
16+
)
17+
18+
--@FAILURE: Encountered unexpected token: "(" "(" recorded first on Aug 3, 2021, 7:20:08 AM
19+
--@FAILURE: Encountered: "(" / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
20+
--@FAILURE: Encountered: <OPENING_BRACKET> / "(", at line 15, column 41, in lexical state DEFAULT. recorded first on 9 Jul 2025, 17:09:17
21+
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
22+
--@FAILURE: --- recorded first on 23-Oct-2026, 4:26:44 pm

‎src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset09.sql‎

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
---
2-
-- #%L
3-
-- JSQLParser library
4-
-- %%
5-
-- Copyright (C) 2004 - 2019 JSQLParser
6-
-- %%
7-
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8-
-- #L%
9-
---
10-
update customers_demo
11-
set cust_address_ntab = cust_address_ntab multiset union cust_address_ntab
12-
13-
--@FAILURE: Encountered unexpected token: "multiset" <S_IDENTIFIER> recorded first on Aug 3, 2021, 7:20:08 AM
14-
--@FAILURE: Encountered: <S_IDENTIFIER> / "multiset", at line 11, column 43, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
15-
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
1+
---
2+
-- #%L
3+
-- JSQLParser library
4+
-- %%
5+
-- Copyright (C) 2004 - 2019 JSQLParser
6+
-- %%
7+
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
-- #L%
9+
---
10+
update customers_demo
11+
set cust_address_ntab = cust_address_ntab multiset union cust_address_ntab
12+
13+
--@FAILURE: Encountered unexpected token: "multiset" <S_IDENTIFIER> recorded first on Aug 3, 2021, 7:20:08 AM
14+
--@FAILURE: Encountered: <S_IDENTIFIER> / "multiset", at line 11, column 43, in lexical state DEFAULT. recorded first on 23 May 2025, 22:04:10
15+
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
16+
--@FAILURE: --- recorded first on 23-Oct-2026, 4:26:44 pm

‎src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/cast_multiset13.sql‎

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
---
2-
-- #%L
3-
-- JSQLParser library
4-
-- %%
5-
-- Copyright (C) 2004 - 2019 JSQLParser
6-
-- %%
7-
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8-
-- #L%
9-
---
10-
select customer_id, cust_address_ntab
11-
multiset except distinct cust_address2_ntab multiset_except
12-
from customers_demo
13-
14-
--@FAILURE: Encountered unexpected token: "except" "EXCEPT" recorded first on Aug 3, 2021, 7:20:08 AM
15-
--@FAILURE: Encountered unexpected token: "distinct" "DISTINCT" recorded first on Mar 25, 2023, 9:18:30 AM
16-
--@FAILURE: Encountered unexpected token: "cust_address2_ntab" <S_IDENTIFIER> recorded first on Feb 8, 2025, 6:46:21 AM
17-
--@FAILURE: Encountered: <S_IDENTIFIER> / "cust_address2_ntab", at line 11, column 26, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08
18-
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
1+
---
2+
-- #%L
3+
-- JSQLParser library
4+
-- %%
5+
-- Copyright (C) 2004 - 2019 JSQLParser
6+
-- %%
7+
-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
-- #L%
9+
---
10+
select customer_id, cust_address_ntab
11+
multiset except distinct cust_address2_ntab multiset_except
12+
from customers_demo
13+
14+
--@FAILURE: Encountered unexpected token: "except" "EXCEPT" recorded first on Aug 3, 2021, 7:20:08 AM
15+
--@FAILURE: Encountered unexpected token: "distinct" "DISTINCT" recorded first on Mar 25, 2023, 9:18:30 AM
16+
--@FAILURE: Encountered unexpected token: "cust_address2_ntab" <S_IDENTIFIER> recorded first on Feb 8, 2025, 6:46:21 AM
17+
--@FAILURE: Encountered: <S_IDENTIFIER> / "cust_address2_ntab", at line 11, column 26, in lexical state DEFAULT. recorded first on 15 May 2025, 16:24:08
18+
--@FAILURE: --- recorded first on 11 Apr 2026, 22:18:19
19+
--@FAILURE: --- recorded first on 23-Oct-2026, 4:26:44 pm

0 commit comments

Comments
 (0)