KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.RIBulkChecker
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.error.StandardException;
27 import org.apache.derby.iapi.sql.ResultSet;
28
29 import org.apache.derby.iapi.types.BooleanDataValue;
30 import org.apache.derby.iapi.types.DataValueDescriptor;
31 import org.apache.derby.iapi.types.RowLocation;
32 import org.apache.derby.iapi.sql.execute.ExecRow;
33 import org.apache.derby.iapi.sql.LanguageProperties;
34
35 import org.apache.derby.iapi.store.access.ConglomerateController;
36 import org.apache.derby.iapi.store.access.GenericScanController;
37 import org.apache.derby.iapi.store.access.GroupFetchScanController;
38 import org.apache.derby.iapi.store.access.ScanController;
39 import org.apache.derby.iapi.store.access.TransactionController;
40 import org.apache.derby.iapi.types.DataValueDescriptor;
41
42 import org.apache.derby.iapi.services.io.FormatableBitSet;
43
44 /**
45  * Do a merge run comparing all the foreign keys from the
46  * foreign key conglomerate against the referenced keys
47  * from the primary key conglomerate. The scanControllers
48  * are passed in by the caller (caller controls locking on
49  * said conglomerates).
50  * <p>
51  * The comparision is done via a merge. Consequently,
52  * it is imperative that the scans are on keyed conglomerates
53  * (indexes) and that the referencedKeyScan is a unique scan.
54  * <p>
55  * Performance is no worse than N + M where N is foreign key
56  * rows and M is primary key rows.
57  * <p>
58  * Bulk fetch is used to further speed performance. The
59  * fetch size is LanguageProperties.BULK_FETCH_DEFAULT
60  *
61  * @see LanguageProperties
62  */

