Project

General

Profile

7061-2-fwd.patch

Radu Apetrii, 02/15/2023 08:49 AM

Download (17.4 KB)

View differences:

new/src/com/goldencode/p2j/persist/AdaptiveQuery.java 2023-02-15 10:28:21 +0000
345 345
**     SVL 20230108          Improved performance by replacing some "for-each" loops with indexed "for" loops.
346 346
**     SVL 20230109          Reflected PreselectQuery.components() now providing direct access to the
347 347
**                           components array in order to improve performance.
348
**     RAA 20230213          Added the possibility to execute a query in a lazy manner. Also, when a result
349
**                           set is created, ProgressiveResults can no longer be the type returned.
348 350
*/
349 351

  
350 352
/*
......
403 405
package com.goldencode.p2j.persist;
404 406

  
405 407
import java.lang.reflect.*;
408
import java.sql.*;
406 409
import java.util.*;
407 410
import java.util.function.*;
408 411
import java.util.logging.*;
412

  
409 413
import com.goldencode.p2j.persist.event.*;
410 414
import com.goldencode.p2j.persist.lock.*;
411 415
import com.goldencode.p2j.persist.orm.*;
......
2956 2960
   /**
2957 2961
    * Execute the query to create a first level result set.
2958 2962
    * <p>
2963
    * This case is for persistent databases:
2959 2964
    * If we are executing the query after a re-validation, or if the query's sort phrase does not match
2960 2965
    * any legacy index, fall back to the superclass' implementation. Otherwise, this implementation creates
2961 2966
    * an instance of {@code ProgressiveResults}, which defers actually executing the query until
2962 2967
    * the first request to fetch a result.
2968
    * 
2969
    * This case is for temporary tables:
2970
    * This implementation can create either a {@code ScrollingResults} or a type of {@code Results}
2971
    * determined by the execution of the super function.
2963 2972
    *
2964 2973
    * @param   persistence
2965 2974
    *          Object which is used to execute the query.
......
2970 2979
    *          string.
2971 2980
    *
2972 2981
    * @return  An instance of {@code ProgressiveResults} which fetches progressively larger
2973
    *          brackets of query results as the results are accessed.
2982
    *          brackets of query results as the results are accessed (for persistent cases),
2983
    *          Or
2984
    *          An instance of {@code ScrollingResults}, possibly fetched in a lazy manner (for temporary
2985
    *          cases).
2974 2986
    *
2975 2987
    * @throws  PersistenceException
2976 2988
    *          not thrown by this implementation.
......
2980 2992
   throws PersistenceException
2981 2993
   {
2982 2994
      Results results = null;
2995
      boolean temporary = persistence.isTemporary();
2996
      if (temporary)
2997
      {
2998
         Long templateRowid = getTemplateQueryRowid(args);
2999
         if (templateRowid != null)
3000
         {
3001
            results = super.executeQuery(persistence, fql, args);
3002
            return results;
3003
         }
3004
         
3005
         return new ScrollingResults(persistence, executeScroll(persistence, fql, args, temporary));
3006
      }
2983 3007
      
2984 3008
      if (cacheOnReval || probablyRequiresResort())
2985 3009
      {
......
3008 3032
      }
3009 3033
      
3010 3034
      return results;
3035
      
3036
   }
3037
   
3038
   /**
3039
    * Function responsible with returning a list of {@code ScrollableResults}.
3040
    * It converts the FQL into SQL and executes the query against the SQL server.
3041
    * If the query is intended for temporary tables, then the execution could be done in a lazy manner.
3042
    * 
3043
    * @param   <T>
3044
    *          The type of the rows returned in the list.
3045
    * @param   persistence
3046
    *          Object which is used to execute the query.
3047
    * @param   fql
3048
    *          FQL query string.
3049
    * @param   args
3050
    *          Substitution parameters to be inserted into placeholders within the FQL query
3051
    *          string.
3052
    * @param   lazyMode
3053
    *          Flag that indicates whether the query should be executed in a lazy manner.
3054
    *          Not all queries can be executed with this option, but the checks for that are not done here.
3055
    *          
3056
    * @return  A scrollable list of rows of type {@code <T>} from SQL server, as specified by the
3057
    *          {@code fql} query.
3058
    *          
3059
    * @throws  PersistenceException
3060
    *          when an error occurred while performing the requested operations.
3061
    */
3062
   protected <T> ScrollableResults<T> executeScroll(Persistence persistence,
3063
                                                    String fql,
3064
                                                    Object[] args,
3065
                                                    boolean lazyMode)
