KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > catalog > TabInfoImpl


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.catalog.TabInfoImpl
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.catalog;
23
24 import org.apache.derby.iapi.services.io.FormatableBitSet;
25 import org.apache.derby.iapi.services.context.ContextService;
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27 import org.apache.derby.iapi.services.io.StreamStorable;
28 import org.apache.derby.iapi.error.StandardException;
29 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
30 import org.apache.derby.iapi.sql.dictionary.CatalogRowFactory;
31 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
32 import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
33 import org.apache.derby.iapi.sql.execute.ExecIndexRow;
34 import org.apache.derby.iapi.sql.execute.ExecRow;
35 import org.apache.derby.iapi.sql.execute.ExecutionContext;
36 import org.apache.derby.iapi.sql.execute.ExecutionFactory;
37 import org.apache.derby.iapi.sql.execute.RowChanger;
38 import org.apache.derby.iapi.sql.execute.TupleFilter;
39 import org.apache.derby.iapi.sql.Activation;
40
41 import org.apache.derby.iapi.store.access.ConglomerateController;
42 import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
43 import org.apache.derby.iapi.store.access.Qualifier;
44 import org.apache.derby.iapi.store.access.ScanController;
45 import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
46 import org.apache.derby.iapi.store.access.TransactionController;
47
48 import org.apache.derby.iapi.types.DataValueDescriptor;
49 import org.apache.derby.iapi.types.DataValueFactory;
50
51 import org.apache.derby.iapi.types.RowLocation;
52 import org.apache.derby.catalog.UUID;
53 import java.util.Enumeration JavaDoc;
54 import java.util.Properties JavaDoc;
55
56 /**
57 * A poor mans structure used in DataDictionaryImpl.java.
58 * Used to save heapId, name pairs for non core tables.
59 *
60 * @author jamie
61 */

