Project

General

Profile

7035-20230201.patch

Dănuț Filimon, 02/01/2023 04:21 AM

Download (43.8 KB)

View differences:

new/src/com/goldencode/p2j/persist/FQLBundle.java 2023-02-01 08:34:40 +0000
19 19
** 008 EVL 20160223          Javadoc fixes to make compatible with Oracle Java 8 for Solaris 10.
20 20
** 009 ECF 20200906          New ORM implementation.
21 21
** 010 OM  20221103          Renamed class to FQLBundle.
22
** 011 DDF 20230201          Refactored ParameterIndices into ParameterDiff. (refs: #7035)
22 23
*/
23 24

  
24 25
/*
......
153 154
   /** Parallel set of FQL statements for dirty database use */
154 155
   private List<String> dirtyStatements = null;
155 156
   
156
   /** Mapping of indices in the array of query substitution parameters */
157
   private ParameterIndices paramIndices = null;
157
   /** Mapping of substitution parameters functions */
158
   private ParameterDiff paramDiff = null;
158 159
   
159 160
   /**
160 161
    * Default constructor.
......
347 348
   }
348 349
   
349 350
   /**
350
    * Get the <code>ParameterIndices</code> object associated with this
351
    * Get the <code>ParameterDiff</code> object associated with this
351 352
    * bundle.  This object maintains an array of zero-based indices into the
352
    * array of query substitution arguments for the base (i.e., unaugmented)
353
    * array of query substitution parameters lambdas for the base (i.e., unaugmented)
353 354
    * where clause, as it exists <i>after</i> preprocessing is complete.  This
354 355
    * additional level of indirection is necessary because the query
355 356
    * substitution placeholders may have been reordered within the FQL where
356 357
    * clause expression during the FQL preprocessing rewrite step, and some
357 358
    * parameters may have been inlined into the where clause.
358 359
    *
359
    * @return  An object which provides a mapping of indices into the query
360
    *          substitution parameter list.
360
    * @return  An object which provides a mapping of query substitution parameter
361
    *          functions.
361 362
    */
362
   ParameterIndices getParameterIndices()
363
   ParameterDiff getParameterDiff()
363 364
   {
364
      return paramIndices;
365
      return paramDiff;
365 366
   }
366 367
   
367 368
   /**
368
    * Set the <code>ParameterIndices</code> object associated with this
369
    * Set the <code>ParameterDiff</code> object associated with this
369 370
    * bundle.  This object maintains an array of zero-based indices into the
370
    * array of query substitution arguments for the base (i.e., unaugmented)
371
    * array of query substitution parameters lambdas for the base (i.e., unaugmented)
371 372
    * where clause, as it exists <i>after</i> preprocessing is complete.  This
372 373
    * additional level of indirection is necessary because the query
373 374
    * substitution placeholders may have been reordered within the FQL where
......
375 376
    * parameters may have been inlined into the where clause.
376 377
    *
377 378
    * @param   paramIndices
378
    *          An object which provides a mapping of indices into the query
379
    *          substitution parameter list.
379
    *          An object which provides a mapping of query substitution parameter
380
    *          functions.
380 381
    */
381
   void setParameterIndices(ParameterIndices paramIndices)
382
   void setParameterDiff(ParameterDiff paramDiff)
382 383
   {
383
      this.paramIndices = paramIndices;
384
      this.paramDiff = paramDiff;
384 385
   }
385 386
   
386 387
   /**
new/src/com/goldencode/p2j/persist/FQLHelper.java 2023-02-01 08:34:55 +0000
130 130
**                           prevent NPE in proxy case.
131 131
**     CA  20221006          Added JMX instrumentation for FQL prepare (in 'obtain'). Refs #6814
132 132
**     OM  20221103          Class renamed to FQLHelper.
133
**     DDF 20230201          Method call changed due to method refactoring of FQLBundle and 
134
**                           FQLPreprocessor. (refs: #7035)
133 135
*/
134 136

  
135 137
/*
......
971 973
         }
972 974
      }
973 975
      
974
      // Store query substitution parameter indices.
976
      // Store query substitution parameter lambdas.
975 977
      // TODO:  currently, these are shared, and not dialect specific, but
976 978
      // only because we do not inline parameters from this class.  Were this
977
      // to change, we would need to maintain separate ParameterIndices
979
      // to change, we would need to maintain separate ParameterDiff
978 980
      // objects for the primary and dirty database statements.
979 981
      if (primary)
980 982
      {
981
         bundle.setParameterIndices(fqlPreprocessor.getParameterIndices());
983
         bundle.setParameterDiff(fqlPreprocessor.getParameterDiff());
982 984
      }
983 985
   }
984 986
   
new/src/com/goldencode/p2j/persist/FQLPreprocessor.java 2023-02-01 08:35:16 +0000
281 281
**                           are not the same), to be aware of the external buffers (i.e. added for CAN-FIND
282 282
**                           sub-select clauses).  The translate will be performed before the query is being
283 283
**                           executed.
284
**     DDF 20230201          Extracted query parameters from the where clause and refactored ParameterIndices
285
**                           into ParameterDiff to store a mapping of substitution parameter lambdas for all
286
**                           parameters (parameters given at query initialization and the ones extracted 
287
**                           from the AST). (refs: #7035)
284 288
*/
285 289

  
286 290
/*
......
466 470
 * substitution parameters in the proper order:
467 471
 * <ul>
468 472
 *   <li>{@link #getFQL()}
469
 *   <li>{@link #getParameterIndices()}
473
 *   <li>{@link #getParameterDiff()}
470 474
 *   <li>{@link #ansiJoins()}
471 475
 * </ul>
472 476
 * <p>
......
614 618
    */
615 619
   private boolean inlinedTernary = false;
616 620
   
617
   /** Mapping of index positions for substitution parameters after rewrite */
618
   private ParameterIndices paramIndices = null;
621
   /** Mapping of substitution parameters functions after rewrite */
622
   private ParameterDiff paramDiff = null;
619 623
   
620 624
   /** Map of properties used by this where clause, keyed by DMO entity */
621 625
   private Map<String, Set<String>> restrictionProperties = null;
......
653 657
   /** Flag indicating that the query depends on mutable SESSION attribute(s). */
654 658
   private boolean dependsOnSessionAttribute = false;
655 659
   
660
   /** List of extracted parameters from the where clause */
661
   private List<Object> parametersDiff = null;
662
   
656 663
   /**
657 664
    * Factory method which accepts an unprocessed where clause, the database
658 665
    * instance and the database dialect associated with the enclosing query,
......
1288 1295
   }
1289 1296
   
1290 1297
   /**
1291
    * Get the <code>ParameterIndices</code> object associated with this query.
1298
    * Get the <code>ParameterDiff</code> object associated with this query.
1292 1299
    * This object maintains an array of zero-based indices into the array of
1293
    * query substitution arguments for the where clause, as it exists
1300
    * query substitution parameter lambdas for the where clause, as it exists
1294 1301
    * <i>after</i> preprocessing is complete.  This additional level of
1295 1302
    * indirection is necessary because the query substitution placeholders may
1296 1303
    * have been reordered within the FQL where clause expression during the
......
1298 1305
    * inlined into the where clause.
1299 1306
    *
1300 1307
    * @return  An object which provides a mapping of indices into the query
1301
    *          substitution parameter list.
1308
    *          substitution parameter lambdas list.
1302 1309
    */
1303
   ParameterIndices getParameterIndices()
1310
   ParameterDiff getParameterDiff()
1304 1311
   {
1305
      return paramIndices;
1312
      return paramDiff;
1306 1313
   }
1307 1314
   
1308 1315
   /**
......
1563 1570
                    "[" + database + "] Preprocessed FQL:  " + fql + sep + root.dumpTree());
1564 1571
         }
1565 1572
         
1566
         this.paramIndices = createParameterIndices(root, parameters);
1573
         this.paramDiff = createParameterDiffs(root, parameters);
1567 1574
      }
1568 1575
   }
1569 1576
   
......
2609 2616
      Set<HQLAst> nullsInInSet = null;
2610 2617
      Set<HQLAst> droppedTrims = null;
2611 2618
      
2619
      int parameterCounter = parameters != null ? parameters.length : 0;
2620
      FqlType parameterType = null;
2621
      
2612 2622
      boolean doInline = inline;
2613 2623
      inline = false;
2614 2624
      HQLAst parent;
......
2938 2948
               
2939 2949
               break;
2940 2950
               
2951
            // The BOOL_TRUE and BOOL_FALSE cases are not handled because are duplicates
2952
            // Change node type to SUBST for future prepared statement processing
2953
            case NUM_LITERAL:
2954
               if (parameterType == null)
2955
               {
2956
                  parameterType = FqlType.INTEGER;
2957
               }
2958
            case DEC_LITERAL:
2959
               if (parameterType == null)
2960
               {
2961
                  parameterType = FqlType.DECIMAL;
2962
               }
2963
            case STRING:
2964
               if (parameterType == null)
2965
               {
2966
                  parameterType = FqlType.TEXT;
2967
               }
2968
               
2969
               // Add an index and datatype annotation to the current node.
2970
               // The extracted-value annotation stores the value of the node.
2971
               next.putAnnotation("index", (long) parameterCounter++);
2972
               next.putAnnotation("datatype", parameterType.toString());
2973
               next.putAnnotation("extracted-value", next.getText());
2974
               
2975
               if (parametersDiff == null)
2976
               {
2977
                  parametersDiff = new ArrayList<>();
2978
               }
2979
               
2980
               parametersDiff.add(next.getText());
2981
               parameterType = null;
2982
               
2983
               // Change the node type and value
2984
               next.setType(SUBST);
2985
               next.setText("?");
2986
               
2987
               // Stop the inline of the extracted parameters.
2988
               break;
2941 2989
            // Possibly inline certain query substitution parameters.
2942 2990
            case SUBST:
2943 2991
               parent = (HQLAst) next.getParent();
......
5848 5896
   }
5849 5897
   
5850 5898
   /**
5851
    * Create the mapping of substitution parameters to their corresponding
5899
    * Create the mapping of substitution parameters functions to their corresponding
5852 5900
    * substitution placeholders in the rewritten FQL where clause.  These
5853 5901
    * placeholders (<code>?</code>) may have been reordered or removed (due to
5854 5902
    * inlining) during the rewrite process.
5855 5903
    * <p>
5856 5904
    * During parsing of the FQL clause, an index annotation was added to each
5857 5905
    * AST of type <code>SUBST</code> (token type for the query substitution
5858
    * parameter placeholder), denoting that placeholder's position in the
5859
    * original where clause.  We now walk the rewritten AST, extracting this
5860
    * annotation and storing it in a new list.  The resulting array defines
5906
    * parameter placeholder), and each <code>NUM_LITERAL</code>, <code>DEC_LITERAL</code>,
5907
    * <code>STRING</code> which is substituted to <code>SUBST</code> 
5908
    * denoting that placeholder's lambda in the original where clause.  
5909
    * We now walk the rewritten AST, extracting this annotation
5910
    * and storing it in a new list.  The resulting array defines
5861 5911
    * the new order of the substitution parameters.  For parameters which
5862 5912
    * were dropped, due to inlining, a null placeholder will appear in the new
5863 5913
    * list.
......
5870 5920
    * @return  Object which maps new query substitution parameter positions to their positions in the original
5871 5921
    *          parameters array. These indices are zero-based.
5872 5922
    */
5873
   private ParameterIndices createParameterIndices(HQLAst root, Object[] parameters)
5923
   private ParameterDiff createParameterDiffs(HQLAst root, Object[] parameters)
5874 5924
   {
5875
      if (parameters == null)
5925
      // If there are no arguments or substituted parameters
5926
      if (parameters == null && parametersDiff == null)
5876 5927
      {
5877
         return (new ParameterIndices(null));
5928
         return (new ParameterDiff(null));
5878 5929
      }
5879 5930
      
5880
      List<Integer> indices = new ArrayList<>(parameters.length);
5881
      
5931
      int paramCounter = parameters != null ? parameters.length : 0;
5932
      paramCounter += parametersDiff != null ? parametersDiff.size() : 0;
5933
      @SuppressWarnings("unchecked")
5934
      Function<Object[], Object>[] retrieveParameters = new Function[paramCounter];
5935

  
5882 5936
      // Extract the "index" annotation from each SUBST node, in order of
5883 5937
      // the tree walk, which will correspond to the order of the placeholders
5884 5938
      // in the final, infix expression.
5939
      
5940
      // There are two types of parameters, parameters that are substituted from the beginning,
5941
      // and those that are substituted in the mainWalk() method.
5942
      // In the case of the "extracted-value" annotation being present, create a function 
5943
      // that returns the value after being casted to a BaseDataType.
5944
      // For the substituted parameters that already existed, the function returns
5945
      // the index positioned value in the params given.
5946
      int functionCounter = 0;
5885 5947
      Iterator<Aast> iter = root.iterator();
5886 5948
      while (iter.hasNext())
5887 5949
      {
5888
         Long index = null;
5889 5950
         HQLAst next = (HQLAst) iter.next();
5890 5951
         switch (next.getType())
5891 5952
         {
5892 5953
            case SUBST:
5893
               index = (Long) next.getAnnotation("index");
5894
               indices.add(index.intValue());
5895
               break;
5896
               
5897
            case NUM_LITERAL:
5898
            case DEC_LITERAL:
5899
            case STRING:
5900
            case IS_NULL:
5901
            case NOT_NULL:
5902
            case BOOL_FALSE:
5903 5954
               if (inline && next.isAnnotation("inlined"))
5904 5955
               {
5905
                  // Allow null to remain at this position in the array.
5906
                  indices.add(null);
5907
               }
5956
                  break;
5957
               }
5958
               
5959
               Function<Object[], Object> rp = null;
5960
               
5961
               if (next.isAnnotation("extracted-value"))
5962
               {
5963
                  rp = (Object[] params) -> 
5964
                  {
5965
                     String value = (String) next.getAnnotation("extracted-value");
5966
                     FqlType fqlType = Enum.valueOf(FqlType.class, (String) next.getAnnotation("datatype"));
5967
                     switch (fqlType)
5968
                     {
5969
                        case INTEGER:
5970
                           return new integer(value);
5971
                        case DECIMAL:
5972
                           return new decimal(value);
5973
                        case TEXT:
5974
                           assert (value.charAt(0) == '\'');
5975
                           assert (value.charAt(value.length() - 1) == '\'');
5976
                           value = value.substring(1, value.length() - 1);
5977
                           return new character(value);
5978
                        default:
5979
                           throw new IllegalStateException("No matching datatype for the extracted value.");
5980
                     }
5981
                  };
5982
               }
5983
               else 
5984
               {
5985
                  rp = (Object[] params) -> 
5986
                  {
5987
                     Long index = (Long) next.getAnnotation("index");
5988
                     return params[index.intValue()];
5989
                  };
5990
               }
5991
               
5992
               retrieveParameters[functionCounter++] = rp;
5993
               
5908 5994
               break;
5995
//            case NUM_LITERAL:
5996
//            case DEC_LITERAL:
5997
//            case STRING:
5998
//            case IS_NULL:
5999
//            case NOT_NULL:
6000
//            case BOOL_FALSE:
6001
//               if (inline && next.isAnnotation("inlined"))
6002
//               {
6003
//                  // Allow null to remain at this position in the array.
6004
//                  indices.add(null);
6005
//               }
6006
//               break;
5909 6007
               
5910 6008
            default:
5911 6009
               break;
5912 6010
         }
5913 6011
      }
5914 6012
      
5915
      Integer[] idx = indices.toArray(new Integer[indices.size()]);
5916
      
5917
      return (new ParameterIndices(idx));
6013
      return (new ParameterDiff(retrieveParameters));
5918 6014
   }
