KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.CreateIndexConstantAction
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
26 import org.apache.derby.iapi.services.loader.ClassFactory;
27 import org.apache.derby.iapi.services.loader.ClassInspector;
28
29 import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
30
31 import org.apache.derby.iapi.sql.execute.ConstantAction;
32 import org.apache.derby.iapi.sql.execute.ExecutionContext;
33 import org.apache.derby.iapi.sql.execute.ExecRow;
34 import org.apache.derby.iapi.sql.execute.ExecIndexRow;
35
36 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
37 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
38 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptorList;
39 import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
40 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
41 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
42 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
43 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
44 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
45 import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
46 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
47 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
48 import org.apache.derby.iapi.sql.dictionary.StatisticsDescriptor;
49 import org.apache.derby.iapi.sql.depend.DependencyManager;
50 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
51 import org.apache.derby.iapi.sql.Activation;
52
53 import org.apache.derby.iapi.types.DataValueFactory;
54 import org.apache.derby.iapi.types.DataTypeDescriptor;
55 import org.apache.derby.iapi.types.TypeId;
56 import org.apache.derby.iapi.types.RowLocation;
57
58 import org.apache.derby.iapi.reference.SQLState;
59
60 import org.apache.derby.iapi.error.StandardException;
61
62 import org.apache.derby.iapi.store.access.ColumnOrdering;
63 import org.apache.derby.iapi.store.access.ConglomerateController;
64 import org.apache.derby.iapi.store.access.GroupFetchScanController;
65 import org.apache.derby.iapi.store.access.RowLocationRetRowSource;
66 import org.apache.derby.iapi.store.access.ScanController;
67 import org.apache.derby.iapi.store.access.SortObserver;
68 import org.apache.derby.iapi.store.access.SortController;
69 import org.apache.derby.iapi.store.access.TransactionController;
70 import org.apache.derby.iapi.types.DataValueDescriptor;
71
72
73 import org.apache.derby.catalog.UUID;
74 import org.apache.derby.catalog.types.StatisticsImpl;
75
76 import java.util.Properties JavaDoc;
77 import org.apache.derby.iapi.services.io.FormatableBitSet;
78
79 /**
80  * This class describes actions that are ALWAYS performed for a
81  * CREATE TABLE Statement at Execution time.
82  *
83  * @author Jeff Lichtman Cribbed from from CreateTableConstantAction
84  */

