Skip to content

Commit 33c4030

Browse files
authored
Structure FOR PORTION intervals in UPDATE and DELETE (#2622)
1 parent 6860852 commit 33c4030

15 files changed

Lines changed: 367 additions & 56 deletions

File tree

src/main/java/net/sf/jsqlparser/parser/feature/Feature.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ public enum Feature {
340340
* @see Update
341341
*/
342342
update,
343+
344+
/** Application-time FOR PORTION OF in UPDATE and DELETE. */
345+
forPortion,
343346
/**
344347
* "UPDATE table1 SET ... FROM table2
345348
*/
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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;
11+
12+
import java.util.function.Consumer;
13+
import net.sf.jsqlparser.expression.Expression;
14+
import net.sf.jsqlparser.expression.ExpressionVisitor;
15+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
16+
17+
/** The application-time interval affected by an UPDATE or DELETE statement. */
18+
public class ForPortionClause extends ASTNodeAccessImpl {
19+
private String periodName;
20+
private Expression fromExpression;
21+
private Expression toExpression;
22+
23+
public ForPortionClause(String periodName, Expression fromExpression, Expression toExpression) {
24+
this.periodName = periodName;
25+
this.fromExpression = fromExpression;
26+
this.toExpression = toExpression;
27+
}
28+
29+
public String getPeriodName() {
30+
return periodName;
31+
}
32+
33+
public void setPeriodName(String periodName) {
34+
this.periodName = periodName;
35+
}
36+
37+
public Expression getFromExpression() {
38+
return fromExpression;
39+
}
40+
41+
public void setFromExpression(Expression fromExpression) {
42+
this.fromExpression = fromExpression;
43+
}
44+
45+
public Expression getToExpression() {
46+
return toExpression;
47+
}
48+
49+
public void setToExpression(Expression toExpression) {
50+
this.toExpression = toExpression;
51+
}
52+
53+
/** Visits both interval bounds, preserving the caller's context. */
54+
public <S> void accept(ExpressionVisitor<?> visitor, S context) {
55+
fromExpression.accept(visitor, context);
56+
toExpression.accept(visitor, context);
57+
}
58+
59+
public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> expressionPrinter) {
60+
builder.append("FOR PORTION OF ").append(periodName).append(" FROM ");
61+
expressionPrinter.accept(fromExpression);
62+
builder.append(" TO ");
63+
expressionPrinter.accept(toExpression);
64+
return builder;
65+
}
66+
67+
@Override
68+
public String toString() {
69+
StringBuilder builder = new StringBuilder();
70+
return appendTo(builder, builder::append).toString();
71+
}
72+
}

src/main/java/net/sf/jsqlparser/statement/delete/Delete.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import net.sf.jsqlparser.expression.OracleHint;
1414
import net.sf.jsqlparser.expression.PreferringClause;
1515
import net.sf.jsqlparser.schema.Table;
16+
import net.sf.jsqlparser.statement.ForPortionClause;
1617
import net.sf.jsqlparser.statement.OutputClause;
1718
import net.sf.jsqlparser.statement.ReturningClause;
1819
import net.sf.jsqlparser.statement.Statement;
@@ -39,6 +40,7 @@ public class Delete implements Statement {
3940

4041
private List<WithItem<?>> withItemsList;
4142
private Table table;
43+
private ForPortionClause forPortionClause;
4244
private OracleHint oracleHint = null;
4345
private List<Table> tables;
4446
private List<FromItem> usingFromItemList;
@@ -113,6 +115,19 @@ public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
113115
return statementVisitor.visit(this, context);
114116
}
115117

118+
public ForPortionClause getForPortionClause() {
119+
return forPortionClause;
120+
}
121+
122+
public void setForPortionClause(ForPortionClause forPortionClause) {
123+
this.forPortionClause = forPortionClause;
124+
}
125+
126+
public Delete withForPortionClause(ForPortionClause forPortionClause) {
127+
setForPortionClause(forPortionClause);
128+
return this;
129+
}
130+
116131
public Table getTable() {
117132
return table;
118133
}
@@ -261,6 +276,9 @@ public String toString() {
261276
b.append(" FROM");
262277
}
263278
b.append(" ").append(table);
279+
if (forPortionClause != null) {
280+
b.append(' ').append(forPortionClause);
281+
}
264282

265283
if (usingFromItemList != null && !usingFromItemList.isEmpty()) {
266284
b.append(" USING ");

src/main/java/net/sf/jsqlparser/statement/update/Update.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import net.sf.jsqlparser.expression.PreferringClause;
1515
import net.sf.jsqlparser.schema.Column;
1616
import net.sf.jsqlparser.schema.Table;
17+
import net.sf.jsqlparser.statement.ForPortionClause;
1718
import net.sf.jsqlparser.statement.OutputClause;
1819
import net.sf.jsqlparser.statement.ReturningClause;
1920
import net.sf.jsqlparser.statement.Statement;
@@ -40,6 +41,7 @@ public class Update implements Statement {
4041

4142
private List<WithItem<?>> withItemsList;
4243
private Table table;
44+
private ForPortionClause forPortionClause;
4345
private Expression where;
4446
private PreferringClause preferringClause;
4547
private List<UpdateSet> updateSets;
@@ -114,6 +116,19 @@ public Update addWithItemsList(Collection<? extends WithItem<?>> withItemsList)
114116
return this.withWithItemsList(collection);
115117
}
116118

119+
public ForPortionClause getForPortionClause() {
120+
return forPortionClause;
121+
}
122+
123+
public void setForPortionClause(ForPortionClause forPortionClause) {
124+
this.forPortionClause = forPortionClause;
125+
}
126+
127+
public Update withForPortionClause(ForPortionClause forPortionClause) {
128+
setForPortionClause(forPortionClause);
129+
return this;
130+
}
131+
117132
public Table getTable() {
118133
return table;
119134
}
@@ -372,6 +387,9 @@ public String toString() {
372387
b.append("IGNORE ");
373388
}
374389
b.append(table);
390+
if (forPortionClause != null) {
391+
b.append(' ').append(forPortionClause);
392+
}
375393
if (startJoins != null) {
376394
for (Join join : startJoins) {
377395
if (join.isSimple()) {

src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,9 @@ public <S> Void visit(Delete delete, S context) {
13581358

13591359
visitJoins(delete.getJoins(), context);
13601360

1361+
if (delete.getForPortionClause() != null) {
1362+
delete.getForPortionClause().accept(this, context);
1363+
}
13611364
if (delete.getWhere() != null) {
13621365
delete.getWhere().accept(this, context);
13631366
}
@@ -1421,6 +1424,9 @@ public <S> Void visit(Update update, S context) {
14211424
}
14221425
}
14231426

1427+
if (update.getForPortionClause() != null) {
1428+
update.getForPortionClause().accept(this, context);
1429+
}
14241430
if (update.getWhere() != null) {
14251431
update.getWhere().accept(this, context);
14261432
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import net.sf.jsqlparser.expression.ExpressionVisitor;
1313
import net.sf.jsqlparser.statement.update.UpdateSet;
14+
import net.sf.jsqlparser.statement.ForPortionClause;
1415

1516
import java.util.List;
1617

@@ -43,6 +44,14 @@ public static void deparseUpdateSets(List<UpdateSet> updateSets, StringBuilder b
4344
}
4445
}
4546

47+
protected void deparseForPortionClause(ForPortionClause clause,
48+
ExpressionVisitor<StringBuilder> visitor) {
49+
if (clause != null) {
50+
builder.append(' ');
51+
clause.appendTo(builder, expression -> expression.accept(visitor, null));
52+
}
53+
}
54+
4655
public StringBuilder getBuilder() {
4756
return builder;
4857
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public void deParse(Delete delete) {
7777
builder.append(" FROM");
7878
}
7979
builder.append(" ").append(delete.getTable().toString());
80+
deparseForPortionClause(delete.getForPortionClause(), expressionVisitor);
8081

8182
if (delete.getUsingFromItemList() != null && !delete.getUsingFromItemList().isEmpty()) {
8283
builder.append(" USING").append(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public void deParse(Update update) {
6161
builder.append("IGNORE ");
6262
}
6363
builder.append(update.getTable());
64+
deparseForPortionClause(update.getForPortionClause(), expressionVisitor);
6465
if (update.getStartJoins() != null) {
6566
for (Join join : update.getStartJoins()) {
6667
if (join.isSimple()) {

src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS
138138
* all {@link Feature}' for SQL UPDATE including {@link #SELECT}
139139
*/
140140
public static final FeaturesAllowed UPDATE = new FeaturesAllowed("UPDATE", Feature.update,
141+
Feature.forPortion,
141142
Feature.updateJoins,
142143
Feature.updateFrom, Feature.updateLimit, Feature.updateOrderBy, Feature.updateReturning,
143144
Feature.updateUseSelect)
@@ -146,7 +147,7 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS
146147
* all {@link Feature}' for SQL UPDATE including {@link #SELECT}
147148
*/
148149
public static final FeaturesAllowed DELETE =
149-
new FeaturesAllowed("DELETE", Feature.delete, Feature.deleteJoin,
150+
new FeaturesAllowed("DELETE", Feature.delete, Feature.forPortion, Feature.deleteJoin,
150151
Feature.deleteLimit, Feature.deleteOrderBy, Feature.deleteTables,
151152
Feature.deleteReturningExpressionList,
152153
Feature.truncate)

src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java

Lines changed: 28 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@ public enum MariaDbVersion implements Version {
2626
V10_5_4("10.5.4",
2727
EnumSet.of(// supported if used with jdbc
2828
Feature.jdbcParameter,
29-
Feature.jdbcNamedParameter,
30-
// expressions
31-
Feature.exprLike,
32-
// https://mariadb.com/kb/en/select/
29+
Feature.jdbcNamedParameter, // expressions
30+
Feature.exprLike, // https://mariadb.com/kb/en/select/
3331
Feature.select,
3432
Feature.selectGroupBy, Feature.function,
3533
Feature.selectHaving,
@@ -49,12 +47,9 @@ public enum MariaDbVersion implements Version {
4947
// https://mariadb.com/kb/en/select/#distinct
5048
Feature.distinct,
5149

52-
Feature.setOperation,
53-
// https://mariadb.com/kb/en/union/
54-
Feature.setOperationUnion,
55-
// https://mariadb.com/kb/en/intersect/
56-
Feature.setOperationIntersect,
57-
// https://mariadb.com/kb/en/except/
50+
Feature.setOperation, // https://mariadb.com/kb/en/union/
51+
Feature.setOperationUnion, // https://mariadb.com/kb/en/intersect/
52+
Feature.setOperationIntersect, // https://mariadb.com/kb/en/except/
5853
Feature.setOperationExcept,
5954

6055
// https://mariadb.com/kb/en/common-table-expressions/
@@ -71,7 +66,8 @@ public enum MariaDbVersion implements Version {
7166
Feature.insertReturningExpressionList,
7267

7368
// https://mariadb.com/kb/en/update/
74-
Feature.update,
69+
Feature.update, // https://mariadb.com/kb/en/application-time-periods/
70+
Feature.forPortion,
7571
Feature.updateJoins,
7672
Feature.updateOrderBy, Feature.updateLimit,
7773

@@ -87,17 +83,12 @@ public enum MariaDbVersion implements Version {
8783
Feature.execute, Feature.executeCall,
8884

8985
// https://mariadb.com/kb/en/drop/
90-
Feature.drop,
91-
// https://mariadb.com/kb/en/drop-index/
92-
Feature.dropIndex,
93-
// https://mariadb.com/kb/en/drop-table/
94-
Feature.dropTable,
95-
// https://mariadb.com/kb/en/drop-database/
86+
Feature.drop, // https://mariadb.com/kb/en/drop-index/
87+
Feature.dropIndex, // https://mariadb.com/kb/en/drop-table/
88+
Feature.dropTable, // https://mariadb.com/kb/en/drop-database/
9689
// SCHEMA = DATABASE
97-
Feature.dropSchema,
98-
// https://mariadb.com/kb/en/drop-view/
99-
Feature.dropView,
100-
// https://mariadb.com/kb/en/drop-sequence/
90+
Feature.dropSchema, // https://mariadb.com/kb/en/drop-view/
91+
Feature.dropView, // https://mariadb.com/kb/en/drop-sequence/
10192
Feature.dropSequence, Feature.dropTableIfExists, Feature.dropIndexIfExists,
10293
Feature.dropViewIfExists, Feature.dropSchemaIfExists,
10394
Feature.dropSequenceIfExists,
@@ -106,48 +97,32 @@ public enum MariaDbVersion implements Version {
10697
Feature.upsert,
10798

10899
// https://mariadb.com/kb/en/alter/
109-
Feature.alterTable,
110-
// https://mariadb.com/kb/en/alter-sequence/
111-
Feature.alterSequence,
112-
// https://mariadb.com/kb/en/alter-view/
113-
Feature.alterView,
114-
// https://mariadb.com/kb/en/create-view/
100+
Feature.alterTable, // https://mariadb.com/kb/en/alter-sequence/
101+
Feature.alterSequence, // https://mariadb.com/kb/en/alter-view/
102+
Feature.alterView, // https://mariadb.com/kb/en/create-view/
115103
Feature.createView,
116104
Feature.createOrReplaceView,
117105
Feature.createViewWithComment,
118106

119107
// https://mariadb.com/kb/en/create-table/
120108
Feature.createTable, Feature.createTableCreateOptionStrings,
121109
Feature.createTableTableOptionStrings,
122-
Feature.createTableFromSelect, Feature.createTableIfNotExists,
123-
// https://mariadb.com/kb/en/create-index/
124-
Feature.createIndex,
125-
// https://mariadb.com/kb/en/create-sequence/
126-
Feature.createSequence,
127-
// https://mariadb.com/kb/en/create-database/
128-
Feature.createSchema,
129-
// https://mariadb.com/kb/en/create-trigger/
110+
Feature.createTableFromSelect, Feature.createTableIfNotExists, // https://mariadb.com/kb/en/create-index/
111+
Feature.createIndex, // https://mariadb.com/kb/en/create-sequence/
112+
Feature.createSequence, // https://mariadb.com/kb/en/create-database/
113+
Feature.createSchema, // https://mariadb.com/kb/en/create-trigger/
130114
Feature.createTrigger,
131115

132116
// https://mariadb.com/kb/en/describe/
133-
Feature.describe,
134-
// https://mariadb.com/kb/en/explain/
135-
Feature.explain,
136-
// https://mariadb.com/kb/en/show/
137-
Feature.show,
138-
// https://mariadb.com/kb/en/show-tables/
139-
Feature.showTables,
140-
// https://mariadb.com/kb/en/show-columns/
141-
Feature.showColumns,
142-
// https://mariadb.com/kb/en/show-index/
143-
Feature.showIndex,
144-
// https://mariadb.com/kb/en/use/
145-
Feature.use,
146-
// https://mariadb.com/kb/en/grant/
147-
Feature.grant,
148-
// https://mariadb.com/kb/en/commit/
149-
Feature.commit,
150-
// https://mariadb.com/kb/en/optimizer-hints/
117+
Feature.describe, // https://mariadb.com/kb/en/explain/
118+
Feature.explain, // https://mariadb.com/kb/en/show/
119+
Feature.show, // https://mariadb.com/kb/en/show-tables/
120+
Feature.showTables, // https://mariadb.com/kb/en/show-columns/
121+
Feature.showColumns, // https://mariadb.com/kb/en/show-index/
122+
Feature.showIndex, // https://mariadb.com/kb/en/use/
123+
Feature.use, // https://mariadb.com/kb/en/grant/
124+
Feature.grant, // https://mariadb.com/kb/en/commit/
125+
Feature.commit, // https://mariadb.com/kb/en/optimizer-hints/
151126
Feature.mySqlHintStraightJoin,
152127
Feature.mysqlCalcFoundRows,
153128
Feature.mysqlSqlCacheFlag)),

0 commit comments

Comments
 (0)