6995-6129b.patch
new/src/com/goldencode/p2j/persist/Persistence.java 2023-01-26 11:46:46 +0000 | ||
---|---|---|
579 | 579 |
** OM 20221103 New class names for FQLPreprocessor, FQLExpression, FQLBundle, and FQLCache. |
580 | 580 |
** CA 20221109 Implemented runtime for EXCEPT/FIELDS options - only NO-LOCK records are loaded |
581 | 581 |
** as 'partial/incomplete'. |
582 |
** RAA 20230126 Removed the checks for no-undo as they are no longer necessary. |
|
582 | 583 |
*/ |
583 | 584 | |
584 | 585 |
/* |
... | ... | |
2862 | 2863 |
|
2863 | 2864 |
Query query = getQuery(local, fql, 0, 0, values, false); |
2864 | 2865 |
count = query.executeUpdate(session); |
2865 |
if (noUndo) |
|
2866 |
{ |
|
2867 |
session.noUndoBulkUpdate(query); |
|
2868 |
} |
|
2869 | 2866 |
|
2870 | 2867 |
if (LOG.isLoggable(Level.FINER)) |
2871 | 2868 |
{ |
... | ... | |
3474 | 3471 |
|
3475 | 3472 |
rc = query.executeUpdate(session); |
3476 | 3473 |
|
3477 |
if (noUndo) |
|
3478 |
{ |
|
3479 |
session.noUndoBulkUpdate(query); |
|
3480 |
} |
|
3481 |
|
|
3482 | 3474 |
if (LOG.isLoggable(Level.FINER)) |
3483 | 3475 |
{ |
3484 | 3476 |
LOG.log(Level.FINER, "[" + sql + "] rc = " + rc); |
new/src/com/goldencode/p2j/persist/TempTableHelper.java 2023-01-26 11:49:21 +0000 | ||
---|---|---|
54 | 54 |
** OM 20221027 H2 dialect requires that the index names to be truly unique. |
55 | 55 |
** SVL 20230110 P2JIndex.components() provides direct access to the components array in order to |
56 | 56 |
** improve performance. |
57 |
** RAA 20230126 Added "no-undo" as a temp table postfix in constructor. |
|
57 | 58 |
*/ |
58 | 59 | |
59 | 60 |
/* |
... | ... | |
392 | 393 |
String primarySqlIndexName = null; |
393 | 394 |
|
394 | 395 |
String createTemporaryTablePostfix = dialect.getCreateTemporaryTablePostfix(); |
396 |
String createTemporaryNoUndoTablePostfix = dialect.getCreateTemporaryTableNoUndoPostfix(); |
|
395 | 397 |
String delimiter = dialect.getDelimiter(); |
396 | 398 |
String suffix = createTemporaryTablePostfix + delimiter; |
397 | 399 |
while (databaseIndexes.hasNext()) |
... | ... | |
622 | 624 |
{ |
623 | 625 |
table.append(tab).append("primary key (").append(Session.PK).append(")\n"); |
624 | 626 |
} |
625 |
table.append(")").append(createTemporaryTablePostfix).append(delimiter); |
|
627 |
|
|
628 |
table.append(")").append(createTemporaryTablePostfix); |
|
629 |
if (dmo.noUndo) |
|
630 |
{ |
|
631 |
table.append(createTemporaryNoUndoTablePostfix); |
|
632 |
} |
|
633 |
|
|
634 |
table.append(delimiter); |
|
626 | 635 |
|
627 | 636 |
String tableDDL = table.toString(); |
628 | 637 |
ddlCreateTables.add(tableDDL); |
new/src/com/goldencode/p2j/persist/dialect/Dialect.java 2023-01-26 11:53:44 +0000 | ||
---|---|---|
91 | 91 |
** RAA 20230109 Added method getSequenceSetValString(). |
92 | 92 |
** SVL 20230110 P2JIndex.components() provides direct access to the components array in order to |
93 | 93 |
** improve performance. |
94 |
** RAA 20230126 Added method for creating a temp table postfix responsible with the "no-undo" |
|
95 |
** keyword. By default it is null, representing the string of an undoable table. |
|
94 | 96 |
*/ |
95 | 97 | |
96 | 98 |
/* |
... | ... | |
1297 | 1299 |
public abstract String getCreateTemporaryTablePostfix(); |
1298 | 1300 |
|
1299 | 1301 |
/** |
1302 |
* Return the ending of the DDL statement that creates a temporary no-undo table. |
|
1303 |
* |
|
1304 |
* @return A string representing the ending of the DDL statement that creates a temporary |
|
1305 |
* no-undo table, or empty string if the table is undoable. |
|
1306 |
*/ |
|
1307 |
public String getCreateTemporaryTableNoUndoPostfix() |
|
1308 |
{ |
|
1309 |
return null; |
|
1310 |
} |
|
1311 |
|
|
1312 |
/** |
|
1300 | 1313 |
* Returns the beginning of the DDL statement for creating an index. |
1301 | 1314 |
* |
1302 | 1315 |
* @param unique |
new/src/com/goldencode/p2j/persist/dialect/P2JH2Dialect.java 2023-01-26 11:56:09 +0000 | ||
---|---|---|
105 | 105 |
** OM 20221026 Excluded table name from index name by default. It will be added as needed by |
106 | 106 |
** dialects. |
107 | 107 |
** RAA 20230109 Overrided methods getSequenceSetValString() and getSequenceCurrValString(). |
108 |
** RAA 20230126 Overrided method for returning the postfix of a no-undo temp-table. |
|
108 | 109 |
*/ |
109 | 110 | |
110 | 111 |
/* |
... | ... | |
1329 | 1330 |
} |
1330 | 1331 |
|
1331 | 1332 |
/** |
1333 |
* Return the ending of the DDL statement that creates a temporary no-undo table. |
|
1334 |
* |
|
1335 |
* @return A string representing the ending of the DDL statement that creates a temporary |
|
1336 |
* no-undo table. |
|
1337 |
*/ |
|
1338 |
@Override |
|
1339 |
public String getCreateTemporaryTableNoUndoPostfix() |
|
1340 |
{ |
|
1341 |
return " noundo"; |
|
1342 |
} |
|
1343 |
|
|
1344 |
/** |
|
1332 | 1345 |
* Obtain a DDL statement which drops a SQL index. |
1333 | 1346 |
* |
1334 | 1347 |
* @param ifExists |
new/src/com/goldencode/p2j/persist/orm/SQLRedo.java 1970-01-01 00:00:00 +0000 | ||
---|---|---|
1 |
/* |
|
2 |
** Module : SQLRedo.java |
|
3 |
** Abstract : Redoable SQL operation for NO-UNDO temp-table use. |
|
4 |
** |
|
5 |
** Copyright (c) 2020, Golden Code Development Corporation. |
|
6 |
** |
|
7 |
** -#- -I- --Date-- ---------------------------------Description--------------------------------- |
|
8 |
** 001 ECF 20200413 First revision. A redoable SQL operation for use with NO-UNDO temp-tables. |
|
9 |
*/ |
|
10 | ||
11 |
/* |
|
12 |
** This program is free software: you can redistribute it and/or modify |
|
13 |
** it under the terms of the GNU Affero General Public License as |
|
14 |
** published by the Free Software Foundation, either version 3 of the |
|
15 |
** License, or (at your option) any later version. |
|
16 |
** |
|
17 |
** This program is distributed in the hope that it will be useful, |
|
18 |
** but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
19 |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
20 |
** GNU Affero General Public License for more details. |
|
21 |
** |
|
22 |
** You may find a copy of the GNU Affero GPL version 3 at the following |
|
23 |
** location: https://www.gnu.org/licenses/agpl-3.0.en.html |
|
24 |
** |
|
25 |
** Additional terms under GNU Affero GPL version 3 section 7: |
|
26 |
** |
|
27 |
** Under Section 7 of the GNU Affero GPL version 3, the following additional |
|
28 |
** terms apply to the works covered under the License. These additional terms |
|
29 |
** are non-permissive additional terms allowed under Section 7 of the GNU |
|
30 |
** Affero GPL version 3 and may not be removed by you. |
|
31 |
** |
|
32 |
** 0. Attribution Requirement. |
|
33 |
** |
|
34 |
** You must preserve all legal notices or author attributions in the covered |
|
35 |
** work or Appropriate Legal Notices displayed by works containing the covered |
|
36 |
** work. You may not remove from the covered work any author or developer |
|
37 |
** credit already included within the covered work. |
|
38 |
** |
|
39 |
** 1. No License To Use Trademarks. |
|
40 |
** |
|
41 |
** This license does not grant any license or rights to use the trademarks |
|
42 |
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks |
|
43 |
** of Golden Code Development Corporation. You are not authorized to use the |
|
44 |
** name Golden Code, FWD, or the names of any author or contributor, for |
|
45 |
** publicity purposes without written authorization. |
|
46 |
** |
|
47 |
** 2. No Misrepresentation of Affiliation. |
|
48 |
** |
|
49 |
** You may not represent yourself as Golden Code Development Corporation or FWD. |
|
50 |
** |
|
51 |
** You may not represent yourself for publicity purposes as associated with |
|
52 |
** Golden Code Development Corporation, FWD, or any author or contributor to |
|
53 |
** the covered work, without written authorization. |
|
54 |
** |
|
55 |
** 3. No Misrepresentation of Source or Origin. |
|
56 |
** |
|
57 |
** You may not represent the covered work as solely your work. All modified |
|
58 |
** versions of the covered work must be marked in a reasonable way to make it |
|
59 |
** clear that the modified work is not originating from Golden Code Development |
|
60 |
** Corporation or FWD. All modified versions must contain the notices of |
|
61 |
** attribution required in this license. |
|
62 |
*/ |
|
63 | ||
64 |
package com.goldencode.p2j.persist.orm; |
|
65 | ||
66 |
import com.goldencode.p2j.persist.*; |
|
67 | ||
68 |
/** |
|
69 |
* This class re-applies a single database insert, update, or [bulk] delete action, in order to |
|
70 |
* redo such an action that was undone by a database rollback (savepoint or full transaction). |
|
71 |
* It is needed to implement the NO-UNDO feature of 4GL temp-tables. |
|
72 |
* <p> |
|
73 |
* The top-level class is abstract. To use this class, instantiate one of the specialized, |
|
74 |
* concrete, inner subclasses. |
|
75 |
*/ |
|
76 |
abstract class SQLRedo |
|
77 |
{ |
|
78 |
/** Lambda which performs the redo action and possibly throws a persistence exception */ |
|
79 |
private final ThrowingAction action; |
|
80 |
|
|
81 |
/** Flag indicating that the original action was rolled back and redo is required */ |
|
82 |
private boolean active = false; |
|
83 |
|
|
84 |
/** |
|
85 |
* Constructor. |
|
86 |
* |
|
87 |
* @param action |
|
88 |
* Lambda which performs the redo action and possibly throws a persistence exception. |
|
89 |
*/ |
|
90 |
protected SQLRedo(ThrowingAction action) |
|
91 |
{ |
|
92 |
this.action = action; |
|
93 |
} |
|
94 |
|
|
95 |
/** |
|
96 |
* Mark this redo action as active, meaning the original action which this object was undone |
|
97 |
* by a full or sub-transaction rollback, and needs to be re-applied. If an instance of this |
|
98 |
* class is not marked active, it is a no-op. |
|
99 |
*/ |
|
100 |
void setActive() |
|
101 |
{ |
|
102 |
active = true; |
|
103 |
} |
|
104 |
|
|
105 |
/** |
|
106 |
* Perform this object's redo action, if it was marked active. |
|
107 |
* |
|
108 |
* @throws PersistenceException |
|
109 |
* if there is an error executing the action. |
|
110 |
*/ |
|
111 |
void perform() |
|
112 |
throws PersistenceException |
|
113 |
{ |
|
114 |
if (active) |
|
115 |
{ |
|
116 |
action.run(); |
|
117 |
} |
|
118 |
} |
|
119 |
|
|
120 |
/** |
|
121 |
* A no-arg functional interface which throws PersistenceException, to avoid having to handle |
|
122 |
* this exception in every defined lambda expression. |
|
123 |
*/ |
|
124 |
@FunctionalInterface |
|
125 |
protected interface ThrowingAction |
|
126 |
{ |
|
127 |
/** |
|
128 |
* Run a SQL operation. |
|
129 |
* |
|
130 |
* @throws PersistenceException |
|
131 |
* if a persistence error occurs. |
|
132 |
*/ |
|
133 |
public void run() |
|
134 |
throws PersistenceException; |
|
135 |
} |
|
136 |
|
|
137 |
/** |
|
138 |
* An insert action for a single record. |
|
139 |
*/ |
|
140 |
static class Insert |
|
141 |
extends SQLRedo |
|
142 |
{ |
|
143 |
Insert(Persister persister, BaseRecord dmo) |
|
144 |
{ |
|
145 |
super(() -> persister.insert(dmo)); |
|
146 |
} |
|
147 |
} |
|
148 |
|
|
149 |
/** |
|
150 |
* An update action for a single record. |
|
151 |
*/ |
|
152 |
static class Update |
|
153 |
extends SQLRedo |
|
154 |
{ |
|
155 |
Update(Persister persister, BaseRecord dmo) |
|
156 |
{ |
|
157 |
super(() -> persister.update(dmo)); |
|
158 |
} |
|
159 |
} |
|
160 |
|
|
161 |
/** |
|
162 |
* A delete action for a single record. |
|
163 |
*/ |
|
164 |
static class Delete |
|
165 |
extends SQLRedo |
|
166 |
{ |
|
167 |
Delete(Persister persister, Class<? extends BaseRecord> dmoClass, Long id) |
|
168 |
{ |
|
169 |
super(() -> persister.delete(dmoClass, id)); |
|
170 |
} |
|
171 |
} |
|
172 |
|
|
173 |
/** |
|
174 |
* A bulk action (delete or update) which affects 0 or more records. |
|
175 |
*/ |
|
176 |
static class BulkUpdate |
|
177 |
extends SQLRedo |
|
178 |
{ |
|
179 |
BulkUpdate(Session session, SQLQuery query) |
|
180 |
{ |
|
181 |
super(() -> query.executeUpdate(session)); |
|
182 |
} |
|
183 |
} |
|
184 |
} |
new/src/com/goldencode/p2j/persist/orm/SavepointManager.java 2023-01-26 12:00:49 +0000 | ||
---|---|---|
23 | 23 |
** with a Savepoint at a later time when the invoker requires. |
24 | 24 |
** CA 20220630 Cleanup the 'redoable' list once the full transaction ends. |
25 | 25 |
** CA 20230116 Avoid creating a collection until is needed. |
26 |
** RAA 20230126 Removed all code that was linked to redo operations as it is no longer needed. |
|
26 | 27 |
*/ |
27 | 28 | |
28 | 29 |
/* |
... | ... | |
138 | 139 |
/** Stack of block states which coincide with transaction block scopes */ |
139 | 140 |
private final Deque<Block> blocks = new ArrayDeque<>(); |
140 | 141 |
|
141 |
/** The list of redoable insert, update, and delete SQL operations for NO-UNDO temp-tables */ |
|
142 |
private final List<SQLRedo> redoable = new ArrayList<>(64); |
|
143 |
|
|
144 | 142 |
/** Database session used for savepoint processing */ |
145 | 143 |
private Session session = null; |
146 | 144 |
|
... | ... | |
319 | 317 |
|
320 | 318 |
/** |
321 | 319 |
* Roll back the active block, which entails rolling back any savepoint, rolling up tracked |
322 |
* resources, and marking any tracked undoable records as stale and any redoable operations |
|
323 |
* as active. |
|
320 |
* resources, and marking any tracked undoable records as stale. |
|
324 | 321 |
* |
325 | 322 |
* @param transaction |
326 | 323 |
* {@code true} if the current block is a full transaction; {@code false} if it is |
... | ... | |
469 | 466 |
} |
470 | 467 |
|
471 | 468 |
/** |
472 |
* Create a redoable SQL operation for the insertion of a NO-UNDO record into the database. If |
|
473 |
* the original operation is rolled back at the database, this operation must be re-applied |
|
474 |
* after the full or sub-transaction which rolled it back completes. |
|
475 |
* |
|
476 |
* @param dmo |
|
477 |
* DMO which was updated. |
|
478 |
*/ |
|
479 |
void noUndoInsert(BaseRecord dmo) |
|
480 |
{ |
|
481 |
if (session != null && activeBlock != null) |
|
482 |
{ |
|
483 |
SQLRedo.Insert redo = new SQLRedo.Insert(session.getPersister(), dmo.deepCopy()); |
|
484 |
redoable.add(redo); |
|
485 |
} |
|
486 |
} |
|
487 |
|
|
488 |
/** |
|
489 |
* Create a redoable SQL operation for the update of a NO-UNDO record in the database. If |
|
490 |
* the original operation is rolled back at the database, this operation must be re-applied |
|
491 |
* after the full or sub-transaction which rolled it back completes. |
|
492 |
* |
|
493 |
* @param dmo |
|
494 |
* DMO which was updated. |
|
495 |
*/ |
|
496 |
void noUndoUpdate(BaseRecord dmo) |
|
497 |
{ |
|
498 |
if (session != null && activeBlock != null && dmo.checkState(CHANGED)) |
|
499 |
{ |
|
500 |
SQLRedo.Update redo = new SQLRedo.Update(session.getPersister(), dmo.deepCopy()); |
|
501 |
redoable.add(redo); |
|
502 |
} |
|
503 |
} |
|
504 |
|
|
505 |
/** |
|
506 |
* Create a redoable SQL operation for the deletion of a NO-UNDO record from the database. If |
|
507 |
* the original operation is rolled back at the database, this operation must be re-applied |
|
508 |
* after the full or sub-transaction which rolled it back completes. |
|
509 |
* |
|
510 |
* @param dmoClass |
|
511 |
* Implementation class of the DMO which was deleted. |
|
512 |
* @param id |
|
513 |
* Primary key of the record which was deleted. |
|
514 |
*/ |
|
515 |
void noUndoDelete(Class<? extends BaseRecord> dmoClass, Long id) |
|
516 |
{ |
|
517 |
if (session != null && activeBlock != null) |
|
518 |
{ |
|
519 |
SQLRedo.Delete redo = new SQLRedo.Delete(session.getPersister(), dmoClass, id); |
|
520 |
redoable.add(redo); |
|
521 |
} |
|
522 |
} |
|
523 |
|
|
524 |
/** |
|
525 |
* Create a redoable SQL operation for the bulk update of zero or more NO-UNDO records in |
|
526 |
* the database. The operation may be an update or a delete. If the original operation is |
|
527 |
* rolled back at the database, this operation must be re-applied after the full or |
|
528 |
* sub-transaction which rolled it back completes. |
|
529 |
* |
|
530 |
* @param query |
|
531 |
* SQL query which performed the original bulk operation. |
|
532 |
*/ |
|
533 |
void noUndoBulkUpdate(SQLQuery query) |
|
534 |
{ |
|
535 |
if (session != null && activeBlock != null) |
|
536 |
{ |
|
537 |
SQLRedo.BulkUpdate redo = new SQLRedo.BulkUpdate(session, query); |
|
538 |
redoable.add(redo); |
|
539 |
} |
|
540 |
} |
|
541 |
|
|
542 |
/** |
|
543 | 469 |
* Set a savepoint in the active block and in every previous block which has not yet had one set, |
544 | 470 |
* except for the outermost (which represents the full transaction block). |
545 | 471 |
* <p> |
... | ... | |
622 | 548 |
private void prepareBlock() |
623 | 549 |
{ |
624 | 550 |
parentBlock = blocks.peek(); |
625 |
activeBlock = new Block(blocks.size(), redoable);
|
|
551 |
activeBlock = new Block(blocks.size()); |
|
626 | 552 |
blocks.push(activeBlock); |
627 | 553 |
|
628 | 554 |
if (debug) |
... | ... | |
643 | 569 |
Block lastActiveBlock = activeBlock; |
644 | 570 |
Block popped = blocks.pop(); |
645 | 571 |
|
646 |
// reapply undone changes for any NO-UNDO temporary tables |
|
647 |
if (session != null && lastActiveBlock != null) |
|
648 |
{ |
|
649 |
lastActiveBlock.maybeReapplyNoUndo(session); |
|
650 |
} |
|
651 |
|
|
652 | 572 |
// reactivate the next block in the stack (if any) |
653 | 573 |
activeBlock = blocks.isEmpty() ? null : blocks.pop(); |
654 | 574 |
parentBlock = blocks.isEmpty() ? null : blocks.peek(); |
... | ... | |
666 | 586 |
{ |
667 | 587 |
// full transaction is finished, deactivate savepoint manager (i.e., remove session) |
668 | 588 |
this.session = null; |
669 |
if (redoable != null) |
|
670 |
{ |
|
671 |
redoable.clear(); |
|
672 |
} |
|
673 | 589 |
} |
674 | 590 |
} |
675 | 591 |
|
... | ... | |
739 | 655 |
/** The current element being processed or the last one which was processed. */ |
740 | 656 |
private BaseRecord changedLastIteration = null; |
741 | 657 |
|
742 |
/** List of SQL redo helpers for NO-UNDO records, shared among all blocks */ |
|
743 |
private final List<SQLRedo> redoable; |
|
744 |
|
|
745 |
/** Starting index for this block in full transaction redoable list */ |
|
746 |
private final int redoHead; |
|
747 |
|
|
748 | 658 |
/** Database savepoint for a sub-transaction block ({@code null} for full transaction */ |
749 | 659 |
private Savepoint savepoint = null; |
750 | 660 |
|
751 |
/** Have we rolled back NO-UNDO changes in this block which will need to be re-applied? */ |
|
752 |
private boolean noUndoRolledBack = false; |
|
753 |
|
|
754 | 661 |
/** |
755 | 662 |
* Constructor. |
756 | 663 |
*/ |
757 |
Block(int txLevel, List<SQLRedo> redoable)
|
|
664 |
Block(int txLevel) |
|
758 | 665 |
{ |
759 | 666 |
this.txLevel = txLevel; |
760 |
this.redoable = redoable; |
|
761 |
this.redoHead = redoable.size(); |
|
762 | 667 |
} |
763 | 668 |
|
764 | 669 |
/** |
... | ... | |
832 | 737 |
} |
833 | 738 |
|
834 | 739 |
/** |
835 |
* Roll back changes to undoable records and activate redoable actions for NO-UNDO records.
|
|
740 |
* Roll back changes to undoable records. |
|
836 | 741 |
*/ |
837 | 742 |
void rollback() |
838 | 743 |
throws PersistenceException |
839 | 744 |
{ |
840 | 745 |
if (txLevel > 0 && savepoint == null) |
841 | 746 |
{ |
842 |
// no DMOs were updated within this block, so nothing to undo nor mark for deferred redo
|
|
747 |
// no DMOs were updated within this block, so nothing to undo |
|
843 | 748 |
return; |
844 | 749 |
} |
845 | 750 |
|
... | ... | |
860 | 765 |
changedIsIterated = false; |
861 | 766 |
} |
862 | 767 |
} |
863 |
|
|
864 |
int redoSize = redoable.size(); |
|
865 |
if (redoSize > redoHead) |
|
866 |
{ |
|
867 |
noUndoRolledBack = true; |
|
868 |
|
|
869 |
for (int i = redoHead; i < redoSize; i++) |
|
870 |
{ |
|
871 |
redoable.get(i).setActive(); |
|
872 |
} |
|
873 |
} |
|
874 | 768 |
} |
875 | 769 |
|
876 | 770 |
/** Notify the FastFind cache that the changed tables need to be invalidated. */ |
... | ... | |
912 | 806 |
} |
913 | 807 |
|
914 | 808 |
/** |
915 |
* Indicate whether this block is tracking any NO-UNDO records. |
|
916 |
* |
|
917 |
* @return {@code true} if there are any NO-UNDO records associated with this block, else |
|
918 |
* {@code false}. |
|
919 |
*/ |
|
920 |
boolean isTrackingNoUndo() |
|
921 |
{ |
|
922 |
return redoable.size() > redoHead; |
|
923 |
} |
|
924 |
|
|
925 |
/** |
|
926 |
* Re-apply any changes to no-undo records which were rolled back in the most recent |
|
927 |
* savepoint or full transaction. |
|
928 |
* |
|
929 |
* @param session |
|
930 |
* Database session helper object. |
|
931 |
*/ |
|
932 |
void maybeReapplyNoUndo(Session session) |
|
933 |
{ |
|
934 |
if (!noUndoRolledBack) |
|
935 |
{ |
|
936 |
// nothing to do |
|
937 |
return; |
|
938 |
} |
|
939 |
|
|
940 |
boolean fullTx = false; |
|
941 |
|
|
942 |
try |
|
943 |
{ |
|
944 |
// if the active block was a full transaction block, we need to start a separate, |
|
945 |
// full, transaction to re-roll forward any NO-UNDO changes that were rolled back |
|
946 |
// at the database; for sub-transactions, we will still be in the context of the |
|
947 |
// existing transaction |
|
948 |
if (txLevel == 0) |
|
949 |
{ |
|
950 |
fullTx = session.beginTransaction(null); |
|
951 |
} |
|
952 |
|
|
953 |
int redoSize = redoable.size(); |
|
954 |
for (int i = redoHead; i < redoSize; i++) |
|
955 |
{ |
|
956 |
SQLRedo redo = redoable.get(i); |
|
957 |
redo.perform(); |
|
958 |
} |
|
959 |
|
|
960 |
if (fullTx) |
|
961 |
{ |
|
962 |
session.commit(); |
|
963 |
} |
|
964 |
} |
|
965 |
catch (PersistenceException exc) |
|
966 |
{ |
|
967 |
if (fullTx) |
|
968 |
{ |
|
969 |
if (log.isLoggable(Level.SEVERE)) |
|
970 |
{ |
|
971 |
log.log(Level.SEVERE, "Error reapplying rolled back NO-UNDO changes", exc); |
|
972 |
} |
|
973 |
|
|
974 |
try |
|
975 |
{ |
|
976 |
session.rollback(); |
|
977 |
} |
|
978 |
catch (PersistenceException exc1) |
|
979 |
{ |
|
980 |
if (log.isLoggable(Level.SEVERE)) |
|
981 |
{ |
|
982 |
log.log(Level.SEVERE, "Error rolling back NO-UNDO reapply transaction", exc1); |
|
983 |
} |
|
984 |
} |
|
985 |
} |
|
986 |
|
|
987 |
// TODO: proper error handling |
|
988 |
throw new StopConditionException(exc); |
|
989 |
} |
|
990 |
} |
|
991 |
|
|
992 |
/** |
|
993 | 809 |
* Get a debug text representation of this object. |
994 | 810 |
* |
995 | 811 |
* @return Text representation of state. |
new/src/com/goldencode/p2j/persist/orm/Session.java 2023-01-26 12:04:15 +0000 | ||
---|---|---|
32 | 32 |
** the database, and not just returned. |
33 | 33 |
** CA 20230104 If a cached record is incomplete, preserve the dirty properties when loading the full |
34 | 34 |
** record. |
35 |
** RAA 20230126 Removed everything that had to do with redo operations as it is no longer needed. |
|
35 | 36 |
*/ |
36 | 37 | |
37 | 38 |
/* |
... | ... | |
737 | 738 |
boolean wasNew = dmo.checkState(NEW); |
738 | 739 |
boolean wasDirty = wasNew || dmo.isDirty(); |
739 | 740 |
|
740 |
if (wasDirty && savepointManager != null) |
|
741 |
{ |
|
742 |
// undoable events must be logged with the DMO before the insert/update takes place, because |
|
743 |
// the logging might trigger a database savepoint to be lazily set, and this savepoint must |
|
744 |
// include the insert/update |
|
745 |
|
|
746 |
if (dmo.checkState(NOUNDO)) |
|
747 |
{ |
|
748 |
if (wasNew) |
|
749 |
{ |
|
750 |
savepointManager.noUndoInsert(dmo); |
|
751 |
} |
|
752 |
else |
|
753 |
{ |
|
754 |
savepointManager.noUndoUpdate(dmo); |
|
755 |
} |
|
756 |
} |
|
757 |
} |
|
758 |
|
|
759 | 741 |
// decide what to do with the record |
760 | 742 |
if (wasNew) |
761 | 743 |
{ |
... | ... | |
867 | 849 |
|
868 | 850 |
// attempt to delete the record if it is not newly created (i.e., as of yet unflushed) |
869 | 851 |
if (!dmo.checkState(NEW)) |
870 |
{ |
|
871 |
if (savepointManager != null && dmo.checkState(NOUNDO)) |
|
872 |
{ |
|
873 |
savepointManager.noUndoDelete(dmo.getClass(), dmo.primaryKey()); |
|
874 |
} |
|
875 |
|
|
852 |
{ |
|
876 | 853 |
success = persister.delete(dmo); |
877 | 854 |
} |
878 | 855 |
|
... | ... | |
951 | 928 |
@SuppressWarnings("unchecked") |
952 | 929 |
Class<? extends Record> recordClass = (Class<? extends Record>) dmoClass; |
953 | 930 |
|
954 |
if (savepointManager != null && cached != null && cached.checkState(NOUNDO)) |
|
955 |
{ |
|
956 |
savepointManager.noUndoDelete(recordClass, id); |
|
957 |
} |
|
958 |
|
|
959 | 931 |
success = persister.delete(recordClass, id); |
960 | 932 |
} |
961 | 933 |
|
... | ... | |
1512 | 1484 |
} |
1513 | 1485 |
|
1514 | 1486 |
/** |
1515 |
* Create a redoable SQL operation for the bulk update of zero or more NO-UNDO records in |
|
1516 |
* the database. The operation may be an update or a delete. If the original operation is |
|
1517 |
* rolled back at the database, this operation must be re-applied after the full or |
|
1518 |
* sub-transaction which rolled it back completes. |
|
1519 |
* <p> |
|
1520 |
* This method delegates to the session's savepoint manager, if any, whose responsibility it |
|
1521 |
* is to track and apply the corresponding redoable SQL operation at the appropriate moment. |
|
1522 |
* |
|
1523 |
* @param query |
|
1524 |
* FQL query which performed the original bulk operation. |
|
1525 |
*/ |
|
1526 |
public void noUndoBulkUpdate(Query query) |
|
1527 |
{ |
|
1528 |
noUndoBulkUpdate(query.getSqlQuery()); |
|
1529 |
} |
|
1530 |
|
|
1531 |
/** |
|
1532 |
* Create a redoable SQL operation for the bulk update of zero or more NO-UNDO records in |
|
1533 |
* the database. The operation may be an update or a delete. If the original operation is |
|
1534 |
* rolled back at the database, this operation must be re-applied after the full or |
|
1535 |
* sub-transaction which rolled it back completes. |
|
1536 |
* <p> |
|
1537 |
* This method delegates to the session's savepoint manager, if any, whose responsibility it |
|
1538 |
* is to track and apply the corresponding redoable SQL operation at the appropriate moment. |
|
1539 |
* |
|
1540 |
* @param query |
|
1541 |
* SQL query which performed the original bulk operation. |
|
1542 |
*/ |
|
1543 |
public void noUndoBulkUpdate(SQLQuery query) |
|
1544 |
{ |
|
1545 |
if (savepointManager != null) |
|
1546 |
{ |
|
1547 |
savepointManager.noUndoBulkUpdate(query); |
|
1548 |
} |
|
1549 |
} |
|
1550 |
|
|
1551 |
/** |
|
1552 | 1487 |
* Get the zero-based transaction block nesting level, where 0 indicates the current block is a full |
1553 | 1488 |
* transaction block, 1 indicates the current block is the first level of nested subtransaction, and so |
1554 | 1489 |
* on. Note that this includes only blocks with transaction properties; no-transaction blocks which may |