Project

General

Profile

6695.patch

Radu Apetrii, 10/31/2022 07:03 AM

Download (24.5 KB)

View differences:

new/src/com/goldencode/p2j/persist/AdaptiveQuery.java 2022-10-31 09:25:05 +0000
3276 3276
   protected void fetch(boolean available, LockType lockType, boolean errorIfNull)
3277 3277
   throws MissingRecordException
3278 3278
   {
3279
      if (available && getResults().isAutoFetch())
3280
      {
3281
         return;
3282
      }
3283

  
3279 3284
      super.fetch(available, lockType, errorIfNull);
3280 3285
      
3281 3286
      if (!isScrolling() && !foundFirst && available && offEnd == OffEnd.NONE)
......
3790 3795
      }
3791 3796
      
3792 3797
      /**
3798
       * Is the result delegate responsible for fetching? This is usually true when using
3799
       * query delegates which handle the fetching process already.
3800
       * 
3801
       * @return   {@code true} for complex results which also do the fetching
3802
       * 
3803
       */
3804
      @Override
3805
      public boolean isAutoFetch()
3806
      {
3807
         return true;
3808
      }
3809
      
3810
      /**
3793 3811
       * Get the array of objects at the current result row.
3794 3812
       *
3795 3813
       * @return  Object array or <code>null</code>.
3796 3814
       */
3797 3815
      public Object[] get()
3798 3816
      {
3799
         int len = buffers.length;
3800
         Object[] row = new Object[len];
3801
         for (int i = 0; i < len; i++)
3817
         return get(null);
3818
      }
3819
      
3820
      /**
3821
       * Get the array of objects at the current result row if lazy fetching allows it.
3822
       *
3823
       * @param   fetching
3824
       *          The instance responsible with lazy fetching.
3825
       * @return  Object array or <code>null</code>.
3826
       */
3827
      public Object[] get(LazyFetching fetching)
3828
      {
3829
         // if lazy fetching is not intended at all or
3830
         // if lazy fetching is intended and the record is OK to be used
3831
         if (fetching == null || fetching.isFullRecordOk())
3802 3832
         {
3803
            row[i] = get(i);
3833
            int len = buffers.length;
3834
            Object[] row = new Object[len];
3835
            for (int i = 0; i < len; i++)
3836
            {
3837
               row[i] = get(i);
3838
            }
3839
            
3840
            return row;
3804 3841
         }
3805 3842
         
3806
         return row;
3843
         throw new IllegalStateException("This kind of Results does not support lazy fetching");
3807 3844
      }
3808 3845
      
3809 3846
      /**
new/src/com/goldencode/p2j/persist/PreselectQuery.java 2022-10-27 13:02:52 +0000
585 585
**     OM  20220530          Fixed flush of nursery (only the affected index).
586 586
**     OM  20220701          Flatten calls to initialize().
587 587
**     CA  20221006          Added JMX instrumentation for query assemble. Refs #6814
588
**     RAA 20221010          Added class PreselectLazyFetching which enables the possibility of lazy fetching
589
**                           for Preselect queries on temporary no-undo tables.
588 590
**     CA  20221013          In 'repositionByID', if the row number is after the last row in the ResultSet,
589 591
**                           assume an error (query off-end) and do not try to fetch the record.
590 592
*/
......
762 764
   /** Has query been registered for resource cleanup? */
763 765
   private boolean regCleaner = false;
764 766
   
767
   /** Instance of lazy fetching. */
768
   private LazyFetching fetching = new PreselectLazyFetching();
769
   
765 770
   /** Cleaner executed when this query's block is exit. */
766 771
   private final Finalizable cleaner = new Finalizable()
767 772
   {
......
5669 5674
         }
5670 5675
         else