85
86 class CreateIndexConstantAction extends IndexConstantAction
87 {
88
89     private boolean unique;
90     private String JavaDoc indexType;
91     private long conglomId;
92     private String JavaDoc[] columnNames;
93     private boolean[] isAscending;
94     private boolean isConstraint;
95     private UUID conglomerateUUID;
96     private Properties JavaDoc properties;
97
98     private ExecRow indexTemplateRow;
99
100
101     // CONSTRUCTORS
102
/**
103      * Make the ConstantAction for a CREATE INDEX statement.
104      *
105      * @param unique True means it will be a unique index
106      * @param indexType The type of index (BTREE, for example)
107      * @param schemaName the schema that table (and index) lives in.
108      * @param indexName Name of the index
109      * @param tableName Name of table the index will be on
110      * @param tableId UUID of table
111      * @param conglomId Conglomerate ID of the index, if known in advance
112      * @param columnNames Names of the columns in the index, in order
113      * @param isAscending Array of booleans telling asc/desc on each column
114      * @param isConstraint TRUE if index is backing up a constraint, else FALSE
115      * @param conglomerateUUID ID of conglomerate
116      * @param properties The optional properties list associated with the index.
117      */

118     CreateIndexConstantAction(
119                                 boolean unique,
120                                 String JavaDoc indexType,
121                                 String JavaDoc schemaName,
122                                 String JavaDoc indexName,
123                                 String JavaDoc tableName,
124                                 UUID tableId,
125                                 long conglomId,
126                                 String JavaDoc[] columnNames,
127                                 boolean[] isAscending,
128                                 boolean isConstraint,
129                                 UUID conglomerateUUID,
130                                 Properties JavaDoc properties)
131     {
132         super(tableId, indexName, tableName, schemaName);
133         this.unique = unique;
134         this.indexType = indexType;
135         this.conglomId= conglomId;
136         this.columnNames = columnNames;
137         this.isAscending = isAscending;
138         this.isConstraint = isConstraint;
139         this.conglomerateUUID = conglomerateUUID;
140         this.properties = properties;
141     }
142
143     ///////////////////////////////////////////////
144
//
145
// OBJECT SHADOWS
146
//
147
///////////////////////////////////////////////
148

149     public String JavaDoc toString()
150     {
151         // Do not put this under SanityManager.DEBUG - it is needed for
152
// error reporting.
153
return "CREATE INDEX " + indexName;
154     }
155
156     // INTERFACE METHODS
157

158
159     /**
160      * This is the guts of the Execution-time logic for CREATE INDEX.
161      *
162      * @see ConstantAction#executeConstantAction
163      *
164      * @exception StandardException Thrown on failure
165      */

166     public void executeConstantAction( Activation activation )
167                         throws StandardException
168     {
169         boolean forCreateTable;
170         TableDescriptor td;
171         UUID toid;
172         ColumnDescriptor columnDescriptor;
173         int[] baseColumnPositions;
174         IndexRowGenerator indexRowGenerator = null;
175         ExecRow[] baseRows;
176         ExecIndexRow[] indexRows;
177         ExecRow[] compactBaseRows;
178         GroupFetchScanController scan;
179         RowLocationRetRowSource rowSource;
180         long sortId;
181         int maxBaseColumnPosition = -1;
182
183         LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
184         DataDictionary dd = lcc.getDataDictionary();
185         DependencyManager dm = dd.getDependencyManager();
186         TransactionController tc = lcc.getTransactionExecute();
187
188         /* Remember whether or not we are doing a create table */
189         forCreateTable = activation.getForCreateTable();
190
191         /*
192         ** Inform the data dictionary that we are about to write to it.
193         ** There are several calls to data dictionary "get" methods here
194         ** that might be done in "read" mode in the data dictionary, but
195         ** it seemed safer to do this whole operation in "write" mode.
196         **
197         ** We tell the data dictionary we're done writing at the end of
198         ** the transaction.
199         */

200         dd.startWriting(lcc);
201
202         /*
203         ** If the schema descriptor is null, then
204         ** we must have just read ourselves in.
205         ** So we will get the corresponding schema
206         ** descriptor from the data dictionary.
207         */

208         SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, tc, true) ;
209
210
211         /* Get the table descriptor. */
212         /* See if we can get the TableDescriptor
213          * from the Activation. (Will be there
214          * for backing indexes.)
215          */

216         td = activation.getDDLTableDescriptor();
217
218         if (td == null)
219         {
220             /* tableId will be non-null if adding an index to
221              * an existing table (as opposed to creating a
222              * table with a constraint with a backing index).
223              */

224             if (tableId != null)
225             {
226                 td = dd.getTableDescriptor(tableId);
227             }
228             else
229             {
230                 td = dd.getTableDescriptor(tableName, sd);
231             }
232         }
233
234         if (td == null)
235         {
236             throw StandardException.newException(SQLState.LANG_CREATE_INDEX_NO_TABLE,
237                         indexName, tableName);
238         }
239
240         if (td.getTableType() == TableDescriptor.SYSTEM_TABLE_TYPE)
241         {
242             throw StandardException.newException(SQLState.LANG_CREATE_SYSTEM_INDEX_ATTEMPTED,
243                         indexName, tableName);
244         }
245
246         /* Get a shared table lock on the table. We need to lock table before
247          * invalidate dependents, otherwise, we may interfere with the
248          * compilation/re-compilation of DML/DDL. See beetle 4325 and $WS/
249          * docs/language/SolutionsToConcurrencyIssues.txt (point f).
250          */

251         lockTableForDDL(tc, td.getHeapConglomerateId(), false);
252
253         // invalidate any prepared statements that
254
// depended on this table (including this one)
255
if (! forCreateTable)
256         {
257             dm.invalidateFor(td, DependencyManager.CREATE_INDEX, lcc);
258         }
259
260         // Translate the base column names to column positions
261
baseColumnPositions = new int[columnNames.length];
262         for (int i = 0; i < columnNames.length; i++)
263         {
264             // Look up the column in the data dictionary
265
columnDescriptor = td.getColumnDescriptor(columnNames[i]);
266             if (columnDescriptor == null)
267             {
268                 throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE,
269                                                             columnNames[i],
270                                                             tableName);
271             }
272
273             TypeId typeId = columnDescriptor.getType().getTypeId();
274
275             // Don't allow a column to be created on a non-orderable type
276
ClassFactory cf = lcc.getLanguageConnectionFactory().getClassFactory();
277             boolean isIndexable = typeId.orderable(cf);
278
279             if (isIndexable && typeId.userType()) {
280                 String JavaDoc userClass = typeId.getCorrespondingJavaTypeName();
281
282                 // Don't allow indexes to be created on classes that
283
// are loaded from the database. This is because recovery
284
// won't be able to see the class and it will need it to
285
// run the compare method.
286
try {
287                     if (cf.isApplicationClass(cf.loadApplicationClass(userClass)))
288                         isIndexable = false;
289                 } catch (ClassNotFoundException JavaDoc cnfe) {
290                     // shouldn't happen as we just check the class is orderable
291
isIndexable = false;
292                 }
293             }
294
295             if (!isIndexable) {
296                 throw StandardException.newException(SQLState.LANG_COLUMN_NOT_ORDERABLE_DURING_EXECUTION,
297                     typeId.getSQLTypeName());
298             }
299
300             // Remember the position in the base table of each column
301
baseColumnPositions[i] = columnDescriptor.getPosition();
302
303             if (maxBaseColumnPosition < baseColumnPositions[i])
304                 maxBaseColumnPosition = baseColumnPositions[i];
305         }
306
307         // check if we have similar indices already for this table
308
ConglomerateDescriptor[] congDescs = td.getConglomerateDescriptors();
309         boolean duplicate = false;
310
311         for (int i = 0; i < congDescs.length; i++)
312         {
313             ConglomerateDescriptor cd = congDescs[i];
314             if ( ! cd.isIndex())
315                 continue;
316             IndexRowGenerator irg = cd.getIndexDescriptor();
317             int[] bcps = irg.baseColumnPositions();
318             boolean[] ia = irg.isAscending();
319             int j = 0;
320
321             /* For an index to be considered a duplicate of already existing index, the
322              * following conditions have to be satisfied:
323              * 1. the set of columns (both key and include columns) and their
324              * order in the index is the same as that of an existing index AND
325              * 2. the ordering attributes are the same AND
326              * 3. both the previously existing index and the one being created
327              * are non-unique OR the previously existing index is unique
328              */

329
330             if ((bcps.length == baseColumnPositions.length) &&
331                 (irg.isUnique() || !unique) &&
332                 indexType.equals(irg.indexType()))
333             {
334                 for (; j < bcps.length; j++)
335                 {
336                     if ((bcps[j] != baseColumnPositions[j]) || (ia[j] != isAscending[j]))
337                         break;
338                 }
339             }
340
341             if (j == baseColumnPositions.length) // duplicate
342
{
343                 /*
344                  * Don't allow users to create a duplicate index. Allow if being done internally
345                  * for a constraint
346                  */

347                 if (!isConstraint)
348                 {
349                     activation.addWarning(
350                             StandardException.newWarning(
351                                 SQLState.LANG_INDEX_DUPLICATE,
352                                 cd.getConglomerateName()));
353
354                     return;
355                 }
356
357                 //Duplicate indexes share the physical conglomerate underneath
358
conglomId = cd.getConglomerateNumber();
359                 indexRowGenerator = cd.getIndexDescriptor();
360                 //DERBY-655 and DERBY-1343
361
//Duplicate indexes will have unqiue logical conglomerate UUIDs.
362
conglomerateUUID = dd.getUUIDFactory().createUUID();
363                 duplicate = true;
364                 break;
365             }
366         }
367
368         /* If this index already has an essentially same one, we share the
369          * conglomerate with the old one, and just simply add a descriptor
370          * entry into SYSCONGLOMERATES.
371          */

