Skip to content

Commit 7c21242

Browse files
TSQL Compliant NEXT VALUE FOR sequence_id (but keeping the spurious NEXTVAL FOR expression) (#1216)
Co-authored-by: Tobias <[email protected]>
1 parent 537649b commit 7c21242

File tree

5 files changed

+59
-9
lines changed

5 files changed

+59
-9
lines changed

src/main/java/net/sf/jsqlparser/expression/NextValExpression.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*-
1+
/* -
22
* #%L
33
* JSQLParser library
44
* %%
@@ -10,14 +10,34 @@
1010
package net.sf.jsqlparser.expression;
1111

1212
import java.util.List;
13+
import java.util.regex.Pattern;
1314
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
1415

1516
public class NextValExpression extends ASTNodeAccessImpl implements Expression {
1617

17-
private List<String> nameList;
18+
public static final Pattern NEXT_VALUE_PATTERN = Pattern.compile("NEXT\\s+VALUE\\s+FOR", Pattern.CASE_INSENSITIVE);
19+
private final List<String> nameList;
20+
private boolean usingNextValueFor = false;
1821

19-
public NextValExpression(List<String> nameList) {
22+
public NextValExpression(List<String> nameList, String image) {
2023
this.nameList = nameList;
24+
// Test if we shall use NEXT VALUE FOR instead of NEXTVAL FOR
25+
if (NEXT_VALUE_PATTERN.matcher(image).matches()) {
26+
usingNextValueFor = true;
27+
}
28+
}
29+
30+
public boolean isUsingNextValueFor() {
31+
return usingNextValueFor;
32+
}
33+
34+
public void setUsingNextValueFor(boolean usingNextValueFor) {
35+
this.usingNextValueFor = usingNextValueFor;
36+
}
37+
38+
public NextValExpression withNextValueFor(boolean usingNextValueFor) {
39+
setUsingNextValueFor(usingNextValueFor);
40+
return this;
2141
}
2242

2343
public List<String> getNameList() {
@@ -37,7 +57,9 @@ public String getName() {
3757

3858
@Override
3959
public String toString() {
40-
return "NEXTVAL FOR " + getName();
60+
return (usingNextValueFor
61+
? "NEXT VALUE FOR "
62+
: "NEXTVAL FOR ") + getName();
4163
}
4264

4365
@Override

src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ public void visit(DateTimeLiteralExpression literal) {
917917

918918
@Override
919919
public void visit(NextValExpression nextVal) {
920-
buffer.append("NEXTVAL FOR ").append(nextVal.getName());
920+
buffer.append(nextVal.isUsingNextValueFor() ? "NEXT VALUE FOR " : "NEXTVAL FOR ").append(nextVal.getName());
921921
}
922922

923923
@Override

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
255255
| <K_MOVEMENT: "MOVEMENT">
256256
| <K_NATURAL:"NATURAL">
257257
| <K_NEXT:"NEXT">
258-
| <K_NEXTVAL:"NEXTVAL">
258+
| <K_NEXTVAL: ( (("NEXTVAL")(" ")+("FOR")) | ( ("NEXT")(" ")+("VALUE") (" ")+("FOR") ) )>
259259
| <K_NO:"NO">
260260
| <K_NOCACHE:"NOCACHE">
261261
| <K_NOCYCLE:"NOCYCLE">
@@ -3454,11 +3454,12 @@ Expression PrimaryExpression() #PrimaryExpression:
34543454

34553455
NextValExpression NextValExpression() : {
34563456
List<String> data = new ArrayList<String>();
3457+
Token token;
34573458
}
34583459
{
3459-
<K_NEXTVAL> <K_FOR> data = RelObjectNameList()
3460+
token=<K_NEXTVAL> data = RelObjectNameList()
34603461
{
3461-
return new NextValExpression(data);
3462+
return new NextValExpression(data, token.image);
34623463
}
34633464
}
34643465

src/test/java/net/sf/jsqlparser/statement/builder/ReflectionModelTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class ReflectionModelTest {
5050
new net.sf.jsqlparser.expression.MySQLGroupConcat(),
5151
new net.sf.jsqlparser.expression.MySQLIndexHint("action", "indexQualifier",
5252
asList("idx_name", "idx_name_col")),
53-
new net.sf.jsqlparser.expression.NextValExpression(asList("sequence")),
53+
new net.sf.jsqlparser.expression.NextValExpression(asList("sequence" ), "NEXT VALUE"),
5454
new net.sf.jsqlparser.expression.NotExpression(),
5555
new net.sf.jsqlparser.expression.NullValue(), new net.sf.jsqlparser.expression.NumericBind(),
5656
new net.sf.jsqlparser.expression.OracleHierarchicalExpression(),

src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,18 @@ public void testInsertMultiRowValueDifferent() throws JSQLParserException {
197197
fail("should not work");
198198
}
199199

200+
@Test
201+
@Ignore
202+
public void testOracleInsertMultiRowValue() throws JSQLParserException {
203+
String sqlStr
204+
= "INSERT ALL\n"
205+
+ " INTO suppliers (supplier_id, supplier_name) VALUES (1000, 'IBM')\n"
206+
+ " INTO suppliers (supplier_id, supplier_name) VALUES (2000, 'Microsoft')\n"
207+
+ " INTO suppliers (supplier_id, supplier_name) VALUES (3000, 'Google')\n"
208+
+ "SELECT * FROM dual;";
209+
assertSqlCanBeParsedAndDeparsed(sqlStr, true);
210+
}
211+
200212
@Test
201213
public void testSimpleInsert() throws JSQLParserException {
202214
assertSqlCanBeParsedAndDeparsed("INSERT INTO example (num, name, address, tel) VALUES (1, 'name', 'test ', '1234-1234')");
@@ -332,6 +344,11 @@ public void testNextVal() throws JSQLParserException {
332344
assertSqlCanBeParsedAndDeparsed("INSERT INTO tracker (monitor_id, user_id, module_name, item_id, item_summary, team_id, date_modified, action, visible, id) VALUES (?, ?, ?, ?, ?, ?, to_date(?, 'YYYY-MM-DD HH24:MI:SS'), ?, ?, NEXTVAL FOR TRACKER_ID_SEQ)");
333345
}
334346

347+
@Test
348+
public void testNextValueFor() throws JSQLParserException {
349+
assertSqlCanBeParsedAndDeparsed("INSERT INTO tracker (monitor_id, user_id, module_name, item_id, item_summary, team_id, date_modified, action, visible, id) VALUES (?, ?, ?, ?, ?, ?, to_date(?, 'YYYY-MM-DD HH24:MI:SS'), ?, ?, NEXT VALUE FOR TRACKER_ID_SEQ)");
350+
}
351+
335352
@Test
336353
public void testNextValIssue773() throws JSQLParserException {
337354
assertSqlCanBeParsedAndDeparsed("INSERT INTO tableA (ID, c1, c2) SELECT hibernate_sequence.nextval, c1, c2 FROM tableB");
@@ -358,4 +375,14 @@ public void testOracleHint() throws JSQLParserException {
358375

359376
//@todo: add a testcase supposed to not finding a misplaced hint
360377
}
378+
379+
@Test
380+
public void testInsertTableArrays4() throws JSQLParserException {
381+
assertSqlCanBeParsedAndDeparsed(
382+
"INSERT INTO sal_emp\n"
383+
+ " VALUES ('Carol',\n"
384+
+ " ARRAY[20000, 25000, 25000, 25000],\n"
385+
+ " ARRAY[['breakfast', 'consulting'], ['meeting', 'lunch']])",
386+
true);
387+
}
361388
}

0 commit comments

Comments
 (0)