62 class TabInfoImpl
63 {
64     /**
65      * ROWNOTDUPLICATE is out of range for a row
66      * number. If a return code does not equal
67      * this value, then it refers to the row
68      * that is a duplicate.
69      */

70     static final int ROWNOTDUPLICATE = -1;
71
72     private IndexInfoImpl[] indexes;
73     private long heapConglomerate;
74     private int numIndexesSet;
75     private boolean heapSet;
76     private final CatalogRowFactory crf;
77
78     /**
79      * Constructor
80      *
81      * @param crf the associated CatalogRowFactory
82      */

83     TabInfoImpl(CatalogRowFactory crf)
84     {
85         this.heapConglomerate = -1;
86         this.crf = crf;
87
88         int numIndexes = crf.getNumIndexes();
89
90         if (numIndexes > 0)
91         {
92             indexes = new IndexInfoImpl[numIndexes];
93
94             /* Init indexes */
95             for (int indexCtr = 0; indexCtr < numIndexes; indexCtr++)
96             {
97                 indexes[indexCtr] = new IndexInfoImpl(
98                                             indexCtr,
99                                             crf);
100             }
101         }
102     }
103
104     /**
105      * Get the conglomerate for the heap.
106      *
107      * @return long The conglomerate for the heap.
108      */

109     long getHeapConglomerate()
110     {
111         return heapConglomerate;
112     }
113
114     /**
115      * Set the heap conglomerate for this.
116      *
117      * @param heapConglomerate The new heap conglomerate.
118      */

119     void setHeapConglomerate(long heapConglomerate)
120     {
121         this.heapConglomerate = heapConglomerate;
122         heapSet = true;
123     }
124
125     /**
126      * Get the conglomerate for the specified index.
127      *
128      * @return long The conglomerate for the specified index.
129      */

130     long getIndexConglomerate(int indexID)
131     {
132         if (SanityManager.DEBUG)
133         {
134             SanityManager.ASSERT(indexes != null,
135                 "indexes is expected to be non-null");
136             if (indexID >= indexes.length)
137             {
138                 SanityManager.THROWASSERT(
139                     "indexID (" + indexID + ") is out of range(0-" +
140                     indexes.length + ")");
141             }
142         }
143
144         return indexes[indexID].getConglomerateNumber();
145     }
146
147     /**
148      * Set the index conglomerate for the table.
149      *
150      * @param index Index number for index for table
151      * @param indexConglomerate The conglomerate for that index
152      */

153     void setIndexConglomerate(int index, long indexConglomerate)
154     {
155         /* Index names must be set before conglomerates.
156          * Also verify that we are not setting the same conglomerate
157          * twice.
158          */

159         if (SanityManager.DEBUG)
160         {
161             SanityManager.ASSERT(indexes[index] != null,
162                 "indexes[index] expected to be non-null");
163             SanityManager.ASSERT(indexes[index].getConglomerateNumber() == -1,
164                 "indexes[index] expected to be -1");
165         }
166         indexes[index].setConglomerateNumber(indexConglomerate);
167
168         /* We are completely initialized when all indexes have
169          * their conglomerates initialized
170          */

171         numIndexesSet++;
172     }
173
174     /**
175      * Set the index conglomerate for the table.
176      *
177      * @param cd The ConglomerateDescriptor for one of the index
178      * for this table.
179      */

180     void setIndexConglomerate(ConglomerateDescriptor cd)
181     {
182         int index;
183         String JavaDoc indexName = cd.getConglomerateName();
184
185         if (SanityManager.DEBUG)
186         {
187             SanityManager.ASSERT(indexes != null,
188                 "indexes is expected to be non-null");
189         }
190
191         for (index = 0; index < indexes.length; index++)
192         {
193             /* All index names expected to be set before
194              * any conglomerate is set.
195              */

196             if (SanityManager.DEBUG)
197             {
198                 SanityManager.ASSERT(indexes[index] != null,
199                     "indexes[index] expected to be non-null");
200                 SanityManager.ASSERT(indexes[index].getIndexName() != null,
201                     "indexes[index].getIndexName() expected to be non-null");
202             }
203
204             /* Do we have a match? */
205             if (indexes[index].getIndexName().equals(indexName))
206             {
207                 indexes[index].setConglomerateNumber(cd.getConglomerateNumber());
208                 break;
209             }
210         }
211
212         if (SanityManager.DEBUG)
213         {
214             if (index == indexes.length)
215             {
216                 SanityManager.THROWASSERT("match not found for " + indexName);
217             }
218         }
219
220         /* We are completely initialized when all indexIds are initialized */
221         numIndexesSet++;
222     }
223
224     /**
225      * Get the table name.
226      *
227      * @return String The table name.
228      */

229     String JavaDoc getTableName()
230     {
231         return crf.getCatalogName();
232     }
233
234     /**
235      * Get the index name.
236      *
237      * @param indexId Index number for index for table
238      *
239      * @return String The index name.
240      */

241     String JavaDoc getIndexName(int indexId)
242     {
243         return indexes[indexId].getIndexName();
244     }
245
246     /**
247      * Get the CatalogRowFactory for this.
248      *
249      * @return CatalogRowFactory The CatalogRowFactory for this.
250      */

251     CatalogRowFactory getCatalogRowFactory()
252     {
253         return crf;
254     }
255
256     /**
257      * Is this fully initialized.
258      * (i.e., is all conglomerate info initialized)
259      *
260      * @return boolean Whether or not this is fully initialized.
261      */

262     boolean isComplete()
263     {
264         /* We are complete when heap conglomerate and all
265          * index conglomerates are set.
266          */

267         if (! heapSet)
268         {
269             return false;
270         }
271         return (indexes == null || indexes.length == numIndexesSet);
272     }
273
274     /**
275      * Get the column count for the specified index number.
276      *
277      * @param indexNumber The index number.
278      *
279      * @return int The column count for the specified index.
280      */

281     int getIndexColumnCount(int indexNumber)
282     {
283         if (SanityManager.DEBUG)
284         {
285             SanityManager.ASSERT(indexes != null,
286                 "indexes is expected to be non-null");
287
288             if (!(indexNumber < indexes.length))
289             {
290                 SanityManager.THROWASSERT("indexNumber (" + indexNumber + ") is out of range(0-" +
291                 indexes.length + ")");
292             }
293         }
294
295         return indexes[indexNumber].getColumnCount();
296     }
297
298     /**
299      * Get the IndexRowGenerator for the specified index number.
300      *
301      * @param indexNumber The index number.
302      *
303      * @return IndexRowGenerator The IRG for the specified index number.
304      */

305     IndexRowGenerator getIndexRowGenerator(int indexNumber)
306     {
307         if (SanityManager.DEBUG)
308         {
309             SanityManager.ASSERT(indexes != null,
310                 "indexes is expected to be non-null");
311             if (indexNumber >= indexes.length)
312             {
313                 SanityManager.THROWASSERT(
314                     "indexNumber (" + indexNumber + ") is out of range(0-" +
315                     indexes.length + ")");
316             }
317         }
318         return indexes[indexNumber].getIndexRowGenerator();
319     }
320
321     /**
322      * Set the IndexRowGenerator for the specified index number.
323      *
324      * @param indexNumber The index number.
325      * @param irg The IndexRowGenerator for the specified index number.
326      */

327     void setIndexRowGenerator(int indexNumber, IndexRowGenerator irg)
328     {
329         if (SanityManager.DEBUG)
330         {
331             SanityManager.ASSERT(indexes != null,
332                 "indexes is expected to be non-null");
333             if (indexNumber >= indexes.length)
334             {
335                 SanityManager.THROWASSERT(
336                     "indexNumber (" + indexNumber + ") is out of range(0-" +
337                     indexes.length + ")");
338             }
339         }
340
341         indexes[indexNumber].setIndexRowGenerator(irg);
342     }
343
344     /**
345      * Get the number of indexes on this catalog.
346      *
347      * @return int The number of indexes on this catalog.
348      */

349     int getNumberOfIndexes()
350     {
351         if (indexes == null)
352         {
353             return 0;
354         }
355         else
356         {
357             return indexes.length;
358         }
359     }
360
361     /**
362      * Get the base column position for a column within a catalog
363      * given the (0-based) index number for this catalog and the
364      * (0-based) column number for the column within the index.
365      *
366      * @param indexNumber The index number
367      * @param colNumber The column number within the index
368      *
369      * @return int The base column position for the column.
370      */

371     int getBaseColumnPosition(int indexNumber, int colNumber)
372     {
373         if (SanityManager.DEBUG)
374         {
375             SanityManager.ASSERT(indexes != null,
376                 "indexes is expected to be non-null");
377             if (indexNumber >= indexes.length)
378             {
379                 SanityManager.THROWASSERT("indexNumber (" + indexNumber + ") is out of range(0-" +
380                     indexes.length + ")");
381             }
382         }
383
384         return indexes[indexNumber].getBaseColumnPosition(colNumber);
385     }
386
387     /**
388      * Return whether or not this index is declared unique
389      *
390      * @param indexNumber The index number
391      *
392      * @return boolean Whether or not this index is declared unique
393      */

394     boolean isIndexUnique(int indexNumber)
395     {
396         if (SanityManager.DEBUG)
397         {
398             SanityManager.ASSERT(indexes != null,
399                 "indexes is expected to be non-null");
400
401             if (indexNumber >= indexes.length)
402             {
403                 SanityManager.THROWASSERT("indexNumber (" + indexNumber + ") is out of range(0-" +
404                     indexes.length + ")");
405             }
406         }
407
408         return indexes[indexNumber].isIndexUnique();
409     }
410
411     /**
412      * Inserts a base row into a catalog and inserts all the corresponding
413      * index rows.
414      *
415      * @param row row to insert
416      * @param tc transaction
417      * @param wait to wait on lock or quickly TIMEOUT
418      * @return row number (>= 0) if duplicate row inserted into an index
419      * ROWNOTDUPLICATE otherwise
420      *
421      * @exception StandardException Thrown on failure
422      */

423     int insertRow( ExecRow row, TransactionController tc, boolean wait)
424         throws StandardException
425     {
426
427         RowLocation[] notUsed = new RowLocation[1];
428
429         return insertRowListImpl(new ExecRow[] {row},tc,notUsed, wait);
430     }
431
432     /**
433      * Inserts a list of base rows into a catalog and inserts all the corresponding
434      * index rows.
435      *
436      * @param rowList List of rows to insert
437      * @param tc transaction controller
438      *
439      *
440      * @return row number (>= 0) if duplicate row inserted into an index
441      * ROWNOTDUPLICATE otherwise
442      *
443      * @exception StandardException Thrown on failure
444      */

445     int insertRowList(ExecRow[] rowList, TransactionController tc )
446         throws StandardException
447     {
448         RowLocation[] notUsed = new RowLocation[1];
449
450         return insertRowListImpl(rowList,tc,notUsed, true);
451     }
452
453     /**
454       Insert logic to insert a list of rows into a table. This logic has two
455       odd features.
456
457       <OL>
458       <LI>Returns an indication if any returned row was a duplicate.
459       <LI>Returns the RowLocation of the last row inserted.
460       </OL>
461       @param rowList the list of rows to insert
462       @param tc transaction controller
463       @param rowLocationOut on output rowLocationOut[0] is set to the
464              last RowLocation inserted.
465       @param wait to wait on lock or quickly TIMEOUT
466       @return row number (>= 0) if duplicate row inserted into an index
467                 ROWNOTDUPLICATE otherwise
468      */

469     private int insertRowListImpl(ExecRow[] rowList, TransactionController tc, RowLocation[] rowLocationOut,
470                                    boolean wait)
471         throws StandardException
472     {
473         ConglomerateController heapController;
474         RowLocation heapLocation;
475         ExecIndexRow indexableRow;
476         int insertRetCode;
477         int retCode = ROWNOTDUPLICATE;
478         int indexCount = crf.getNumIndexes();
479         ConglomerateController[] indexControllers = new ConglomerateController[ indexCount ];
480
481         // Open the conglomerates
482
heapController =
483             tc.openConglomerate(
484                 getHeapConglomerate(),
485                 false,
486                 (TransactionController.OPENMODE_FORUPDATE |
487                     ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
488                 TransactionController.MODE_RECORD,
489                 TransactionController.ISOLATION_REPEATABLE_READ);
490         
491         /* NOTE: Due to the lovely problem of trying to add
492          * a new column to syscolumns and an index on that
493          * column during upgrade, we have to deal with the
494          * issue of the index not existing yet. So, it's okay
495          * if the index doesn't exist yet. (It will magically
496          * get created at a later point during upgrade.)
497          */

498
499         for ( int ictr = 0; ictr < indexCount; ictr++ )
500         {
501             long conglomNumber = getIndexConglomerate(ictr);
502             if (conglomNumber > -1)
503             {
504                 indexControllers[ ictr ] =
505                     tc.openConglomerate(
506                         conglomNumber,
507                         false,
508                         (TransactionController.OPENMODE_FORUPDATE |
509                             ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
510                         TransactionController.MODE_RECORD,
511                         TransactionController.ISOLATION_REPEATABLE_READ);
512             }
513         }
514
515         heapLocation = heapController.newRowLocationTemplate();
516         rowLocationOut[0]=heapLocation;
517
518         // loop through rows on this list, inserting them into system table
519
for (int rowNumber = 0; rowNumber < rowList.length; rowNumber++)
520         {
521             ExecRow row = rowList[rowNumber];
522             // insert the base row and get its new location
523
heapController.insertAndFetchLocation(row.getRowArray(), heapLocation);
524             
525             for ( int ictr = 0; ictr < indexCount; ictr++ )
526             {
527                 if (indexControllers[ ictr ] == null)
528                 {
529                     continue;
530                 }
531
532                 // Get an index row based on the base row
533
indexableRow = getIndexRowFromHeapRow( getIndexRowGenerator(ictr),
534                                                        heapLocation,
535                                                        row );
536
537                 insertRetCode =
538                     indexControllers[ ictr ].insert(indexableRow.getRowArray());
539
540                 if ( insertRetCode == ConglomerateController.ROWISDUPLICATE )
541                 {
542                     retCode = rowNumber;
543                 }
544             }
545
546         } // end loop through rows on list
547

548         // Close the open conglomerates
549
for ( int ictr = 0; ictr < indexCount; ictr++ )
550         {
551             if (indexControllers[ ictr ] == null)
552             {
553                 continue;
554             }
555
556             indexControllers[ ictr ].close();
557         }
558         heapController.close();
559
560         return retCode;
561     }
562
563
564     /**
565       * Given a key row, delete all matching heap rows and their index
566       * rows.
567       * <p>
568       * LOCKING: row locking if there is a key; otherwise,
569       * table locking.
570       *
571       * @param tc transaction controller
572       * @param key key to delete by.
573       * @param indexNumber Key is appropriate for this index.
574       * @return the number of rows deleted. If key is not unique,
575       * this may be more than one.
576       * @exception StandardException Thrown on failure
577       */

578     int deleteRow( TransactionController tc, ExecIndexRow key, int indexNumber )
579         throws StandardException
580     {
581         // Always row locking
582
return deleteRows(tc,
583                            key,
584                            ScanController.GE,
585                            null,
586                            null,
587                            key,
588                            ScanController.GT,
589                            indexNumber,
590                            true);
591     }
592
593     int deleteRow( TransactionController tc, ExecIndexRow key,
594                             int indexNumber, boolean wait)
595         throws StandardException
596     {
597         // Always row locking
598
return deleteRows(tc,
599                            key,
600                            ScanController.GE,
601                            null,
602                            null,
603                            key,
604                            ScanController.GT,
605                            indexNumber,
606                            wait);
607     }
608     
609     /**
610       * Delete the set of rows defined by a scan on an index
611       * from the table. Most of the parameters are simply passed
612       * to TransactionController.openScan. Please refer to the
613       * TransactionController documentation for details.
614       * <p>
615       * LOCKING: row locking if there is a start and a stop
616       * key; otherwise, table locking
617       *
618       * @param tc transaction controller
619       * @param startKey key to start the scan.
620       * @param startOp operation to start the scan.
621       * @param stopKey key to start the scan.
622       * @param qualifier a qualifier for the scan.
623       * @param filter filter on base rows
624       * @param stopOp operation to start the scan.
625       * @param indexNumber Key is appropriate for this index.
626       * @return the number of rows deleted.
627       * @exception StandardException Thrown on failure
628       * @see TransactionController#openScan
629       */

630     int deleteRows(TransactionController tc,
631                             ExecIndexRow startKey,
632                             int startOp,
633                             Qualifier[][] qualifier,
634                             TupleFilter filter,
635                             ExecIndexRow stopKey,
636                             int stopOp,
637                             int indexNumber) throws StandardException
638     {
639         return deleteRows(tc,
640                    startKey,
641                    startOp,
642                    qualifier,
643                    filter,
644                    stopKey,
645                    stopOp,
646                    indexNumber,
647                    true);
648     }
649
650     /**
651      * @inheritDoc
652      */

653     private int deleteRows(TransactionController tc,
654                           ExecIndexRow startKey,
655                           int startOp,
656                           Qualifier[][] qualifier,
657                           TupleFilter filter,
658                           ExecIndexRow stopKey,
659                           int stopOp,
660                           int indexNumber,
661                           boolean wait)
662          throws StandardException
663     {
664         ConglomerateController heapCC;
665         ScanController drivingScan;
666         ExecIndexRow drivingIndexRow;
667         RowLocation baseRowLocation;
668         RowChanger rc;
669         ExecRow baseRow = crf.makeEmptyRow();
670         int rowsDeleted = 0;
671         boolean passedFilter = true;
672         
673         rc = getRowChanger( tc, (int[])null,baseRow );
674
675         /*
676         ** If we have a start and a stop key, then we are going to
677         ** get row locks, otherwise, we are getting table locks.
678         ** This may be excessive locking for the case where there
679         ** is a start key and no stop key or vice versa.
680         */

681         int lockMode = ((startKey != null) && (stopKey != null)) ?
682                 tc.MODE_RECORD :
683                 tc.MODE_TABLE;
684
685         /*
686         ** Don't use level 3 if we have the same start/stop key.
687         */

688         int isolation =
689             ((startKey != null) && (stopKey != null) && (startKey == stopKey)) ?
690                 TransactionController.ISOLATION_REPEATABLE_READ :
691                 TransactionController.ISOLATION_SERIALIZABLE;
692
693         // Row level locking
694
rc.open(lockMode, wait);
695
696         DataValueDescriptor[] startKeyRow =
697             startKey == null ? null : startKey.getRowArray();
698
699         DataValueDescriptor[] stopKeyRow =
700             stopKey == null ? null : stopKey.getRowArray();
701
702         /* Open the heap conglomerate */
703         heapCC = tc.openConglomerate(
704                     getHeapConglomerate(),
705                     false,
706                     (TransactionController.OPENMODE_FORUPDATE |
707                             ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
708                     lockMode,
709                     TransactionController.ISOLATION_REPEATABLE_READ);
710
711         drivingScan = tc.openScan(
712             getIndexConglomerate(indexNumber), // conglomerate to open
713
false, // don't hold open across commit
714
(TransactionController.OPENMODE_FORUPDATE |
715                 ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
716             lockMode,
717             isolation,
718             (FormatableBitSet) null, // all fields as objects
719
startKeyRow, // start position - first row
720
startOp, // startSearchOperation
721
qualifier, //scanQualifier
722
stopKeyRow, // stop position - through last row
723
stopOp); // stopSearchOperation
724

725         // Get an index row based on the base row
726
drivingIndexRow = getIndexRowFromHeapRow(
727             getIndexRowGenerator( indexNumber ),
728             heapCC.newRowLocationTemplate(),
729             crf.makeEmptyRow());
730
731         while (drivingScan.fetchNext(drivingIndexRow.getRowArray()))
732         {
733             baseRowLocation = (RowLocation)
734                         drivingIndexRow.getColumn(drivingIndexRow.nColumns());
735
736             boolean base_row_exists =
737                 heapCC.fetch(
738                     baseRowLocation, baseRow.getRowArray(), (FormatableBitSet) null);
739
740             if (SanityManager.DEBUG)
741             {
742                 // it can not be possible for heap row to disappear while
743
// holding scan cursor on index at ISOLATION_REPEATABLE_READ.
744
SanityManager.ASSERT(base_row_exists, "base row not found");
745             }
746
747             // only delete rows which pass the base-row filter
748
if ( filter != null ) { passedFilter = filter.execute( baseRow ).equals( true ); }
749             if ( passedFilter )
750             {
751                 rc.deleteRow( baseRow, baseRowLocation );
752                 rowsDeleted++;
753             }
754         }
755
756         heapCC.close();
757         drivingScan.close();
758         rc.close();
759         
760         return rowsDeleted;
761     }
762
763     /**
764       * Given a key row, return the first matching heap row.
765       * <p>
766       * LOCKING: shared row locking.
767       *
768       * @param tc transaction controller
769       * @param key key to read by.
770       * @param indexNumber Key is appropriate for this index.
771       * @exception StandardException Thrown on failure
772       */

773     ExecRow getRow( TransactionController tc,
774                         ExecIndexRow key,
775                         int indexNumber )
776         throws StandardException
777     {
778         ConglomerateController heapCC;
779
780         /* Open the heap conglomerate */
781         heapCC = tc.openConglomerate(
782                     getHeapConglomerate(),
783                     false,
784                     0, // for read only
785
TransactionController.MODE_RECORD,
786                     TransactionController.ISOLATION_REPEATABLE_READ);
787
788         try { return getRow( tc, heapCC, key, indexNumber ); }
789         finally { heapCC.close(); }
790     }
791
792     /**
793      * Given an index row and index number return the RowLocation
794      * in the heap of the first matching row.
795      * Used by the autoincrement code to get the RowLocation in
796      * syscolumns given a <tablename, columname> pair.
797      *
798      * @see DataDictionaryImpl#computeRowLocation(TransactionController, TableDescriptor, String)
799      *
800      * @param tc Transaction Controller to use.
801      * @param key Index Row to search in the index.
802      * @param indexNumber Identifies the index to use.
803      *
804      * @exception StandardException thrown on failure.
805      */

806     RowLocation getRowLocation(TransactionController tc,
807                                       ExecIndexRow key,
808                                       int indexNumber)
809               throws StandardException
810     {
811         ConglomerateController heapCC;
812         heapCC = tc.openConglomerate(
813                     getHeapConglomerate(),
814                     false,
815                     0, // for read only
816
TransactionController.MODE_RECORD,
817                     TransactionController.ISOLATION_REPEATABLE_READ);
818
819         try
820         {
821             RowLocation rl[] = new RowLocation[1];
822             ExecRow notUsed = getRowInternal(tc, heapCC, key, indexNumber, rl);
823             return rl[0];
824         }
825         finally
826         {
827             heapCC.close();
828         }
829     }
830     /**
831       * Given a key row, return the first matching heap row.
832       * <p>
833       * LOCKING: shared row locking.
834       *
835       * @param tc transaction controller
836       * @param heapCC heap to look in
837       * @param key key to read by.
838       * @param indexNumber Key is appropriate for this index.
839       * @exception StandardException Thrown on failure
840       */

841     ExecRow getRow( TransactionController tc,
842                            ConglomerateController heapCC,
843                            ExecIndexRow key,
844                            int indexNumber)
845                             
846          throws StandardException
847     {
848         RowLocation rl[] = new RowLocation[1];
849         return getRowInternal(tc, heapCC, key, indexNumber, rl);
850     }
851
852     /**
853       * @exception StandardException Thrown on failure
854       */

855     private ExecRow getRowInternal( TransactionController tc,
856                                     ConglomerateController heapCC,
857                                     ExecIndexRow key,
858                                     int indexNumber,
859                                     RowLocation rl[])
860
861          throws StandardException
862     {
863         ScanController drivingScan;
864         ExecIndexRow drivingIndexRow;
865         RowLocation baseRowLocation;
866         ExecRow baseRow = crf.makeEmptyRow();
867
868         drivingScan = tc.openScan(
869             getIndexConglomerate(indexNumber),
870                                  // conglomerate to open
871
false, // don't hold open across commit
872
0, // open for read
873
TransactionController.MODE_RECORD,
874             TransactionController.ISOLATION_REPEATABLE_READ,
875             (FormatableBitSet) null, // all fields as objects
876
key.getRowArray(), // start position - first row
877
ScanController.GE, // startSearchOperation
878
null, //scanQualifier
879
key.getRowArray(), // stop position - through last row
880
ScanController.GT); // stopSearchOperation
881

882         // Get an index row based on the base row
883
drivingIndexRow = getIndexRowFromHeapRow(
884             getIndexRowGenerator( indexNumber ),
885             heapCC.newRowLocationTemplate(),
886             crf.makeEmptyRow());
887
888         try {
889             if (drivingScan.fetchNext(drivingIndexRow.getRowArray()))
890             {
891                 rl[0] = baseRowLocation = (RowLocation)
892                     drivingIndexRow.getColumn(drivingIndexRow.nColumns());
893                 boolean base_row_exists =
894                     heapCC.fetch(
895                         baseRowLocation, baseRow.getRowArray(), (FormatableBitSet) null);
896
897                 if (SanityManager.DEBUG)
898                 {
899                     // it can not be possible for heap row to disappear while
900
// holding scan cursor on index at ISOLATION_REPEATABLE_READ.
901
SanityManager.ASSERT(base_row_exists, "base row not found");
902                 }
903
904                 return baseRow;
905             }
906             else
907             {
908                 return null;
909             }
910         }
911
912         finally {
913             drivingScan.close();
914         }
915     }
916
917     /**
918      * Updates a base row in a catalog and updates all the corresponding
919      * index rows.
920      *
921      * @param key key row
922      * @param newRow new version of the row
923      * @param indexNumber index that key operates
924      * @param indicesToUpdate array of booleans, one for each index on the catalog.
925      * if a boolean is true, that means we must update the
926      * corresponding index because changes in the newRow
927      * affect it.
928      * @param colsToUpdate array of ints indicating which columns (1 based)
929      * to update. If null, do all.
930      * @param tc transaction controller
931      *
932      * @exception StandardException Thrown on failure
933      */

934     void updateRow( ExecIndexRow key,
935                            ExecRow newRow,
936                            int indexNumber,
937                            boolean[] indicesToUpdate,
938                            int[] colsToUpdate,
939                            TransactionController tc )
940         throws StandardException
941     {
942         updateRow(key, newRow, indexNumber, indicesToUpdate, colsToUpdate, tc, true);
943     }
944
945     /**
946      * Updates a base row in a catalog and updates all the corresponding
947      * index rows.
948      *
949      * @param key key row
950      * @param newRow new version of the row
951      * @param indexNumber index that key operates
952      * @param indicesToUpdate array of booleans, one for each index on the catalog.
953      * if a boolean is true, that means we must update the
954      * corresponding index because changes in the newRow
955      * affect it.
956      * @param colsToUpdate array of ints indicating which columns (1 based)
957      * to update. If null, do all.
958      * @param tc transaction controller
959      * @param wait If true, then the caller wants to wait for locks. False will be
960      * when we using a nested user xaction - we want to timeout right away if the parent
961      * holds the lock. (bug 4821)
962      *
963      * @exception StandardException Thrown on failure
964      */

965     void updateRow( ExecIndexRow key,
966                            ExecRow newRow,
967                            int indexNumber,
968                            boolean[] indicesToUpdate,
969                            int[] colsToUpdate,
970                            TransactionController tc,
971                            boolean wait )
972         throws StandardException
973     {
974         ExecRow[] newRows = new ExecRow[1];
975         newRows[0] = newRow;
976         updateRow(key, newRows, indexNumber, indicesToUpdate, colsToUpdate, tc, wait);
977     }
978
979     /**
980      * Updates a set of base rows in a catalog with the same key on an index
981      * and updates all the corresponding index rows.
982      *
983      * @param key key row
984      * @param newRows new version of the array of rows
985      * @param indexNumber index that key operates
986      * @param indicesToUpdate array of booleans, one for each index on the catalog.
987      * if a boolean is true, that means we must update the
988      * corresponding index because changes in the newRow
989      * affect it.
990      * @param colsToUpdate array of ints indicating which columns (1 based)
991      * to update. If null, do all.
992      * @param tc transaction controller
993      *
994      * @exception StandardException Thrown on failure
995      */

996     void updateRow( ExecIndexRow key,
997                            ExecRow[] newRows,
998                            int indexNumber,
999                            boolean[] indicesToUpdate,
1000                           int[] colsToUpdate,
1001                           TransactionController tc )
1002        throws StandardException
1003    {
1004        updateRow(key, newRows, indexNumber, indicesToUpdate, colsToUpdate, tc, true);
1005    }
1006
1007    /**
1008     * Updates a set of base rows in a catalog with the same key on an index
1009     * and updates all the corresponding index rows. If parameter wait is true,
1010     * then the caller wants to wait for locks. When using a nested user xaction
1011     * we want to timeout right away if the parent holds the lock.
1012     *
1013     * @param key key row
1014     * @param newRows new version of the array of rows
1015     * @param indexNumber index that key operates
1016     * @param indicesToUpdate array of booleans, one for each index on the catalog.
1017     * if a boolean is true, that means we must update the
1018     * corresponding index because changes in the newRow
1019     * affect it.
1020     * @param colsToUpdate array of ints indicating which columns (1 based)
1021     * to update. If null, do all.
1022     * @param tc transaction controller
1023     * @param wait If true, then the caller wants to wait for locks. When
1024     * using a nested user xaction we want to timeout right away
1025     * if the parent holds the lock. (bug 4821)
1026     *
1027     * @exception StandardException Thrown on failure
1028     */

1029    private void updateRow( ExecIndexRow key,
1030                           ExecRow[] newRows,
1031                           int indexNumber,
1032                           boolean[] indicesToUpdate,
1033                           int[] colsToUpdate,
1034                           TransactionController tc,
1035                           boolean wait)
1036        throws StandardException
1037    {
1038        ConglomerateController heapCC;
1039        ScanController drivingScan;
1040        ExecIndexRow drivingIndexRow;
1041        RowLocation baseRowLocation;
1042        ExecIndexRow templateRow;
1043        ExecRow baseRow = crf.makeEmptyRow();
1044
1045        if (SanityManager.DEBUG)
1046        {
1047            SanityManager.ASSERT( indicesToUpdate.length == crf.getNumIndexes(),
1048                                 "Wrong number of indices." );
1049        }
1050
1051        RowChanger rc = getRowChanger( tc, colsToUpdate,baseRow );
1052
1053        // Row level locking
1054
rc.openForUpdate(indicesToUpdate, TransactionController.MODE_RECORD, wait);
1055
1056        /* Open the heap conglomerate */
1057        heapCC = tc.openConglomerate(
1058                    getHeapConglomerate(),
1059                    false,
1060                    (TransactionController.OPENMODE_FORUPDATE |
1061                    ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
1062                    TransactionController.MODE_RECORD,
1063                    TransactionController.ISOLATION_REPEATABLE_READ);
1064
1065        drivingScan = tc.openScan(
1066            getIndexConglomerate(indexNumber), // conglomerate to open
1067
false, // don't hold open across commit
1068
(TransactionController.OPENMODE_FORUPDATE |
1069            ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
1070            TransactionController.MODE_RECORD,
1071            TransactionController.ISOLATION_REPEATABLE_READ,
1072            (FormatableBitSet) null, // all fields as objects
1073
key.getRowArray(), // start position - first row
1074
ScanController.GE, // startSearchOperation
1075
null, //scanQualifier
1076
key.getRowArray(), // stop position - through last row
1077
ScanController.GT); // stopSearchOperation
1078

1079        // Get an index row based on the base row
1080
drivingIndexRow = getIndexRowFromHeapRow(
1081            getIndexRowGenerator( indexNumber ),
1082            heapCC.newRowLocationTemplate(),
1083            crf.makeEmptyRow());
1084
1085        int rowNum = 0;
1086        while (drivingScan.fetchNext(drivingIndexRow.getRowArray()))
1087        {
1088            baseRowLocation = (RowLocation)
1089                        drivingIndexRow.getColumn(drivingIndexRow.nColumns());
1090            boolean base_row_exists =
1091                heapCC.fetch(
1092                    baseRowLocation, baseRow.getRowArray(), (FormatableBitSet) null);
1093
1094            if (SanityManager.DEBUG)
1095            {
1096                // it can not be possible for heap row to disappear while
1097
// holding scan cursor on index at ISOLATION_REPEATABLE_READ.
1098
SanityManager.ASSERT(base_row_exists, "base row not found");
1099            }
1100            
1101            rc.updateRow(baseRow, (rowNum == newRows.length - 1) ?
1102                        newRows[rowNum] : newRows[rowNum++], baseRowLocation );
1103        }
1104        rc.finish();
1105        heapCC.close();
1106        drivingScan.close();
1107        rc.close();
1108    }
1109
1110    /**
1111     * Get the Properties associated with creating the heap.
1112     *
1113     * @return The Properties associated with creating the heap.
1114     */

1115    Properties JavaDoc getCreateHeapProperties()
1116    {
1117        return crf.getCreateHeapProperties();
1118    }
1119
1120    /**
1121     * Get the Properties associated with creating the specified index.
1122     *
1123     * @param indexNumber The specified index number.
1124     *
1125     * @return The Properties associated with creating the specified index.
1126     */

1127    Properties JavaDoc getCreateIndexProperties(int indexNumber)
1128    {
1129        return crf.getCreateIndexProperties(indexNumber);
1130    }
1131
1132    /**
1133      * Gets a row changer for this catalog.
1134      *
1135      * @param tc transaction controller
1136      * @param changedCols the columns to change (1 based), may be null
1137      * @param baseRow used to detemine column types at creation time
1138      * only. The row changer does ***Not*** keep a referance to
1139      * this row or change it in any way.
1140      *
1141      * @return a row changer for this catalog.
1142      * @exception StandardException Thrown on failure
1143      */

1144    private RowChanger getRowChanger( TransactionController tc,
1145                                       int[] changedCols,
1146                                       ExecRow baseRow)
1147        throws StandardException
1148    {
1149        RowChanger rc;
1150        int indexCount = crf.getNumIndexes();
1151        IndexRowGenerator[] irgs = new IndexRowGenerator[ indexCount ];
1152        long[] cids = new long[ indexCount ];
1153
1154        if (SanityManager.DEBUG)
1155        {
1156            if (changedCols != null)
1157            {
1158                for (int i = changedCols.length - 1; i >= 0; i--)
1159                {
1160                    SanityManager.ASSERT(changedCols[i] != 0,
1161                        "Column id is 0, but should be 1 based");
1162                }
1163            }
1164        }
1165
1166        for ( int ictr = 0; ictr < indexCount; ictr++ )
1167        {
1168            irgs[ictr] = getIndexRowGenerator(ictr);
1169            cids[ictr] = getIndexConglomerate(ictr);
1170        }
1171
1172        rc = crf.getExecutionFactory().getRowChanger(getHeapConglomerate(),
1173                                            (StaticCompiledOpenConglomInfo) null,
1174                                            (DynamicCompiledOpenConglomInfo) null,
1175                                            irgs,
1176                                            cids,
1177                                            (StaticCompiledOpenConglomInfo[]) null,
1178                                            (DynamicCompiledOpenConglomInfo[]) null,
1179                                            crf.getHeapColumnCount(),
1180                                            tc,
1181                                            changedCols,
1182                                            getStreamStorableHeapColIds(baseRow),
1183                                            (Activation) null);
1184        return rc;
1185    }
1186
1187    private boolean computedStreamStorableHeapColIds = false;
1188    private int[] streamStorableHeapColIds;
1189    private int[] getStreamStorableHeapColIds(ExecRow baseRow) throws StandardException
1190    {
1191        if (!computedStreamStorableHeapColIds)
1192        {
1193            int sshcidLen = 0;
1194            //
1195
//Compute the length of streamStorableHeapColIds
1196
//One entry for each column id.
1197
DataValueDescriptor[] ra = baseRow.getRowArray();
1198            for(int ix=0;ix<ra.length;ix++)
1199                if (ra[ix] instanceof StreamStorable) sshcidLen++;
1200
1201            //
1202
//If we have some streamStorableHeapColIds we
1203
//allocate an array to remember them and fill in
1204
//the array with the 0 based column ids. If we
1205
//have none leave streamStorableHeapColIds Null.
1206
if (sshcidLen > 0)
1207            {
1208                streamStorableHeapColIds = new int[sshcidLen];
1209                int sshcidOffset=0;
1210                for(int ix=0;ix<ra.length;ix++)
1211                    if (ra[ix] instanceof StreamStorable)
1212                        streamStorableHeapColIds[sshcidOffset++] = ix;
1213            }
1214            computedStreamStorableHeapColIds = true;
1215        }
1216        return streamStorableHeapColIds;
1217    }
1218
1219    /**
1220     * Get an index row based on a row from the heap.
1221     *
1222     * @param irg IndexRowGenerator to use
1223     * @param rl RowLocation for heap
1224     * @param heapRow Row from the heap
1225     *
1226     * @return ExecIndexRow Index row.
1227     *
1228     * @exception StandardException Thrown on error
1229     */

1230    private ExecIndexRow getIndexRowFromHeapRow(IndexRowGenerator irg,
1231                                   RowLocation rl,
1232                                   ExecRow heapRow)
1233        throws StandardException
1234    {
1235        ExecIndexRow indexRow;
1236
1237        indexRow = irg.getIndexRowTemplate();
1238        // Get an index row based on the base row
1239
irg.getIndexRow(heapRow, rl, indexRow, (FormatableBitSet) null);
1240
1241        return indexRow;
1242    }
1243
1244    public String JavaDoc toString()
1245    {
1246        if (SanityManager.DEBUG)
1247        {
1248            return "name: " + this.getTableName() +
1249                "\n\theapCongolomerate: "+heapConglomerate +
1250                "\n\tnumIndexes: " + ((indexes != null) ? indexes.length : 0) +
1251                "\n\tnumIndexesSet: " + numIndexesSet +
1252                "\n\theapSet: " + heapSet +
1253                "\n";
1254        }
1255        else
1256        {
1257            return "";
1258        }
1259    }
1260}
1261
Popular Tags