372         DataDescriptorGenerator ddg = dd.getDataDescriptorGenerator();
373         if (duplicate)
374         {
375             ConglomerateDescriptor cgd =
376                 ddg.newConglomerateDescriptor(conglomId, indexName, true,
377                                           indexRowGenerator, isConstraint,
378                                           conglomerateUUID, td.getUUID(), sd.getUUID() );
379             dd.addDescriptor(cgd, sd, DataDictionary.SYSCONGLOMERATES_CATALOG_NUM, false, tc);
380             // add newly added conglomerate to the list of conglomerate
381
// descriptors in the td.
382
ConglomerateDescriptorList cdl =
383                 td.getConglomerateDescriptorList();
384             cdl.add(cgd);
385
386             // can't just return yet, need to get member "indexTemplateRow"
387
// because create constraint may use it
388
}
389
390         // Describe the properties of the index to the store using Properties
391
// RESOLVE: The following properties assume a BTREE index.
392
Properties JavaDoc indexProperties;
393         
394         if (properties != null)
395         {
396             indexProperties = properties;
397         }
398         else
399         {
400             indexProperties = new Properties JavaDoc();
401         }
402
403         // Tell it the conglomerate id of the base table
404
indexProperties.put("baseConglomerateId",
405                             Long.toString(td.getHeapConglomerateId()));
406
407         // All indexes are unique because they contain the RowLocation.
408
// The number of uniqueness columns must include the RowLocation
409
// if the user did not specify a unique index.
410
indexProperties.put("nUniqueColumns",
411                     Integer.toString(unique ? baseColumnPositions.length :
412                                                 baseColumnPositions.length + 1)
413                             );
414
415         // By convention, the row location column is the last column
416
indexProperties.put("rowLocationColumn",
417                             Integer.toString(baseColumnPositions.length));
418
419         // For now, all columns are key fields, including the RowLocation
420
indexProperties.put("nKeyFields",
421                             Integer.toString(baseColumnPositions.length + 1));
422
423         // For now, assume that all index columns are ordered columns
424
if (! duplicate)
425         {
426             indexRowGenerator = new IndexRowGenerator(indexType, unique,
427                                                     baseColumnPositions,
428                                                     isAscending,
429                                                     baseColumnPositions.length);
430         }
431
432         /* Now add the rows from the base table to the conglomerate.
433          * We do this by scanning the base table and inserting the
434          * rows into a sorter before inserting from the sorter
435          * into the index. This gives us better performance
436          * and a more compact index.
437          */

