KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > iapi > db > ConsistencyChecker


1 /*
2
3    Derby - Class org.apache.derby.iapi.db.ConsistencyChecker
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.iapi.db;
23
24 import org.apache.derby.iapi.error.StandardException;
25 import org.apache.derby.iapi.error.PublicAPI;
26
27 import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
28 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
29 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
30 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
31 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
32 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
33 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
34 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
35 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
36
37 import org.apache.derby.iapi.sql.depend.DependencyManager;
38
39 import org.apache.derby.iapi.sql.execute.ExecRow;
40 import org.apache.derby.iapi.sql.execute.ExecutionContext;
41
42 import org.apache.derby.iapi.types.DataValueDescriptor;
43 import org.apache.derby.iapi.types.DataValueFactory;
44
45
46 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
47 import org.apache.derby.iapi.sql.conn.ConnectionUtil;
48
49 import org.apache.derby.iapi.store.access.TransactionController;
50 import org.apache.derby.iapi.types.RowLocation;
51 import org.apache.derby.iapi.store.access.ScanController;
52 import org.apache.derby.iapi.store.access.ConglomerateController;
53 import org.apache.derby.iapi.store.access.RowUtil;
54
55 import org.apache.derby.iapi.services.sanity.SanityManager;
56
57 import org.apache.derby.iapi.reference.SQLState;
58
59 import org.apache.derby.iapi.services.io.FormatableBitSet;
60
61 import java.sql.SQLException JavaDoc;
62
63 /**
64  * The ConsistencyChecker class provides static methods for verifying
65  * the consistency of the data stored within a database.
66  *
67  *
68    <p>This class can only be used within an SQL-J statement, a Java procedure or a server side Java method.
69    <p>This class can be accessed using the class alias <code> CONSISTENCYCHECKER </code> in SQL-J statements.
70  */

