6709-20230106.patch
new/rules/annotations/index_selection.rules 2023-01-05 08:39:54 +0000 | ||
---|---|---|
114 | 114 |
** Fixed conversion of sorting by extent fields with non-constant index. |
115 | 115 |
** 042 ECF 20200906 New ORM implementation. |
116 | 116 |
** 043 IAS 20210209 Do not use word index field for sorting |
117 |
** 044 DDF 20230105 Use hint to set related_buffer annotation to true if |
|
118 |
** in a FIND. |
|
117 | 119 |
*/ |
118 | 120 |
--> |
119 | 121 | |
... | ... | |
187 | 189 |
<worker class="com.goldencode.p2j.schema.SchemaWorker" namespace="schema" /> |
188 | 190 |
<worker class="com.goldencode.p2j.uast.ProgressPatternWorker" namespace="prog" /> |
189 | 191 |
<worker class="com.goldencode.p2j.convert.IndexSelectionWorker" namespace="isw" /> |
192 |
<worker class="com.goldencode.p2j.uast.UastHintsWorker" namespace="uhw" /> |
|
190 | 193 |
|
191 | 194 |
<!-- variables --> |
192 | 195 |
<variable name="record" type="com.goldencode.ast.Aast" /> |
... | ... | |
225 | 228 |
<variable name="tableCount" type="java.lang.Integer" /> |
226 | 229 |
<variable name="countingTables" type="java.lang.Boolean" /> |
227 | 230 |
<variable name="functypes" type="java.util.ArrayList" /> |
231 |
<variable name="inFind" type="java.lang.Boolean" /> |
|
232 |
<variable name="enableFindFieldRef" type="java.lang.Boolean" /> |
|
228 | 233 |
|
229 | 234 |
<!-- function libraries --> |
230 | 235 |
<include name="common-progress" /> |
... | ... | |
350 | 355 |
<rule>functypes.add(prog.func_raw)</rule> |
351 | 356 |
<rule>functypes.add(prog.func_memptr)</rule> |
352 | 357 |
<rule>functypes.add(prog.func_poly)</rule> |
358 |
|
|
359 |
<rule>inFind = false</rule> |
|
353 | 360 |
</init-rules> |
354 | 361 |
|
355 | 362 |
<walk-rules> |
356 | 363 |
|
364 |
<!-- if the type is Find and hint is provided --> |
|
365 |
<rule>type == prog.KW_FIND |
|
366 |
<action>enableFindFieldRef = uhw.getUastBoolean("enable_find_field_reference")</action> |
|
367 |
<rule>enableFindFieldRef != null |
|
368 |
<action>inFind = enableFindFieldRef</action> |
|
369 |
</rule> |
|
370 |
</rule> |
|
371 |
|
|
357 | 372 |
<!-- query-level initialization --> |
358 | 373 |
<rule> |
359 | 374 |
(type == prog.open_query or |
... | ... | |
549 | 564 |
<!-- in a multi-table query, remember that this field |
550 | 565 |
is a reference back to a different but previous |
551 | 566 |
buffer in the same query --> |
552 |
<rule on="false">queryBufferOrder.contains(getNoteLong("refid")) |
|
567 |
<rule on="false">queryBufferOrder.contains(getNoteLong("refid")) or inFind
|
|
553 | 568 |
<action>putNote("related_buffer", true)</action> |
554 | 569 |
<action on="false">putNote("related_buffer", false)</action> |
555 | 570 |
</rule> |
... | ... | |
611 | 626 |
<!-- in a multi-table query, remember that this field |
612 | 627 |
is a reference back to a different but previous |
613 | 628 |
buffer in the same query --> |
614 |
<rule>queryBufferOrder.contains(getNoteLong("refid")) |
|
629 |
<rule>queryBufferOrder.contains(getNoteLong("refid")) or inFind
|
|
615 | 630 |
<action>putNote("related_buffer", true)</action> |
616 | 631 |
<action on="false">putNote("related_buffer", false)</action> |
617 | 632 |
</rule> |
... | ... | |
1015 | 1030 |
<action>extentSortFields.clear()</action> |
1016 | 1031 |
</rule> |
1017 | 1032 |
|
1033 |
<!-- reset flag --> |
|
1034 |
<rule>inFind and type == prog.KW_FIND |
|
1035 |
<action>inFind = false</action> |
|
1036 |
</rule> |
|
1037 |
|
|
1018 | 1038 |
</ascent-rules> |
1019 | 1039 |
|
1020 | 1040 |
<post-rules> |
new/rules/annotations/nested_find.rules 2023-01-05 08:40:17 +0000 | ||
---|---|---|
13 | 13 |
** that reference the same buffer. The purpose is to |
14 | 14 |
** create a report where nested finds are classified |
15 | 15 |
** using the NEXT/PREV/LAST/FIRST/WHERE keywords. |
16 |
** 002 DDF 20230105 Changed the annotation value stored to the tree id. |
|
16 | 17 |
*/ |
17 | 18 |
--> |
18 | 19 | |
... | ... | |
78 | 79 |
<variable name="inWhere" type="java.lang.Boolean" /> |
79 | 80 |
<variable name="bufferName" type="java.lang.String" /> |
80 | 81 |
<variable name="annotationValue" type="java.lang.String" /> |
81 |
<variable name="annotationObject" type="java.lang.Object" />
|
|
82 |
<variable name="annotationObject" type="com.goldencode.ast.Aast" />
|
|
82 | 83 | |
83 | 84 |
<init-rules> |
84 | 85 |
<rule>scopedDict = create("com.goldencode.p2j.util.ScopedSymbolDictionary")</rule> |
... | ... | |
97 | 98 |
<action>recordAst = this.getChildAt(0)</action> |
98 | 99 |
<rule>recordAst != null |
99 | 100 |
<action>annotationValue = #(java.lang.String) recordAst.getAnnotation("bufname")</action> |
100 |
<action>annotationObject = recordAst.getAnnotation("bufname")</action> |
|
101 |
<action>scopedDict.addSymbol(false, annotationValue, annotationObject)</action> |
|
101 |
<action>scopedDict.addSymbol(false, annotationValue, this.parent)</action> |
|
102 | 102 |
</rule> |
103 | 103 |
</rule> |
104 | 104 |
|
... | ... | |
117 | 117 |
previously --> |
118 | 118 |
<rule>inWhere and scopedDict.size() > 0 and evalLib("fields") |
119 | 119 |
<action>bufferName = #(java.lang.String) this.getAnnotation("bufname")</action> |
120 |
<rule>scopedDict.lookupSymbol(bufferName) != null |
|
121 |
<action>putReferenceNote(currentFindAst.getId(), "nested_find", true)</action> |
|
120 |
<action>annotationObject = #(com.goldencode.ast.Aast) scopedDict.lookupSymbol(bufferName)</action> |
|
121 |
<rule>annotationObject != null |
|
122 |
<action>putReferenceNote(currentFindAst.getId(), "nested_find", annotationObject.getId())</action> |
|
122 | 123 |
</rule> |
123 | 124 |
</rule> |
124 | 125 |
</walk-rules> |
new/rules/convert/expressions.rules 2023-01-05 08:40:40 +0000 | ||
---|---|---|
232 | 232 |
** initialized at the method's execution, and not at the caller's arguments. |
233 | 233 |
** (backed out CA/20210428). |
234 | 234 |
** GES 20210722 Exclude Java method calls from built-in OO 4GL processing. |
235 |
** DDF 20230105 Include hint value if exists when the casting to P2JQuery.Parameter is inserted. |
|
235 | 236 |
*/ |
236 | 237 |
--> |
237 | 238 | |
... | ... | |
1306 | 1307 |
<rule> |
1307 | 1308 |
getNoteBoolean("deferred") and |
1308 | 1309 |
!(isNote("delegated_eval") and getNoteBoolean("delegated_eval")) |
1309 |
<action>lastid = createJavaAst(java.cast, "P2JQuery.Parameter", lastid)</action> |
|
1310 |
<action>lastid = createJavaAst(java.lambda, "", lastid)</action> |
|
1311 |
<action>createJavaAst(java.lparens, "", lastid)</action> |
|
1310 |
<!-- use hint if provided --> |
|
1311 |
<rule>(uhw.getUastBoolean("enable_find_field_reference") != null) and |
|
1312 |
uhw.getUastBoolean("enable_find_field_reference") |
|
1313 |
<action on="false">lastid = createJavaAst(java.cast, "P2JQuery.Parameter", lastid)</action> |
|
1314 |
<action on="false">lastid = createJavaAst(java.lambda, "", lastid)</action> |
|
1315 |
<action on="false">createJavaAst(java.lparens, "", lastid)</action> |
|
1316 |
</rule> |
|
1312 | 1317 |
</rule> |
1313 | 1318 |
|
1314 | 1319 |
<!-- dynamic where subscripts in query substitutions need to |
new/src/com/goldencode/p2j/jmx/FwdJMX.java 2023-01-05 08:41:30 +0000 | ||
---|---|---|
22 | 22 |
** OrmDataSetParam, OrmDynamicDataSetParam). |
23 | 23 |
** - OpenClient parameter processing (AppserverAddTableMetaData, ApperverGetJavaParameter, |
24 | 24 |
** AppserverGetOutputParameter). |
25 |
** DDF 20230105 Added a counter for nested find queries (refs: #6709). |
|
25 | 26 |
*/ |
26 | 27 | |
27 | 28 |
/* |
... | ... | |
524 | 525 |
/** Outgoing network traffic */ |
525 | 526 |
NetworkWrites, |
526 | 527 |
/** Widget attributes flush count */ |
527 |
WidgetAttrFlushes; |
|
528 |
WidgetAttrFlushes, |
|
529 |
/** Counter for nested find queries */ |
|
530 |
NestedFindQueries; |
|
528 | 531 |
|
529 | 532 |
/** Counter instance */ |
530 | 533 |
private final SimpleLongCounter counter = new SimpleLongCounter(); |
new/src/com/goldencode/p2j/persist/BufferManager.java 2023-01-05 08:41:51 +0000 | ||
---|---|---|
466 | 466 |
** block scope. |
467 | 467 |
** CA 20221010 Performance improvements - avoid the ProcedureData lookup, by keeping a parallel |
468 | 468 |
** stack of this data for THIS-PROCEDURE. Refs #6826 |
469 |
** DDF 20230105 Added functionality for tracking nested find at runtime. A flag from directory.xml |
|
470 |
** is stored and used to enable runtime tracking. (refs: #6709) |
|
469 | 471 |
*/ |
470 | 472 | |
471 | 473 |
/* |
... | ... | |
530 | 532 |
import java.util.logging.*; |
531 | 533 | |
532 | 534 |
import com.goldencode.cache.*; |
535 |
import com.goldencode.p2j.cfg.Configuration; |
|
533 | 536 |
import com.goldencode.p2j.convert.*; |
537 |
import com.goldencode.p2j.directory.DirectoryService; |
|
534 | 538 |
import com.goldencode.p2j.oo.lang.*; |
535 | 539 |
import com.goldencode.p2j.persist.dirty.*; |
536 | 540 |
import com.goldencode.p2j.persist.id.*; |
... | ... | |
698 | 702 | |
699 | 703 |
/** Track the external scopes pushed on {@link BufferManager}. */ |
700 | 704 |
private final Stack<Boolean> externalScope = new Stack<>(); |
705 |
|
|
706 |
/** Maps a RecordBuffer and the related P2JQuery from a forEach block */ |
|
707 |
private Map<RecordBuffer, P2JQuery> forEachMap = new ConcurrentHashMap<>(); |
|
708 |
|
|
709 |
/** Configuration value from {@code directory.xml} that enables nested find tracking */ |
|
710 |
public static final boolean ENABLE_NESTED_FIND_TRACKING; |
|
711 |
|
|
712 |
static |
|
713 |
{ |
|
714 |
boolean enableNestedFindTracking = false; |
|
715 |
|
|
716 |
if (Configuration.isRuntimeConfig()) |
|
717 |
{ |
|
718 |
DirectoryService ds = DirectoryService.getInstance(); |
|
719 |
if (!ds.bind()) |
|
720 |
{ |
|
721 |
throw new RuntimeException("Directory bind failed"); |
|
722 |
} |
|
723 |
|
|
724 |
try |
|
725 |
{ |
|
726 |
String path = "persistence/enable-nested-find-tracking"; |
|
727 |
enableNestedFindTracking = Utils.getDirectoryNodeBoolean(ds, path, false, false); |
|
728 |
} |
|
729 |
finally |
|
730 |
{ |
|
731 |
ds.unbind(); |
|
732 |
} |
|
733 |
} |
|
734 |
|
|
735 |
ENABLE_NESTED_FIND_TRACKING = enableNestedFindTracking; |
|
736 |
} |
|
701 | 737 | |
702 | 738 |
/** |
703 | 739 |
* Constructor; instances of this class are context-local and must be accessed using the static |
... | ... | |
2728 | 2764 |
} |
2729 | 2765 |
|
2730 | 2766 |
/** |
2767 |
* Add an element to the forEachMap. |
|
2768 |
* If the key already exists, the value is overridden. |
|
2769 |
* |
|
2770 |
* @param rb |
|
2771 |
* RecordBuffer of a P2JQuery from a forEach block |
|
2772 |
* @param q |
|
2773 |
* P2JQuery that is component of a forEach block |
|
2774 |
*/ |
|
2775 |
public static void addForEachMap(RecordBuffer rb, P2JQuery q) |
|
2776 |
{ |
|
2777 |
BufferManager bm = context.get(); |
|
2778 |
bm.forEachMap.put(rb, q); |
|
2779 |
} |
|
2780 |
|
|
2781 |
/** |
|
2782 |
* Remove an element from the forEachMap. |
|
2783 |
* |
|
2784 |
* @param rb |
|
2785 |
* RecordBuffer of a P2JQuery from a forEach block. |
|
2786 |
*/ |
|
2787 |
public static void removeForEachMap(RecordBuffer rb) |
|
2788 |
{ |
|
2789 |
BufferManager bm = context.get(); |
|
2790 |
bm.forEachMap.remove(rb); |
|
2791 |
} |
|
2792 |
|
|
2793 |
/** |
|
2794 |
* Lookup the given key in the forEachMap. |
|
2795 |
* |
|
2796 |
* @param rb |
|
2797 |
* RecordBuffer that is looked up. |
|
2798 |
* |
|
2799 |
* @return true/false |
|
2800 |
*/ |
|
2801 |
public static boolean lookupForEachValue(RecordBuffer rb) |
|
2802 |
{ |
|
2803 |
BufferManager bm = context.get(); |
|
2804 |
return bm.forEachMap.containsKey(rb); |
|
2805 |
} |
|
2806 |
|
|
2807 |
/** |
|
2731 | 2808 |
* Container for batch assign mode information. |
2732 | 2809 |
*/ |
2733 | 2810 |
private static class BatchModeData |
new/src/com/goldencode/p2j/persist/FindQuery.java 2023-01-05 08:41:59 +0000 | ||
---|---|---|
63 | 63 |
** 024 ECF 20210806 Corrected CAN-FIND return value in event of fatal error. Fixed nested query |
64 | 64 |
** error detection/reporting. |
65 | 65 |
** ECF 20210911 Javadoc fix. |
66 |
** DDF 20230105 Added method for checking if FindQuery is nested in a FOR EACH. Tracking is |
|
67 |
** done at runtime only if it's enabled through BufferManager.ENABLE_NESTED_FIND_TRACKING |
|
68 |
** value. |
|
66 | 69 |
*/ |
67 | 70 | |
68 | 71 |
/* |
... | ... | |
121 | 124 |
package com.goldencode.p2j.persist; |
122 | 125 | |
123 | 126 |
import java.util.function.*; |
127 | ||
128 |
import com.goldencode.p2j.jmx.*; |
|
124 | 129 |
import com.goldencode.p2j.persist.lock.*; |
125 | 130 |
import com.goldencode.p2j.util.*; |
126 | 131 | |
... | ... | |
161 | 166 |
/** Flag indicating whether buffer is updated by query */ |
162 | 167 |
private boolean readOnly = false; |
163 | 168 |
|
169 |
/** Counter for measuring nested find initializations */ |
|
170 |
private static final SimpleCounter NestedFindCounter = SimpleCounter.getInstance( |
|
171 |
FwdJMX.Counter.NestedFindQueries |
|
172 |
); |
|
173 |
|
|
164 | 174 |
/** |
165 | 175 |
* Basic constructor which defaults record lock type to |
166 | 176 |
* <code>LockType.SHARE</code>. |
... | ... | |
415 | 425 |
super(); |
416 | 426 |
super.initialize(dmo, where, whereExpr, sort, null, inverse, args, lockType); |
417 | 427 |
|
428 |
if (BufferManager.ENABLE_NESTED_FIND_TRACKING) |
|
429 |
{ |
|
430 |
System.out.println("Current FINDQuery nested status: " + Boolean.toString(isNested())); |
|
431 |
} |
|
432 |
|
|
418 | 433 |
// if the NO-ERROR clause is specified, then a QOEE must not be thrown |
419 | 434 |
setLenientOffEnd(getBuffer().txHelper.errHlp.isSilent()); |
420 | 435 |
setErrorIfNull(true); |
... | ... | |
888 | 903 |
|
889 | 904 |
return true; |
890 | 905 |
} |
906 |
|
|
907 |
/** |
|
908 |
* Check if query is nested in a FOR EACH. |
|
909 |
* |
|
910 |
* @return true if it's nested, false if not |
|
911 |
*/ |
|
912 |
private boolean isNested() |
|
913 |
{ |
|
914 |
if (hasWhereExpression()) |
|
915 |
{ |
|
916 |
return false; |
|
917 |
} |
|
918 |
|
|
919 |
Object[] values = getArgs(); |
|
920 |
|
|
921 |
if (values == null) |
|
922 |
{ |
|
923 |
return false; |
|
924 |
} |
|
925 |
|
|
926 |
for (Object val : values) |
|
927 |
{ |
|
928 |
if (!(val instanceof FieldReference)) |
|
929 |
{ |
|
930 |
continue; |
|
931 |
} |
|
932 |
|
|
933 |
final FieldReference ref = (FieldReference) val; |
|
934 |
RecordBuffer valueRecord = ref.getParentBuffer(); |
|
935 |
if (valueRecord == null) |
|
936 |
{ |
|
937 |
continue; |
|
938 |
} |
|
939 |
|
|
940 |
if (BufferManager.lookupForEachValue(valueRecord)) |
|
941 |
{ |
|
942 |
NestedFindCounter.update(1L); |
|
943 |
return true; |
|
944 |
} |
|
945 |
} |
|
946 |
return false; |
|
947 |
} |
|
891 | 948 |
} |
new/src/com/goldencode/p2j/util/BlockManager.java 2023-01-05 08:42:11 +0000 | ||
---|---|---|
227 | 227 |
** TJD 20220504 Java 11 compatibility minor changes |
228 | 228 |
** CA 20221123 If an 'object' instance is assigned in the FINALLY block and also referenced by |
229 | 229 |
** the RETURN statement, then do not remove it from 'pendingAssign'. |
230 |
** DDF 20230105 Saved the offEndQueries for nested find tracking. offEndQueries are cleared after the |
|
231 |
** forEach block is finished, while tracking requires the components to be available |
|
232 |
** in the body block. |
|
230 | 233 |
*/ |
231 | 234 | |
232 | 235 |
/* |
... | ... | |
293 | 296 |
import com.goldencode.p2j.directory.*; |
294 | 297 |
import com.goldencode.p2j.main.*; |
295 | 298 |
import com.goldencode.p2j.oo.lang.*; |
299 |
import com.goldencode.p2j.persist.*; |
|
296 | 300 |
import com.goldencode.p2j.security.ContextLocal; |
297 |
import com.goldencode.p2j.persist.QueryOffEndException; |
|
298 |
import com.goldencode.p2j.persist.QueryOffEndListener; |
|
299 | 301 | |
300 | 302 |
// the following are dependencies on the UI package which we would prefer to |
301 | 303 |
// eliminate if the services can be cleanly abstracted without making the |
... | ... | |
10500 | 10502 |
|
10501 | 10503 |
wa.tm.pushScope(label, ttype, props, false, false, true, true, btype, block); |
10502 | 10504 |
|
10505 |
Set<P2JQuery> forEachQueries = null; |
|
10503 | 10506 |
try |
10504 | 10507 |
{ |
10505 | 10508 |
try |
... | ... | |
10514 | 10517 |
} |
10515 | 10518 |
finally |
10516 | 10519 |
{ |
10520 |
if (BufferManager.ENABLE_NESTED_FIND_TRACKING) |
|
10521 |
{ |
|
10522 |
forEachQueries = wa.tm.getOffEndQueries(); |
|
10523 |
for (P2JQuery query : forEachQueries) |
|
10524 |
{ |
|
10525 |
if (query.getRecordBuffers() == null) |
|
10526 |
{ |
|
10527 |
continue; |
|
10528 |
} |
|
10529 |
|
|
10530 |
for (RecordBuffer rb : query.getRecordBuffers()) |
|
10531 |
{ |
|
10532 |
BufferManager.addForEachMap(rb, query); |
|
10533 |
} |
|
10534 |
} |
|
10535 |
} |
|
10517 | 10536 |
// after block initialization is finished, the off end listeners |
10518 | 10537 |
// for all the buffers in the collected queries are saved |
10519 | 10538 |
wa.tm.stopOffEndRegistration(); |
... | ... | |
10661 | 10680 |
|
10662 | 10681 |
finally |
10663 | 10682 |
{ |
10683 |
if (forEachQueries != null) |
|
10684 |
{ |
|
10685 |
for (P2JQuery query : forEachQueries) |
|
10686 |
{ |
|
10687 |
if (query.getRecordBuffers() == null) |
|
10688 |
{ |
|
10689 |
continue; |
|
10690 |
} |
|
10691 |
|
|
10692 |
for (RecordBuffer rb : query.getRecordBuffers()) |
|
10693 |
{ |
|
10694 |
BufferManager.removeForEachMap(rb); |
|
10695 |
} |
|
10696 |
} |
|
10697 |
} |
|
10664 | 10698 |
wa.tm.popScope(); |
10665 | 10699 |
} |
10666 | 10700 |
} |
new/src/com/goldencode/p2j/util/TransactionManager.java 2023-01-05 08:42:30 +0000 | ||
---|---|---|
511 | 511 |
** a set instead of a list, as their order is not important. Refs #6824 |
512 | 512 |
** CA 20221010 Performance improvements - avoid the ProcedureData lookup, by keeping a parallel |
513 | 513 |
** stack of this data for THIS-PROCEDURE. Refs #6826 |
514 |
** DDF 20230105 Added functionality to retrieve offEndQuery value. |
|
514 | 515 |
*/ |
515 | 516 | |
516 | 517 |
/* |
... | ... | |
7712 | 7713 |
} |
7713 | 7714 |
|
7714 | 7715 |
/** |
7716 |
* Get the offEndQueries using the context local work area. |
|
7717 |
* |
|
7718 |
* @param wa |
|
7719 |
* Context local work area. |
|
7720 |
* |
|
7721 |
* @return offEndQueries of the context local work area. |
|
7722 |
*/ |
|
7723 |
public static Set<P2JQuery> getOffEndQueries(WorkArea wa) |
|
7724 |
{ |
|
7725 |
return wa.offEndQueries; |
|
7726 |
} |
|
7727 |
|
|
7728 |
/** |
|
7715 | 7729 |
* Helper to expose transaction state in a way that avoids context local lookups. |
7716 | 7730 |
*/ |
7717 | 7731 |
public static class TransactionHelper |
... | ... | |
10185 | 10199 |
copy.addAll(wa.blocks); |
10186 | 10200 |
return copy; |
10187 | 10201 |
} |
10202 | ||
10203 |
/** |
|
10204 |
* Get the offEndQueries using the context local work area. |
|
10205 |
* |
|
10206 |
* @return offEndQueries of the context local work area. |
|
10207 |
*/ |
|
10208 |
public Set<P2JQuery> getOffEndQueries() |
|
10209 |
{ |
|
10210 |
return TransactionManager.getOffEndQueries(wa); |
|
10211 |
} |
|
10188 | 10212 |
} |
10189 | 10213 |
|
10190 | 10214 |
/** |