438
439         rowSource = null;
440         sortId = 0;
441         boolean needToDropSort = false; // set to true once the sorter is created
442

443         /* bulkFetchSIze will be 16 (for now) unless
444          * we are creating the table in which case it
445          * will be 1. Too hard to remove scan when
446          * creating index on new table, so minimize
447          * work where we can.
448          */

449         int bulkFetchSize = (forCreateTable) ? 1 : 16;
450         int numColumns = td.getNumberOfColumns();
451         int approximateRowSize = 0;
452
453         // Create the FormatableBitSet for mapping the partial to full base row
454
FormatableBitSet bitSet = new FormatableBitSet(numColumns+1);
455         for (int index = 0; index < baseColumnPositions.length; index++)
456         {
457             bitSet.set(baseColumnPositions[index]);
458         }
459         FormatableBitSet zeroBasedBitSet = RowUtil.shift(bitSet, 1);
460
461         // Start by opening a full scan on the base table.
462
scan = tc.openGroupFetchScan(
463                             td.getHeapConglomerateId(),
464                             false, // hold
465
0, // open base table read only
466
TransactionController.MODE_TABLE,
467                             TransactionController.ISOLATION_SERIALIZABLE,
468                             zeroBasedBitSet, // all fields as objects
469
(DataValueDescriptor[]) null, // startKeyValue
470
0, // not used when giving null start posn.
471
null, // qualifier
472
(DataValueDescriptor[]) null, // stopKeyValue
473
0); // not used when giving null stop posn.
474

475         // Create an array to put base row template
476
baseRows = new ExecRow[bulkFetchSize];
477         indexRows = new ExecIndexRow[bulkFetchSize];
478         compactBaseRows = new ExecRow[bulkFetchSize];
479
480         try
481         {
482             // Create the array of base row template
483
for (int i = 0; i < bulkFetchSize; i++)
484             {
485                 // create a base row template
486
baseRows[i] = activation.getExecutionFactory().getValueRow(maxBaseColumnPosition);
487
488                 // create an index row template
489
indexRows[i] = indexRowGenerator.getIndexRowTemplate();
490
491                 // create a compact base row template
492
compactBaseRows[i] = activation.getExecutionFactory().getValueRow(
493                                                     baseColumnPositions.length);
494             }
495
496             indexTemplateRow = indexRows[0];
497
498             // Fill the partial row with nulls of the correct type
499
ColumnDescriptorList cdl = td.getColumnDescriptorList();
500             int cdlSize = cdl.size();
501             for (int index = 0, numSet = 0; index < cdlSize; index++)
502             {
503                 if (! zeroBasedBitSet.get(index))
504                 {
505                     continue;
506                 }
507                 numSet++;
508                 ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index);
509                 DataTypeDescriptor dts = cd.getType();
510
511
512                 for (int i = 0; i < bulkFetchSize; i++)
513                 {
514                     // Put the column in both the compact and sparse base rows
515
baseRows[i].setColumn(index + 1,
516                                   dts.getNull());
517                     compactBaseRows[i].setColumn(numSet,
518                                   baseRows[i].getColumn(index + 1));
519                 }
520
521                 // Calculate the approximate row size for the index row
522
approximateRowSize += dts.getTypeId().getApproximateLengthInBytes(dts);
523             }
524
525             // Get an array of RowLocation template
526
RowLocation rl[] = new RowLocation[bulkFetchSize];
527             for (int i = 0; i < bulkFetchSize; i++)
528             {
529                 rl[i] = scan.newRowLocationTemplate();
530
531                 // Get an index row based on the base row
532
indexRowGenerator.getIndexRow(compactBaseRows[i], rl[i], indexRows[i], bitSet);
533             }
534
535             /* now that we got indexTemplateRow, done for duplicate index
536              */

