2424import net .sf .jsqlparser .statement .StatementVisitor ;
2525
2626public abstract class Select extends ASTNodeAccessImpl implements Statement , Expression , FromItem {
27- protected Table forUpdateTable = null ;
27+ protected List < Table > forUpdateTables = null ;
2828 protected List <WithItem <?>> withItemsList ;
2929 Limit limitBy ;
3030 Limit limit ;
@@ -40,6 +40,7 @@ public abstract class Select extends ASTNodeAccessImpl implements Statement, Exp
4040 private boolean skipLocked ;
4141 private Wait wait ;
4242 private boolean noWait = false ;
43+ private boolean forUpdateBeforeOrderBy = false ;
4344 Alias alias ;
4445 Pivot pivot ;
4546 UnPivot unPivot ;
@@ -291,12 +292,92 @@ public void setForMode(ForMode forMode) {
291292 this .forMode = forMode ;
292293 }
293294
295+ /**
296+ * Returns the first table from the {@code FOR UPDATE OF} clause, or {@code null} if no table
297+ * was specified. Use {@link #getForUpdateTables()} to retrieve all tables.
298+ *
299+ * @return the first table, or {@code null}
300+ */
294301 public Table getForUpdateTable () {
295- return this .forUpdateTable ;
302+ return (forUpdateTables != null && !forUpdateTables .isEmpty ()) ? forUpdateTables .get (0 )
303+ : null ;
296304 }
297305
306+ /**
307+ * Sets a single table for the {@code FOR UPDATE OF} clause.
308+ *
309+ * @param forUpdateTable the table, or {@code null} to clear
310+ */
298311 public void setForUpdateTable (Table forUpdateTable ) {
299- this .forUpdateTable = forUpdateTable ;
312+ if (forUpdateTable == null ) {
313+ this .forUpdateTables = null ;
314+ } else {
315+ this .forUpdateTables = new ArrayList <>();
316+ this .forUpdateTables .add (forUpdateTable );
317+ }
318+ }
319+
320+ /**
321+ * Returns the list of tables named in the {@code FOR UPDATE OF t1, t2, ...} clause, or
322+ * {@code null} if no OF clause was present.
323+ *
324+ * @return list of tables, or {@code null}
325+ */
326+ public List <Table > getForUpdateTables () {
327+ return forUpdateTables ;
328+ }
329+
330+ /**
331+ * Sets the list of tables for the {@code FOR UPDATE OF t1, t2, ...} clause.
332+ *
333+ * @param forUpdateTables list of tables
334+ */
335+ public void setForUpdateTables (List <Table > forUpdateTables ) {
336+ this .forUpdateTables = forUpdateTables ;
337+ }
338+
339+ public Select withForUpdateTables (List <Table > forUpdateTables ) {
340+ this .setForUpdateTables (forUpdateTables );
341+ return this ;
342+ }
343+
344+ /**
345+ * Builds and returns a {@link ForUpdateClause} representing the current FOR UPDATE / FOR SHARE
346+ * state of this SELECT, or {@code null} if no FOR clause is present.
347+ *
348+ * @return a {@link ForUpdateClause} view, or {@code null}
349+ */
350+ public ForUpdateClause getForUpdate () {
351+ if (forMode == null ) {
352+ return null ;
353+ }
354+ ForUpdateClause clause = new ForUpdateClause ();
355+ clause .setMode (forMode );
356+ clause .setTables (forUpdateTables );
357+ clause .setWait (wait );
358+ clause .setNoWait (noWait );
359+ clause .setSkipLocked (skipLocked );
360+ return clause ;
361+ }
362+
363+ /**
364+ * Returns {@code true} when the {@code FOR UPDATE} clause appears before the {@code ORDER BY}
365+ * clause in the original SQL (non-standard ordering supported by some databases).
366+ *
367+ * @return {@code true} if FOR UPDATE precedes ORDER BY
368+ */
369+ public boolean isForUpdateBeforeOrderBy () {
370+ return forUpdateBeforeOrderBy ;
371+ }
372+
373+ /**
374+ * Indicates whether the {@code FOR UPDATE} clause precedes the {@code ORDER BY} clause in the
375+ * SQL output.
376+ *
377+ * @param forUpdateBeforeOrderBy {@code true} to emit FOR UPDATE before ORDER BY
378+ */
379+ public void setForUpdateBeforeOrderBy (boolean forUpdateBeforeOrderBy ) {
380+ this .forUpdateBeforeOrderBy = forUpdateBeforeOrderBy ;
300381 }
301382
302383 /**
@@ -380,7 +461,9 @@ public StringBuilder appendTo(StringBuilder builder) {
380461
381462 appendTo (builder , alias , null , pivot , unPivot );
382463
383- builder .append (orderByToString (oracleSiblings , orderByElements ));
464+ if (!forUpdateBeforeOrderBy ) {
465+ builder .append (orderByToString (oracleSiblings , orderByElements ));
466+ }
384467
385468 if (forClause != null ) {
386469 forClause .appendTo (builder );
@@ -405,8 +488,14 @@ public StringBuilder appendTo(StringBuilder builder) {
405488 builder .append (" FOR " );
406489 builder .append (forMode .getValue ());
407490
408- if (getForUpdateTable () != null ) {
409- builder .append (" OF " ).append (forUpdateTable );
491+ if (forUpdateTables != null && !forUpdateTables .isEmpty ()) {
492+ builder .append (" OF " );
493+ for (int i = 0 ; i < forUpdateTables .size (); i ++) {
494+ if (i > 0 ) {
495+ builder .append (", " );
496+ }
497+ builder .append (forUpdateTables .get (i ));
498+ }
410499 }
411500
412501 if (wait != null ) {
@@ -421,6 +510,10 @@ public StringBuilder appendTo(StringBuilder builder) {
421510 }
422511 }
423512
513+ if (forUpdateBeforeOrderBy ) {
514+ builder .append (orderByToString (oracleSiblings , orderByElements ));
515+ }
516+
424517 return builder ;
425518 }
426519
0 commit comments