5919 6015
   
5920 6016
   /**
new/src/com/goldencode/p2j/persist/ParameterDiff.java 2023-02-01 08:34:22 +0000
1
/*
2
** Module   : ParameterDiff.java
3
** Abstract : Mapping of query substitution parameters functions in an array, after where clause preprocessing.
4
**
5
** Copyright (c) 2008-2023, Golden Code Development Corporation.
6
**
7
** -#- -I- --Date-- -JPRM- ------------------------------------Description------------------------------------
8
** 001 ECF 20081009 @40080 Created initial version. A mapping of query substitution parameters in an array,
9
**                         after where clause preprocessing.
10
** 002 OM  20221103        New class names for FQLPreprocessor, FQLExpression, FQLBundle, and FQLCache.
11
** 003 DDF 20230201        Refactored ParameterIndices into ParameterDiff by replacing the Integer indices
12
**                         array with an array of lambdas. Instead of storing the index of the parameters
13
**                         from the AST node, we store a lambda that takes an array of arguments and returns 
14
**                         either an extracted value from the AST, or an existing value from the given array.
15
*/
16

  
17
/*
18
** This program is free software: you can redistribute it and/or modify
19
** it under the terms of the GNU Affero General Public License as
20
** published by the Free Software Foundation, either version 3 of the
21
** License, or (at your option) any later version.
22
**
23
** This program is distributed in the hope that it will be useful,
24
** but WITHOUT ANY WARRANTY; without even the implied warranty of
25
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
** GNU Affero General Public License for more details.
27
**
28
** You may find a copy of the GNU Affero GPL version 3 at the following
29
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
30
** 
31
** Additional terms under GNU Affero GPL version 3 section 7:
32
** 
33
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
34
**   terms apply to the works covered under the License.  These additional terms
35
**   are non-permissive additional terms allowed under Section 7 of the GNU
36
**   Affero GPL version 3 and may not be removed by you.
37
** 
38
**   0. Attribution Requirement.
39
** 
40
**     You must preserve all legal notices or author attributions in the covered
41
**     work or Appropriate Legal Notices displayed by works containing the covered
42
**     work.  You may not remove from the covered work any author or developer
43
**     credit already included within the covered work.
44
** 
45
**   1. No License To Use Trademarks.
46
** 
47
**     This license does not grant any license or rights to use the trademarks
48
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
49
**     of Golden Code Development Corporation. You are not authorized to use the
50
**     name Golden Code, FWD, or the names of any author or contributor, for
51
**     publicity purposes without written authorization.
52
** 
53
**   2. No Misrepresentation of Affiliation.
54
** 
55
**     You may not represent yourself as Golden Code Development Corporation or FWD.
56
** 
57
**     You may not represent yourself for publicity purposes as associated with
58
**     Golden Code Development Corporation, FWD, or any author or contributor to
59
**     the covered work, without written authorization.
60
** 
61
**   3. No Misrepresentation of Source or Origin.
62
** 
63
**     You may not represent the covered work as solely your work.  All modified
64
**     versions of the covered work must be marked in a reasonable way to make it
65
**     clear that the modified work is not originating from Golden Code Development
66
**     Corporation or FWD.  All modified versions must contain the notices of
67
**     attribution required in this license.
68
*/
69

  
70
package com.goldencode.p2j.persist;
71

  
72
import java.util.function.Function;
73

  
74
/**
75
 * A mapping of the active indices in an array of query substitution
76
 * parameters, after an HQL where clause has been preprocessed.  The HQL
77
 * preprocessor may inline or re-order query substitution parameters.  Thus,
78
 * given an array of query substitution parameters, it is necessary to provide
79
 * a means for a query object to organize the remaining parameters when
80
 * submitting a query for execution.
81
 * <p>
82
 * A query object will have the original array of parameters provided by
83
 * business logic, as well as an instance of {@link FQLPreprocessor}.  That
84
 * instance will provide an instance of this class via its {@link
85
 * FQLPreprocessor#getParameterDiff()} method.  To obtain the correct list
86
 * of parameters which corresponds with the preprocessed where clause, the
87
 * query iterates its original array of parameters.  For each index in that
88
 * array, it calls {@link #getIndex(int)} to obtain the remapped position of
89
 * the parameter originally at the current index.  If <code>null</code> is
90
 * returned, it means the parameter originally at the current index has been
91
 * inlined into the where clause.  A non-<code>null</code> value represents
92
 * the zero-based index at which the parameter can be found in the original
93
 * array.
94
 */