537             if (duplicate)
538                 return;
539
540             /* For non-unique indexes, we order by all columns + the RID.
541              * For unique indexes, we just order by the columns.
542              * We create a unique index observer for unique indexes
543              * so that we can catch duplicate key.
544              * We create a basic sort observer for non-unique indexes
545              * so that we can reuse the wrappers during an external
546              * sort.
547              */

548             int numColumnOrderings;
549             SortObserver sortObserver = null;
550             if (unique)
551             {
552                 numColumnOrderings = baseColumnPositions.length;
553                 // if the index is a constraint, use constraintname in possible error messagge
554
String JavaDoc indexOrConstraintName = indexName;
555                 if (conglomerateUUID != null)
556                 {
557                     ConglomerateDescriptor cd = dd.getConglomerateDescriptor(conglomerateUUID);
558                     if ((isConstraint) && (cd != null && cd.getUUID() != null && td != null))
559                     {
560                         ConstraintDescriptor conDesc = dd.getConstraintDescriptor(td,
561                                                                       cd.getUUID());
562                         indexOrConstraintName = conDesc.getConstraintName();
563                     }
564                 }
565                 sortObserver = new UniqueIndexSortObserver(true, isConstraint,
566                                                            indexOrConstraintName,
567                                                            indexTemplateRow,
568                                                            true,
569                                                            td.getName());
570             }
571             else
572             {
573                 numColumnOrderings = baseColumnPositions.length + 1;
574                 sortObserver = new BasicSortObserver(true, false,
575                                                      indexTemplateRow,
576                                                      true);
577             }
578             ColumnOrdering[] order = new ColumnOrdering[numColumnOrderings];
579             for (int i=0; i < numColumnOrderings; i++)
580             {
581                 order[i] = new IndexColumnOrder(i, unique || i < numColumnOrderings - 1
582                                                     ? isAscending[i] : true);
583             }
584
585             // create the sorter
586
sortId = tc.createSort((Properties JavaDoc)null,
587                     indexTemplateRow.getRowArrayClone(),
588                     order,
589                     sortObserver,
590                     false, // not in order
591
scan.getEstimatedRowCount(),
592                     approximateRowSize // est row size, -1 means no idea
593
);
594
595             needToDropSort = true;
596
597             // Populate sorter and get the output of the sorter into a row
598
// source. The sorter has the indexed columns only and the columns
599
// are in the correct order.
600
rowSource = loadSorter(baseRows, indexRows, tc,
601                                    scan, sortId, rl);
602
603             conglomId = tc.createAndLoadConglomerate(
604                     indexType,
605                     indexTemplateRow.getRowArray(), // index row template
606
order, //colums sort order
607
indexProperties,
608                     TransactionController.IS_DEFAULT, // not temporary
609
rowSource,
610                     (long[]) null);
611             
612         }
613         finally
614         {
615
616             /* close the table scan */
617             if (scan != null)
618                 scan.close();
619
620             /* close the sorter row source before throwing exception */
621             if (rowSource != null)
622                 rowSource.closeRowSource();
623
624             /*
625             ** drop the sort so that intermediate external sort run can be
626             ** removed from disk
627             */

628             if (needToDropSort)
629                 tc.dropSort(sortId);
630         }
631
632         ConglomerateController indexController =
633             tc.openConglomerate(
634                 conglomId, false, 0, TransactionController.MODE_TABLE,
635                 TransactionController.ISOLATION_SERIALIZABLE);
636
637         // Check to make sure that the conglomerate can be used as an index
638
if ( ! indexController.isKeyed())
639         {
640             indexController.close();
641             throw StandardException.newException(SQLState.LANG_NON_KEYED_INDEX, indexName,
642                                                            indexType);
643         }
644         indexController.close();
645
646         //
647
// Create a conglomerate descriptor with the conglomId filled in and
648
// add it.
649
//
650