71 public class ConsistencyChecker
72 {
73
74     /** no requirement for a constructor */
75     private ConsistencyChecker() {
76     }
77
78     /**
79      * Check the named table, ensuring that all of its indexes are consistent
80      * with the base table.
81      * Use this
82      * method only within an SQL-J statement; do not call it directly.
83      * <P>When tables are consistent, the method returns true. Otherwise, the method throws an exception.
84      * <p>To check the consistency of a single table:
85      * <p><code>
86      * VALUES ConsistencyChecker::checkTable(<i>SchemaName</i>, <i>TableName</i>)</code></p>
87      * <P>For example, to check the consistency of the table <i>APP.Flights</i>:
88      * <p><code>
89      * VALUES ConsistencyChecker::checkTable('APP', 'FLIGHTS')</code></p>
90      * <p>To check the consistency of all of the tables in the 'APP' schema,
91      * stopping at the first failure:
92      *
93      * <P><code>SELECT tablename, ConsistencyChecker::checkTable(<br>
94      * 'APP', tablename)<br>
95      * FROM sys.sysschemas s, sys.systables t
96      * WHERE s.schemaname = 'APP' AND s.schemaid = t.schemaid</code>
97      *
98      * <p> To check the consistency of an entire database, stopping at the first failure:
99      *
100      * <p><code>SELECT schemaname, tablename,<br>
101      * ConsistencyChecker::checkTable(schemaname, tablename)<br>
102      * FROM sys.sysschemas s, sys.systables t<br>
103      * WHERE s.schemaid = t.schemaid</code>
104      *
105      *
106      *
107      * @param schemaName The schema name of the table.
108      * @param tableName The name of the table
109      *
110      * @return true, if the table is consistent, exception thrown if inconsistent
111      *
112      * @exception SQLException Thrown if some inconsistency
113      * is found, or if some unexpected
114      * exception is thrown..
115      */

116     public static boolean checkTable(String JavaDoc schemaName, String JavaDoc tableName)
117                         throws SQLException JavaDoc
118     {
119         DataDictionary dd;
120         TableDescriptor td;
121         long baseRowCount = -1;
122         TransactionController tc;
123         ConglomerateDescriptor heapCD;
124         ConglomerateDescriptor indexCD;
125         ExecRow baseRow;
126         ExecRow indexRow;
127         RowLocation rl = null;
128         RowLocation scanRL = null;
129         ScanController scan = null;
130         int[] baseColumnPositions;
131         int baseColumns = 0;
132         DataValueFactory dvf;
133         long indexRows;
134         ConglomerateController baseCC = null;
135         ConglomerateController indexCC = null;
136         ExecutionContext ec;
137         SchemaDescriptor sd;
138         ConstraintDescriptor constraintDesc;
139
140         LanguageConnectionContext lcc = ConnectionUtil.getCurrentLCC();
141         tc = lcc.getTransactionExecute();
142
143         try {
144
145             dd = lcc.getDataDictionary();
146
147             dvf = lcc.getDataValueFactory();
148
149             ec = lcc.getExecutionContext() ;
150
151             sd = dd.getSchemaDescriptor(schemaName, tc, true);
152             td = dd.getTableDescriptor(tableName, sd);
153
154             if (td == null)
155             {
156                 throw StandardException.newException(
157                     SQLState.LANG_TABLE_NOT_FOUND,
158                     schemaName + "." + tableName);
159             }
160
161             /* Skip views */
162             if (td.getTableType() == TableDescriptor.VIEW_TYPE)
163             {
164                 return true;
165             }
166
167             /* Open the heap for reading */
168             baseCC = tc.openConglomerate(
169                         td.getHeapConglomerateId(), false, 0,
170                         TransactionController.MODE_TABLE,
171                         TransactionController.ISOLATION_SERIALIZABLE);
172
173             /* Check the consistency of the heap */
174             baseCC.checkConsistency();
175
176             heapCD = td.getConglomerateDescriptor(td.getHeapConglomerateId());
177
178             /* Get a row template for the base table */
179             baseRow = ec.getExecutionFactory().getValueRow(td.getNumberOfColumns());
180
181             /* Fill the row with nulls of the correct type */
182             ColumnDescriptorList cdl = td.getColumnDescriptorList();
183             int cdlSize = cdl.size();
184
185             for (int index = 0; index < cdlSize; index++)
186             {
187                 ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index);
188                 baseRow.setColumn(cd.getPosition(),
189                                         cd.getType().getNull());
190             }
191
192             /* Look at all the indexes on the table */
193             ConglomerateDescriptor[] cds = td.getConglomerateDescriptors();
194             for (int index = 0; index < cds.length; index++)
195             {
196                 indexCD = cds[index];
197                 /* Skip the heap */
198                 if ( ! indexCD.isIndex())
199                     continue;
200
201                 /* Check the internal consistency of the index */
202                 indexCC =
203                     tc.openConglomerate(
204                         indexCD.getConglomerateNumber(),
205                         false,
206                         0,
207                         TransactionController.MODE_TABLE,
208                         TransactionController.ISOLATION_SERIALIZABLE);
209
210                 indexCC.checkConsistency();
211                 indexCC.close();
212                 indexCC = null;
213
214                 /* if index is for a constraint check that the constraint exists */
215
216                 if (indexCD.isConstraint())
217                 {
218                     constraintDesc = dd.getConstraintDescriptor(td, indexCD.getUUID());
219                     if (constraintDesc == null)
220                     {
221                         throw StandardException.newException(
222                                         SQLState.LANG_OBJECT_NOT_FOUND,
223                                         "CONSTRAINT for INDEX",
224                                         indexCD.getConglomerateName());
225                     }
226                 }
227
228                 /*
229                 ** Set the base row count when we get to the first index.
230                 ** We do this here, rather than outside the index loop, so
231                 ** we won't do the work of counting the rows in the base table
232                 ** if there are no indexes to check.
233                 */

234                 if (baseRowCount < 0)
235                 {
236                     scan = tc.openScan(heapCD.getConglomerateNumber(),
237                                         false, // hold
238
0, // not forUpdate
239
TransactionController.MODE_TABLE,
240                                         TransactionController.ISOLATION_SERIALIZABLE,
241                                         RowUtil.EMPTY_ROW_BITSET,
242                                         null, // startKeyValue
243
0, // not used with null start posn.
244
null, // qualifier
245
null, // stopKeyValue
246
0); // not used with null stop posn.
247

248                     /* Also, get the row location template for index rows */
249                     rl = scan.newRowLocationTemplate();
250                     scanRL = scan.newRowLocationTemplate();
251
252                     for (baseRowCount = 0; scan.next(); baseRowCount++)
253                         ; /* Empty statement */
254
255                     scan.close();
256                     scan = null;
257                 }
258
259                 baseColumnPositions =
260                         indexCD.getIndexDescriptor().baseColumnPositions();
261                 baseColumns = baseColumnPositions.length;
262
263                 FormatableBitSet indexColsBitSet = new FormatableBitSet();
264                 for (int i = 0; i < baseColumns; i++)
265                 {
266                     indexColsBitSet.grow(baseColumnPositions[i]);
267                     indexColsBitSet.set(baseColumnPositions[i] - 1);
268                 }
269
270                 /* Get one row template for the index scan, and one for the fetch */
271                 indexRow = ec.getExecutionFactory().getValueRow(baseColumns + 1);
272
273                 /* Fill the row with nulls of the correct type */
274                 for (int column = 0; column < baseColumns; column++)
275                 {
276                     /* Column positions in the data dictionary are one-based */
277                     ColumnDescriptor cd = td.getColumnDescriptor(baseColumnPositions[column]);
278                     indexRow.setColumn(column + 1,
279                                             cd.getType().getNull());
280                 }
281
282                 /* Set the row location in the last column of the index row */
283                 indexRow.setColumn(baseColumns + 1, rl);
284
285                 /* Do a full scan of the index */
286                 scan = tc.openScan(indexCD.getConglomerateNumber(),
287                                     false, // hold
288
0, // not forUpdate
289
TransactionController.MODE_TABLE,
290                                     TransactionController.ISOLATION_SERIALIZABLE,
291                                     (FormatableBitSet) null,
292                                     null, // startKeyValue
293
0, // not used with null start posn.
294
null, // qualifier
295
null, // stopKeyValue
296
0); // not used with null stop posn.
297

298                 DataValueDescriptor[] baseRowIndexOrder =
299                     new DataValueDescriptor[baseColumns];
300                 DataValueDescriptor[] baseObjectArray = baseRow.getRowArray();
301
302                 for (int i = 0; i < baseColumns; i++)
303                 {
304                     baseRowIndexOrder[i] = baseObjectArray[baseColumnPositions[i] - 1];
305                 }
306             
307                 /* Get the index rows and count them */
308                 for (indexRows = 0; scan.fetchNext(indexRow.getRowArray()); indexRows++)
309                 {
310                     /*
311                     ** Get the base row using the RowLocation in the index row,
312                     ** which is in the last column.
313                     */

314                     RowLocation baseRL = (RowLocation) indexRow.getColumn(baseColumns + 1);
315
316                     boolean base_row_exists =
317                         baseCC.fetch(
318                             baseRL, baseObjectArray, indexColsBitSet);
319
320                     /* Throw exception if fetch() returns false */
321                     if (! base_row_exists)
322                     {
323                         String JavaDoc indexName = indexCD.getConglomerateName();
324                         throw StandardException.newException(SQLState.LANG_INCONSISTENT_ROW_LOCATION,
325                                     (schemaName + "." + tableName),
326                                     indexName,
327                                     baseRL.toString(),
328                                     indexRow.toString());
329                     }
330
331                     /* Compare all the column values */
332                     for (int column = 0; column < baseColumns; column++)
333                     {
334                         DataValueDescriptor indexColumn =
335                             indexRow.getColumn(column + 1);
336                         DataValueDescriptor baseColumn =
337                             baseRowIndexOrder[column];
338
339                         /*
340                         ** With this form of compare(), null is considered equal
341                         ** to null.
342                         */

343                         if (indexColumn.compare(baseColumn) != 0)
344                         {
345                             ColumnDescriptor cd =
346                                 td.getColumnDescriptor(
347                                     baseColumnPositions[column]);
348
349                             /*
350                             System.out.println(
351                                 "SQLState.LANG_INDEX_COLUMN_NOT_EQUAL:" +
352                                 "indexCD.getConglomerateName()" + indexCD.getConglomerateName() +
353                                 ";td.getSchemaName() = " + td.getSchemaName() +
354                                 ";td.getName() = " + td.getName() +
355                                 ";baseRL.toString() = " + baseRL.toString() +
356                                 ";cd.getColumnName() = " + cd.getColumnName() +
357                                 ";indexColumn.toString() = " + indexColumn.toString() +
358                                 ";baseColumn.toString() = " + baseColumn.toString() +
359                                 ";indexRow.toString() = " + indexRow.toString());
360                             */

361
362                             throw StandardException.newException(
363                                 SQLState.LANG_INDEX_COLUMN_NOT_EQUAL,
364                                 indexCD.getConglomerateName(),
365                                 td.getSchemaName(),
366                                 td.getName(),
367                                 baseRL.toString(),
368                                 cd.getColumnName(),
369                                 indexColumn.toString(),
370                                 baseColumn.toString(),
371                                 indexRow.toString());
372                         }
373                     }
374                 }
375
376                 /* Clean up after the index scan */
377                 scan.close();
378                 scan = null;
379
380                 /*
381                 ** The index is supposed to have the same number of rows as the
382                 ** base conglomerate.
383                 */

384                 if (indexRows != baseRowCount)
385                 {
386                     throw StandardException.newException(SQLState.LANG_INDEX_ROW_COUNT_MISMATCH,
387                                         indexCD.getConglomerateName(),
388                                         td.getSchemaName(),
389                                         td.getName(),
390                                         Long.toString(indexRows),
391                                         Long.toString(baseRowCount));
392                 }
393             }
394             /* check that all constraints have backing index */
395             ConstraintDescriptorList constraintDescList =
396                 dd.getConstraintDescriptors(td);
397             for (int index = 0; index < constraintDescList.size(); index++)
398             {
399                 constraintDesc = constraintDescList.elementAt(index);
400                 if (constraintDesc.hasBackingIndex())
401                 {
402                     ConglomerateDescriptor conglomDesc;
403
404                     conglomDesc = td.getConglomerateDescriptor(
405                             constraintDesc.getConglomerateId());
406                     if (conglomDesc == null)
407                     {
408                         throw StandardException.newException(
409                                         SQLState.LANG_OBJECT_NOT_FOUND,
410                                         "INDEX for CONSTRAINT",
411                                         constraintDesc.getConstraintName());
412                     }
413                 }
414             }
415             
416         }
417         catch (StandardException se)
418         {
419             throw PublicAPI.wrapStandardException(se);
420         }
421         finally
422         {
423             try
424             {
425                 /* Clean up before we leave */
426                 if (baseCC != null)
427                 {
428                     baseCC.close();
429                     baseCC = null;
430                 }
431                 if (indexCC != null)
432                 {
433                     indexCC.close();
434                     indexCC = null;
435                 }
436                 if (scan != null)
437                 {
438                     scan.close();
439                     scan = null;
440                 }
441             }
442             catch (StandardException se)
443             {
444                 throw PublicAPI.wrapStandardException(se);
445             }
446         }
447
448         return true;
449     }
450 }
451
Popular Tags