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

COVERAGE SUMMARY FOR SOURCE FILE [ConsistencyChecker.java]

nameclass, %method, %block, %line, %
ConsistencyChecker.java100% (1/1)50%  (1/2)93%  (457/493)92%  (98/107)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ConsistencyChecker100% (1/1)50%  (1/2)93%  (457/493)92%  (98/107)
ConsistencyChecker (): void 0%   (0/1)0%   (0/3)0%   (0/2)
checkTable (String, String): boolean 100% (1/1)93%  (457/490)93%  (98/105)

1/*
2 
3   Derby - Class org.apache.derby.iapi.db.ConsistencyChecker
4 
5   Copyright 1999, 2004 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.RowUtil;
53 
54import org.apache.derby.iapi.services.sanity.SanityManager;
55 
56import org.apache.derby.iapi.reference.SQLState;
57 
58import org.apache.derby.iapi.services.io.FormatableBitSet;
59 
60import java.sql.SQLException;
61 
62/**
63 * The ConsistencyChecker class provides static methods for verifying
64 * the consistency of the data stored within a database.
65 * 
66 *
67   <p>This class can only be used within an SQL-J statement, a Java procedure or a server side Java method.
68   <p>This class can be accessed using the class alias <code> CONSISTENCYCHECKER </code> in SQL-J statements.
69 */
70public class ConsistencyChecker
71{
72 
73        /** no requirement for a constructor */
74        private ConsistencyChecker() {
75        }
76 
77        /**
78         * Check the named table, ensuring that all of its indexes are consistent
79         * with the base table.
80         * Use this
81         *  method only within an SQL-J statement; do not call it directly.
82         * <P>When tables are consistent, the method returns true. Otherwise, the method throws an exception.
83         * <p>To check the consistency of a single table:
84         * <p><code>
85         * VALUES ConsistencyChecker::checkTable(<i>SchemaName</i>, <i>TableName</i>)</code></p>
86         * <P>For example, to check the consistency of the table <i>APP.Flights</i>:
87         * <p><code>
88         * VALUES ConsistencyChecker::checkTable('APP', 'FLIGHTS')</code></p>
89         * <p>To check the consistency of all of the tables in the 'APP' schema,
90         * stopping at the first failure: 
91         *
92         * <P><code>SELECT tablename, ConsistencyChecker::checkTable(<br>
93         * 'APP', tablename)<br>
94         * FROM sys.sysschemas s, sys.systables t
95         * WHERE s.schemaname = 'APP' AND s.schemaid = t.schemaid</code>
96         *
97         * <p> To check the consistency of an entire database, stopping at the first failure:
98         *
99         * <p><code>SELECT schemaname, tablename,<br>
100         * ConsistencyChecker::checkTable(schemaname, tablename)<br>
101         * FROM sys.sysschemas s, sys.systables t<br>
102         * WHERE s.schemaid = t.schemaid</code>
103         *
104         *
105         *
106         * @param schemaName        The schema name of the table.
107         * @param tableName                The name of the table
108         *
109         * @return        true, if the table is consistent, exception thrown if inconsistent
110         *
111         * @exception        SQLException        Thrown if some inconsistency
112         *                                                                        is found, or if some unexpected
113         *                                                                        exception is thrown..
114         */
115        public static boolean checkTable(String schemaName, String tableName)
116                                                throws SQLException
117        {
118                DataDictionary                        dd;
119                TableDescriptor                        td;
120                long                                        baseRowCount = -1;
121                TransactionController        tc;
122                ConglomerateDescriptor        heapCD;
123                ConglomerateDescriptor        indexCD;
124                ExecRow                                        baseRow;
125                ExecRow                                        indexRow;
126                RowLocation                                rl = null;
127                RowLocation                                scanRL = null;
128                ScanController                        scan = null;
129                int[]                                        baseColumnPositions;
130                int                                                baseColumns = 0;
131                DataValueFactory                dvf;
132                long                                        indexRows;
133                ConglomerateController        baseCC = null;
134                ConglomerateController        indexCC = null;
135                ExecutionContext                ec;
136                SchemaDescriptor                sd;
137                ConstraintDescriptor        constraintDesc;
138 
139                LanguageConnectionContext lcc = ConnectionUtil.getCurrentLCC();
140                tc = lcc.getTransactionExecute();
141 
142                try {
143 
144            dd = lcc.getDataDictionary();
145 
146            dvf = lcc.getDataValueFactory();
147 
148            ec = lcc.getExecutionContext() ;
149 
150            sd = dd.getSchemaDescriptor(schemaName, tc, true);
151            td = dd.getTableDescriptor(tableName, sd);
152 
153            if (td == null)
154            {
155                throw StandardException.newException(
156                    SQLState.LANG_TABLE_NOT_FOUND, 
157                    schemaName + "." + tableName);
158            }
159 
160            /* Skip views */
161            if (td.getTableType() == TableDescriptor.VIEW_TYPE)
162            {
163                return true;
164            }
165 
166                        /* Open the heap for reading */
167                        baseCC = tc.openConglomerate(
168                                    td.getHeapConglomerateId(), false, 0, 
169                                        TransactionController.MODE_TABLE,
170                                            TransactionController.ISOLATION_SERIALIZABLE);
171 
172                        /* Check the consistency of the heap */
173                        baseCC.checkConsistency();
174 
175                        heapCD = td.getConglomerateDescriptor(td.getHeapConglomerateId());
176 
177                        /* Get a row template for the base table */
178                        baseRow = ec.getExecutionFactory().getValueRow(td.getNumberOfColumns());
179 
180                        /* Fill the row with nulls of the correct type */
181                        ColumnDescriptorList cdl = td.getColumnDescriptorList();
182                        int                                         cdlSize = cdl.size();
183 
184                        for (int index = 0; index < cdlSize; index++)
185                        {
186                                ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index);
187                                baseRow.setColumn(cd.getPosition(),
188                                                                                cd.getType().getNull());
189                        }
190 
191                        /* Look at all the indexes on the table */
192                        ConglomerateDescriptor[] cds = td.getConglomerateDescriptors();
193                        for (int index = 0; index < cds.length; index++)
194                        {
195                                indexCD = cds[index];
196                                /* Skip the heap */
197                                if ( ! indexCD.isIndex())
198                                        continue;
199 
200                                /* Check the internal consistency of the index */
201                                indexCC = 
202                                tc.openConglomerate(
203                                        indexCD.getConglomerateNumber(),
204                        false,
205                                            0,
206                                                TransactionController.MODE_TABLE,
207                            TransactionController.ISOLATION_SERIALIZABLE);
208 
209                                indexCC.checkConsistency();
210                                indexCC.close();
211                                indexCC = null;
212 
213                                /* if index is for a constraint check that the constraint exists */
214 
215                                if (indexCD.isConstraint())
216                                {
217                                        constraintDesc = dd.getConstraintDescriptor(td, indexCD.getUUID());
218                                        if (constraintDesc == null)
219                                        {
220                                                throw StandardException.newException(
221                                                                                SQLState.LANG_OBJECT_NOT_FOUND,
222                                                                                "CONSTRAINT for INDEX",
223                                                                                indexCD.getConglomerateName());
224                                        }
225                                }
226 
227                                /*
228                                ** Set the base row count when we get to the first index.
229                                ** We do this here, rather than outside the index loop, so
230                                ** we won't do the work of counting the rows in the base table
231                                ** if there are no indexes to check.
232                                */
233                                if (baseRowCount < 0)
234                                {
235                                        scan = tc.openScan(heapCD.getConglomerateNumber(),
236                                                                                false,        // hold
237                                                                                0,                // not forUpdate
238                                                                            TransactionController.MODE_TABLE,
239                                                                            TransactionController.ISOLATION_SERIALIZABLE,
240                                        RowUtil.EMPTY_ROW_BITSET,
241                                                                                null,        // startKeyValue
242                                                                                0,                // not used with null start posn.
243                                                                                null,        // qualifier
244                                                                                null,        // stopKeyValue
245                                                                                0);                // not used with null stop posn.
246 
247                                        /* Also, get the row location template for index rows */
248                                        rl = scan.newRowLocationTemplate();
249                                        scanRL = scan.newRowLocationTemplate();
250 
251                                        for (baseRowCount = 0; scan.next(); baseRowCount++)
252                                                ;        /* Empty statement */
253 
254                                        scan.close();
255                                        scan = null;
256                                }
257 
258                                baseColumnPositions =
259                                                indexCD.getIndexDescriptor().baseColumnPositions();
260                                baseColumns = baseColumnPositions.length;
261 
262                                FormatableBitSet indexColsBitSet = new FormatableBitSet();
263                                for (int i = 0; i < baseColumns; i++)
264                                {
265                                        indexColsBitSet.grow(baseColumnPositions[i]);
266                                        indexColsBitSet.set(baseColumnPositions[i] - 1);
267                                }
268 
269                                /* Get one row template for the index scan, and one for the fetch */
270                                indexRow = ec.getExecutionFactory().getValueRow(baseColumns + 1);
271 
272                                /* Fill the row with nulls of the correct type */
273                                for (int column = 0; column < baseColumns; column++)
274                                {
275                                        /* Column positions in the data dictionary are one-based */
276                                         ColumnDescriptor cd = td.getColumnDescriptor(baseColumnPositions[column]);
277                                        indexRow.setColumn(column + 1,
278                                                                                        cd.getType().getNull());
279                                }
280 
281                                /* Set the row location in the last column of the index row */
282                                indexRow.setColumn(baseColumns + 1, rl);
283 
284                                /* Do a full scan of the index */
285                                scan = tc.openScan(indexCD.getConglomerateNumber(),
286                                                                        false,        // hold
287                                                                        0,                // not forUpdate
288                                                                    TransactionController.MODE_TABLE,
289                                                            TransactionController.ISOLATION_SERIALIZABLE,
290                                                                        (FormatableBitSet) null,
291                                                                        null,        // startKeyValue
292                                                                        0,                // not used with null start posn.
293                                                                        null,        // qualifier
294                                                                        null,        // stopKeyValue
295                                                                        0);                // not used with null stop posn.
296 
297                                DataValueDescriptor[] baseRowIndexOrder = 
298                    new DataValueDescriptor[baseColumns];
299                                DataValueDescriptor[] baseObjectArray = baseRow.getRowArray();
300 
301                                for (int i = 0; i < baseColumns; i++)
302                                {
303                                        baseRowIndexOrder[i] = baseObjectArray[baseColumnPositions[i] - 1];
304                                }
305                        
306                                /* Get the index rows and count them */
307                                for (indexRows = 0; scan.fetchNext(indexRow.getRowArray()); indexRows++)
308                                {
309                                        /*
310                                        ** Get the base row using the RowLocation in the index row,
311                                        ** which is in the last column.  
312                                        */
313                                        RowLocation baseRL = (RowLocation) indexRow.getColumn(baseColumns + 1);
314 
315                                        boolean base_row_exists = 
316                                baseCC.fetch(
317                                        baseRL, baseObjectArray, indexColsBitSet);
318 
319                                        /* Throw exception if fetch() returns false */
320                                        if (! base_row_exists)
321                                        {
322                                                String indexName = indexCD.getConglomerateName();
323                                                throw StandardException.newException(SQLState.LANG_INCONSISTENT_ROW_LOCATION, 
324                                                                        (schemaName + "." + tableName),
325                                                                        indexName, 
326                                                                        baseRL.toString(),
327                                                                        indexRow.toString());
328                                        }
329 
330                                        /* Compare all the column values */
331                                        for (int column = 0; column < baseColumns; column++)
332                                        {
333                                                DataValueDescriptor indexColumn =
334                                                        indexRow.getColumn(column + 1);
335                                                DataValueDescriptor baseColumn =
336                                                        baseRowIndexOrder[column];
337 
338                                                /*
339                                                ** With this form of compare(), null is considered equal
340                                                ** to null.
341                                                */
342                                                if (indexColumn.compare(baseColumn) != 0)
343                                                {
344                                                        ColumnDescriptor cd = 
345                                td.getColumnDescriptor(
346                                    baseColumnPositions[column]);
347 
348                            /*
349                            System.out.println(
350                                "SQLState.LANG_INDEX_COLUMN_NOT_EQUAL:" +
351                                "indexCD.getConglomerateName()" + indexCD.getConglomerateName() +
352                                ";td.getSchemaName() = " + td.getSchemaName() +
353                                ";td.getName() = " + td.getName() +
354                                ";baseRL.toString() = " + baseRL.toString() +
355                                ";cd.getColumnName() = " + cd.getColumnName() +
356                                ";indexColumn.toString() = " + indexColumn.toString() +
357                                ";baseColumn.toString() = " + baseColumn.toString() +
358                                ";indexRow.toString() = " + indexRow.toString());
359                            */
360 
361                                                        throw StandardException.newException(
362                                SQLState.LANG_INDEX_COLUMN_NOT_EQUAL, 
363                                indexCD.getConglomerateName(),
364                                td.getSchemaName(),
365                                td.getName(),
366                                baseRL.toString(),
367                                cd.getColumnName(),
368                                indexColumn.toString(),
369                                baseColumn.toString(),
370                                indexRow.toString());
371                                                }
372                                        }
373                                }
374 
375                                /* Clean up after the index scan */
376                                scan.close();
377                                scan = null;
378 
379                                /*
380                                ** The index is supposed to have the same number of rows as the
381                                ** base conglomerate.
382                                */
383                                if (indexRows != baseRowCount)
384                                {
385                                        throw StandardException.newException(SQLState.LANG_INDEX_ROW_COUNT_MISMATCH, 
386                                                                                indexCD.getConglomerateName(),
387                                                                                td.getSchemaName(),
388                                                                                td.getName(),
389                                                                                Long.toString(indexRows),
390                                                                                Long.toString(baseRowCount));
391                                }
392                        }
393                        /* check that all constraints have backing index */
394                        ConstraintDescriptorList constraintDescList = 
395                                dd.getConstraintDescriptors(td);
396                        for (int index = 0; index < constraintDescList.size(); index++)
397                        {
398                                constraintDesc = constraintDescList.elementAt(index);
399                                if (constraintDesc.hasBackingIndex())
400                                {
401                                        ConglomerateDescriptor conglomDesc;
402 
403                                        conglomDesc = td.getConglomerateDescriptor(
404                                                        constraintDesc.getConglomerateId());
405                                        if (conglomDesc == null)
406                                        {
407                                                throw StandardException.newException(
408                                                                                SQLState.LANG_OBJECT_NOT_FOUND,
409                                                                                "INDEX for CONSTRAINT",
410                                                                                constraintDesc.getConstraintName());
411                                        }
412                                }
413                        }
414                        
415                }
416                catch (StandardException se)
417                {
418                        throw PublicAPI.wrapStandardException(se);
419                }
420                finally
421                {
422            try
423            {
424                /* Clean up before we leave */
425                if (baseCC != null)
426                {
427                    baseCC.close();
428                    baseCC = null;
429                }
430                if (indexCC != null)
431                {
432                    indexCC.close();
433                    indexCC = null;
434                }
435                if (scan != null)
436                {
437                    scan.close();
438                    scan = null;
439                }
440            }
441            catch (StandardException se)
442            {
443                throw PublicAPI.wrapStandardException(se);
444            }
445                }
446 
447                return true;
448        }
449}

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