651         ConglomerateDescriptor cgd =
652             ddg.newConglomerateDescriptor(conglomId, indexName, true,
653                                           indexRowGenerator, isConstraint,
654                                           conglomerateUUID, td.getUUID(), sd.getUUID() );
655
656         dd.addDescriptor(cgd, sd, DataDictionary.SYSCONGLOMERATES_CATALOG_NUM, false, tc);
657
658         // add newly added conglomerate to the list of conglomerate descriptors
659
// in the td.
660
ConglomerateDescriptorList cdl = td.getConglomerateDescriptorList();
661         cdl.add(cgd);
662
663         CardinalityCounter cCount = (CardinalityCounter)rowSource;
664         long numRows;
665         if ((numRows = cCount.getRowCount()) > 0)
666         {
667             long[] c = cCount.getCardinality();
668             for (int i = 0; i < c.length; i++)
669             {
670                 StatisticsDescriptor statDesc =
671                     new StatisticsDescriptor(dd, dd.getUUIDFactory().createUUID(),
672                                                 cgd.getUUID(), td.getUUID(), "I", new StatisticsImpl(numRows, c[i]),
673                                                 i + 1);
674                 dd.addDescriptor(statDesc, null,
675                                  DataDictionary.SYSSTATISTICS_CATALOG_NUM,
676                                  true, tc);
677             }
678         }
679     }
680
681     // CLASS METHODS
682

683     ///////////////////////////////////////////////////////////////////////
684
//
685
// GETTERs called by CreateConstraint
686
//
687
///////////////////////////////////////////////////////////////////////
688
ExecRow getIndexTemplateRow()
689     {
690         return indexTemplateRow;
691     }
692
693     /**
694      * Do necessary clean up (close down controllers, etc.) before throwing
695      * a statement exception.
696      *
697      * @param scan ScanController for the heap
698      * @param indexController ConglomerateController for the index
699      */

700     private void statementExceptionCleanup(
701                     ScanController scan,
702                     ConglomerateController indexController)
703         throws StandardException
704     {
705         if (indexController != null)
706         {
707             indexController.close();
708         }
709         if (scan != null)
710         {
711             scan.close();
712         }
713     }
714
715     /**
716      * Scan the base conglomerate and insert the keys into a sorter,
717      * returning a rowSource on the sorter.
718      *
719      * @return RowSource on the sorted index keys.
720      *
721      * @exception StandardException thrown on error
722      */

723     private RowLocationRetRowSource loadSorter(ExecRow[] baseRows,
724                                                ExecIndexRow[] indexRows,
725                                                TransactionController tc,
726                                                GroupFetchScanController scan,
727                                                long sortId,
728                                                RowLocation rl[])
729         throws StandardException
730     {
731         SortController sorter;
732         long rowCount = 0;
733
734         sorter = tc.openSort(sortId);
735
736         try
737         {
738             // Step through all the rows in the base table
739
// prepare an array or rows for bulk fetch
740
int bulkFetchSize = baseRows.length;
741
742             if (SanityManager.DEBUG)
743             {
744                 SanityManager.ASSERT(bulkFetchSize == indexRows.length,
745                     "number of base rows and index rows does not match");
746                 SanityManager.ASSERT(bulkFetchSize == rl.length,
747                     "number of base rows and row locations does not match");
748             }
749
750             DataValueDescriptor[][] baseRowArray = new DataValueDescriptor[bulkFetchSize][];
751
752             for (int i = 0; i < bulkFetchSize; i++)
753                 baseRowArray[i] = baseRows[i].getRowArray();
754
755             // rl[i] and baseRowArray[i] and indexRows[i] are all tied up
756
// beneath the surface. Fetching the base row and row location
757
// from the table scan will automagically set up the indexRow
758
// fetchNextGroup will return how many rows are actually fetched.
759
int bulkFetched = 0;
760
761             while ((bulkFetched = scan.fetchNextGroup(baseRowArray, rl)) > 0)
762             {
763                 for (int i = 0; i < bulkFetched; i++)
764                 {
765                     sorter.insert(indexRows[i].getRowArray());
766                     rowCount++;
767                 }
768             }
769
770             /*
771             ** We've just done a full scan on the heap, so set the number
772             ** of rows so the optimizer will have an accurate count.
773             */

774             scan.setEstimatedRowCount(rowCount);
775         }
776         finally
777         {
778             sorter.close();
779         }
780
781         return new CardinalityCounter(tc.openSortRowSource(sortId));
782     }
783 }
784
785
Popular Tags