EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.iapi.db]

COVERAGE SUMMARY FOR SOURCE FILE [OnlineCompress.java]

nameclass, %method, %block, %line, %
OnlineCompress.java100% (1/1)86%  (6/7)87%  (501/573)90%  (116.7/130)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class OnlineCompress100% (1/1)86%  (6/7)87%  (501/573)90%  (116.7/130)
OnlineCompress (): void 0%   (0/1)0%   (0/3)0%   (0/2)
compressTable (String, String, boolean, boolean, boolean): void 100% (1/1)89%  (31/35)85%  (11/13)
defragmentRows (String, String, DataDictionary, TransactionController): void 100% (1/1)93%  (239/258)94%  (60/64)
fixIndex (DataValueDescriptor [], DataValueDescriptor [], RowLocation, RowLoc... 100% (1/1)80%  (71/89)90%  (11.7/13)
purgeRows (String, String, DataDictionary, TransactionController): void 100% (1/1)72%  (36/50)82%  (9/11)
setup_indexes (TransactionController, TableDescriptor, int [][], ScanControll... 100% (1/1)100% (88/88)100% (16/16)
truncateEnd (String, String, DataDictionary, TransactionController): void 100% (1/1)72%  (36/50)82%  (9/11)

1/*
2 
3   Derby - Class org.apache.derby.iapi.db.OnlineCompress
4 
5   Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 */
20 
21package org.apache.derby.iapi.db;
22 
23import org.apache.derby.iapi.error.StandardException;
24import org.apache.derby.iapi.error.PublicAPI;
25 
26import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
27import org.apache.derby.iapi.sql.dictionary.DataDictionary;
28import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
29import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
30import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
31import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
32import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
33import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
34import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
35 
36import org.apache.derby.iapi.sql.depend.DependencyManager;
37 
38import org.apache.derby.iapi.sql.execute.ExecRow;
39import org.apache.derby.iapi.sql.execute.ExecutionContext;
40 
41import org.apache.derby.iapi.types.DataValueDescriptor;
42import org.apache.derby.iapi.types.DataValueFactory;
43 
44 
45import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
46import org.apache.derby.iapi.sql.conn.ConnectionUtil;
47 
48import org.apache.derby.iapi.store.access.TransactionController;
49import org.apache.derby.iapi.types.RowLocation;
50import org.apache.derby.iapi.store.access.ScanController;
51import org.apache.derby.iapi.store.access.ConglomerateController;
52import org.apache.derby.iapi.store.access.GroupFetchScanController;
53import org.apache.derby.iapi.store.access.RowUtil;
54import org.apache.derby.iapi.store.access.Qualifier;
55 
56import org.apache.derby.iapi.services.sanity.SanityManager;
57 
58import org.apache.derby.iapi.reference.SQLState;
59 
60import org.apache.derby.iapi.services.io.FormatableBitSet;
61 
62import java.sql.SQLException;
63 
64/**
65 
66Implementation of SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE().
67<p>
68Code which implements the following system procedure:
69 
70void SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE(
71    IN SCHEMANAME        VARCHAR(128),
72    IN TABLENAME         VARCHAR(128),
73    IN PURGE_ROWS        SMALLINT,
74    IN DEFRAGMENT_ROWS   SMALLINT,
75    IN TRUNCATE_END      SMALLINT)
76<p>
77Use the SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE system procedure to reclaim 
78unused, allocated space in a table and its indexes. Typically, unused allocated
79space exists when a large amount of data is deleted from a table, and there
80have not been subsequent inserts to use the space freed by the deletes.  
81By default, Derby does not return unused space to the operating system. For 
82example, once a page has been allocated to a table or index, it is not 
83automatically returned to the operating system until the table or index is 
84destroyed. SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE allows you to return unused 
85space to the operating system.
86<p>
87This system procedure can be used to force 3 levels of in place compression
88of a SQL table: PURGE_ROWS, DEFRAGMENT_ROWS, TRUNCATE_END.  Unlike 
89SYSCS_UTIL.SYSCS_COMPRESS_TABLE() all work is done in place in the existing
90table/index.
91<p>
92Syntax:
93SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE(
94    IN SCHEMANAME        VARCHAR(128),
95    IN TABLENAME         VARCHAR(128),
96    IN PURGE_ROWS        SMALLINT,
97    IN DEFRAGMENT_ROWS   SMALLINT,
98    IN TRUNCATE_END      SMALLINT)
99<p>
100SCHEMANAME: 
101An input argument of type VARCHAR(128) that specifies the schema of the table. Passing a null will result in an error.
102<p>
103TABLENAME:
104An input argument of type VARCHAR(128) that specifies the table name of the 
105table. The string must exactly match the case of the table name, and the 
106argument of "Fred" will be passed to SQL as the delimited identifier 'Fred'. 
107Passing a null will result in an error.
108<p>
109PURGE_ROWS:
110If PURGE_ROWS is set to non-zero then a single pass is made through the table 
111which will purge committed deleted rows from the table.  This space is then
112available for future inserted rows, but remains allocated to the table.
113As this option scans every page of the table, it's performance is linearly 
114related to the size of the table.
115<p>
116DEFRAGMENT_ROWS:
117If DEFRAGMENT_ROWS is set to non-zero then a single defragment pass is made
118which will move existing rows from the end of the table towards the front
119of the table.  The goal of the defragment run is to empty a set of pages
120at the end of the table which can then be returned to the OS by the
121TRUNCATE_END option.  It is recommended to only run DEFRAGMENT_ROWS, if also
122specifying the TRUNCATE_END option.  This option scans the whole table and
123needs to update index entries for every base table row move, and thus execution
124time is linearly related to the size of the table.
125<p>
126TRUNCATE_END:
127If TRUNCATE_END is set to non-zero then all contiguous pages at the end of
128the table will be returned to the OS.  Running the PURGE_ROWS and/or 
129DEFRAGMENT_ROWS passes options may increase the number of pages affected.  
130This option itself does no scans of the table, so performs on the order of a 
131few system calls.
132<p>
133SQL example:
134To compress a table called CUSTOMER in a schema called US, using all 
135available compress options:
136call SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE('US', 'CUSTOMER', 1, 1, 1);
137 
138To quickly just return the empty free space at the end of the same table, 
139this option will run much quicker than running all phases but will likely
140return much less space:
141call SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE('US', 'CUSTOMER', 0, 0, 1);
142 
143Java example:
144To compress a table called CUSTOMER in a schema called US, using all 
145available compress options:
146 
147CallableStatement cs = conn.prepareCall
148("CALL SYSCS_UTIL.SYSCS_COMPRESS_TABLE(?, ?, ?, ?, ?)");
149cs.setString(1, "US");
150cs.setString(2, "CUSTOMER");
151cs.setShort(3, (short) 1);
152cs.setShort(4, (short) 1);
153cs.setShort(5, (short) 1);
154cs.execute();
155 
156To quickly just return the empty free space at the end of the same table, 
157this option will run much quicker than running all phases but will likely
158return much less space:
159 
160CallableStatement cs = conn.prepareCall
161("CALL SYSCS_UTIL.SYSCS_COMPRESS_TABLE(?, ?, ?, ?, ?)");
162cs.setString(1, "US");
163cs.setString(2, "CUSTOMER");
164cs.setShort(3, (short) 0);
165cs.setShort(4, (short) 0);
166cs.setShort(5, (short) 1);
167cs.execute();
168 
169<p>
170It is recommended that the SYSCS_UTIL.SYSCS_COMPRESS_TABLE procedure is 
171issued in auto-commit mode.
172Note: This procedure acquires an exclusive table lock on the table being compressed. All statement plans dependent on the table or its indexes are invalidated. For information on identifying unused space, see the Derby Server and Administration Guide.
173 
174TODO LIST:
175o defragment requires table level lock in nested user transaction, which
176  will conflict with user lock on same table in user transaction.
177 
178**/
179public class OnlineCompress
180{
181 
182        /** no requirement for a constructor */
183        private OnlineCompress() {
184        }
185 
186    /**
187     * Implementation of SYSCS_UTIL.SYSCS_INPLACE_COMPRESS_TABLE().
188     * <p>
189     * Top level implementation of the system procedure.  All the 
190     * real work is found in the other routines in this file implementing
191     * the 3 phases of inplace compression:  purge, defragment, and truncate.
192     * <p>
193     * @param schemaName        schema name of table, required
194     * @param tableName         table name to be compressed
195     * @param purgeRows         if true, do a purge pass on the table
196     * @param defragmentRows    if true, do a defragment pass on the table
197     * @param truncateEnd       if true, return empty pages at end to OS.
198     *
199         * @exception  SQLException  Errors returned by throwing SQLException.
200     **/
201        public static void compressTable(
202    String  schemaName, 
203    String  tableName,
204    boolean purgeRows,
205    boolean defragmentRows,
206    boolean truncateEnd)
207        throws SQLException
208        {
209                LanguageConnectionContext lcc       = ConnectionUtil.getCurrentLCC();
210                TransactionController     tc        = lcc.getTransactionExecute();
211 
212                try 
213        {
214            DataDictionary data_dictionary = lcc.getDataDictionary();
215 
216            // Each of the following may give up locks allowing ddl on the
217            // table, so each phase needs to do the data dictionary lookup.
218            // The order is important as it makes sense to first purge
219            // deleted rows, then defragment existing non-deleted rows, and
220            // finally to truncate the end of the file which may have been
221            // made larger by the previous purge/defragment pass.
222 
223            if (purgeRows)
224                purgeRows(schemaName, tableName, data_dictionary, tc);
225 
226            if (defragmentRows)
227                defragmentRows(schemaName, tableName, data_dictionary, tc);
228 
229            if (truncateEnd)
230                truncateEnd(schemaName, tableName, data_dictionary, tc);
231        }
232                catch (StandardException se)
233                {
234                        throw PublicAPI.wrapStandardException(se);
235                }
236 
237        }
238 
239    /**
240     * Defragment rows in the given table.
241     * <p>
242     * Scans the rows at the end of a table and moves them to free spots
243     * towards the beginning of the table.  In the same transaction all
244     * associated indexes are updated to reflect the new location of the
245     * base table row.
246     * <p>
247     * After a defragment pass, if was possible, there will be a set of
248     * empty pages at the end of the table which can be returned to the
249     * operating system by calling truncateEnd().  The allocation bit
250     * maps will be set so that new inserts will tend to go to empty and
251     * half filled pages starting from the front of the conglomerate.
252     *
253     * @param schemaName        schema of table to defragement
254     * @param tableName         name of table to defragment
255     * @param data_dictionary   An open data dictionary to look up the table in.
256     * @param tc                transaction controller to use to do updates.
257     *
258     **/
259        private static void defragmentRows(
260    String                  schemaName, 
261    String                  tableName,
262    DataDictionary          data_dictionary,
263    TransactionController   tc)
264        throws SQLException
265        {
266        GroupFetchScanController base_group_fetch_cc = null;
267        int                      num_indexes         = 0;
268 
269        int[][]                  index_col_map       =  null;
270        ScanController[]         index_scan          =  null;
271        ConglomerateController[] index_cc            =  null;
272        DataValueDescriptor[][]  index_row           =  null;
273 
274                LanguageConnectionContext lcc       = ConnectionUtil.getCurrentLCC();
275                TransactionController     nested_tc = null;
276 
277                try {
278 
279            SchemaDescriptor sd = 
280                data_dictionary.getSchemaDescriptor(
281                    schemaName, nested_tc, true);
282            TableDescriptor td = 
283                data_dictionary.getTableDescriptor(tableName, sd);
284            nested_tc = 
285                tc.startNestedUserTransaction(false);
286 
287            if (td == null)
288            {
289                throw StandardException.newException(
290                    SQLState.LANG_TABLE_NOT_FOUND, 
291                    schemaName + "." + tableName);
292            }
293 
294            switch (td.getTableType())
295            {
296            /* Skip views and vti tables */
297            case TableDescriptor.VIEW_TYPE:
298            case TableDescriptor.VTI_TYPE:
299                    return;
300            // other types give various errors here
301            // DERBY-719,DERBY-720
302            default:
303                    break;
304            }
305 
306 
307                        ConglomerateDescriptor heapCD = 
308                td.getConglomerateDescriptor(td.getHeapConglomerateId());
309 
310                        /* Get a row template for the base table */
311                        ExecRow baseRow = 
312                lcc.getExecutionContext().getExecutionFactory().getValueRow(
313                    td.getNumberOfColumns());
314 
315 
316                        /* Fill the row with nulls of the correct type */
317                        ColumnDescriptorList cdl = td.getColumnDescriptorList();
318                        int                                         cdlSize = cdl.size();
319 
320                        for (int index = 0; index < cdlSize; index++)
321                        {
322                                ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index);
323                                baseRow.setColumn(cd.getPosition(), cd.getType().getNull());
324                        }
325 
326            DataValueDescriptor[][] row_array = new DataValueDescriptor[100][];
327            row_array[0] = baseRow.getRowArray();
328            RowLocation[] old_row_location_array = new RowLocation[100];
329            RowLocation[] new_row_location_array = new RowLocation[100];
330 
331            // Create the following 3 arrays which will be used to update
332            // each index as the scan moves rows about the heap as part of
333            // the compress:
334            //     index_col_map - map location of index cols in the base row, 
335            //                     ie. index_col_map[0] is column offset of 1st
336            //                     key collumn in base row.  All offsets are 0 
337            //                     based.
338            //     index_scan - open ScanController used to delete old index row
339            //     index_cc   - open ConglomerateController used to insert new 
340            //                  row
341 
342            ConglomerateDescriptor[] conglom_descriptors = 
343                td.getConglomerateDescriptors();
344 
345            // conglom_descriptors has an entry for the conglomerate and each 
346            // one of it's indexes.
347            num_indexes = conglom_descriptors.length - 1;
348 
349            // if indexes exist, set up data structures to update them
350            if (num_indexes > 0)
351            {
352                // allocate arrays
353                index_col_map   = new int[num_indexes][];
354                index_scan      = new ScanController[num_indexes];
355                index_cc        = new ConglomerateController[num_indexes];
356                index_row       = new DataValueDescriptor[num_indexes][];
357 
358                setup_indexes(
359                    nested_tc,
360                    td,
361                    index_col_map,
362                    index_scan,
363                    index_cc,
364                    index_row);
365 
366            }
367 
368                        /* Open the heap for reading */
369                        base_group_fetch_cc = 
370                nested_tc.defragmentConglomerate(
371                    td.getHeapConglomerateId(), 
372                    false,
373                    true, 
374                    TransactionController.OPENMODE_FORUPDATE, 
375                                    TransactionController.MODE_TABLE,
376                                        TransactionController.ISOLATION_SERIALIZABLE);
377 
378            int num_rows_fetched = 0;
379            while ((num_rows_fetched = 
380                        base_group_fetch_cc.fetchNextGroup(
381                            row_array, 
382                            old_row_location_array, 
383                            new_row_location_array)) != 0)
384            {
385                if (num_indexes > 0)
386                {
387                    for (int row = 0; row < num_rows_fetched; row++)
388                    {
389                        for (int index = 0; index < num_indexes; index++)
390                        {
391                            fixIndex(
392                                row_array[row],
393                                index_row[index],
394                                old_row_location_array[row],
395                                new_row_location_array[row],
396                                index_cc[index],
397                                index_scan[index],
398                                index_col_map[index]);
399                        }
400                    }
401                }
402            }
403 
404            // TODO - It would be better if commits happened more frequently
405            // in the nested transaction, but to do that there has to be more
406            // logic to catch a ddl that might jump in the middle of the 
407            // above loop and invalidate the various table control structures
408            // which are needed to properly update the indexes.  For example
409            // the above loop would corrupt an index added midway through
410            // the loop if not properly handled.  See DERBY-1188.  
411            nested_tc.commit();
412                        
413                }
414                catch (StandardException se)
415                {
416                        throw PublicAPI.wrapStandardException(se);
417                }
418                finally
419                {
420            try
421            {
422                /* Clean up before we leave */
423                if (base_group_fetch_cc != null)
424                {
425                    base_group_fetch_cc.close();
426                    base_group_fetch_cc = null;
427                }
428 
429                if (num_indexes > 0)
430                {
431                    for (int i = 0; i < num_indexes; i++)
432                    {
433                        if (index_scan != null && index_scan[i] != null)
434                        {
435                            index_scan[i].close();
436                            index_scan[i] = null;
437                        }
438                        if (index_cc != null && index_cc[i] != null)
439                        {
440                            index_cc[i].close();
441                            index_cc[i] = null;
442                        }
443                    }
444                }
445 
446                if (nested_tc != null)
447                {
448                    nested_tc.destroy();
449                }
450 
451            }
452            catch (StandardException se)
453            {
454                throw PublicAPI.wrapStandardException(se);
455            }
456                }
457 
458                return;
459        }
460 
461    /**
462     * Purge committed deleted rows from conglomerate.
463     * <p>
464     * Scans the table and purges any committed deleted rows from the 
465     * table.  If all rows on a page are purged then page is also 
466     * reclaimed.
467     * <p>
468     *
469     * @param schemaName        schema of table to defragement
470     * @param tableName         name of table to defragment
471     * @param data_dictionary   An open data dictionary to look up the table in.
472     * @param tc                transaction controller to use to do updates.
473     *
474     **/
475        private static void purgeRows(
476    String                  schemaName, 
477    String                  tableName,
478    DataDictionary          data_dictionary,
479    TransactionController   tc)
480        throws StandardException
481        {
482        SchemaDescriptor sd = 
483            data_dictionary.getSchemaDescriptor(schemaName, tc, true);
484        TableDescriptor  td = 
485            data_dictionary.getTableDescriptor(tableName, sd);
486 
487        if (td == null)
488        {
489            throw StandardException.newException(
490                SQLState.LANG_TABLE_NOT_FOUND, 
491                schemaName + "." + tableName);
492        }
493 
494        switch (td.getTableType())
495        {
496        /* Skip views and vti tables */
497        case TableDescriptor.VIEW_TYPE:
498        case TableDescriptor.VTI_TYPE:
499                break;
500        // other types give various errors here
501        // DERBY-719,DERBY-720
502        default:
503          {
504 
505            ConglomerateDescriptor[] conglom_descriptors = 
506                td.getConglomerateDescriptors();
507 
508            for (int cd_idx = 0; cd_idx < conglom_descriptors.length; cd_idx++)
509            {
510                ConglomerateDescriptor cd = conglom_descriptors[cd_idx];
511 
512                tc.purgeConglomerate(cd.getConglomerateNumber());
513            }
514          }
515        }
516 
517        return;
518    }
519 
520    /**
521     * Truncate end of conglomerate.
522     * <p>
523     * Returns the contiguous free space at the end of the table back to
524     * the operating system.  Takes care of space allocation bit maps, and
525     * OS call to return the actual space.
526     * <p>
527     *
528     * @param schemaName        schema of table to defragement
529     * @param tableName         name of table to defragment
530     * @param data_dictionary   An open data dictionary to look up the table in.
531     * @param tc                transaction controller to use to do updates.
532     *
533     **/
534        private static void truncateEnd(
535    String                  schemaName, 
536    String                  tableName,
537    DataDictionary          data_dictionary,
538    TransactionController   tc)
539        throws StandardException
540        {
541        SchemaDescriptor sd = 
542            data_dictionary.getSchemaDescriptor(schemaName, tc, true);
543        TableDescriptor  td = 
544            data_dictionary.getTableDescriptor(tableName, sd);
545 
546        if (td == null)
547        {
548            throw StandardException.newException(
549                SQLState.LANG_TABLE_NOT_FOUND, 
550                schemaName + "." + tableName);
551        }
552 
553        switch (td.getTableType())
554        {
555        /* Skip views and vti tables */
556        case TableDescriptor.VIEW_TYPE:
557        case TableDescriptor.VTI_TYPE:
558                break;
559        // other types give various errors here
560        // DERBY-719,DERBY-720
561        default:
562          {
563          ConglomerateDescriptor[] conglom_descriptors = 
564                td.getConglomerateDescriptors();
565 
566            for (int cd_idx = 0; cd_idx < conglom_descriptors.length; cd_idx++)
567            {
568                ConglomerateDescriptor cd = conglom_descriptors[cd_idx];
569 
570                tc.compressConglomerate(cd.getConglomerateNumber());
571            }
572          }
573        }
574 
575        return;
576    }
577 
578    private static void setup_indexes(
579    TransactionController       tc,
580    TableDescriptor             td,
581    int[][]                     index_col_map,
582    ScanController[]            index_scan,
583    ConglomerateController[]    index_cc,
584    DataValueDescriptor[][]     index_row)
585                throws StandardException
586    {
587 
588        // Initialize the following 3 arrays which will be used to update
589        // each index as the scan moves rows about the heap as part of
590        // the compress:
591        //     index_col_map - map location of index cols in the base row, ie.
592        //                     index_col_map[0] is column offset of 1st key
593        //                     collumn in base row.  All offsets are 0 based.
594        //     index_scan - open ScanController used to delete old index row
595        //     index_cc   - open ConglomerateController used to insert new row
596 
597        ConglomerateDescriptor[] conglom_descriptors =
598                td.getConglomerateDescriptors();
599 
600 
601        int index_idx = 0;
602        for (int cd_idx = 0; cd_idx < conglom_descriptors.length; cd_idx++)
603        {
604            ConglomerateDescriptor index_cd = conglom_descriptors[cd_idx];
605 
606            if (!index_cd.isIndex())
607            {
608                // skip the heap descriptor entry
609                continue;
610            }
611 
612            // ScanControllers are used to delete old index row
613            index_scan[index_idx] = 
614                tc.openScan(
615                    index_cd.getConglomerateNumber(),
616                    true,        // hold
617                    TransactionController.OPENMODE_FORUPDATE,
618                    TransactionController.MODE_TABLE,
619                    TransactionController.ISOLATION_SERIALIZABLE,
620                    null,   // full row is retrieved, 
621                            // so that full row can be used for start/stop keys
622                    null,        // startKeyValue - will be reset with reopenScan()
623                    0,                // 
624                    null,        // qualifier
625                    null,        // stopKeyValue  - will be reset with reopenScan()
626                    0);                // 
627 
628            // ConglomerateControllers are used to insert new index row
629            index_cc[index_idx] = 
630                tc.openConglomerate(
631                    index_cd.getConglomerateNumber(),
632                    true,  // hold
633                    TransactionController.OPENMODE_FORUPDATE,
634                    TransactionController.MODE_TABLE,
635                    TransactionController.ISOLATION_SERIALIZABLE);
636 
637            // build column map to allow index row to be built from base row
638            int[] baseColumnPositions   = 
639                index_cd.getIndexDescriptor().baseColumnPositions();
640            int[] zero_based_map        = 
641                new int[baseColumnPositions.length];
642 
643            for (int i = 0; i < baseColumnPositions.length; i++)
644            {
645                zero_based_map[i] = baseColumnPositions[i] - 1; 
646            }
647 
648            index_col_map[index_idx] = zero_based_map;
649 
650            // build row array to delete from index and insert into index
651            //     length is length of column map + 1 for RowLocation.
652            index_row[index_idx] = 
653                new DataValueDescriptor[baseColumnPositions.length + 1];
654 
655            index_idx++;
656        }
657 
658        return;
659    }
660 
661 
662    /**
663     * Delete old index row and insert new index row in input index.
664     * <p>
665     *
666     * @param base_row      all columns of base row
667     * @param index_row     an index row template, filled in by this routine
668     * @param old_row_loc   old location of base row, used to delete index
669     * @param new_row_loc   new location of base row, used to update index
670     * @param index_cc      index conglomerate to insert new row
671     * @param index_scan    index scan to delete old entry
672     * @param index_col_map description of mapping of index row to base row,
673     *                      
674     *
675         * @exception  StandardException  Standard exception policy.
676     **/
677    private static void fixIndex(
678    DataValueDescriptor[]   base_row,
679    DataValueDescriptor[]   index_row,
680    RowLocation             old_row_loc,
681    RowLocation             new_row_loc,
682    ConglomerateController  index_cc,
683    ScanController          index_scan,
684        int[]                                        index_col_map)
685        throws StandardException
686    {
687        if (SanityManager.DEBUG)
688        {
689            // baseColumnPositions should describe all columns in index row
690            // except for the final column, which is the RowLocation.
691            SanityManager.ASSERT(index_col_map != null);
692            SanityManager.ASSERT(index_row != null);
693            SanityManager.ASSERT(
694                (index_col_map.length == (index_row.length - 1)));
695        }
696 
697        // create the index row to delete from from the base row, using map
698        for (int index = 0; index < index_col_map.length; index++)
699        {
700            index_row[index] = base_row[index_col_map[index]];
701        }
702        // last column in index in the RowLocation
703        index_row[index_row.length - 1] = old_row_loc;
704 
705        // position the scan for the delete, the scan should already be open.
706        // This is done by setting start scan to full key, GE and stop scan
707        // to full key, GT.
708        index_scan.reopenScan(
709            index_row,
710            ScanController.GE,
711            (Qualifier[][]) null,
712            index_row,
713            ScanController.GT);
714 
715        // position the scan, serious problem if scan does not find the row.
716        if (index_scan.next())
717        {
718            index_scan.delete();
719        }
720        else
721        {
722            // Didn't find the row we wanted to delete.
723            if (SanityManager.DEBUG)
724            {
725                SanityManager.THROWASSERT(
726                    "Did not find row to delete." +
727                    "base_row = " + RowUtil.toString(base_row) +
728                    "index_row = " + RowUtil.toString(index_row));
729            }
730        }
731 
732        // insert the new index row into the conglomerate
733        index_row[index_row.length - 1] = new_row_loc;
734 
735        index_cc.insert(index_row);
736 
737        return;
738    }
739}

[all classes][org.apache.derby.iapi.db]
EMMA 2.0.5312 (C) Vladimir Roubtsov