KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.RowChangerImpl
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.io.FormatableBitSet;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27
28 import org.apache.derby.iapi.error.StandardException;
29
30 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
31 import org.apache.derby.iapi.sql.conn.StatementContext;
32 import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
33 import org.apache.derby.iapi.sql.execute.ExecRow;
34 import org.apache.derby.iapi.sql.execute.ExecutionContext;
35 import org.apache.derby.iapi.sql.execute.RowChanger;
36 import org.apache.derby.iapi.sql.execute.ExecutionFactory;
37 import org.apache.derby.iapi.sql.execute.TemporaryRowHolder;
38
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.StaticCompiledOpenConglomInfo;
44 import org.apache.derby.iapi.store.access.TransactionController;
45
46 import org.apache.derby.iapi.types.DataValueDescriptor;
47
48 import org.apache.derby.iapi.types.RowLocation;
49
50 import java.util.Vector JavaDoc;
51
52 /**
53   Perform row at a time DML operations of tables and maintain indexes.
54   */

55 class RowChangerImpl implements RowChanger
56 {
57     boolean isOpen = false;
58
59     //
60
//Stuff provided to the constructor
61
boolean[] fixOnUpdate = null;
62     long heapConglom;
63     DynamicCompiledOpenConglomInfo heapDCOCI;
64     StaticCompiledOpenConglomInfo heapSCOCI;
65     long[] indexCIDS = null;
66     DynamicCompiledOpenConglomInfo[] indexDCOCIs;
67     StaticCompiledOpenConglomInfo[] indexSCOCIs;
68     IndexRowGenerator[] irgs = null;
69     Activation activation;
70     TransactionController tc;
71     FormatableBitSet changedColumnBitSet;
72     FormatableBitSet baseRowReadList;
73     private int[] baseRowReadMap; //index=heap column, value=input row column.
74
int[] changedColumnIds;
75     TemporaryRowHolderImpl rowHolder;
76     
77     // for error reporting.
78
String JavaDoc[] indexNames;
79
80     //
81
//Stuff filled in by open
82
private ConglomerateController baseCC;
83     private RowLocation baseRowLocation;
84     private IndexSetChanger isc;
85
86     // a row array with all non-updated columns compacted out
87
private DataValueDescriptor[] sparseRowArray;
88     private int[] partialChangedColumnIds;
89     
90     /**
91       Create a new RowChanger for performing update and delete operations
92       based on partial before and after rows.
93
94       @param heapConglom Conglomerate # for the heap
95       @param heapSCOCI SCOCI for heap.
96       @param heapDCOCI DCOCI for heap
97       @param irgs the IndexRowGenerators for the table's indexes. We use
98         positions in this array as local id's for indexes. To support updates,
99         only indexes that change need be included.
100       @param indexCIDS the conglomerateids for the table's idexes.
101         indexCIDS[ix] corresponds to the same index as irgs[ix].
102       @param indexSCOCIs the SCOCIs for the table's idexes.
103         indexSCOCIs[ix] corresponds to the same index as irgs[ix].
104       @param indexDCOCIs the DCOCIs for the table's idexes.
105         indexDCOCIs[ix] corresponds to the same index as irgs[ix].
106       @param numberOfColumns Number of columns in partial write row.
107       @param changedColumnIdsInput array of 1 based ints indicating the columns
108         to be updated. Only used for updates
109       @param tc the transaction controller
110       @param baseRowReadList bit set of columns read from base row. 1 based.
111       @param baseRowReadMap BaseRowReadMap[heapColId]->ReadRowColumnId. (0 based)
112       @exception StandardException Thrown on error
113       */

114     public RowChangerImpl(
115                long heapConglom,
116                StaticCompiledOpenConglomInfo heapSCOCI,
117                DynamicCompiledOpenConglomInfo heapDCOCI,
118                IndexRowGenerator[] irgs,
119                long[] indexCIDS,
120                StaticCompiledOpenConglomInfo[] indexSCOCIs,
121                DynamicCompiledOpenConglomInfo[] indexDCOCIs,
122                int numberOfColumns,
123                int[] changedColumnIdsInput,
124                TransactionController tc,
125                FormatableBitSet baseRowReadList,
126                int[] baseRowReadMap,
127                Activation activation)
128          throws StandardException
129     {
130         this.heapConglom = heapConglom;
131         this.heapSCOCI = heapSCOCI;
132         this.heapDCOCI = heapDCOCI;
133         this.irgs = irgs;
134         this.indexCIDS = indexCIDS;
135         this.indexSCOCIs = indexSCOCIs;
136         this.indexDCOCIs = indexDCOCIs;
137         this.tc = tc;
138         this.baseRowReadList = baseRowReadList;
139         this.baseRowReadMap = baseRowReadMap;
140         this.activation = activation;
141
142         if (SanityManager.DEBUG)
143         {
144             SanityManager.ASSERT(indexCIDS != null, "indexCIDS is null");
145         }
146
147         /*
148         ** Construct the update column FormatableBitSet.
149         ** It is 0 based as opposed to the 1 based
150         ** changed column ids.
151         */

152         if (changedColumnIdsInput != null)
153         {
154             /*
155             ** Sometimes replication does not have columns
156             ** in sorted order, and basically needs to
157             ** have the changed columns in non-sorted order.
158             ** So sort them first if needed.
159             */

160             changedColumnIds = RowUtil.inAscendingOrder(changedColumnIdsInput) ?
161                                 changedColumnIdsInput : sortArray(changedColumnIdsInput);
162
163             /*
164             ** Allocate the row array we are going to use during
165             ** update here, to avoid extra work. setup
166             ** the FormatableBitSet of columns being updated. See updateRow
167             ** for the use.
168             **
169             ** changedColumnIds is guaranteed to be in order, so just take
170             ** the last column number in the array to be the highest
171             ** column number.
172             */

173             sparseRowArray =
174                 new DataValueDescriptor[changedColumnIds[changedColumnIds.length - 1] + 1];
175             changedColumnBitSet = new FormatableBitSet(numberOfColumns);
176             for (int i = 0; i < changedColumnIds.length; i++)
177             {
178                 // make sure changedColumnBitSet can accomodate bit
179
// changedColumnIds[i] - 1
180
changedColumnBitSet.grow(changedColumnIds[i]);
181                 changedColumnBitSet.set(changedColumnIds[i] - 1);
182             }
183
184             /*
185             ** If we have a read map and a write map, we
186             ** need to have a way to map the changed column
187             ** ids to be relative to the read map.
188             */

189             if (baseRowReadList != null)
190             {
191                 partialChangedColumnIds = new int[changedColumnIds.length];
192                 int partialColumnNumber = 1;
193                 int currentColumn = 0;
194                 for (int i = 0; i < changedColumnIds.length; i++)
195                 {
196                     for (; currentColumn < changedColumnIds[i]; currentColumn++)
197                     {
198                         if (baseRowReadList.get(currentColumn))
199                         {
200                             partialColumnNumber++;
201                         }
202                     }
203                     partialChangedColumnIds[i] = partialColumnNumber;
204                 }
205             }
206         }
207
208         if (SanityManager.DEBUG)
209         {
210             SanityManager.ASSERT(indexCIDS != null, "indexCIDS is null");
211         }
212         
213     }
214
215     /**
216      * Set the row holder for this changer to use.
217      * If the row holder is set, it wont bother
218      * saving copies of rows needed for deferred
219      * processing. Also, it will never close the
220      * passed in rowHolder.
221      *
222      * @param rowHolder the TemporaryRowHolder
223      */

224     public void setRowHolder(TemporaryRowHolder rowHolder)
225     {
226         this.rowHolder = (TemporaryRowHolderImpl)rowHolder;
227     }
228
229     /**
230      * @see RowChanger#setIndexNames
231      */

232     public void setIndexNames(String JavaDoc[] indexNames)
233     {
234         this.indexNames = indexNames;
235     }
236
237     /**
238       Open this RowChanger.
239
240       <P>Note to avoid the cost of fixing indexes that do not
241       change during update operations use openForUpdate().
242       @param lockMode The lock mode to use
243                             (row or table, see TransactionController)
244
245       @exception StandardException thrown on failure to convert
246       */

247     public void open(int lockMode)
248          throws StandardException
249     {
250         open(lockMode, true);
251     }
252
253     /**
254      * @inheritDoc
255      */

256     public void open(int lockMode, boolean wait)
257          throws StandardException
258     {
259         //
260
//We open for update but say to fix every index on
261
//updates.
262
if (fixOnUpdate == null)
263         {
264             fixOnUpdate = new boolean[irgs.length];
265             for (int ix = 0; ix < irgs.length; ix++)
266                 fixOnUpdate[ix] = true;
267         }
268         openForUpdate(fixOnUpdate, lockMode, wait);
269     }
270
271     /**
272       Open this RowChanger to avoid fixing indexes that do not change
273       during update operations.
274
275       @param fixOnUpdate fixOnUpdat[ix] == true ==> fix index 'ix' on
276       an update operation.
277       @param lockMode The lock mode to use
278                             (row or table, see TransactionController)
279       @param wait If true, then the caller wants to wait for locks. False will be
280                             when we using a nested user xaction - we want to timeout right away
281                             if the parent holds the lock. (bug 4821)
282
283       @exception StandardException thrown on failure to convert
284       */

285     public void openForUpdate(
286                   boolean[] fixOnUpdate, int lockMode, boolean wait
287               )
288          throws StandardException
289     {
290         LanguageConnectionContext lcc = null;
291
292         if (SanityManager.DEBUG)
293             SanityManager.ASSERT( ! isOpen, "RowChanger already open");
294         
295         if (activation != null)
296         {
297             lcc = activation.getLanguageConnectionContext();
298         }
299
300         /* Isolation level - translate from language to store */
301         int isolationLevel;
302         if (lcc == null)
303         {
304             isolationLevel = ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL;
305         }
306         else
307         {
308             isolationLevel = lcc.getCurrentIsolationLevel();
309         }
310
311
312         switch (isolationLevel)
313         {
314             // Even though we preserve the isolation level at READ UNCOMMITTED,
315
// Cloudscape Store will overwrite it to READ COMMITTED for update.
316
case ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL:
317                 isolationLevel =
318                     TransactionController.ISOLATION_READ_UNCOMMITTED;
319                 break;
320
321             case ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL:
322                 isolationLevel =
323                     TransactionController.ISOLATION_READ_COMMITTED;
324                 break;
325
326             case ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL:
327                 isolationLevel =
328                     TransactionController.ISOLATION_REPEATABLE_READ;
329                 break;
330
331             case ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL:
332                 isolationLevel =
333                     TransactionController.ISOLATION_SERIALIZABLE;
334                 break;
335
336             default:
337                 if (SanityManager.DEBUG)
338                 {
339                     SanityManager.THROWASSERT(
340                         "Invalid isolation level - " + isolationLevel);
341                 }
342         }
343
344         try {
345
346         /* We can get called by either an activation or
347          * the DataDictionary. The DD cannot use the
348          * CompiledInfo while the activation can.
349          */

350         if (heapSCOCI != null)
351         {
352             baseCC =
353                 tc.openCompiledConglomerate(
354                     false,
355                     (TransactionController.OPENMODE_FORUPDATE |
356                     ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
357                     lockMode,
358                     isolationLevel,
359                     heapSCOCI,
360                     heapDCOCI);
361         }
362         else
363         {
364             baseCC =
365                 tc.openConglomerate(
366                     heapConglom,
367                     false,
368                     (TransactionController.OPENMODE_FORUPDATE |
369                     ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),
370                     lockMode,
371                     isolationLevel);
372         }
373
374         } catch (StandardException se) {
375             if (activation != null)
376                 activation.checkStatementValidity();
377             throw se;
378         }
379
380         /* Save the ConglomerateController off in the activation
381          * to eliminate the need to open it a 2nd time if we are doing
382          * and index to base row for the search as part of an update or
383          * delete below us.
384          * NOTE: activation can be null. (We don't have it in
385          * the DataDictionary.)
386          */

387         if (activation != null)
388         {
389             activation.checkStatementValidity();
390             activation.setHeapConglomerateController(baseCC);
391         }
392
393         /* Only worry about indexes if there are indexes to worry about */
394         if (indexCIDS.length != 0)
395         {
396             /* IndexSetChanger re-used across executions. */
397             if (isc == null)
398             {
399                 isc = new IndexSetChanger(irgs,
400                                           indexCIDS,
401                                           indexSCOCIs,
402                                           indexDCOCIs,
403                                           indexNames,
404                                           baseCC,
405                                           tc,
406                                           lockMode,
407                                           baseRowReadList,
408                                           isolationLevel,
409                                           activation
410                                           );
411                 isc.setRowHolder(rowHolder);
412             }
413             else
414             {
415
416                 /* Propagate the heap's ConglomerateController to
417                  * all of the underlying index changers.
418                  */

419                 isc.setBaseCC(baseCC);
420             }
421
422             isc.open(fixOnUpdate);
423
424             if (baseRowLocation == null)
425                 baseRowLocation = baseCC.newRowLocationTemplate();
426         }
427
428         isOpen = true;
429     }
430        
431     /**
432       Insert a row into the table and perform associated index maintenance.
433
434       @param baseRow the row.
435       @exception StandardException Thrown on error
436       */

437     public void insertRow(ExecRow baseRow)
438          throws StandardException
439     {
440         if (SanityManager.DEBUG)
441             SanityManager.ASSERT(! baseCC.isKeyed(),
442                                  "Keyed inserts not yet supported");
443
444         if (baseCC.isKeyed())
445         {
446             //kcc.insert(row.key(), row());
447
}
448         else
449         {
450             if (isc != null)
451             {
452                 baseCC.insertAndFetchLocation(baseRow.getRowArray(), baseRowLocation);
453                 isc.insert(baseRow, baseRowLocation);
454             }
455             else
456             {
457                 baseCC.insert(baseRow.getRowArray());
458             }
459         }
460     }
461
462         
463     /**
464       Delete a row from the table and perform associated index maintenance.
465
466       @param baseRow the row.
467       @param baseRowLocation the row's base conglomerate
468          location
469       @exception StandardException Thrown on error
470       */

471     public void deleteRow(ExecRow baseRow, RowLocation baseRowLocation)
472          throws StandardException
473     {
474         if (isc != null)
475         {
476             isc.delete(baseRow, baseRowLocation);
477         }
478         baseCC.delete(baseRowLocation);
479     }
480
481     /**
482       Update a row in the table and perform associated index maintenance.
483
484       @param oldBaseRow the old image of the row.
485       @param newBaseRow the new image of the row.
486       @param baseRowLocation the row's base conglomerate
487          location
488       @exception StandardException Thrown on error
489       */

490     public void updateRow(ExecRow oldBaseRow,
491                           ExecRow newBaseRow,
492                           RowLocation baseRowLocation)
493          throws StandardException
494     {
495         if (isc != null)
496         {
497             isc.update(oldBaseRow, newBaseRow, baseRowLocation);
498         }
499
500         if (changedColumnBitSet != null)
501         {
502             DataValueDescriptor[] baseRowArray = newBaseRow.getRowArray();
503             int[] changedColumnArray = (partialChangedColumnIds == null) ?
504                     changedColumnIds : partialChangedColumnIds;
505             int nextColumnToUpdate = -1;
506             for (int i = 0; i < changedColumnArray.length; i++)
507             {
508                 int copyFrom = changedColumnArray[i] - 1;
509                 nextColumnToUpdate =
510                             changedColumnBitSet.anySetBit(nextColumnToUpdate);
511                 if (SanityManager.DEBUG)
512                 {
513                     SanityManager.ASSERT(nextColumnToUpdate >= 0,
514                         "More columns in changedColumnArray than in changedColumnBitSet");
515                 }
516                 sparseRowArray[nextColumnToUpdate] = baseRowArray[copyFrom];
517             }
518         }
519         else
520         {
521             sparseRowArray = newBaseRow.getRowArray();
522         }
523         baseCC.replace(baseRowLocation,
524                     sparseRowArray,
525                     changedColumnBitSet);
526     }
527
528     /**
529       Finish processing the changes. This means applying the deferred
530       inserts for updates to unique indexes.
531
532       @exception StandardException Thrown on error
533      */

534     public void finish()
535         throws StandardException
536     {
537         if (isc != null)
538         {
539             isc.finish();
540         }
541     }
542
543     /**
544       Close this RowChanger.
545
546       @exception StandardException Thrown on error
547       */

548     public void close()
549         throws StandardException
550     {
551         //
552
//NOTE: isc uses baseCC. Since we close baseCC we free isc for now.
553
//We could consider making isc open its own baseCC or even leaving
554
//baseCC open to promote re-use. We must keep in mind that baseCC
555
//is associated with the opener's TransactionController.
556
if (isc != null)
557         {
558             isc.close();
559         }
560
561         if (baseCC != null)
562         {
563             if (activation == null || activation.getForUpdateIndexScan() == null)
564                 baseCC.close(); //beetle 3865, don't close if borrowed to cursor
565
baseCC = null;
566         }
567         
568         isOpen = false;
569
570         // rowHolder is reused across executions and closed by caller
571
// since caller creates it
572

573         if (activation != null)
574         {
575             activation.clearHeapConglomerateController();
576         }
577     }
578
579     /** @see RowChanger#getHeapConglomerateController */
580     public ConglomerateController getHeapConglomerateController()
581     {
582         return baseCC;
583     }
584
585     private int[] sortArray(int[] input)
586     {
587         /*
588         ** Sotring.sort() will change the underlying array, so we
589         ** 'clone' it first
590         */

591         int[] output = new int[input.length];
592         System.arraycopy(input, 0, output, 0, input.length);
593         java.util.Arrays.sort(output);
594         return output;
595     }
596 }
597
Popular Tags