63 public class RIBulkChecker
64 {
65     private static final int EQUAL = 0;
66     private static final int GREATER_THAN = 1;
67     private static final int LESS_THAN = -1;
68
69     private FKInfo fkInfo;
70     private GroupFetchScanController referencedKeyScan;
71     private DataValueDescriptor[][] referencedKeyRowArray;
72     private GroupFetchScanController foreignKeyScan;
73     private DataValueDescriptor[][] foreignKeyRowArray;
74     private ConglomerateController unreferencedCC;
75     private int failedCounter;
76     private boolean quitOnFirstFailure;
77     private int numColumns;
78     private int currRefRowIndex;
79     private int currFKRowIndex;
80     private int lastRefRowIndex;
81     private int lastFKRowIndex;
82     private ExecRow firstRowToFail;
83
84     /**
85      * Create a RIBulkChecker
86      *
87      * @param referencedKeyScan scan of the referenced key's
88      * backing index. must be unique
89      * @param foreignKeyScan scan of the foreign key's
90      * backing index
91      * @param templateRow a template row for the indexes.
92      * Will be cloned when it is used.
93      * Must be a full index row.
94      * @param quitOnFirstFailure quit on first unreferenced key
95      * @param unreferencedCC put unreferenced keys here
96      * @param firstRowToFail the first row that fails the constraint
97      * is copied to this, if non-null
98      */

99     public RIBulkChecker
100     (
101             GroupFetchScanController referencedKeyScan,
102             GroupFetchScanController foreignKeyScan,
103             ExecRow templateRow,
104             boolean quitOnFirstFailure,
105             ConglomerateController unreferencedCC,
106             ExecRow firstRowToFail
107     )
108     {
109         this.referencedKeyScan = referencedKeyScan;
110         this.foreignKeyScan = foreignKeyScan;
111         this.quitOnFirstFailure = quitOnFirstFailure;
112         this.unreferencedCC = unreferencedCC;
113         this.firstRowToFail = firstRowToFail;
114
115         foreignKeyRowArray = new DataValueDescriptor[LanguageProperties.BULK_FETCH_DEFAULT_INT][];
116         foreignKeyRowArray[0] = templateRow.getRowArrayClone();
117         referencedKeyRowArray = new DataValueDescriptor[LanguageProperties.BULK_FETCH_DEFAULT_INT][];
118         referencedKeyRowArray[0]= templateRow.getRowArrayClone();
119         failedCounter = 0;
120         numColumns = templateRow.getRowArray().length - 1;
121         currFKRowIndex = -1;
122         currRefRowIndex = -1;
123     }
124
125     /**
126      * Perform the check.
127      *
128      * @return the number of failed rows
129      *
130      * @exception StandardException on error
131      */

132     public int doCheck()
133         throws StandardException
134     {
135         DataValueDescriptor[] foreignKey;
136         DataValueDescriptor[] referencedKey;
137
138         int compareResult;
139
140         referencedKey = getNextRef();
141
142         /*
143         ** For each foreign key
144         **
145         ** while (fk > pk)
146         ** next pk
147         ** if no next pk
148         ** failed
149         **
150         ** if fk != pk
151         ** failed
152         */

153         while ((foreignKey = getNextFK()) != null)
154         {
155             /*
156             ** If all of the foreign key is not null and there are no
157             ** referenced keys, then everything fails
158             ** ANSI standard says the referential constraint is
159             ** satisfied if either at least one of the values of the
160             ** referencing columns(i.e., foreign key) is null or the
161             ** value of each referencing column is equal to the
162             ** corresponding referenced column in the referenced table
163             */

164             if (!anyNull(foreignKey) && referencedKey == null)
165             {
166                 do
167                 {
168                     failure(foreignKey);
169                     if (quitOnFirstFailure)
170                     {
171                             return 1;
172                     }
173                 } while ((foreignKey = getNextFK()) != null);
174                 return failedCounter;
175             }
176
177             while ((compareResult = greaterThan(foreignKey, referencedKey)) == GREATER_THAN)
178             {
179                 if ((referencedKey = getNextRef()) == null)
180                 {
181                     do
182                     {
183                         failure(foreignKey);
184                         if (quitOnFirstFailure)
185                         {
186                             return 1;
187                         }
188                     } while ((foreignKey = getNextFK()) != null);
189                     return failedCounter;
190                 }
191             }
192
193             if (compareResult != EQUAL)
194             {
195                 failure(foreignKey);
196                 if (quitOnFirstFailure)
197                 {
198                     return 1;
199                 }
200             }
201         }
202         return failedCounter;
203     }
204
205
206     /*
207      * Use bulk fetch to get the next set of rows,
208      * or read the next out of our internal array.
209      */

210     private DataValueDescriptor[] getNextFK()
211         throws StandardException
212     {
213         if ((currFKRowIndex > lastFKRowIndex) ||
214             (currFKRowIndex == -1))
215         {
216             int rowCount =
217                 foreignKeyScan.fetchNextGroup(foreignKeyRowArray, (RowLocation[]) null);
218
219             if (rowCount == 0)
220             {
221                 currFKRowIndex = -1;
222                 return null;
223             }
224
225             lastFKRowIndex = rowCount - 1;
226             currFKRowIndex = 0;
227         }
228
229         return foreignKeyRowArray[currFKRowIndex++];
230     }
231
232     /*
233      * Use bulk fetch to get the next set of rows,
234      * or read the next out of our internal array.
235      */

236     private DataValueDescriptor[] getNextRef()
237         throws StandardException
238     {
239         if ((currRefRowIndex > lastRefRowIndex) ||
240             (currRefRowIndex == -1))
241         {
242             int rowCount =
243                 referencedKeyScan.fetchNextGroup(referencedKeyRowArray, (RowLocation[]) null);
244
245             if (rowCount == 0)
246             {
247                 currRefRowIndex = -1;
248                 return null;
249             }
250
251             lastRefRowIndex = rowCount - 1;
252             currRefRowIndex = 0;
253         }
254
255         return referencedKeyRowArray[currRefRowIndex++];
256     }
257
258     private void failure(DataValueDescriptor[] foreignKeyRow)
259         throws StandardException
260     {
261         if (failedCounter == 0)
262         {
263             if (firstRowToFail != null)
264             {
265                 firstRowToFail.setRowArray(foreignKeyRow);
266                 // clone it
267
firstRowToFail.setRowArray(firstRowToFail.getRowArrayClone());
268             }
269         }
270             
271         failedCounter++;
272         if (unreferencedCC != null)
273         {
274             unreferencedCC.insert(foreignKeyRow);
275         }
276     }
277     /*
278     ** Returns true if any of the foreign keys are null
279     ** otherwise, false.
280     */

281     private boolean anyNull(DataValueDescriptor[] fkRowArray)
282         throws StandardException
283     {
284         DataValueDescriptor fkCol;
285     
286         /*
287         ** Check all columns excepting the row location.
288         */

289         for (int i = 0; i < numColumns; i++)
290         {
291             fkCol = (DataValueDescriptor)fkRowArray[i];
292
293             /*
294             ** If ANY column in the fk is null,
295             ** return true
296             */

297             if (fkCol.isNull())
298             {
299                 return true;
300             }
301         }
302         return false;
303
304     }
305
306     private int greaterThan(DataValueDescriptor[] fkRowArray, DataValueDescriptor[] refRowArray)
307         throws StandardException
308     {
309         DataValueDescriptor fkCol;
310         DataValueDescriptor refCol;
311         int result;
312     
313         /*
314         ** If ANY column in the fk is null,
315         ** it is assumed to be equal
316         */

317         if (anyNull(fkRowArray))
318                     return EQUAL;
319
320         for (int i = 0; i < numColumns; i++)
321         {
322             fkCol = (DataValueDescriptor)fkRowArray[i];
323             refCol = (DataValueDescriptor)refRowArray[i];
324
325             result = fkCol.compare(refCol);
326
327             if (result == 1)
328             {
329                 return GREATER_THAN;
330             }
331             else if (result == -1)
332             {
333                 return LESS_THAN;
334             }
335
336             /*
337             ** If they are equal, go on to the next
338             ** column.
339             */

340         }
341         
342         /*
343         ** If we got here they must be equal
344         */

345         return EQUAL;
346     }
347 }
348
Popular Tags