3066
   throws PersistenceException
3067
   {
3068
      int scrollMode = ResultSet.TYPE_SCROLL_INSENSITIVE;
3069
      return persistence.scroll(getEntities(), fql, args, 0, 0, scrollMode, lazyMode);
3011 3070
   }
3012 3071
   
3013 3072
   /**
new/src/com/goldencode/p2j/persist/Persistence.java 2023-02-14 11:06:38 +0000
584 584
**     OM  20221103          New class names for FQLPreprocessor, FQLExpression, FQLBundle, and FQLCache.
585 585
**     CA  20221109          Implemented runtime for EXCEPT/FIELDS options - only NO-LOCK records are loaded 
586 586
**                           as 'partial/incomplete'.
587
**     RAA 20230213          Added the possibility to create a query defined with lazy. 
587 588
*/
588 589

  
589 590
/*
......
1311 1312
                                          int scrollMode)
1312 1313
   throws PersistenceException
1313 1314
   {
1315
       return scroll(entities, fql, values, maxResults, startOffset, scrollMode, false);
1316
   }
1317
   
1318
   /**
1319
    * Execute an FQL query and get a scrollable cursor on the result set. Records represented by the result
1320
    * set are not locked by this method.
1321
    *
1322
    * @param   entities
1323
    *          Names of the DMO entities associated with this query statement.
1324
    * @param   fql
1325
    *          FQL query statement to be parsed and executed by ORM framework.
1326
    * @param   values
1327
    *          Substitution values for the query.  If none, this should be an empty array.
1328
    * @param   maxResults
1329
    *          The maximum number of elements to be returned in the list. If this value is non-positive, no
1330
    *          upper limit is applied.
1331
    * @param   startOffset
1332
    *          The 0-based offset of the first record to retrieve.  If this value is non-positive, an offset
1333
    *          of 0 is used by default.
1334
    * @param   scrollMode
1335
    *          Scroll mode which should apply to the result set.
1336
    * @param   lazyMode
1337
    *          Flag that indicates whether the query should be executed in a lazy manner.
1338
    *
1339
    * @return  An object which provides access to a scrollable cursor on the result set.
1340
    *
1341
    * @throws  PersistenceException
1342
    *          if there was an error executing the query.
1343
    */
1344
   public <T> ScrollableResults<T> scroll(String[] entities,
1345
                                          String fql,
1346
                                          Object[] values,
1347
                                          int maxResults,
1348
                                          int startOffset,
1349
                                          int scrollMode,
1350
                                          boolean lazyMode)
1351
   throws PersistenceException
1352
   {
1314 1353
      boolean trace = LOG.isLoggable(Level.FINEST);
1315 1354
      boolean warn = (trace || LOG.isLoggable(Level.WARNING));
1316 1355
      long start = (warn ? System.currentTimeMillis() : 0L);
......
1321 1360
      
1322 1361
      try
1323 1362
      {
1324
         Query query = getQuery(local, fql, maxResults, startOffset, values, readOnly);
1363
         Query query = getQuery(local, fql, maxResults, startOffset, values, readOnly, lazyMode);
1325 1364
         results = query.scroll(local.getSession(), scrollMode);
1326 1365
      }
1327 1366
      catch(UdfException exc)
......
3947 3986
                          boolean readOnly)
3948 3987
   throws PersistenceException
3949 3988
   {
3950
      Query query = local.getQuery(fql, maxResults, startOffset, readOnly);
3989
      return getQuery(local, fql, maxResults, startOffset, values, readOnly, false);
3990
   }
3991
   
3992
   /**
3993
    * Get or create a query for the given FQL query string. A cached query is used if it exists.
3994
    *
3995
    * @param   local
3996
    *          Context-local state.
3997
    * @param   fql
3998
    *          FQL query string.
3999
    * @param   maxResults
4000
    *          The maximum number of results to be returned by the query. If this value is
4001
    *          non-positive, no upper limit is applied.
4002
    * @param   startOffset
4003
    *          The 0-based offset of the first record to retrieve.  If this value is non-positive,
4004
    *          an offset of 0 is used by default.
4005
    * @param   values
4006
    *          Substitution values for the query.  If none, this should be an empty array.
4007
    * @param   readOnly
4008
    *          {@code true} to prepare the query in read-only mode, else {@code false}.
4009
    * @param   lazyMode
4010
    *          Flag that indicates whether the query should be executed in a lazy manner.
4011
    *
4012
    * @return  FQL query object.
4013
    *
4014
    * @throws  PersistenceException
4015
    *          if there was an error creating an ORM session.
4016
    */
