KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > execute > DependentResultSet


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.DependentResultSet
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.execute;
23
24 import org.apache.derby.iapi.services.sanity.SanityManager;
25 import org.apache.derby.iapi.error.StandardException;
26 import org.apache.derby.iapi.types.DataValueFactory;
27 import org.apache.derby.iapi.types.RowLocation;
28 import org.apache.derby.iapi.sql.execute.ExecRow;
29 import org.apache.derby.iapi.sql.execute.ExecIndexRow;
30 import org.apache.derby.iapi.sql.execute.ScanQualifier;
31 import org.apache.derby.iapi.store.access.ConglomerateController;
32 import org.apache.derby.iapi.store.access.ScanController;
33 import org.apache.derby.iapi.store.access.TransactionController;
34 import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
35 import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
36 import org.apache.derby.iapi.sql.execute.CursorResultSet;
37 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
38 import org.apache.derby.iapi.sql.Activation;
39 import org.apache.derby.iapi.types.RefDataValue;
40 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
41 import org.apache.derby.iapi.services.io.FormatableBitSet;
42 import org.apache.derby.iapi.services.loader.GeneratedMethod;
43 import org.apache.derby.iapi.store.access.Qualifier;
44 import org.apache.derby.iapi.sql.execute.ExecutionContext;
45 import org.apache.derby.iapi.sql.execute.TemporaryRowHolder;
46 import java.util.Vector JavaDoc;
47 import java.util.Properties JavaDoc;
48 import org.apache.derby.iapi.reference.SQLState;
49 import org.apache.derby.iapi.services.i18n.MessageService;
50
51
52
53 /**
54  * DependentResultSet should be used by only ON DELETE CASCADE/ON DELETE SET NULL ref
55  * actions implementation to gather the rows from the dependent tables.
56  * Idea is to scan the foreign key index for the rows in
57  * the source table matelized temporary result set. Scanning of foreign key index gives us the
58  * rows that needs to be deleted on dependent tables. Using the row location
59  * we got from the index , base row is fetched.
60 */