95
final class ParameterDiff
96
{
97
   /** Count of substitution parameters functions in use */
98
   private final int count;
99
   
100
   /** Array of functions for substitution parameters */
101
   private final Function<Object[], Object>[] substParamFunctions;
102
   
103
   /**
104
    * Constructor which sets the array of substitution parameters 
105
    * functions of query for the associated where clause.
106
    * 
107
    * @param   substFunctions
108
    *          Array of substitution parameter functions. If
109
    *          <code>null</code>, the associated query string has no query
110
    *          substitution parameters.
111
    */
112
   ParameterDiff(Function<Object[], Object>[] substFunctions)
113
   {
114
      this.substParamFunctions = substFunctions;
115
      int counter = 0;
116
      if (substParamFunctions != null)
117
      {
118
         for (int i = 0; i < substParamFunctions.length; i++)
119
         {
120
            if (substParamFunctions[i] == null)
121
            {
122
               continue;
123
            }
124
            counter++;
125
         }
126
      }
127
      this.count = counter;
128
   }
129
   
130
   /**
131
    * Get the count of query substitution parameters functions which were created for
132
    * the where clause preprocessing step. This is the count of the passed 
133
    * lambda array items to this object's constructor.
134
    * 
135
    * @return  Count of query substitution parameters functions.
136
    */
137
   int getCount()
138
   {
139
      return count;
140
   }
141
   
142
   /**
143
    * Given a position of a query substitution parameter function in the original 
144
    * array of lambdas (before the where clause preprocessing step), get the
145
    * lambda of that parameter in the original array.  Note that the
146
    * original array is not changed, only the mapping of lambdas may have
147
    * changed.  If the index returned matches the <code>position</code>
148
    * supplied, this indicates the parameter's placeholder (<code>?</code>) is
149
    * located at the same relative position in the where clause as before
150
    * preprocessing.
151
    * 
152
    * @param   position
153
    *          Zero-based index of the target substitution parameter function
154
    *          in the original array.
155
    * 
156
    * @return  New, zero-based index of the target substitution parameter function 
157
    *          in the original array, or <code>null</code> if the parameter was
158
    *          inlined during preprocessing of the where clause.
159
    */
160
   Function<Object[], Object> getIndex(int position)
161
   {
162
      return (substParamFunctions == null ? null : substParamFunctions[position]);
163
   }
164
   
165
   /**
166
    * Method for retrieving the substitution parameter functions.
167
    * 
168
    * @return  The substitution parameter functions, or null if
169
    *          no functions were assigned.
170
    */
171
   Function<Object[], Object>[] getSubstParamFunctions()
172
   {
173
      return substParamFunctions;
174
   }
175
   
176
   /**
177
    * Apply the substitution parameters lambdas based on the params given. The params 
178
    * value is used just for already substituded parameters from the where clause,
179
    * while the value of the subtituted parameters from the preprocessing are replaced
180
    * by the value of the node annotation <code>extracted-value</code>. 
181
    * 
182
    * @param   params
183
    *          Parameter array for lambda which selects the parameter value
184
    *          for substituted parameters that were not created during
185
    *          the preprocessing phase.
186
    *          The parameter array is still required for the other lambdas,
187
    *          but not used.
188
    * 
189
    * @return  Object representing the value of the argument.
190
    */
191
   Object[] getSubstParameters(Object[] params)
192
   {
193
      Object[] args = new Object[count];
194
      for (int position = 0; position < substParamFunctions.length; position++)
195
      {
196
         if (substParamFunctions[position] != null)
197
         {
198
            args[position] = substParamFunctions[position].apply(params);
199
         }
200
      }
201
      return args;
202
   }
203
}
new/src/com/goldencode/p2j/persist/ParameterIndices.java 1970-01-01 00:00:00 +0000
1
/*
2
** Module   : ParameterIndices.java
3
** Abstract : Mapping of query substitution parameters in an array, after where clause preprocessing.
4
**
5
** Copyright (c) 2008-2022, Golden Code Development Corporation.
6
**
7
** -#- -I- --Date-- -JPRM- ------------------------------------Description------------------------------------
8
** 001 ECF 20081009 @40080 Created initial version. A mapping of query substitution parameters in an array,
9
**                         after where clause preprocessing.
10
** 002 OM  20221103        New class names for FQLPreprocessor, FQLExpression, FQLBundle, and FQLCache.
11
*/
12

  
13
/*
14
** This program is free software: you can redistribute it and/or modify
15
** it under the terms of the GNU Affero General Public License as
16
** published by the Free Software Foundation, either version 3 of the
17
** License, or (at your option) any later version.
18
**
19
** This program is distributed in the hope that it will be useful,
20
** but WITHOUT ANY WARRANTY; without even the implied warranty of
21
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
** GNU Affero General Public License for more details.
23
**
24
** You may find a copy of the GNU Affero GPL version 3 at the following
25
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
26
** 
27
** Additional terms under GNU Affero GPL version 3 section 7:
28
** 
29
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
30
**   terms apply to the works covered under the License.  These additional terms
31
**   are non-permissive additional terms allowed under Section 7 of the GNU
32
**   Affero GPL version 3 and may not be removed by you.
33
** 
34
**   0. Attribution Requirement.
35
** 
36
**     You must preserve all legal notices or author attributions in the covered
37
**     work or Appropriate Legal Notices displayed by works containing the covered
38
**     work.  You may not remove from the covered work any author or developer
39
**     credit already included within the covered work.
40
** 
41
**   1. No License To Use Trademarks.
42
** 
43
**     This license does not grant any license or rights to use the trademarks
44
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
45
**     of Golden Code Development Corporation. You are not authorized to use the
46
**     name Golden Code, FWD, or the names of any author or contributor, for
47
**     publicity purposes without written authorization.
48
** 
49
**   2. No Misrepresentation of Affiliation.
50
** 
51
**     You may not represent yourself as Golden Code Development Corporation or FWD.
52
** 
53
**     You may not represent yourself for publicity purposes as associated with
54
**     Golden Code Development Corporation, FWD, or any author or contributor to
55
**     the covered work, without written authorization.
56
** 
57
**   3. No Misrepresentation of Source or Origin.
58
** 
59
**     You may not represent the covered work as solely your work.  All modified
60
**     versions of the covered work must be marked in a reasonable way to make it
61
**     clear that the modified work is not originating from Golden Code Development
62
**     Corporation or FWD.  All modified versions must contain the notices of
63
**     attribution required in this license.
64
*/
65

  
66
package com.goldencode.p2j.persist;
67

  
68
/**
69
 * A mapping of the active indices in an array of query substitution
70
 * parameters, after an HQL where clause has been preprocessed.  The HQL
71
 * preprocessor may inline or re-order query substitution parameters.  Thus,
72
 * given an array of query substitution parameters, it is necessary to provide
73
 * a means for a query object to organize the remaining parameters when
74
 * submitting a query for execution.
75
 * <p>
76
 * A query object will have the original array of parameters provided by
77
 * business logic, as well as an instance of {@link FQLPreprocessor}.  That
78
 * instance will provide an instance of this class via its {@link
79
 * FQLPreprocessor#getParameterIndices()} method.  To obtain the correct list
80
 * of parameters which corresponds with the preprocessed where clause, the
81
 * query iterates its original array of parameters.  For each index in that
82
 * array, it calls {@link #getIndex(int)} to obtain the remapped position of
83
 * the parameter originally at the current index.  If <code>null</code> is
84
 * returned, it means the parameter originally at the current index has been
85
 * inlined into the where clause.  A non-<code>null</code> value represents
86
 * the zero-based index at which the parameter can be found in the original
87
 * array.
88
 */
