001: /*
002:
003: Derby - Class org.apache.derbyTesting.functionTests.util.T_ConsistencyChecker
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derbyTesting.functionTests.util;
023:
024: import org.apache.derby.iapi.error.StandardException;
025:
026: import org.apache.derby.iapi.sql.dictionary.DataDictionaryContext;
027: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
028: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
029: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
030: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
031: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
032: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
033:
034: import org.apache.derby.iapi.sql.depend.DependencyManager;
035:
036: import org.apache.derby.iapi.reference.SQLState;
037:
038: import org.apache.derby.iapi.sql.execute.ExecRow;
039: import org.apache.derby.iapi.sql.execute.ExecutionContext;
040:
041: import org.apache.derby.iapi.types.DataValueFactory;
042: import org.apache.derby.iapi.types.DataTypeDescriptor;
043:
044: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
045:
046: import org.apache.derby.iapi.store.access.TransactionController;
047: import org.apache.derby.iapi.types.RowLocation;
048: import org.apache.derby.iapi.store.access.ScanController;
049: import org.apache.derby.iapi.store.access.ConglomerateController;
050:
051: import org.apache.derby.iapi.services.context.ContextService;
052:
053: import org.apache.derby.iapi.services.io.FormatableBitSet;
054:
055: /**
056: * This class has methods for corrupting a database.
057: * IT MUST NOT BE DISTRIBUTED WITH THE PRODUCT.
058: *
059: * NOTE: The entry points to this class are all static,
060: * for easy access via the query language. Each of the
061: * static methods instantiates an object from the class
062: * and calls methods off of that object. This allows
063: * the sharing of code across the various static methods.
064: */
065: public class T_ConsistencyChecker {
066: private DataDictionary dd;
067: private TransactionController tc;
068: private LanguageConnectionContext lcc;
069: private DataValueFactory dvf;
070: private ExecutionContext ec;
071: private String indexName;
072: private String schemaName;
073: private String tableName;
074: private ConglomerateDescriptor id;
075: private SchemaDescriptor sd;
076: private TableDescriptor td;
077:
078: T_ConsistencyChecker(String schemaName, String tableName,
079: String indexName) throws StandardException {
080: this .schemaName = schemaName;
081: this .tableName = tableName;
082: this .indexName = indexName;
083: }
084:
085: /**
086: * Delete the first row from the heap, without
087: * deleting it from the indexes on the table.
088: *
089: * @param schemaName The schema name.
090: * @param tableName The table name.
091: *
092: * @return Nothing.
093: *
094: * @exception StandardException Thrown on error
095: */
096: public static void deleteFirstHeapRow(String schemaName,
097: String tableName) throws StandardException {
098: T_ConsistencyChecker t_cc = new T_ConsistencyChecker(
099: schemaName, tableName, null);
100: t_cc.getContexts();
101: t_cc.getDescriptors();
102:
103: /* Open a scan on the heap */
104: ScanController heapScan = t_cc.openUnqualifiedHeapScan();
105:
106: // Move to the 1st row in the heap
107: heapScan.next();
108:
109: // Delete the 1st row in the heap
110: heapScan.delete();
111:
112: heapScan.close();
113: }
114:
115: /**
116: * Get the first row from the heap and insert it into
117: * the heap again, without
118: * inserting it from the indexes on the table.
119: *
120: * @param schemaName The schema name.
121: * @param tableName The table name.
122: *
123: * @return Nothing.
124: *
125: * @exception StandardException Thrown on error
126: */
127: public static void reinsertFirstHeapRow(String schemaName,
128: String tableName) throws StandardException {
129: T_ConsistencyChecker t_cc = new T_ConsistencyChecker(
130: schemaName, tableName, null);
131: t_cc.getContexts();
132: t_cc.getDescriptors();
133:
134: /* Open a scan on the heap */
135: ScanController heapScan = t_cc.openUnqualifiedHeapScan();
136:
137: // Move to the 1st row in the heap
138: heapScan.next();
139:
140: // Fetch the 1st row
141: ExecRow firstRow = t_cc.getHeapRowOfNulls();
142: heapScan.fetch(firstRow.getRowArray());
143: heapScan.close();
144:
145: // Insert another copy of the 1st row into the heap
146: ConglomerateController heapCC = t_cc.openHeapCC();
147: heapCC.insert(firstRow.getRowArray());
148: heapCC.close();
149: }
150:
151: /**
152: * Set all of the columns in the first row from
153: * the heap to null, without
154: * updating the indexes on the table.
155: *
156: * @param schemaName The schema name.
157: * @param tableName The table name.
158: *
159: * @return Nothing.
160: *
161: * @exception StandardException Thrown on error
162: */
163: public static void nullFirstHeapRow(String schemaName,
164: String tableName) throws StandardException {
165: T_ConsistencyChecker t_cc = new T_ConsistencyChecker(
166: schemaName, tableName, null);
167: t_cc.getContexts();
168: t_cc.getDescriptors();
169:
170: /* Open a scan on the heap */
171: ScanController heapScan = t_cc.openUnqualifiedHeapScan();
172:
173: // Move to the 1st row in the heap
174: heapScan.next();
175:
176: // Get the RowLocation
177: RowLocation baseRL = heapScan.newRowLocationTemplate();
178: heapScan.fetchLocation(baseRL);
179:
180: // Replace the current row with nulls
181: heapScan.replace(t_cc.getHeapRowOfNulls().getRowArray(),
182: (FormatableBitSet) null);
183:
184: heapScan.close();
185: }
186:
187: /**
188: * Get the first row from the heap and insert it into
189: * the specified index, with a bad row location, without
190: * inserting it into the heap or the other indexes on the table.
191: *
192: * @param schemaName The schema name.
193: * @param tableName The table name.
194: * @param indexName The specified index.
195: *
196: * @return Nothing.
197: *
198: * @exception StandardException Thrown on error
199: */
200: public static void insertBadRowLocation(String schemaName,
201: String tableName, String indexName)
202: throws StandardException {
203: T_ConsistencyChecker t_cc = new T_ConsistencyChecker(
204: schemaName, tableName, indexName);
205: t_cc.getContexts();
206: t_cc.getDescriptors();
207:
208: /* Open a scan on the heap */
209: ScanController heapScan = t_cc.openUnqualifiedHeapScan();
210:
211: // Get the RowLocation
212: RowLocation baseRL = heapScan.newRowLocationTemplate();
213: RowLocation badRL = heapScan.newRowLocationTemplate();
214: heapScan.close();
215:
216: /* Open a scan on the index */
217: ExecRow indexRow = t_cc.getIndexTemplateRow(baseRL);
218: ScanController indexScan = t_cc.openUnqualifiedIndexScan();
219:
220: // Move to the 1st row in the index
221: indexScan.next();
222:
223: // Fetch the 1st row
224: indexScan.fetch(indexRow.getRowArray());
225: indexScan.close();
226:
227: // Insert another copy of the 1st row into the index with a bad row location
228: int keyLength = t_cc.getIndexDescriptor().getIndexDescriptor()
229: .baseColumnPositions().length;
230: indexRow.setColumn(keyLength + 1, badRL);
231:
232: ConglomerateController indexCC = t_cc.openIndexCC();
233: indexCC.insert(indexRow.getRowArray());
234: indexCC.close();
235: }
236:
237: /**
238: * Swap the values in the specified columns of the
239: * first row from the heap, without
240: * updating the indexes on the table.
241: *
242: * @param schemaName The schema name.
243: * @param tableName The table name.
244: * @param firstColumn First column #.
245: * @param secondColumn Second column #.
246: *
247: * @return Nothing.
248: *
249: * @exception StandardException Thrown on error
250: */
251: public static void swapColumnsInFirstHeapRow(String schemaName,
252: String tableName, int firstColumn, int secondColumn)
253: throws StandardException {
254: }
255:
256: /* Get the various contexts */
257: private void getContexts() throws StandardException {
258: lcc = (LanguageConnectionContext) ContextService
259: .getContext(LanguageConnectionContext.CONTEXT_ID);
260: tc = lcc.getTransactionExecute();
261:
262: dd = lcc.getDataDictionary();
263:
264: dvf = lcc.getDataValueFactory();
265:
266: ec = (ExecutionContext) (ContextService
267: .getContext(ExecutionContext.CONTEXT_ID));
268: }
269:
270: /* Get the various descriptors */
271: private void getDescriptors() throws StandardException {
272: sd = dd.getSchemaDescriptor(schemaName, tc, true);
273: td = dd.getTableDescriptor(tableName, sd);
274:
275: if (td == null) {
276: throw StandardException.newException(
277: SQLState.LANG_TABLE_NOT_FOUND, schemaName + "."
278: + tableName);
279: }
280:
281: if (indexName != null) {
282: id = dd.getConglomerateDescriptor(indexName, sd, true);
283: if (id == null) {
284: throw StandardException.newException(
285: SQLState.LANG_INDEX_NOT_FOUND, indexName);
286: }
287: }
288: }
289:
290: /* Get a heap row full of nulls */
291: private ExecRow getHeapRowOfNulls() throws StandardException {
292: ConglomerateController baseCC;
293: ExecRow baseRow;
294:
295: /* Open the heap for reading */
296: baseCC = tc.openConglomerate(td.getHeapConglomerateId(), false,
297: 0, TransactionController.MODE_TABLE,
298: TransactionController.ISOLATION_SERIALIZABLE);
299:
300: /* Get a row template for the base table */
301: baseRow = ec.getExecutionFactory().getValueRow(
302: td.getNumberOfColumns());
303:
304: /* Fill the row with nulls of the correct type */
305: ColumnDescriptorList cdl = td.getColumnDescriptorList();
306: int cdlSize = cdl.size();
307:
308: for (int index = 0; index < cdlSize; index++) {
309: ColumnDescriptor cd = (ColumnDescriptor) cdl
310: .elementAt(index);
311: DataTypeDescriptor dts = cd.getType();
312: baseRow.setColumn(cd.getPosition(), dts.getNull());
313: }
314:
315: baseCC.close();
316: return baseRow;
317: }
318:
319: /* Open an unqualified scan on the heap for update */
320: private ScanController openUnqualifiedHeapScan()
321: throws StandardException {
322: ScanController heapScan;
323:
324: heapScan = tc.openScan(
325: td.getHeapConglomerateId(),
326: false, // hold
327: TransactionController.OPENMODE_FORUPDATE, // forUpdate
328: TransactionController.MODE_TABLE,
329: TransactionController.ISOLATION_SERIALIZABLE,
330: (FormatableBitSet) null, null, // startKeyValue
331: 0, // not used with null start posn.
332: null, // qualifier
333: null, // stopKeyValue
334: 0); // not used with null stop posn.
335:
336: return heapScan;
337: }
338:
339: /* Open the heap conglomerate for update */
340: private ConglomerateController openHeapCC()
341: throws StandardException {
342: ConglomerateController heapCC;
343:
344: heapCC = tc.openConglomerate(td.getHeapConglomerateId(),
345: false,
346: TransactionController.OPENMODE_FORUPDATE, // forUpdate
347: TransactionController.MODE_TABLE,
348: TransactionController.ISOLATION_SERIALIZABLE);
349:
350: return heapCC;
351: }
352:
353: /* Get a template row for the specified index */
354: private ExecRow getIndexTemplateRow(RowLocation baseRL)
355: throws StandardException {
356: int[] baseColumnPositions;
357: int baseColumns = 0;
358: ExecRow indexScanTemplate;
359:
360: baseColumnPositions = id.getIndexDescriptor()
361: .baseColumnPositions();
362: baseColumns = baseColumnPositions.length;
363:
364: FormatableBitSet indexColsBitSet = new FormatableBitSet();
365: for (int i = 0; i < baseColumns; i++) {
366: indexColsBitSet.grow(baseColumnPositions[i]);
367: indexColsBitSet.set(baseColumnPositions[i] - 1);
368: }
369:
370: /* Get a row template */
371: indexScanTemplate = ec.getExecutionFactory().getValueRow(
372: baseColumns + 1);
373:
374: /* Fill the row with nulls of the correct type */
375: for (int column = 0; column < baseColumns; column++) {
376: /* Column positions in the data dictionary are one-based */
377: ColumnDescriptor cd = td
378: .getColumnDescriptor(baseColumnPositions[column]);
379: DataTypeDescriptor dts = cd.getType();
380: indexScanTemplate.setColumn(column + 1, dts.getNull());
381: }
382:
383: /* Set the row location in the last column of the index row */
384: indexScanTemplate.setColumn(baseColumns + 1, baseRL);
385:
386: return indexScanTemplate;
387: }
388:
389: /* Open an unqualified scan on the index for update */
390: private ScanController openUnqualifiedIndexScan()
391: throws StandardException {
392: ScanController indexScan;
393:
394: indexScan = tc.openScan(
395: id.getConglomerateNumber(),
396: false, // hold
397: TransactionController.OPENMODE_FORUPDATE, // forUpdate
398: TransactionController.MODE_TABLE,
399: TransactionController.ISOLATION_SERIALIZABLE,
400: (FormatableBitSet) null, null, // startKeyValue
401: 0, // not used with null start posn.
402: null, // qualifier
403: null, // stopKeyValue
404: 0); // not used with null stop posn.
405:
406: return indexScan;
407: }
408:
409: /* Open the index conglomerate for update */
410: private ConglomerateController openIndexCC()
411: throws StandardException {
412: ConglomerateController indexCC;
413:
414: indexCC = tc.openConglomerate(id.getConglomerateNumber(),
415: false,
416: TransactionController.OPENMODE_FORUPDATE, // forUpdate
417: TransactionController.MODE_TABLE,
418: TransactionController.ISOLATION_SERIALIZABLE);
419:
420: return indexCC;
421: }
422:
423: /* Return the ConglomerateDescriptor for the index */
424: private ConglomerateDescriptor getIndexDescriptor() {
425: return id;
426: }
427:
428: // following methods are originally from a different class - used in the test store/backupRestore1
429: // original comment for that class:
430: /**
431: * This class provides static methods for checking the consistency of database
432: * objects like tables.
433: */
434:
435: /**
436: * Run all of the consistency checkers which do not take parameters.
437: * Actually, just run the ones that "make sense" to run. Today,
438: * that is:
439: * countOpens()
440: *
441: * @return String If an inconsistency is found, and if DEBUG is on,
442: * then a string will be returned with more info.
443: * If DEBUG is off, then a simple string will be
444: * returned stating whether or not there are open scans.
445: *
446: * @exception StandardException Thrown on error
447: * @exception java.sql.SQLException Thrown on error
448: */
449: public static String runConsistencyChecker()
450: throws StandardException, java.sql.SQLException {
451: return countOpens() + countDependencies();
452: }
453:
454: /**
455: * Check to make sure that there are no open conglomerates, scans or sorts.
456: *
457: * @return String If an inconsistency is found, and if DEBUG is on,
458: * then a string will be returned with more info.
459: * If DEBUG is off, then a simple string will be
460: * returned stating whether or not there are open scans.
461: *
462: * @exception StandardException Thrown on error
463: */
464: public static String countOpens() throws StandardException {
465: int numOpens = 0;
466: LanguageConnectionContext lcc;
467: String output = "No open scans, etc.\n";
468: TransactionController tc;
469:
470: lcc = (LanguageConnectionContext) ContextService
471: .getContext(LanguageConnectionContext.CONTEXT_ID);
472: tc = lcc.getTransactionExecute();
473:
474: numOpens = tc.countOpens(TransactionController.OPEN_TOTAL);
475:
476: if (numOpens > 0) {
477: output = numOpens
478: + " conglomerates/scans/sorts found open\n";
479:
480: }
481:
482: return output;
483: }
484:
485: /**
486: * Check to make sure that there are no active dependencies (stored or
487: * in memory).
488: *
489: * @return String If an inconsistency is found, and if DEBUG is on,
490: * then a string will be returned with more info.
491: * If DEBUG is off, then a simple string will be
492: * returned stating whether or not there are open scans.
493: *
494: * @exception StandardException Thrown on error
495: * @exception java.sql.SQLException Thrown on error
496: */
497: public static String countDependencies() throws StandardException,
498: java.sql.SQLException {
499: int numDependencies = 0;
500: DataDictionary dd;
501: DataDictionaryContext ddc;
502: DependencyManager dm;
503: StringBuffer debugBuf = new StringBuffer();
504:
505: ddc = (DataDictionaryContext) (ContextService
506: .getContext(DataDictionaryContext.CONTEXT_ID));
507:
508: dd = ddc.getDataDictionary();
509: dm = dd.getDependencyManager();
510:
511: numDependencies = dm.countDependencies();
512:
513: if (numDependencies > 0) {
514: debugBuf.append(numDependencies + " dependencies found");
515: } else {
516: debugBuf.append("No outstanding dependencies.\n");
517: }
518:
519: return debugBuf.toString();
520: }
521: }
|