61 class DependentResultSet extends NoPutResultSetImpl implements CursorResultSet
62 {
63
64
65     ConglomerateController heapCC;
66     RowLocation baseRowLocation; // base row location we got from the index
67
ExecRow indexRow; //templeate to fetch the index row
68
IndexRow indexQualifierRow; // template for the index qualifier row
69
ScanController indexSC; // Index Scan Controller
70
StaticCompiledOpenConglomInfo indexScoci;
71     DynamicCompiledOpenConglomInfo indexDcoci;
72     int numFkColumns;
73     boolean isOpen; // source result set is opened or not
74
boolean deferred;
75     TemporaryRowHolderResultSet source; // Current parent table result set
76
TransactionController tc;
77     String JavaDoc parentResultSetId;
78     int[] fkColArray;
79     RowLocation rowLocation;
80     TemporaryRowHolder[] sourceRowHolders;
81     TemporaryRowHolderResultSet[] sourceResultSets;
82     int[] sourceOpened;
83     int sArrayIndex;
84     Vector JavaDoc sVector;
85
86
87     protected ScanController scanController;
88     protected boolean scanControllerOpened;
89     protected boolean isKeyed;
90     protected boolean firstScan = true;
91     protected ExecIndexRow startPosition;
92     protected ExecIndexRow stopPosition;
93     protected ExecRow candidate;
94
95     // set in constructor and not altered during
96
// life of object.
97
protected long conglomId;
98     protected DynamicCompiledOpenConglomInfo heapDcoci;
99     protected StaticCompiledOpenConglomInfo heapScoci;
100     protected GeneratedMethod resultRowAllocator;
101     protected GeneratedMethod startKeyGetter;
102     protected int startSearchOperator;
103     protected GeneratedMethod stopKeyGetter;
104     protected int stopSearchOperator;
105     protected Qualifier[][] qualifiers;
106     public String JavaDoc tableName;
107     public String JavaDoc userSuppliedOptimizerOverrides;
108     public String JavaDoc indexName;
109     protected boolean runTimeStatisticsOn;
110     protected FormatableBitSet accessedCols;
111     public int rowsPerRead;
112     public boolean forUpdate;
113     private boolean sameStartStopPosition;
114     public int isolationLevel;
115     public int lockMode;
116
117
118     // Run time statistics
119
private Properties JavaDoc scanProperties;
120     public String JavaDoc startPositionString;
121     public String JavaDoc stopPositionString;
122     public boolean isConstraint;
123     public boolean coarserLock;
124     public boolean oneRowScan;
125     protected long rowsThisScan;
126
127     //
128
// class interface
129
//
130
DependentResultSet(
131         long conglomId,
132         StaticCompiledOpenConglomInfo scoci,
133         Activation activation,
134         GeneratedMethod resultRowAllocator,
135         int resultSetNumber,
136         GeneratedMethod startKeyGetter, int startSearchOperator,
137         GeneratedMethod stopKeyGetter, int stopSearchOperator,
138         boolean sameStartStopPosition,
139         Qualifier[][] qualifiers,
140         String JavaDoc tableName,
141         String JavaDoc userSuppliedOptimizerOverrides,
142         String JavaDoc indexName,
143         boolean isConstraint,
144         boolean forUpdate,
145         int colRefItem,
146         int lockMode,
147         boolean tableLocked,
148         int isolationLevel,
149         int rowsPerRead,
150         boolean oneRowScan,
151         double optimizerEstimatedRowCount,
152         double optimizerEstimatedCost,
153         String JavaDoc parentResultSetId,
154         long fkIndexConglomId,
155         int fkColArrayItem,
156         int rltItem
157         ) throws StandardException
158     {
159         super(activation,
160                 resultSetNumber,
161                 optimizerEstimatedRowCount,
162                 optimizerEstimatedCost);
163
164         this.conglomId = conglomId;
165
166         /* Static info created at compile time and can be shared across
167          * instances of the plan.
168          * Dynamic info created on 1st instantiation of this ResultSet as
169          * it cannot be shared.
170          */

171         this.heapScoci = scoci;
172         heapDcoci = activation.getTransactionController().getDynamicCompiledConglomInfo(conglomId);
173
174         if (SanityManager.DEBUG) {
175             SanityManager.ASSERT( activation!=null, "table scan must get activation context");
176             SanityManager.ASSERT( resultRowAllocator!= null, "table scan must get row allocator");
177             if (sameStartStopPosition)
178             {
179                 SanityManager.ASSERT(stopKeyGetter == null,
180                     "stopKeyGetter expected to be null when sameStartStopPosition is true");
181             }
182         }
183
184         this.resultRowAllocator = resultRowAllocator;
185
186         this.startKeyGetter = startKeyGetter;
187         this.startSearchOperator = startSearchOperator;
188         this.stopKeyGetter = stopKeyGetter;
189         this.stopSearchOperator = stopSearchOperator;
190         this.sameStartStopPosition = sameStartStopPosition;
191         this.qualifiers = qualifiers;
192         this.tableName = tableName;
193         this.userSuppliedOptimizerOverrides = userSuppliedOptimizerOverrides;
194         this.indexName = "On Foreign Key"; // RESOLVE , get actual indexName;
195
this.isConstraint = isConstraint;
196         this.forUpdate = forUpdate;
197         this.rowsPerRead = rowsPerRead;
198         this.oneRowScan = oneRowScan;
199
200         // retrieve the valid column list from
201
// the saved objects, if it exists
202
this.accessedCols = null;
203         if (colRefItem != -1)
204         {
205             this.accessedCols = (FormatableBitSet)(activation.getPreparedStatement().
206                         getSavedObject(colRefItem));
207         }
208         
209         
210         //unless the table locking is specified in sys.systables,
211
//irrespective of what optimizer says choose record level
212
//locking for dependent result sets.
213
if (! tableLocked)
214         {
215             this.lockMode = TransactionController.MODE_RECORD;
216         }else
217         {
218             this.lockMode = lockMode;
219         }
220
221
222         //Because the scan for the tables in this result set are done
223
//internally for delete cascades, isolation should be set to
224
//REPEATABLE READ irrespective what the user level isolation level is.
225
this.isolationLevel = TransactionController.ISOLATION_REPEATABLE_READ;
226
227         runTimeStatisticsOn = (activation != null &&
228                                activation.getLanguageConnectionContext().getRunTimeStatisticsMode());
229
230         /* Only call row allocators once */
231         candidate = (ExecRow) resultRowAllocator.invoke(activation);
232         
233
234         tc = activation.getTransactionController();
235         //values required to scan the forein key index.
236
indexDcoci = tc.getDynamicCompiledConglomInfo(fkIndexConglomId);
237         indexScoci = tc.getStaticCompiledConglomInfo(fkIndexConglomId);
238         
239         this.parentResultSetId = parentResultSetId;
240         this.fkColArray = (int[])(activation.getPreparedStatement().
241                         getSavedObject(fkColArrayItem));
242
243         this.rowLocation = (RowLocation)(activation.getPreparedStatement().
244                                          getSavedObject(rltItem));
245         numFkColumns = fkColArray.length;
246         indexQualifierRow = new IndexRow(numFkColumns);
247         constructorTime += getElapsedMillis(beginTime);
248     }
249
250
251     /**
252      * Get a scan controller positioned using searchRow as
253      * the start/stop position. The assumption is that searchRow
254      * is of the same format as the index being opened.
255      * @param searchRow the row to match
256      * @exception StandardException on error
257      */

258
259
260     private ScanController openIndexScanController(ExecRow searchRow) throws StandardException
261     {
262         setupQualifierRow(searchRow);
263         indexSC = tc.openCompiledScan(
264                       false, // hold
265
TransactionController.OPENMODE_FORUPDATE, // update only
266
lockMode, // lock Mode
267
isolationLevel, //isolation level
268
(FormatableBitSet)null, // retrieve all fields
269
indexQualifierRow.getRowArray(), // startKeyValue
270
ScanController.GE, // startSearchOp
271
null, // qualifier
272
indexQualifierRow.getRowArray(), // stopKeyValue
273
ScanController.GT, // stopSearchOp
274
indexScoci,
275                       indexDcoci
276                       );
277
278         return indexSC;
279
280     }
281
282     
283     //reopen the scan with a differnt search row
284
private void reopenIndexScanController(ExecRow searchRow) throws StandardException
285     {
286
287         setupQualifierRow(searchRow);
288         indexSC.reopenScan(
289                         indexQualifierRow.getRowArray(), // startKeyValue
290
ScanController.GE, // startSearchOp
291
null, // qualifier
292
indexQualifierRow.getRowArray(), // stopKeyValue
293
ScanController.GT // stopSearchOp
294
);
295     }
296
297     
298     /*
299     ** Do reference copy for the qualifier row. No cloning.
300     ** So we cannot get another row until we are done with
301     ** this one.
302     */

303     private void setupQualifierRow(ExecRow searchRow)
304     {
305         Object JavaDoc[] indexColArray = indexQualifierRow.getRowArray();
306         Object JavaDoc[] baseColArray = searchRow.getRowArray();
307
308         for (int i = 0; i < numFkColumns; i++)
309         {
310             indexColArray[i] = baseColArray[fkColArray[i] - 1];
311         }
312     }
313
314
315     private void openIndexScan(ExecRow searchRow) throws StandardException
316     {
317
318         if (indexSC == null)
319         {
320             indexSC = openIndexScanController(searchRow);
321             //create a template for the index row
322
indexRow = indexQualifierRow.getClone();
323             indexRow.setColumn(numFkColumns + 1, rowLocation.getClone());
324
325         }else
326         {
327             reopenIndexScanController(searchRow);
328         }
329     }
330
331
332     /**
333       Fetch a row from the index scan.
334
335       @return The row or null. Note that the next call to fetch will
336       replace the columns in the returned row.
337       @exception StandardException Ooops
338       */

339     private ExecRow fetchIndexRow()
340          throws StandardException
341     {
342         if (!indexSC.fetchNext(indexRow.getRowArray()))
343         {
344             return null;
345         }
346         return indexRow;
347     }
348
349     
350
351     /**
352       Fetch the base row corresponding to the current index row
353
354       @return The base row row or null.
355       @exception StandardException Ooops
356       */

357     private ExecRow fetchBaseRow()
358          throws StandardException
359     {
360
361         if (currentRow == null)
362         {
363             currentRow =
364                 getCompactRow(candidate, accessedCols, (FormatableBitSet) null, isKeyed);
365         }
366
367         baseRowLocation = (RowLocation) indexRow.getColumn(indexRow.getRowArray().length);
368         boolean base_row_exists =
369             heapCC.fetch(
370                 baseRowLocation, candidate.getRowArray(),accessedCols);
371
372         if (SanityManager.DEBUG)
373         {
374             SanityManager.ASSERT(base_row_exists, "base row disappeared.");
375         }
376
377         return currentRow;
378     }
379     
380
381     ExecRow searchRow = null; //the current row we are searching for
382

383     //this function will return an index row on dependent table
384
public ExecRow getNextRowCore() throws StandardException
385     {
386         
387         beginTime = getCurrentTimeMillis();
388         if (searchRow == null)
389         {
390             //we are searching for a row first time
391
if((searchRow = getNextParentRow())!=null)
392                openIndexScan(searchRow);
393         }
394     
395         ExecRow currentIndexRow = null;
396         while(searchRow != null)
397         {
398             //get if the current search row has more
399
//than one row in the dependent tables
400
currentIndexRow = fetchIndexRow();
401     
402             if(currentIndexRow !=null)
403                 break;
404             if((searchRow = getNextParentRow())!=null)
405                openIndexScan(searchRow);
406         }
407
408         nextTime += getElapsedMillis(beginTime);
409         if(currentIndexRow!= null)
410         {
411             rowsSeen++;
412             return fetchBaseRow();
413         }else
414         {
415             return currentIndexRow;
416         }
417         
418         
419     }
420
421
422     //this function will return the rows from the parent result sets
423
private ExecRow getNextParentRow() throws StandardException
424     {
425
426         ExecRow cRow;
427         TemporaryRowHolder rowHolder;
428
429         if(sourceOpened[sArrayIndex] == 0)
430         {
431             rowHolder = sourceRowHolders[sArrayIndex];
432             source = (TemporaryRowHolderResultSet)rowHolder.getResultSet();
433             source.open(); //open the cursor result set
434
sourceOpened[sArrayIndex] = -1;
435             sourceResultSets[sArrayIndex] = source;
436         }
437
438         if(sourceOpened[sArrayIndex] == 1)
439         {
440             source = sourceResultSets[sArrayIndex];
441             source.reStartScan(sourceRowHolders[sArrayIndex].getTemporaryConglomId(),
442                               sourceRowHolders[sArrayIndex].getPositionIndexConglomId());
443             sourceOpened[sArrayIndex] = -1;
444             
445         }
446
447         if(sVector.size() > sourceRowHolders.length)
448         {
449             addNewSources();
450         }
451
452         cRow = source.getNextRow();
453         while(cRow == null && (sArrayIndex+1) < sourceRowHolders.length)
454         {
455
456             //opening the next source;
457
sArrayIndex++;
458             if(sourceOpened[sArrayIndex] == 0)
459             {
460                 rowHolder = sourceRowHolders[sArrayIndex];
461                 source = (TemporaryRowHolderResultSet)rowHolder.getResultSet();
462                 source.open(); //open the cursor result set
463
sourceOpened[sArrayIndex] = -1;
464                 sourceResultSets[sArrayIndex] = source;
465             }
466
467             if(sourceOpened[sArrayIndex] == 1)
468             {
469                 source = sourceResultSets[sArrayIndex];
470                 source.reStartScan(sourceRowHolders[sArrayIndex].getTemporaryConglomId(),
471                                   sourceRowHolders[sArrayIndex].getPositionIndexConglomId());
472                 sourceOpened[sArrayIndex] = -1;
473             }
474         
475             cRow = source.getNextRow();
476         }
477
478         if(cRow == null)
479         {
480             //which means no source has any more currently rows.
481
sArrayIndex = 0;
482             //mark all the sources to restartScan.
483
for(int i =0 ; i < sourceOpened.length ; i++)
484                 sourceOpened[i] = 1;
485         }
486         
487         return cRow;
488     }
489
490
491
492     /*
493     ** Open the heap Conglomerate controller
494     **
495     ** @param transaction controller will open one if null
496     */

497     public ConglomerateController openHeapConglomerateController()
498         throws StandardException
499     {
500         return tc.openCompiledConglomerate(
501                     false,
502                     TransactionController.OPENMODE_FORUPDATE,
503                     lockMode,
504                     isolationLevel,
505                     heapScoci,
506                     heapDcoci);
507     }
508
509
510
511
512     /**
513       Close the all the opens we did in this result set.
514       */

515     public void close()
516         throws StandardException
517     {
518         //save the information for the runtime stastics
519
// This is where we get the scan properties for the reference index scans
520
if (runTimeStatisticsOn)
521         {
522             startPositionString = printStartPosition();
523             stopPositionString = printStopPosition();
524             scanProperties = getScanProperties();
525         }
526
527         if (indexSC != null)
528         {
529             indexSC.close();
530             indexSC = null;
531         }
532
533         if ( heapCC != null )
534         {
535             heapCC.close();
536             heapCC = null;
537         }
538         if(isOpen)
539         {
540             source.close();
541         }
542         
543         closeTime += getElapsedMillis(beginTime);
544     }
545
546     public void finish() throws StandardException
547     {
548         if (source != null)
549             source.finish();
550         finishAndRTS();
551     }
552
553     public void openCore() throws StandardException
554     {
555
556         sVector = activation.getParentResultSet(parentResultSetId);
557         int size = sVector.size();
558         sourceRowHolders = new TemporaryRowHolder[size];
559         sourceOpened = new int[size];
560         sourceResultSets = new TemporaryRowHolderResultSet[size];
561         for(int i = 0 ; i < size ; i++)
562         {
563             sourceRowHolders[i] = (TemporaryRowHolder)sVector.elementAt(i);
564             sourceOpened[i] = 0;
565         }
566
567         //open the table scan
568
heapCC = openHeapConglomerateController();
569         numOpens++;
570         openTime += getElapsedMillis(beginTime);
571     }
572
573
574     private void addNewSources()
575     {
576         int size = sVector.size();
577         TemporaryRowHolder[] tsourceRowHolders = new TemporaryRowHolder[size];
578         int[] tsourceOpened = new int[size];
579         TemporaryRowHolderResultSet[] tsourceResultSets = new TemporaryRowHolderResultSet[size];
580         
581         //copy the source we have now
582
System.arraycopy(sourceRowHolders, 0, tsourceRowHolders, 0 , sourceRowHolders.length);
583         System.arraycopy(sourceOpened, 0, tsourceOpened , 0 ,sourceOpened.length);
584         System.arraycopy(sourceResultSets , 0, tsourceResultSets ,0 ,sourceResultSets.length);
585
586         //copy the new sources
587
for(int i = sourceRowHolders.length; i < size ; i++)
588         {
589             tsourceRowHolders[i] = (TemporaryRowHolder)sVector.elementAt(i);
590             tsourceOpened[i] = 0;
591         }
592
593         sourceRowHolders = tsourceRowHolders;
594         sourceOpened = tsourceOpened ;
595         sourceResultSets = tsourceResultSets;
596     }
597
598
599
600     /**
601      * Can we get instantaneous locks when getting share row
602      * locks at READ COMMITTED.
603      */

604     private boolean canGetInstantaneousLocks()
605     {
606         return false;
607     }
608
609
610     public long getTimeSpent(int type)
611     {
612         return constructorTime + openTime + nextTime + closeTime;
613     }
614
615
616     //Cursor result set information.
617
public RowLocation getRowLocation() throws StandardException
618     {
619         return baseRowLocation;
620     }
621
622     public ExecRow getCurrentRow() throws StandardException
623     {
624         return currentRow;
625     }
626
627
628     public Properties JavaDoc getScanProperties()
629     {
630         if (scanProperties == null)
631         {
632             scanProperties = new Properties JavaDoc();
633         }
634         try
635         {
636             if (indexSC != null)
637             {
638                 indexSC.getScanInfo().getAllScanInfo(scanProperties);
639                 /* Did we get a coarser lock due to
640                  * a covering lock, lock escalation
641                  * or configuration?
642                  */

643                 coarserLock = indexSC.isTableLocked() &&
644                     (lockMode == TransactionController.MODE_RECORD);
645             }
646         }
647         catch(StandardException se)
648         {
649                 // ignore
650
}
651
652         return scanProperties;
653     }
654
655     public String JavaDoc printStartPosition()
656     {
657         return printPosition(ScanController.GE, indexQualifierRow);
658     }
659
660     public String JavaDoc printStopPosition()
661     {
662         return printPosition(ScanController.GT, indexQualifierRow);
663     }
664
665
666     /**
667      * Return a start or stop positioner as a String.
668      *
669      * If we already generated the information, then use
670      * that. Otherwise, invoke the activation to get it.
671      */

672     private String JavaDoc printPosition(int searchOperator, ExecIndexRow positioner)
673     {
674         String JavaDoc idt = "";
675         String JavaDoc output = "";
676
677         String JavaDoc searchOp = null;
678         switch (searchOperator)
679         {
680             case ScanController.GE:
681                 searchOp = ">=";
682                 break;
683
684             case ScanController.GT:
685                 searchOp = ">";
686                 break;
687
688             default:
689                 if (SanityManager.DEBUG)
690                 {
691                     SanityManager.THROWASSERT("Unknown search operator " +
692                                                 searchOperator);
693                 }
694
695                 // NOTE: This does not have to be internationalized because
696
// this code should never be reached.
697
searchOp = "unknown value (" + searchOperator + ")";
698                 break;
699         }
700
701         if(positioner !=null)
702         {
703             output = output + "\t" +
704                 MessageService.getTextMessage(
705                                           SQLState.LANG_POSITIONER,
706                                           searchOp,
707                                           String.valueOf(positioner.nColumns())) +
708                 "\n";
709
710             output = output + "\t" +
711                 MessageService.getTextMessage(
712                                               SQLState.LANG_ORDERED_NULL_SEMANTICS) +
713                 "\n";
714             for (int position = 0; position < positioner.nColumns(); position++)
715             {
716                 if (positioner.areNullsOrdered(position))
717                 {
718                     output = output + position + " ";
719                 }
720             }
721     
722         }
723     
724         return output + "\n";
725     }
726
727
728     /**
729      * Return an array of Qualifiers as a String
730      */

731     public String JavaDoc printQualifiers()
732     {
733         //There are no qualifiers in thie result set for index scans.
734
String JavaDoc idt = "";
735         return idt + MessageService.getTextMessage(SQLState.LANG_NONE);
736     }
737 }
738
739
740
741
742
743
744
745
746
747
748
749
Popular Tags