89
final class ParameterIndices
90
{
91
   /** Count of substitution parameters in use */
92
   private final int count;
93
   
94
   /** Mapping of indices of parameters in original array */
95
   private final Integer[] indices;
96
   
97
   /**
98
    * Constructor which sets the array of new index positions of query
99
    * substitution parameters for the associated where clause.
100
    * 
101
    * @param   indices
102
    *          Array of zero-based index positions of query substitution
103
    *          parameters in the original array of parameters.  If
104
    *          <code>null</code>, the associated query string has no query
105
    *          substitution parameters.
106
    */
107
   ParameterIndices(Integer[] indices)
108
   {
109
      int i = 0;
110
      
111
      if (indices != null)
112
      {
113
         for (Integer next : indices)
114
         {
115
            if (next != null)
116
            {
117
               i++;
118
            }
119
         }
120
      }
121
      
122
      this.indices = indices;
123
      this.count = i;
124
   }
125
   
126
   /**
127
    * Get the count of query substitution parameters which survived the where
128
    * clause preprocessing step.  This is the count of non-<code>null</code>
129
    * index positions in the array of indices passed to this object's
130
    * constructor.
131
    * 
132
    * @return  Count of query substitution parameters.
133
    */
134
   int getCount()
135
   {
136
      return count;
137
   }
138
   
139
   /**
140
    * Given a position of a query substitution parameter in the original array
141
    * of parameters (before the where clause preprocessing step), get the new,
142
    * zero-based index of that parameter in the original array.  Note that the
143
    * original array is not changed, only the mapping of indices may have
144
    * changed.  If the index returned matches the <code>position</code>
145
    * supplied, this indicates the parameter's placeholder (<code>?</code>) is
146
    * located at the same relative position in the where clause as before
147
    * preprocessing.
148
    * 
149
    * @param   position
150
    *          Zero-based index of the target substitution parameter in the
151
    *          original array.
152
    * 
153
    * @return  New, zero-based index of the target substitution parameter in
154
    *          the original array, or <code>null</code> if the parameter was
155
    *          inlined during preprocessing of the where clause.
156
    */
157
   Integer getIndex(int position)
158
   {
159
      return (indices == null ? null : indices[position]);
160
   }
161
}
new/src/com/goldencode/p2j/persist/QueryComponent.java 2023-02-01 08:35:30 +0000
32 32
**     CA  20221130 Refactored the WHERE clause translation (when the bound and definition buffers are not the
33 33
**                  same), to be aware of the external buffers (i.e. added for CAN-FIND sub-select clauses).  
34 34
**                  The translate will be performed before the query is being executed.
35
**     DDF 20230201 Refactored ParameterIndices into ParameterDiff. Extracted arguments also need to be
36
**                  resolved. (refs: #7035)
35 37
*/
36 38

  
37 39
/*
......
490 492
   protected Object[] getArgs()
491 493
   throws PersistenceException
492 494
   {
493
      if (dfArgs != null && currentArgs == null)
495
      if (currentArgs == null)
494 496
      {
495 497
         currentArgs = filterArgs(getHQLPreprocessor());
496 498
      }
......
594 596
      // in this case the processDynamicFilters() is not required to be called before calling
595 597
      // resolveArgs() because it was called before constructing the preprocessor
596 598
      Object[] intermediate = resolveArgs();
597
      if (intermediate == null)
599
      ParameterDiff pd = preproc.getParameterDiff();
600
      if (intermediate == null && pd == null)
598 601
      {
599 602
         return null;
600 603
      }
601 604
      
602
      ParameterIndices pi = preproc.getParameterIndices();
603
      int len = pi.getCount();
604
      Object[] filteredArgs = new Object[len];
605
      for (int i = 0, count = 0; count < len; i++)
606
      {
607
         Integer nextIndex = pi.getIndex(i);
608
         if (nextIndex == null)
609
         {
610
            // original substitution parameter was inlined into HQL by preprocessor;  skip it
611
            continue;
612
         }
613
         
614
         // Substitution placeholders may have been reordered if this
615
         // statement was rewritten by the HQL preprocessor. Make sure
616
         // we access the correct substitution parameter.
617
         Object next = intermediate[nextIndex];
618
         
619
         filteredArgs[count++] = next;
620
      }
605
      if (pd == null)
606
      {
607
         return intermediate;
608
      }
609

  
610
      Object[] filteredArgs = pd.getSubstParameters(intermediate);
611
      for (int i = 0; i < filteredArgs.length; i++)
612
      {
613
         // Substitution parameters returned also need to be resolved.
614
         filteredArgs[i] = resolveArg(filteredArgs[i]);
615
      }
616
      
617
//      ParameterIndices pi = preproc.getParameterIndices();
618
//      int len = pi.getCount();
619
//      Object[] filteredArgs = new Object[len];
620
//      for (int i = 0, count = 0; count < len; i++)
621
//      {
622
//         Integer nextIndex = pi.getIndex(i);
623
//         if (nextIndex == null)
624
//         {
625
//            // original substitution parameter was inlined into HQL by preprocessor;  skip it
626
//            continue;
627
//         }
628
//         
629
//         // Substitution placeholders may have been reordered if this
630
//         // statement was rewritten by the HQL preprocessor. Make sure
631
//         // we access the correct substitution parameter.
632
//         Object next = intermediate[nextIndex];
633
//         
634
//         filteredArgs[count++] = next;
635
//      }
621 636
      
622 637
      return filteredArgs;
623 638
   }
new/src/com/goldencode/p2j/persist/RandomAccessQuery.java 2023-02-01 08:35:47 +0000
346 346
**                           are not the same), to be aware of the external buffers (i.e. added for CAN-FIND
347 347
**                           sub-select clauses).  The translate will be performed before the query is being
348 348
**                           executed.
349
**     DDF 20230201          Refactoring ParameterIndices into ParameterDiff and added method for retrieving 
350
**                           parameter values. (refs: #7035)
349 351
*/
350 352

  
351 353
/*
......
4239 4241
      boolean debug = LOG.isLoggable(Level.FINE);
4240 4242
      
4241 4243
      DirtyShareContext dirtyContext = buffer.getDirtyContext();
4242
      ParameterIndices pi = activeBundle.getParameterIndices();
4244
      ParameterDiff pi = activeBundle.getParameterDiff();
4243 4245
      int origArgCount = (values == null ? 0 : values.length);
4244 4246
      int baseArgCount = (pi == null ? origArgCount : pi.getCount());
4245 4247
      
......
4326 4328
            // resolve these parameters.
4327 4329
            for (int j = 0, i = startIndex; i < baseArgCount; j++)
4328 4330
            {
4329
               int k = -1;
4330
               if (pi == null)
4331
               {
4332
                  k = j;
4333
               }
4334
               else
4335
               {
4336
                  Integer idx = pi.getIndex(j);
4337
                  if (idx == null)
4338
                  {
4339
                     // original substitution parameter was inlined into HQL by preprocessor;  skip it
4340
                     continue;
4341
                  }
4342
                  k = idx;
4343
               }
4331
//               int k = -1;
4332
//               if (pi == null)
4333
//               {
4334
//                  k = j;
4335
//               }
4336
//               else
4337
//               {
4338
//                  Integer idx = pi.getIndex(j);
4339
//                  if (idx == null)
4340
//                  {
4341
//                     // original substitution parameter was inlined into HQL by preprocessor;  skip it
4342
//                     continue;
4343
//                  }
4344
//                  k = idx;
4345
//               }
4344 4346
               
4345 4347
               // Substitution placeholders may have been reordered if this
4346 4348
               // statement was rewritten by the HQL preprocessor. Make sure
4347 4349
               // we access the correct substitution parameter.
4348
               Object next = values[k];
4350
               Function<Object[], Object> currentParameterFunction = pi.getIndex(j);
4351
               Object next = currentParameterFunction.apply(values);
4349 4352
               
4350 4353
               // store parameters in the base args array, resolving them first if necessary
4351 4354
               if (next instanceof Resolvable)
new/src/com/goldencode/p2j/persist/RecordBuffer.java 2023-02-01 08:36:16 +0000
1260 1260
**                           runtime.
1261 1261
**     CA  20230123          isPropertyIndexed must have protected access, because is accessed from static
1262 1262
**                           methods. 
1263
**     DDF 20230201          Refactoring ParameterIndices into ParameterDiff and added method for retrieving 
1264
**                           parameter values. (refs: #7035)
1263 1265
*/
1264 1266

  
1265 1267
/*
......
10707 10709
            
10708 10710
            if (args != null && args.length > 0)
10709 10711
            {
10710
               ParameterIndices pi = preproc.getParameterIndices();
10711
               int len = pi.getCount();
10712
               List<Object> argList = new ArrayList<>(len);
10713
               for (int i = 0, count = 0; count < len; i++)
10714
               {
10715
                  Integer nextIndex = pi.getIndex(i);
10716
                  if (nextIndex == null)
10717
                  {
10718
                     // original substitution parameter was inlined into HQL by preprocessor;
10719
                     // skip it.
10720
                     continue;
10721
                  }
10722
                  
10723
                  // substitution placeholders may have been reordered if this statement was
10724
                  // rewritten by the HQL preprocessor; make sure we access the correct
10725
                  // substitution parameter
10726
                  Object next = args[nextIndex];
10727
                  argList.add(next);
10728
                  
10729
                  count++;
10730
               }
10731
               args = argList.toArray();
10712
               ParameterDiff pd = preproc.getParameterDiff();
10713
               Object[] filteredArgs = pd.getSubstParameters(args);
10714
               args = filteredArgs;
10715
               
10716
//               ParameterDiff pi = preproc.getParameterDiff();
10717
//               int len = pi.getCount();
10718
//               List<Object> argList = new ArrayList<>(len);
10719
//               for (int i = 0, count = 0; count < len; i++)
10720
//               {
10721
//                  Integer nextIndex = pi.getIndex(i);
10722
//                  if (nextIndex == null)
10723
//                  {
10724
//                     // original substitution parameter was inlined into HQL by preprocessor;
10725
//                     // skip it.
10726
//                     continue;
10727
//                  }
10728
//                  
10729
//                  // substitution placeholders may have been reordered if this statement was
10730
//                  // rewritten by the HQL preprocessor; make sure we access the correct
10731
//                  // substitution parameter
10732
//                  Object next = args[nextIndex];
10733
//                  argList.add(next);
10734
//                  
10735
//                  count++;
10736
//               }
10737
//               args = argList.toArray();
10732 10738
            }
10733 10739
         }
10734 10740
         
new/src/com/goldencode/p2j/persist/TemporaryBuffer.java 2023-02-01 08:36:49 +0000
640 640
**                           runtime.
641 641
**     HC  20230118          Eliminated some of the uses of String.toUpperCase and/or
642 642
**                           String.toLowerCase for performance.
643
**     DDF 20230201          Refactoring ParameterIndices into ParameterDiff and added method for retrieving 
644
**                           parameter values. (refs: #7035)
643 645
*/
644 646

  
645 647
/*
......
7709 7711
         
7710 7712
         if (args != null && args.length > 0)
7711 7713
         {
7712
            ParameterIndices pi = preproc.getParameterIndices();
7713
            int len = pi.getCount();
7714
            List<Object> argList = new ArrayList<>(len);
7715
            for (int i = 0, count = 0; count < len; i++)
7716
            {
7717
               Integer nextIndex = pi.getIndex(i);
7718
               if (nextIndex == null)
7719
               {
7720
                  // original substitution parameter was inlined into HQL by preprocessor;
7721
                  // skip it.
7722
                  continue;
7723
               }
7724
               
7725
               // substitution placeholders may have been reordered if this statement was
7726
               // rewritten by the HQL preprocessor; make sure we access the correct
7727
               // substitution parameter
7728
               Object next = args[nextIndex];
7729
               argList.add(next);
7730
               
7731
               count++;
7732
            }
7733
            args = argList.toArray();
7714
            ParameterDiff pd = preproc.getParameterDiff();
7715
            Object[] filteredArgs = pd.getSubstParameters(args);
7716
            args = filteredArgs;
7717
//            ParameterDiff pi = preproc.getParameterDiff();
7718
//            int len = pi.getCount();
7719
//            List<Object> argList = new ArrayList<>(len);
7720
//            for (int i = 0, count = 0; count < len; i++)
7721
//            {
7722
//               Integer nextIndex = pi.getIndex(i);
7723
//               if (nextIndex == null)
7724
//               {
7725
//                  // original substitution parameter was inlined into HQL by preprocessor;
7726
//                  // skip it.
7727
//                  continue;
7728
//               }
7729
//               
7730
//               // substitution placeholders may have been reordered if this statement was
7731
//               // rewritten by the HQL preprocessor; make sure we access the correct
7732
//               // substitution parameter
7733
//               Object next = args[nextIndex];
7734
//               argList.add(next);
7735
//               
7736
//               count++;
7737
//            }
7738
//            args = argList.toArray();
7734 7739
         }
7735 7740
      }
7736 7741
      String delStmt = query.toFinalExpression();