5671 5676
         {
5672
            Object[] data = available ? results.get() : null;
5673
            coreFetch(data, lockType, errorIfNull, false);
5677
            if (!results.isAutoFetch())
5678
            {
5679
               Object[] data = available ? results.get(fetching) : null;
5680
               coreFetch(data, lockType, errorIfNull, false);
5681
            }   
5674 5682
            
5675 5683
            if (available)
5676 5684
            {
......
5732 5740
   {
5733 5741
      int recFetched = 0;
5734 5742
      Iterator<QueryComponent> iter = components();
5743
      boolean isTemporary = persistence.isTemporary();
5744
      
5735 5745
      for (int i = 0; iter.hasNext(); i++)
5736 5746
      {
5737 5747
         QueryComponent comp = iter.next();
5738 5748
         RecordBuffer buffer = comp.getBuffer();
5749
           
5750
         if (isTemporary && !((TemporaryBuffer)buffer).isUndoable() && data != null && data[i] == null)
5751
         {
5752
            recFetched++;
5753
            continue;
5754
         }
5755
         
5739 5756
         boolean dirtyCopy = false;
5740 5757
         Record dmo = null;
5741 5758
         LockType lt = lockType;
......
6669 6686
      @Override
6670 6687
      public Object[] get()
6671 6688
      {
6672
         return (cursor == 0) ? new Object[] { templateRowid } : null; 
6689
         return get(null);
6690
      }
6691
      
6692
      /**
6693
       * Get the array of objects at the current result row if lazy fetching allows it.
6694
       *
6695
       * @param   fetching
6696
       *          The instance responsible with lazy fetching.
6697
       * @return  Object array or {@code null}.
6698
       */
6699
      @Override
6700
      public Object[] get(LazyFetching fetching)
6701
      {
6702
         if (cursor != 0)
6703
            return null;
6704
         
6705
         // if lazy fetching is not intended at all or
6706
         // if lazy fetching is intended and the record is OK to be used
6707
         if (fetching == null || fetching.isFullRecordOk())
6708
         {
6709
            return new Object[] { templateRowid };
6710
         }
6711
         
6712
         throw new IllegalStateException("This kind of Results does not support lazy fetching");
6673 6713
      }
6674 6714
      
6675 6715
      /**
......
6791 6831
         // else cursor is -1 (before), 0 (on single record), 1 (after)
6792 6832
      }
6793 6833
   }
6834
   
6835
   /**
6836
    * Class that implements the concept of {@link LazyFetching} for {@link PreselectQuery}.
6837
    * It provides a quick response as to whether a {@link Record} should be lazy fetched or not.
6838
    */
6839
   class PreselectLazyFetching
6840
   implements LazyFetching
6841
   {
6842

  
6843
      /**
6844
       * Method to check if a {@link Record} should be fully/partially fetched or not.
6845
       * Fully fetched means that a {@code Record} should be retrieved from the database,
6846
       * partially fetched means that a {@code Record} should be retrieved from the cache.
6847
       * 
6848
       * @param   comp
6849
       *          The number of the {@link QueryComponent} for which we check it's {@link RecordBuffer}.
6850
       * @param   id
6851
       *          The id of the {@code Record} that is about to be put in the {@code RecordBuffer}.
6852
       * @return  {@code true} if a {@code Record} should be fully/partially fetched, 
6853
       *          {@code false} otherwise.
6854
       */
6855
      @Override
6856
      public boolean shouldFetch(Integer comp, Long id)
6857
      {
6858
         QueryComponent component = components.get(comp);
6859
         RecordBuffer buffer = component.getBuffer();
6860
         if (!buffer.isTemporary() || ((TemporaryBuffer)buffer).isUndoable())
6861
         {
6862
            return true;
6863
         }
6864
         return component.checkFetching(id);
6865
         
6866
      }
6867

  
6868
      /**
6869
       * Setter for the {@code oldId}, which is responsible with knowing the id of the
6870
       * last {@code Record} that was inside the {@link RecordBuffer}.
6871
       * 
6872
       * @param   comp
6873
       *          The number of the {@link QueryComponent} for which we check it's {@code RecordBuffer}.
6874
       * @param   id
6875
       *          The id of the old {@code Record}.
6876
       */
6877
      @Override
6878
      public void setOldId(Integer comp, Long id)
6879
      {
6880
         components.get(comp).setOldId(id);
6881
      }
6882

  
6883
      /**
6884
       * Method for checking if the {@code Record} is hydrated or is affected by lazy fetching.
6885
       * 
6886
       * @return  {@code true} if the {@code Record} is hydrated and is OK to be used, 
6887
       *          {@code false} otherwise.  
6888
       */
6889
      @Override
6890
      public boolean isFullRecordOk()
6891
      {
6892
         return true;
6893
      }
6894
      
6895
   }
6794 6896
}
6795 6897

  
new/src/com/goldencode/p2j/persist/PresortCompoundQuery.java 2022-10-27 12:15:52 +0000
90 90
import java.io.*;
91 91
import java.util.*;
92 92
import com.goldencode.p2j.persist.lock.*;
93
import com.goldencode.p2j.persist.orm.LazyFetching;
93 94
import com.goldencode.p2j.util.*;
94 95

  
95 96
/**
......
651 652
       */
652 653
      public Object[] get()
653 654
      {
654
         return row;
655
         return get(null);
656
      }
657
      
658
      /**
659
       * Get the array of objects at the current result row if lazy fetching allows it.
660
       *
661
       * @param   fetching
662
       *          The instance responsible with lazy fetching.
663
       * @return  Object array or <code>null</code>.
664
       */
665
      public Object[] get(LazyFetching fetching)
666
      {
667
         // if lazy fetching is not intended at all or
668
         // if lazy fetching is intended and the record is OK to be used
669
         if (fetching == null || fetching.isFullRecordOk())
670
         {
671
            return row;
672
         }
673
         
674
         throw new IllegalStateException("This kind of Results does not support lazy fetching");   
655 675
      }
656 676
      
657 677
      /**
new/src/com/goldencode/p2j/persist/Presorter.java 2022-10-27 10:39:27 +0000
96 96
import java.util.function.*;
97 97
import com.goldencode.p2j.util.*;
98 98
import com.goldencode.p2j.persist.event.SessionListener;
99
import com.goldencode.p2j.persist.orm.LazyFetching;
99 100

  
100 101
/**
101 102
 * This helper class performs client-side (i.e., relative to the database
......
934 935
       */
935 936
      public Object[] get()
936 937
      {
938
         return get(null);
939
      }
940
      
941
      /**
942
       * Get the array of objects at the current result row if lazy fetching allows it.
943
       *
944
       * @param   fetching
945
       *          The instance responsible with lazy fetching.
946
       * @return  Object array or <code>null</code>.
947
       */
948
      public Object[] get(LazyFetching fetching)
949
      {
937 950
         if (scrolling)
938 951
         {
939
            return super.get();
952
            return super.get(fetching);
940 953
         }
941 954
         else
942 955
         {
943
            Object[] datum = (Object[]) currentRow;
944
            
945
            return datum;
956
            // if lazy fetching is not intended at all or
957
            // if lazy fetching is intended and the record is OK to be used
958
            if (fetching == null || fetching.isFullRecordOk())
959
            {
960
               Object[] datum = (Object[]) currentRow;
961
               return datum;
962
            }
963

  
964
            throw new IllegalStateException("Record is not hydrated and should be, in order to be used");
946 965
         }
947 966
      }
948 967
      
new/src/com/goldencode/p2j/persist/ProgressiveResults.java 2022-10-31 09:28:01 +0000
199 199
import java.util.*;
200 200
import java.util.logging.*;
201 201
import com.goldencode.p2j.persist.event.*;
202
import com.goldencode.p2j.persist.orm.LazyFetching;
202 203
import com.goldencode.p2j.util.*;
203 204
import com.goldencode.p2j.util.ErrorManager;
204 205

  
......
459 460
    */
460 461
   public Object[] get()
461 462
   {
463
      return get(null);
464
   }
465
   
466
   /**
467
    * Get the array of objects at the current result row.
468
    *
469
    * @param   fetching
470
    *          The instance responsible with lazy fetching. 
471
    * @return  Object array or <code>null</code>.
472
    */
473
   public Object[] get(LazyFetching fetching)
474
   {
462 475
      if (position < 0)
463 476
      {
464 477
         return null;
465 478
      }
466 479
      
480
      // we can use cache if lazy fetching is not intended at all or
481
      // if lazy fetching is intended and the record is OK to be used
482
      boolean canUseCache = fetching == null || fetching.isFullRecordOk();
483
      
467 484
      // If we have a cache and it contains the requested record, retrieve from the cache.
468
      if (cache != null && position < cache.size())
485
      if (canUseCache && cache != null && position < cache.size())
469 486
      {
470 487
         return cache.get(position);
471 488
      }
......
476 493
         Results results = getResults(bracket);
477 494
         if (results != null)
478 495
         {
479
            return results.get();
496
            return results.get(fetching);
480 497
         }
481 498
      }
482 499
      catch (Exception exc)
new/src/com/goldencode/p2j/persist/QueryComponent.java 2022-10-31 09:28:50 +0000
164 164
   /** Index information string as it is returned by INDEX-INFORMATION. */
165 165
   private String indexInfo = null;
166 166
   
167
   /** The id of the old Record that was in the buffer. */
168
   private Long oldId = null;
169
   
167 170
   /**
168 171
    * The list of dynamic filters. These are filters added dynamically, at runtime and can also be
169 172
    * removed dynamically.
......
828 831
   }
829 832
   
830 833
   /**
834
    * Method used for checking if fetching is necessary for this component.
835
    * 
836
    * @param   id
837
    *          The id of the {@code Record} that will potentially be fetched.
838
    * @return  true if the buffer needs to fetch this record, or false otherwise.
839
    */
840
   public boolean checkFetching(Long id)
841
   {
842
      Record record = buffer.getCurrentRecord();
843
      if (record == null)
844
      {
845
         return true;
846
      }
847
      
848
      Long bufferId = record.getId();
849
      if (bufferId != null && id.equals(bufferId) && id.equals(oldId))
850
      {
851
         return false;
852
      }
853
     
854
      return true;
855
   }
856
   
857
   /**
858
    * Setter for the old record's id.
859
    * 
860
    * @param   id
861
    *          The id of the record that was just fetched.
862
    */
863
   public void setOldId(Long id)
864
   {
865
      oldId = id;
866
   }
867
   
868
   /**
831 869
    * Set the record buffer for this component's query.
832 870
    * 
833 871
    * @param    buffer
new/src/com/goldencode/p2j/persist/Results.java 2022-10-31 09:29:16 +0000
71 71

  
72 72
package com.goldencode.p2j.persist;
73 73

  
74
import com.goldencode.p2j.persist.orm.LazyFetching;
75

  
74 76
/**
75 77
 * An abstraction layer between a joinable query implementation and its results.  This interface
76 78
 * defines methods for manipulating a results set using a scrollable cursor paradigm.  Each row
......
122 124
   public boolean isLast();
123 125
   
124 126
   /**
127
    * Method to implement if lazy fetching is intended. By default, this is not the case.
128
    * 
129
    * @return  {@code false} by default. If lazy fetching is intended, then this method needs
130
    *          to be implemented to return {@code true}. 
131
    */
132
   default public boolean isAutoFetch() 
133
   {
134
      return false;
135
   }
136
   
137
   /**
125 138
    * Get the array of objects at the current result row.
126 139
    *
127 140
    * @return  Object array or {@code null}.
......
129 142
   public Object[] get();
130 143
   
131 144
   /**
145
    * Get the array of objects at the current result row. The default method involves no lazy fetching.
146
    * If lazy fetching is desired, then this method needs to be implemented.
147
    * 
148
    * @param   fetching
149
    *          The instance responsible with lazy fetching.
150
    * @return  Array of {@code Object}s and {@code null}s.
151
    */
152
   default public Object[] get(LazyFetching fetching) 
153
   {
154
      if (fetching != null)
155
      {
156
         throw new IllegalStateException(this.getClass().getName() + 
157
                                         " does not implement get() with onlyDifferences.");
158
      }
159
      return get();
160
   }
161
   
162
   /**
132 163
    * Get the object at the current result row, at the specified column.
133 164
    *
134 165
    * @param   column
......
241 272
   {
242 273
      throw new IllegalStateException("Cannot add a row for this type of results");
243 274
   }
244
}
275
}
new/src/com/goldencode/p2j/persist/ResultsAdapter.java 2022-10-31 09:30:10 +0000
83 83

  
84 84
import java.io.*;
85 85

  
86
import com.goldencode.p2j.persist.orm.LazyFetching;
87

  
86 88
/**
87 89
 * An implementation of the {@code Results} interface which delegates all work to another {@code
88 90
 * Results} implementation.  A worker can be connected at any time using {@link #setResults}, or
......
203 205
   }
204 206
   
205 207
   /**
208
    * Is the result delegate responsible for fetching? This is usually true when using
209
    * query delegates which handle the fetching process already.
210
    * 
211
    * @return   {@code true} for complex results which also do the fetching
212
    * 
213
    */
214
   @Override
215
   public boolean isAutoFetch()
216
   {
217
      return results.isAutoFetch();
218
   }
219
   
220
   /**
206 221
    * Get the array of objects at the current result row.
207 222
    *
208 223
    * @return  Object array or {@code null}.
......
211 226
   {
212 227
      return results.get();
213 228
   }
229

  
230
   /**
231
    * Get the array of objects at the current result row if lazy fetching allows it.
232
    * 
233
    * @param   fetching
234
    *          The instance responsible with lazy fetching.
235
    * @return  Object array or {@code null}.
236
    */
237
   public Object[] get(LazyFetching fetching)
238
   {
239
      return results.get(fetching);
240
   }
214 241
   
215 242
   /**
216 243
    * Get the object at the current result row, at the specified column.
......
405 432
         provider.provideNewResults(this);
406 433
      }
407 434
   }
408
}
435
}
new/src/com/goldencode/p2j/persist/ScrollingResults.java 2022-10-31 09:30:33 +0000
197 197
   }
198 198
   
199 199
   /**
200
    * Get an array of objects or nulls at the current result row if lazy fetching allows it.
201
    * 
202
    * @param   fetching
203
    *          The instance responsible with lazy fetching.  
204
    * @return  Object array or <code>null</code>.
205
    */
206
   public Object[] get(LazyFetching fetching)
207
   {
208
      return results.get(fetching);
209
   }
210
   
211
   /**
200 212
    * Get the object at the current result row, at the specified column.
201 213
    *
202 214
    * @param   column
new/src/com/goldencode/p2j/persist/SimpleResults.java 2022-10-31 09:30:52 +0000
82 82

  
83 83
import java.util.*;
84 84

  
85
import com.goldencode.p2j.persist.orm.LazyFetching;
86

  
85 87
/**
86 88
 * A simple implementation of {@code Results} which stores row data in a list provided to the
87 89
 * constructor. The row data consists of a list of array objects. Each object in the array is
......
209 211
    */
210 212
   public Object[] get()
211 213
   {
214
      return get(null);
215
   }
216
   
217
   /**
218
    * Get the array of objects at the current result row if lazy fetching allows it.
219
    *
220
    * @param   fetching
221
    *          The instance responsible with lazy fetching.
222
    * @return  Object array or {@code null}.
223
    */
224
   public Object[] get(LazyFetching fetching)
225
   {
212 226
      if (position < 0 || position > getNumberOfLoadedRows() - 1)
213 227
      {
214 228
         return null;
215 229
      }
216 230
      
217
      Object res = rows.get(position);
218
      if (res instanceof Object[])
219
      {
220
         return (Object[]) res;
221
      }
222
      else
223
      {
224
          return new Object[] { res };
225
      }
226
   }
231
      // if lazy fetching is not intended at all or
232
      // if lazy fetching is intended and the record is OK to be used
233
      if (fetching == null || fetching.isFullRecordOk())
234
      {
235
         Object res = rows.get(position);
236
         if (res instanceof Object[])
237
         {
238
            return (Object[]) res;
239
         }
240
         else
241
         {
242
             return new Object[] { res };
243
         }
244
      }
245
      
246
      throw new IllegalStateException("This kind of Results does not support lazy fetching");
247
   } 
227 248
   
228 249
   /**
229 250
    * Get the object at the current result row, at the specified column.
new/src/com/goldencode/p2j/persist/orm/BaseRecord.java 2022-10-31 09:31:18 +0000
703 703
   }
704 704
   
705 705
   /**
706
    * Getter for the id of the current record.
707
    * 
708
    * @return  id
709
    *          The id that was requested.
710
    */
711
   public Long getId()
712
   {
713
      return id;
714
   }
715
   
716
   /**
706 717
    * Indicate whether any of this record's validatable properties are dirty and have not been validated.
707 718
    * 
708 719
    * @return  {@code true} if record needs validation, else {@code false}.
new/src/com/goldencode/p2j/persist/orm/ScrollableResults.java 2022-10-31 09:32:44 +0000
107 107
    * @param   session
108 108
    *          The {@code Session} to be used.
109 109
    */
110
   public ScrollableResults(Statement stmt, ResultSet rs, List<RowStructure> rowStructure, Session session)
110
   public ScrollableResults(Statement stmt, 
111
                            ResultSet rs, 
112
                            List<RowStructure> rowStructure, 
113
                            Session session)
111 114
   {
112 115
      this.stmt = stmt;
113 116
      this.rs = rs;
......
192 195
   }
193 196
   
194 197
   /**
195
    * Obtain the full set of values on current row. An array of primary keys or full {@code Record} will be
196
    * returned.
198
    * Obtain the full set of values on current row. An array of primary keys or full {@code Record}s,  
199
    * or {@code null}s will be returned. First two cases correspond to the need of fetching,
200
    * while {@code null} means that no fetching is necessary for that component.
197 201
    * 
202
    * @param   fetching
203
    *          The instance responsible with lazy fetching.
204
    *          
198 205
    * @return  An array of {@code Object} s if the cursor is on a valid position. Otherwise {@code null} is
199 206
    *          returned. The type of returned elements may be both {@code Long} when an array of PKs (recids)
200 207
    *          is queried or an array of full {@code Record}s. The caller is responsible for handling both
201 208
    *          cases (including hydration, if needed).
202 209
    */
203
   public Object[] get()
210
   public Object[] get(LazyFetching fetching)
204 211
   {
212
      
205 213
      return execute(() ->
206 214
      {
207 215
         int rowSize = (rowStructure == null) ? 0 : rowStructure.size();
......
227 235
            ret = new Object[rowSize];
228 236
            int rsOffset = 1;
229 237
            int recCnt = 0;
238
            
230 239
            for (RowStructure rowStruct : rowStructure)
231 240
            {
232 241
               int expColumnCount = rowStruct.count;
242
               Long object = rs.getLong(rsOffset);
243
 
244
               //if fetching is not null, lazy fetching is intended
245
               if (fetching != null)
246
               {
247
                  if (object != null && !fetching.shouldFetch(recCnt, object))
248
                  {
249
                     ret[recCnt] = null;
250
                     // position on next record
251
                     rsOffset += expColumnCount;
252
                     ++recCnt;
253
                     continue;
254
                  } 
255
               }
256
               
233 257
               try
234 258
               {
235 259
                  ret[recCnt] =
236 260
                     SQLQuery.hydrateRecord(rs, rowStruct.dmoClass, rsOffset, expColumnCount, session);
261
                  if (fetching != null)
262
                  {
263
                     fetching.setOldId(recCnt, object);
264
                  }
237 265
               }
238 266
               catch (PersistenceException e)
239 267
               {
......
250 278
   }
251 279
   
252 280
   /**
281
    * Obtain the full set of values on current row. An array of primary keys or full {@code Record} will be
282
    * returned.
283
    * 
284
    * @return  An array of {@code Object} s if the cursor is on a valid position. Otherwise {@code null} is
285
    *          returned. The type of returned elements may be both {@code Long} when an array of PKs (recids)
286
    *          is queried or an array of full {@code Record}s. The caller is responsible for handling both
287
    *          cases (including hydration, if needed).
288
    */
289
   public Object[] get()
290
   {
291
      return get(null);
292
   }
293
   
294
   /**
253 295
    * Obtain the selection of values on current row.
254 296
    * 
255 297
    * @param    dmoInfo