Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / iapi / db / ConsistencyChecker.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/iapi/db/ConsistencyChecker.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/iapi/db/ConsistencyChecker.java
new file mode 100644 (file)
index 0000000..330f8d5
--- /dev/null
@@ -0,0 +1,444 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.iapi.db.ConsistencyChecker\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.db;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.error.PublicAPI;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;\r
+import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;\r
+\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.sql.execute.ExecutionFactory;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.DataValueFactory;\r
+\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.conn.ConnectionUtil;\r
+\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.types.RowLocation;\r
+import org.apache.derby.iapi.store.access.ScanController;\r
+import org.apache.derby.iapi.store.access.ConglomerateController;\r
+import org.apache.derby.iapi.store.access.RowUtil;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+import java.sql.SQLException;\r
+\r
+/**\r
+ * The ConsistencyChecker class provides static methods for verifying\r
+ * the consistency of the data stored within a database.\r
+ * \r
+ *\r
+   <p>This class can only be used within an SQL-J statement, a Java procedure or a server side Java method.\r
+   <p>This class can be accessed using the class alias <code> CONSISTENCYCHECKER </code> in SQL-J statements.\r
+ */\r
+public class ConsistencyChecker\r
+{\r
+\r
+       /** no requirement for a constructor */\r
+       private ConsistencyChecker() {\r
+       }\r
+\r
+       /**\r
+        * Check the named table, ensuring that all of its indexes are consistent\r
+        * with the base table.\r
+        * Use this\r
+        *  method only within an SQL-J statement; do not call it directly.\r
+        * <P>When tables are consistent, the method returns true. Otherwise, the method throws an exception.\r
+        * <p>To check the consistency of a single table:\r
+        * <p><code>\r
+        * VALUES ConsistencyChecker::checkTable(<i>SchemaName</i>, <i>TableName</i>)</code></p>\r
+        * <P>For example, to check the consistency of the table <i>APP.Flights</i>:\r
+        * <p><code>\r
+        * VALUES ConsistencyChecker::checkTable('APP', 'FLIGHTS')</code></p>\r
+        * <p>To check the consistency of all of the tables in the 'APP' schema,\r
+        * stopping at the first failure: \r
+        *\r
+        * <P><code>SELECT tablename, ConsistencyChecker::checkTable(<br>\r
+        * 'APP', tablename)<br>\r
+        * FROM sys.sysschemas s, sys.systables t\r
+        * WHERE s.schemaname = 'APP' AND s.schemaid = t.schemaid</code>\r
+        *\r
+        * <p> To check the consistency of an entire database, stopping at the first failure:\r
+        *\r
+        * <p><code>SELECT schemaname, tablename,<br>\r
+        * ConsistencyChecker::checkTable(schemaname, tablename)<br>\r
+        * FROM sys.sysschemas s, sys.systables t<br>\r
+        * WHERE s.schemaid = t.schemaid</code>\r
+        *\r
+        *\r
+        *\r
+        * @param schemaName    The schema name of the table.\r
+        * @param tableName             The name of the table\r
+        *\r
+        * @return      true, if the table is consistent, exception thrown if inconsistent\r
+        *\r
+        * @exception   SQLException    Thrown if some inconsistency\r
+        *                                                                      is found, or if some unexpected\r
+        *                                                                      exception is thrown..\r
+        */\r
+       public static boolean checkTable(String schemaName, String tableName)\r
+                                               throws SQLException\r
+       {\r
+               DataDictionary                  dd;\r
+               TableDescriptor                 td;\r
+               long                                    baseRowCount = -1;\r
+               TransactionController   tc;\r
+               ConglomerateDescriptor  heapCD;\r
+               ConglomerateDescriptor  indexCD;\r
+               ExecRow                                 baseRow;\r
+               ExecRow                                 indexRow;\r
+               RowLocation                             rl = null;\r
+               RowLocation                             scanRL = null;\r
+               ScanController                  scan = null;\r
+               int[]                                   baseColumnPositions;\r
+               int                                             baseColumns = 0;\r
+               DataValueFactory                dvf;\r
+               long                                    indexRows;\r
+               ConglomerateController  baseCC = null;\r
+               ConglomerateController  indexCC = null;\r
+               SchemaDescriptor                sd;\r
+               ConstraintDescriptor    constraintDesc;\r
+\r
+               LanguageConnectionContext lcc = ConnectionUtil.getCurrentLCC();\r
+               tc = lcc.getTransactionExecute();\r
+\r
+               try {\r
+\r
+            dd = lcc.getDataDictionary();\r
+\r
+            dvf = lcc.getDataValueFactory();\r
+            \r
+            ExecutionFactory ef = lcc.getLanguageConnectionFactory().getExecutionFactory();\r
+\r
+            sd = dd.getSchemaDescriptor(schemaName, tc, true);\r
+            td = dd.getTableDescriptor(tableName, sd);\r
+\r
+            if (td == null)\r
+            {\r
+                throw StandardException.newException(\r
+                    SQLState.LANG_TABLE_NOT_FOUND, \r
+                    schemaName + "." + tableName);\r
+            }\r
+\r
+            /* Skip views */\r
+            if (td.getTableType() == TableDescriptor.VIEW_TYPE)\r
+            {\r
+                return true;\r
+            }\r
+\r
+                       /* Open the heap for reading */\r
+                       baseCC = tc.openConglomerate(\r
+                                   td.getHeapConglomerateId(), false, 0, \r
+                                       TransactionController.MODE_TABLE,\r
+                                           TransactionController.ISOLATION_SERIALIZABLE);\r
+\r
+                       /* Check the consistency of the heap */\r
+                       baseCC.checkConsistency();\r
+\r
+                       heapCD = td.getConglomerateDescriptor(td.getHeapConglomerateId());\r
+\r
+                       /* Get a row template for the base table */\r
+                       baseRow = ef.getValueRow(td.getNumberOfColumns());\r
+\r
+                       /* Fill the row with nulls of the correct type */\r
+                       ColumnDescriptorList cdl = td.getColumnDescriptorList();\r
+                       int                                      cdlSize = cdl.size();\r
+\r
+                       for (int index = 0; index < cdlSize; index++)\r
+                       {\r
+                               ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index);\r
+                               baseRow.setColumn(cd.getPosition(),\r
+                                                                               cd.getType().getNull());\r
+                       }\r
+\r
+                       /* Look at all the indexes on the table */\r
+                       ConglomerateDescriptor[] cds = td.getConglomerateDescriptors();\r
+                       for (int index = 0; index < cds.length; index++)\r
+                       {\r
+                               indexCD = cds[index];\r
+                               /* Skip the heap */\r
+                               if ( ! indexCD.isIndex())\r
+                                       continue;\r
+\r
+                               /* Check the internal consistency of the index */\r
+                               indexCC = \r
+                               tc.openConglomerate(\r
+                                       indexCD.getConglomerateNumber(),\r
+                        false,\r
+                                           0,\r
+                                               TransactionController.MODE_TABLE,\r
+                           TransactionController.ISOLATION_SERIALIZABLE);\r
+\r
+                               indexCC.checkConsistency();\r
+                               indexCC.close();\r
+                               indexCC = null;\r
+\r
+                               /* if index is for a constraint check that the constraint exists */\r
+\r
+                               if (indexCD.isConstraint())\r
+                               {\r
+                                       constraintDesc = dd.getConstraintDescriptor(td, indexCD.getUUID());\r
+                                       if (constraintDesc == null)\r
+                                       {\r
+                                               throw StandardException.newException(\r
+                                                                               SQLState.LANG_OBJECT_NOT_FOUND,\r
+                                                                               "CONSTRAINT for INDEX",\r
+                                                                               indexCD.getConglomerateName());\r
+                                       }\r
+                               }\r
+\r
+                               /*\r
+                               ** Set the base row count when we get to the first index.\r
+                               ** We do this here, rather than outside the index loop, so\r
+                               ** we won't do the work of counting the rows in the base table\r
+                               ** if there are no indexes to check.\r
+                               */\r
+                               if (baseRowCount < 0)\r
+                               {\r
+                                       scan = tc.openScan(heapCD.getConglomerateNumber(),\r
+                                                                               false,  // hold\r
+                                                                               0,              // not forUpdate\r
+                                                                           TransactionController.MODE_TABLE,\r
+                                                                           TransactionController.ISOLATION_SERIALIZABLE,\r
+                                        RowUtil.EMPTY_ROW_BITSET,\r
+                                                                               null,   // startKeyValue\r
+                                                                               0,              // not used with null start posn.\r
+                                                                               null,   // qualifier\r
+                                                                               null,   // stopKeyValue\r
+                                                                               0);             // not used with null stop posn.\r
+\r
+                                       /* Also, get the row location template for index rows */\r
+                                       rl = scan.newRowLocationTemplate();\r
+                                       scanRL = scan.newRowLocationTemplate();\r
+\r
+                                       for (baseRowCount = 0; scan.next(); baseRowCount++)\r
+                                               ;       /* Empty statement */\r
+\r
+                                       scan.close();\r
+                                       scan = null;\r
+                               }\r
+\r
+                               baseColumnPositions =\r
+                                               indexCD.getIndexDescriptor().baseColumnPositions();\r
+                               baseColumns = baseColumnPositions.length;\r
+\r
+                               FormatableBitSet indexColsBitSet = new FormatableBitSet();\r
+                               for (int i = 0; i < baseColumns; i++)\r
+                               {\r
+                                       indexColsBitSet.grow(baseColumnPositions[i]);\r
+                                       indexColsBitSet.set(baseColumnPositions[i] - 1);\r
+                               }\r
+\r
+                               /* Get one row template for the index scan, and one for the fetch */\r
+                               indexRow = ef.getValueRow(baseColumns + 1);\r
+\r
+                               /* Fill the row with nulls of the correct type */\r
+                               for (int column = 0; column < baseColumns; column++)\r
+                               {\r
+                                       /* Column positions in the data dictionary are one-based */\r
+                                       ColumnDescriptor cd = td.getColumnDescriptor(baseColumnPositions[column]);\r
+                                       indexRow.setColumn(column + 1,\r
+                                                                                       cd.getType().getNull());\r
+                               }\r
+\r
+                               /* Set the row location in the last column of the index row */\r
+                               indexRow.setColumn(baseColumns + 1, rl);\r
+\r
+                               /* Do a full scan of the index */\r
+                               scan = tc.openScan(indexCD.getConglomerateNumber(),\r
+                                                                       false,  // hold\r
+                                                                       0,              // not forUpdate\r
+                                                                   TransactionController.MODE_TABLE,\r
+                                                           TransactionController.ISOLATION_SERIALIZABLE,\r
+                                                                       (FormatableBitSet) null,\r
+                                                                       null,   // startKeyValue\r
+                                                                       0,              // not used with null start posn.\r
+                                                                       null,   // qualifier\r
+                                                                       null,   // stopKeyValue\r
+                                                                       0);             // not used with null stop posn.\r
+\r
+                               DataValueDescriptor[] baseRowIndexOrder = \r
+                    new DataValueDescriptor[baseColumns];\r
+                               DataValueDescriptor[] baseObjectArray = baseRow.getRowArray();\r
+\r
+                               for (int i = 0; i < baseColumns; i++)\r
+                               {\r
+                                       baseRowIndexOrder[i] = baseObjectArray[baseColumnPositions[i] - 1];\r
+                               }\r
+                       \r
+                               /* Get the index rows and count them */\r
+                               for (indexRows = 0; scan.fetchNext(indexRow.getRowArray()); indexRows++)\r
+                               {\r
+                                       /*\r
+                                       ** Get the base row using the RowLocation in the index row,\r
+                                       ** which is in the last column.  \r
+                                       */\r
+                                       RowLocation baseRL = (RowLocation) indexRow.getColumn(baseColumns + 1);\r
+\r
+                                       boolean base_row_exists = \r
+                               baseCC.fetch(\r
+                                       baseRL, baseObjectArray, indexColsBitSet);\r
+\r
+                                       /* Throw exception if fetch() returns false */\r
+                                       if (! base_row_exists)\r
+                                       {\r
+                                               String indexName = indexCD.getConglomerateName();\r
+                                               throw StandardException.newException(SQLState.LANG_INCONSISTENT_ROW_LOCATION, \r
+                                                                       (schemaName + "." + tableName),\r
+                                                                       indexName, \r
+                                                                       baseRL.toString(),\r
+                                                                       indexRow.toString());\r
+                                       }\r
+\r
+                                       /* Compare all the column values */\r
+                                       for (int column = 0; column < baseColumns; column++)\r
+                                       {\r
+                                               DataValueDescriptor indexColumn =\r
+                                                       indexRow.getColumn(column + 1);\r
+                                               DataValueDescriptor baseColumn =\r
+                                                       baseRowIndexOrder[column];\r
+\r
+                                               /*\r
+                                               ** With this form of compare(), null is considered equal\r
+                                               ** to null.\r
+                                               */\r
+                                               if (indexColumn.compare(baseColumn) != 0)\r
+                                               {\r
+                                                       ColumnDescriptor cd = \r
+                                td.getColumnDescriptor(\r
+                                    baseColumnPositions[column]);\r
+\r
+                            /*\r
+                            System.out.println(\r
+                                "SQLState.LANG_INDEX_COLUMN_NOT_EQUAL:" +\r
+                                "indexCD.getConglomerateName()" + indexCD.getConglomerateName() +\r
+                                ";td.getSchemaName() = " + td.getSchemaName() +\r
+                                ";td.getName() = " + td.getName() +\r
+                                ";baseRL.toString() = " + baseRL.toString() +\r
+                                ";cd.getColumnName() = " + cd.getColumnName() +\r
+                                ";indexColumn.toString() = " + indexColumn.toString() +\r
+                                ";baseColumn.toString() = " + baseColumn.toString() +\r
+                                ";indexRow.toString() = " + indexRow.toString());\r
+                            */\r
+\r
+                                                       throw StandardException.newException(\r
+                                SQLState.LANG_INDEX_COLUMN_NOT_EQUAL, \r
+                                indexCD.getConglomerateName(),\r
+                                td.getSchemaName(),\r
+                                td.getName(),\r
+                                baseRL.toString(),\r
+                                cd.getColumnName(),\r
+                                indexColumn.toString(),\r
+                                baseColumn.toString(),\r
+                                indexRow.toString());\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               /* Clean up after the index scan */\r
+                               scan.close();\r
+                               scan = null;\r
+\r
+                               /*\r
+                               ** The index is supposed to have the same number of rows as the\r
+                               ** base conglomerate.\r
+                               */\r
+                               if (indexRows != baseRowCount)\r
+                               {\r
+                                       throw StandardException.newException(SQLState.LANG_INDEX_ROW_COUNT_MISMATCH, \r
+                                                                               indexCD.getConglomerateName(),\r
+                                                                               td.getSchemaName(),\r
+                                                                               td.getName(),\r
+                                                                               Long.toString(indexRows),\r
+                                                                               Long.toString(baseRowCount));\r
+                               }\r
+                       }\r
+                       /* check that all constraints have backing index */\r
+                       ConstraintDescriptorList constraintDescList = \r
+                               dd.getConstraintDescriptors(td);\r
+                       for (int index = 0; index < constraintDescList.size(); index++)\r
+                       {\r
+                               constraintDesc = constraintDescList.elementAt(index);\r
+                               if (constraintDesc.hasBackingIndex())\r
+                               {\r
+                                       ConglomerateDescriptor conglomDesc;\r
+\r
+                                       conglomDesc = td.getConglomerateDescriptor(\r
+                                                       constraintDesc.getConglomerateId());\r
+                                       if (conglomDesc == null)\r
+                                       {\r
+                                               throw StandardException.newException(\r
+                                                                               SQLState.LANG_OBJECT_NOT_FOUND,\r
+                                                                               "INDEX for CONSTRAINT",\r
+                                                                               constraintDesc.getConstraintName());\r
+                                       }\r
+                               }\r
+                       }\r
+                       \r
+               }\r
+               catch (StandardException se)\r
+               {\r
+                       throw PublicAPI.wrapStandardException(se);\r
+               }\r
+               finally\r
+               {\r
+            try\r
+            {\r
+                /* Clean up before we leave */\r
+                if (baseCC != null)\r
+                {\r
+                    baseCC.close();\r
+                    baseCC = null;\r
+                }\r
+                if (indexCC != null)\r
+                {\r
+                    indexCC.close();\r
+                    indexCC = null;\r
+                }\r
+                if (scan != null)\r
+                {\r
+                    scan.close();\r
+                    scan = null;\r
+                }\r
+            }\r
+            catch (StandardException se)\r
+            {\r
+                throw PublicAPI.wrapStandardException(se);\r
+            }\r
+               }\r
+\r
+               return true;\r
+       }\r
+}\r