4017
   private Query getQuery(Context local,
4018
                          String fql,
4019
                          int maxResults,
4020
                          int startOffset,
4021
                          Object[] values,
4022
                          boolean readOnly,
4023
                          boolean lazyMode)
4024
   throws PersistenceException
4025
   {
4026
      Query query = local.getQuery(fql, maxResults, startOffset, readOnly, lazyMode);
3951 4027
      
3952 4028
      // Bind parameters, if any.  It is OK to do this with cached queries, because each use is
3953 4029
      // guaranteed to reset the parameters.
......
4251 4327
      Query getQuery(String fql, int maxResults, int startOffset, boolean readOnly)
4252 4328
      throws PersistenceException
4253 4329
      {
4330
         return getQuery(fql, maxResults, startOffset, readOnly, false);
4331
      }
4332
      
4333
      /**
4334
       * Get a cached query for the given combination of FQL query string, maximum result rows,
4335
       * and starting row offset, creating and caching a new query if no such query already is
4336
       * cached. The cache is fixed size. When it is full and a new query needs to be added, the
4337
       * least recently used query is removed.
4338
       * 
4339
       * @param   fql
4340
       *          FQL query string.
4341
       * @param   maxResults
4342
       *          The maximum number of results to be returned.
4343
       * @param   startOffset
4344
       *          Zero-based offset of first result to be returned (undefined results unless
4345
       *          {@code fql} includes an {@code order by} phrase).
4346
       * @param   readOnly
4347
       *          {@code true} to execute the query in read-only mode, else {@code false}.
4348
       * @param   lazyMode
4349
       *          Flag that indicates whether the query should be executed in a lazy manner.
4350
       * 
4351
       * @return  A {@code Query} object for the requested {@code fql}.
4352
       * 
4353
       * @throws  PersistenceException
4354
       *          if there was an error creating an ORM session.
4355
       */
4356
      Query getQuery(String fql, int maxResults, int startOffset, boolean readOnly, boolean lazyMode)
4357
      throws PersistenceException
4358
      {
4254 4359
         Query query = null;
4255 4360
         fql = fql.trim(); // just in case
4256 4361
         
......
4281 4386
            // an incorrect value from a previous usage
4282 4387
            query.setMaxResults((maxResults > 0) ? maxResults : -1);
4283 4388
            query.setFirstResult(Math.max(startOffset, 0));
4389
            query.setLazyMode(lazyMode);
4284 4390
         }
4285 4391
         
4286 4392
         query.setReadOnly(readOnly);
new/src/com/goldencode/p2j/persist/orm/FqlToSqlConverter.java 2023-02-14 11:06:38 +0000
47 47
**     SVL 20230108 Improved performance by replacing some "for-each" loops with indexed "for" loops.
48 48
**         20221031 Collected fields of "select" query.
49 49
**         20221101 Fixed possible NPE.
50
**     RAA 20230213 Added the keyword "lazy". This can be appended to the SQL that gets generated.
50 51
*/
51 52

  
52 53
/*
......
192 193
   /** The maximum numbers of results in a query. Used for paging results. */
193 194
   private int maxResults = -1;
194 195
   
196
   /** Flag for selecting results in a lazy manner. Used in {@code Select} statements. */
197
   private boolean lazyMode = false;
198
   
195 199
   /** The offset of the record to start a result with. Used for paging results. */
196 200
   private int startOffset = -1;
197 201
   
......
530 534
    * @param   fql
531 535
    *          A valid {@code FQL} statement.
532 536
    * @param   maxResults
533
    *          The maximum numbers of results tobe returned.
537
    *          The maximum numbers of results to be returned.
534 538
    * @param   startOffset
535 539
    *          The start offset. Together with {@code maxResults} this parameter helps
536 540
    *          implementing paging of a bigger the result set.
......
543 547
    */
544 548
   public String toSQL(String fql, int maxResults, int startOffset, List<RowStructure> rowStructure)
545 549
   {
550
      return toSQL(fql, maxResults, startOffset, rowStructure, false);
551
   }
552
   
553
   /**
554
    * Converts a {@code FQL} statement into its SQL representation.
555
    * 
556
    * @param   fql
557
    *          A valid {@code FQL} statement.
558
    * @param   maxResults
559
    *          The maximum numbers of results to be returned.
560
    * @param   startOffset
561
    *          The start offset. Together with {@code maxResults} this parameter helps
562
    *          implementing paging of a bigger the result set.
563
    * @param   rowStructure
564
    *          (Acts as an output parameter). If not {@code null}, at return, the map will contain
565
    *          the list of entities returned and the number of fields coded in the generated
566
    *          {@code SELECT} statement for each of them.
567
    * @param   lazyMode
568
    *          Should the returned SQL execute the statement in a lazy manner?
569
    *          {@code true} if the answer is yes, {@code false} otherwise.
570
    *            
571
    * @return  The SQL representation of the {@code fql}. 
572
    */
573
   public String toSQL(String fql,
574
                       int maxResults,
575
                       int startOffset,
576
                       List<RowStructure> rowStructure,
577
                       boolean lazyMode)
578
   {
546 579
      if (LOG.isLoggable(Level.FINE))
547 580
      {
548 581
         LOG.log(Level.FINE, 
......
578 611
      sb = new StringBuilder(fql.length());
579 612
      this.maxResults = maxResults;
580 613
      this.startOffset = startOffset;
614
      this.lazyMode = lazyMode;
581 615
      processStatement(root);
582 616
      
583 617
      String sql = sb.toString();
......
1423 1457
         {
1424 1458
            generatePaging();
1425 1459
         }
1460
         
1461
         if (lazyMode)
1462
         {
1463
            generateLazyMode();
1464
         }
1426 1465
      }
1427 1466
      
1428 1467
      if (aliases.pop() != topLevelAliasMap)
......
1564 1603
   }
1565 1604
   
1566 1605
   /**
1606
    * Add the keyword "lazy" to the end of the SQL. This works only when there is a 
1607
    * {@code Select} statement that is intended to be executed in a lazy manner.
1608
    */
1609
   private void generateLazyMode()
1610
   {
1611
      sb.append("\n");
1612
      sb.append("lazy");
1613
   }
1614
   
1615
   /**
1567 1616
    * Generates the {@code ORDER BY} part of the query. The output is directly appended to
1568 1617
    * {@code sb}.
1569 1618
    * 
new/src/com/goldencode/p2j/persist/orm/Query.java 2023-02-14 11:06:38 +0000
26 26
**     SBI 20221023 Added a usage of SQLQuery.uniqueResult(Session session, RowStructure rowStructure).
27 27
**     CA  20221031 Javadoc fixes.
28 28
**     IAS 20230209 Fixed ${TZ} placeholder value
29
**     RAA 20230213 Added lazyMode flag. This is useful if the intention is to execute the query in a lazy
30
**                  manner.
29 31
*/
30 32

  
31 33
/*
......
127 129
   private int maxResults = -1;
128 130
   
129 131
   /**
132
    * Flag accepted by the {@code Select} query. If it is set to {@code true}, then the query will be
133
    * executed in a lazy manner.
134
    * By default, queries are executed in a preselect manner.
135
    */
136
   private boolean lazyMode = false;
137
   
138
   /**
130 139
    * The index of the first matching results accepted by the (SELECT) query. Used in combination 
131 140
    * with {@code firstResult} to configure result pagination.
132 141
    */
......
176 185
   }
177 186
   
178 187
   /**
188
    * Setter for the {@code lazyMode} flag.
189
    * Note: this method should only be called if the {@code Query} executed is a {@code Select}.
190
    * 
191
    * @param   lazyMode
192
    *          If {@code true}, the {@code Query} will be executed in a lazy manner.
193
    */
194
   public void setLazyMode(boolean lazyMode)
195
   {
196
      this.lazyMode = lazyMode;
197
   }
198
   
199
   /**
179 200
    * Configures the index of the first row to be returned by this query. Depending on the SQL
180 201
    * dialect from the {@code session}, the value is injected as the parameter of SQL
181 202
    * {@code limit} clause.
......
349 370
         {
350 371
            FqlToSqlConverter fql2sql = FqlToSqlConverter.getInstance(dialect, db, params);
351 372
            rowStructure = new ArrayList<>(2); // this should be enough for most cases
352
            String sql = fql2sql.toSQL(fql, maxResults, firstResult, rowStructure);
373
            String sql = fql2sql.toSQL(fql, maxResults, firstResult, rowStructure, lazyMode);
353 374
            paramCount = fql2sql.getLastConversionParamCount();
354 375
            wasRewritten = fql2sql.isQueryWasRewritten();
355 376
            userTableStatRead = fql2sql.isUserTableStatRead();