0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.catalog.TabInfoImpl
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to you under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.impl.sql.catalog;
0023:
0024: import org.apache.derby.iapi.services.io.FormatableBitSet;
0025: import org.apache.derby.iapi.services.context.ContextService;
0026: import org.apache.derby.iapi.services.sanity.SanityManager;
0027: import org.apache.derby.iapi.services.io.StreamStorable;
0028: import org.apache.derby.iapi.error.StandardException;
0029: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0030: import org.apache.derby.iapi.sql.dictionary.CatalogRowFactory;
0031: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
0032: import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
0033: import org.apache.derby.iapi.sql.execute.ExecIndexRow;
0034: import org.apache.derby.iapi.sql.execute.ExecRow;
0035: import org.apache.derby.iapi.sql.execute.ExecutionContext;
0036: import org.apache.derby.iapi.sql.execute.ExecutionFactory;
0037: import org.apache.derby.iapi.sql.execute.RowChanger;
0038: import org.apache.derby.iapi.sql.execute.TupleFilter;
0039: import org.apache.derby.iapi.sql.Activation;
0040:
0041: import org.apache.derby.iapi.store.access.ConglomerateController;
0042: import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
0043: import org.apache.derby.iapi.store.access.Qualifier;
0044: import org.apache.derby.iapi.store.access.ScanController;
0045: import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
0046: import org.apache.derby.iapi.store.access.TransactionController;
0047:
0048: import org.apache.derby.iapi.types.DataValueDescriptor;
0049: import org.apache.derby.iapi.types.DataValueFactory;
0050:
0051: import org.apache.derby.iapi.types.RowLocation;
0052: import org.apache.derby.catalog.UUID;
0053: import java.util.Enumeration;
0054: import java.util.Properties;
0055:
0056: /**
0057: * A poor mans structure used in DataDictionaryImpl.java.
0058: * Used to save heapId, name pairs for non core tables.
0059: *
0060: * @author jamie
0061: */
0062: class TabInfoImpl {
0063: /**
0064: * ROWNOTDUPLICATE is out of range for a row
0065: * number. If a return code does not equal
0066: * this value, then it refers to the row
0067: * that is a duplicate.
0068: */
0069: static final int ROWNOTDUPLICATE = -1;
0070:
0071: private IndexInfoImpl[] indexes;
0072: private long heapConglomerate;
0073: private int numIndexesSet;
0074: private boolean heapSet;
0075: private final CatalogRowFactory crf;
0076:
0077: /**
0078: * Constructor
0079: *
0080: * @param crf the associated CatalogRowFactory
0081: */
0082: TabInfoImpl(CatalogRowFactory crf) {
0083: this .heapConglomerate = -1;
0084: this .crf = crf;
0085:
0086: int numIndexes = crf.getNumIndexes();
0087:
0088: if (numIndexes > 0) {
0089: indexes = new IndexInfoImpl[numIndexes];
0090:
0091: /* Init indexes */
0092: for (int indexCtr = 0; indexCtr < numIndexes; indexCtr++) {
0093: indexes[indexCtr] = new IndexInfoImpl(indexCtr, crf);
0094: }
0095: }
0096: }
0097:
0098: /**
0099: * Get the conglomerate for the heap.
0100: *
0101: * @return long The conglomerate for the heap.
0102: */
0103: long getHeapConglomerate() {
0104: return heapConglomerate;
0105: }
0106:
0107: /**
0108: * Set the heap conglomerate for this.
0109: *
0110: * @param heapConglomerate The new heap conglomerate.
0111: */
0112: void setHeapConglomerate(long heapConglomerate) {
0113: this .heapConglomerate = heapConglomerate;
0114: heapSet = true;
0115: }
0116:
0117: /**
0118: * Get the conglomerate for the specified index.
0119: *
0120: * @return long The conglomerate for the specified index.
0121: */
0122: long getIndexConglomerate(int indexID) {
0123: if (SanityManager.DEBUG) {
0124: SanityManager.ASSERT(indexes != null,
0125: "indexes is expected to be non-null");
0126: if (indexID >= indexes.length) {
0127: SanityManager
0128: .THROWASSERT("indexID (" + indexID
0129: + ") is out of range(0-"
0130: + indexes.length + ")");
0131: }
0132: }
0133:
0134: return indexes[indexID].getConglomerateNumber();
0135: }
0136:
0137: /**
0138: * Set the index conglomerate for the table.
0139: *
0140: * @param index Index number for index for table
0141: * @param indexConglomerate The conglomerate for that index
0142: */
0143: void setIndexConglomerate(int index, long indexConglomerate) {
0144: /* Index names must be set before conglomerates.
0145: * Also verify that we are not setting the same conglomerate
0146: * twice.
0147: */
0148: if (SanityManager.DEBUG) {
0149: SanityManager.ASSERT(indexes[index] != null,
0150: "indexes[index] expected to be non-null");
0151: SanityManager.ASSERT(
0152: indexes[index].getConglomerateNumber() == -1,
0153: "indexes[index] expected to be -1");
0154: }
0155: indexes[index].setConglomerateNumber(indexConglomerate);
0156:
0157: /* We are completely initialized when all indexes have
0158: * their conglomerates initialized
0159: */
0160: numIndexesSet++;
0161: }
0162:
0163: /**
0164: * Set the index conglomerate for the table.
0165: *
0166: * @param cd The ConglomerateDescriptor for one of the index
0167: * for this table.
0168: */
0169: void setIndexConglomerate(ConglomerateDescriptor cd) {
0170: int index;
0171: String indexName = cd.getConglomerateName();
0172:
0173: if (SanityManager.DEBUG) {
0174: SanityManager.ASSERT(indexes != null,
0175: "indexes is expected to be non-null");
0176: }
0177:
0178: for (index = 0; index < indexes.length; index++) {
0179: /* All index names expected to be set before
0180: * any conglomerate is set.
0181: */
0182: if (SanityManager.DEBUG) {
0183: SanityManager.ASSERT(indexes[index] != null,
0184: "indexes[index] expected to be non-null");
0185: SanityManager
0186: .ASSERT(indexes[index].getIndexName() != null,
0187: "indexes[index].getIndexName() expected to be non-null");
0188: }
0189:
0190: /* Do we have a match? */
0191: if (indexes[index].getIndexName().equals(indexName)) {
0192: indexes[index].setConglomerateNumber(cd
0193: .getConglomerateNumber());
0194: break;
0195: }
0196: }
0197:
0198: if (SanityManager.DEBUG) {
0199: if (index == indexes.length) {
0200: SanityManager.THROWASSERT("match not found for "
0201: + indexName);
0202: }
0203: }
0204:
0205: /* We are completely initialized when all indexIds are initialized */
0206: numIndexesSet++;
0207: }
0208:
0209: /**
0210: * Get the table name.
0211: *
0212: * @return String The table name.
0213: */
0214: String getTableName() {
0215: return crf.getCatalogName();
0216: }
0217:
0218: /**
0219: * Get the index name.
0220: *
0221: * @param indexId Index number for index for table
0222: *
0223: * @return String The index name.
0224: */
0225: String getIndexName(int indexId) {
0226: return indexes[indexId].getIndexName();
0227: }
0228:
0229: /**
0230: * Get the CatalogRowFactory for this.
0231: *
0232: * @return CatalogRowFactory The CatalogRowFactory for this.
0233: */
0234: CatalogRowFactory getCatalogRowFactory() {
0235: return crf;
0236: }
0237:
0238: /**
0239: * Is this fully initialized.
0240: * (i.e., is all conglomerate info initialized)
0241: *
0242: * @return boolean Whether or not this is fully initialized.
0243: */
0244: boolean isComplete() {
0245: /* We are complete when heap conglomerate and all
0246: * index conglomerates are set.
0247: */
0248: if (!heapSet) {
0249: return false;
0250: }
0251: return (indexes == null || indexes.length == numIndexesSet);
0252: }
0253:
0254: /**
0255: * Get the column count for the specified index number.
0256: *
0257: * @param indexNumber The index number.
0258: *
0259: * @return int The column count for the specified index.
0260: */
0261: int getIndexColumnCount(int indexNumber) {
0262: if (SanityManager.DEBUG) {
0263: SanityManager.ASSERT(indexes != null,
0264: "indexes is expected to be non-null");
0265:
0266: if (!(indexNumber < indexes.length)) {
0267: SanityManager
0268: .THROWASSERT("indexNumber (" + indexNumber
0269: + ") is out of range(0-"
0270: + indexes.length + ")");
0271: }
0272: }
0273:
0274: return indexes[indexNumber].getColumnCount();
0275: }
0276:
0277: /**
0278: * Get the IndexRowGenerator for the specified index number.
0279: *
0280: * @param indexNumber The index number.
0281: *
0282: * @return IndexRowGenerator The IRG for the specified index number.
0283: */
0284: IndexRowGenerator getIndexRowGenerator(int indexNumber) {
0285: if (SanityManager.DEBUG) {
0286: SanityManager.ASSERT(indexes != null,
0287: "indexes is expected to be non-null");
0288: if (indexNumber >= indexes.length) {
0289: SanityManager
0290: .THROWASSERT("indexNumber (" + indexNumber
0291: + ") is out of range(0-"
0292: + indexes.length + ")");
0293: }
0294: }
0295: return indexes[indexNumber].getIndexRowGenerator();
0296: }
0297:
0298: /**
0299: * Set the IndexRowGenerator for the specified index number.
0300: *
0301: * @param indexNumber The index number.
0302: * @param irg The IndexRowGenerator for the specified index number.
0303: */
0304: void setIndexRowGenerator(int indexNumber, IndexRowGenerator irg) {
0305: if (SanityManager.DEBUG) {
0306: SanityManager.ASSERT(indexes != null,
0307: "indexes is expected to be non-null");
0308: if (indexNumber >= indexes.length) {
0309: SanityManager
0310: .THROWASSERT("indexNumber (" + indexNumber
0311: + ") is out of range(0-"
0312: + indexes.length + ")");
0313: }
0314: }
0315:
0316: indexes[indexNumber].setIndexRowGenerator(irg);
0317: }
0318:
0319: /**
0320: * Get the number of indexes on this catalog.
0321: *
0322: * @return int The number of indexes on this catalog.
0323: */
0324: int getNumberOfIndexes() {
0325: if (indexes == null) {
0326: return 0;
0327: } else {
0328: return indexes.length;
0329: }
0330: }
0331:
0332: /**
0333: * Get the base column position for a column within a catalog
0334: * given the (0-based) index number for this catalog and the
0335: * (0-based) column number for the column within the index.
0336: *
0337: * @param indexNumber The index number
0338: * @param colNumber The column number within the index
0339: *
0340: * @return int The base column position for the column.
0341: */
0342: int getBaseColumnPosition(int indexNumber, int colNumber) {
0343: if (SanityManager.DEBUG) {
0344: SanityManager.ASSERT(indexes != null,
0345: "indexes is expected to be non-null");
0346: if (indexNumber >= indexes.length) {
0347: SanityManager
0348: .THROWASSERT("indexNumber (" + indexNumber
0349: + ") is out of range(0-"
0350: + indexes.length + ")");
0351: }
0352: }
0353:
0354: return indexes[indexNumber].getBaseColumnPosition(colNumber);
0355: }
0356:
0357: /**
0358: * Return whether or not this index is declared unique
0359: *
0360: * @param indexNumber The index number
0361: *
0362: * @return boolean Whether or not this index is declared unique
0363: */
0364: boolean isIndexUnique(int indexNumber) {
0365: if (SanityManager.DEBUG) {
0366: SanityManager.ASSERT(indexes != null,
0367: "indexes is expected to be non-null");
0368:
0369: if (indexNumber >= indexes.length) {
0370: SanityManager
0371: .THROWASSERT("indexNumber (" + indexNumber
0372: + ") is out of range(0-"
0373: + indexes.length + ")");
0374: }
0375: }
0376:
0377: return indexes[indexNumber].isIndexUnique();
0378: }
0379:
0380: /**
0381: * Inserts a base row into a catalog and inserts all the corresponding
0382: * index rows.
0383: *
0384: * @param row row to insert
0385: * @param tc transaction
0386: * @param wait to wait on lock or quickly TIMEOUT
0387: * @return row number (>= 0) if duplicate row inserted into an index
0388: * ROWNOTDUPLICATE otherwise
0389: *
0390: * @exception StandardException Thrown on failure
0391: */
0392: int insertRow(ExecRow row, TransactionController tc, boolean wait)
0393: throws StandardException {
0394:
0395: RowLocation[] notUsed = new RowLocation[1];
0396:
0397: return insertRowListImpl(new ExecRow[] { row }, tc, notUsed,
0398: wait);
0399: }
0400:
0401: /**
0402: * Inserts a list of base rows into a catalog and inserts all the corresponding
0403: * index rows.
0404: *
0405: * @param rowList List of rows to insert
0406: * @param tc transaction controller
0407: *
0408: *
0409: * @return row number (>= 0) if duplicate row inserted into an index
0410: * ROWNOTDUPLICATE otherwise
0411: *
0412: * @exception StandardException Thrown on failure
0413: */
0414: int insertRowList(ExecRow[] rowList, TransactionController tc)
0415: throws StandardException {
0416: RowLocation[] notUsed = new RowLocation[1];
0417:
0418: return insertRowListImpl(rowList, tc, notUsed, true);
0419: }
0420:
0421: /**
0422: Insert logic to insert a list of rows into a table. This logic has two
0423: odd features.
0424:
0425: <OL>
0426: <LI>Returns an indication if any returned row was a duplicate.
0427: <LI>Returns the RowLocation of the last row inserted.
0428: </OL>
0429: @param rowList the list of rows to insert
0430: @param tc transaction controller
0431: @param rowLocationOut on output rowLocationOut[0] is set to the
0432: last RowLocation inserted.
0433: @param wait to wait on lock or quickly TIMEOUT
0434: @return row number (>= 0) if duplicate row inserted into an index
0435: ROWNOTDUPLICATE otherwise
0436: */
0437: private int insertRowListImpl(ExecRow[] rowList,
0438: TransactionController tc, RowLocation[] rowLocationOut,
0439: boolean wait) throws StandardException {
0440: ConglomerateController heapController;
0441: RowLocation heapLocation;
0442: ExecIndexRow indexableRow;
0443: int insertRetCode;
0444: int retCode = ROWNOTDUPLICATE;
0445: int indexCount = crf.getNumIndexes();
0446: ConglomerateController[] indexControllers = new ConglomerateController[indexCount];
0447:
0448: // Open the conglomerates
0449: heapController = tc.openConglomerate(getHeapConglomerate(),
0450: false,
0451: (TransactionController.OPENMODE_FORUPDATE | ((wait) ? 0
0452: : TransactionController.OPENMODE_LOCK_NOWAIT)),
0453: TransactionController.MODE_RECORD,
0454: TransactionController.ISOLATION_REPEATABLE_READ);
0455:
0456: /* NOTE: Due to the lovely problem of trying to add
0457: * a new column to syscolumns and an index on that
0458: * column during upgrade, we have to deal with the
0459: * issue of the index not existing yet. So, it's okay
0460: * if the index doesn't exist yet. (It will magically
0461: * get created at a later point during upgrade.)
0462: */
0463:
0464: for (int ictr = 0; ictr < indexCount; ictr++) {
0465: long conglomNumber = getIndexConglomerate(ictr);
0466: if (conglomNumber > -1) {
0467: indexControllers[ictr] = tc
0468: .openConglomerate(
0469: conglomNumber,
0470: false,
0471: (TransactionController.OPENMODE_FORUPDATE | ((wait) ? 0
0472: : TransactionController.OPENMODE_LOCK_NOWAIT)),
0473: TransactionController.MODE_RECORD,
0474: TransactionController.ISOLATION_REPEATABLE_READ);
0475: }
0476: }
0477:
0478: heapLocation = heapController.newRowLocationTemplate();
0479: rowLocationOut[0] = heapLocation;
0480:
0481: // loop through rows on this list, inserting them into system table
0482: for (int rowNumber = 0; rowNumber < rowList.length; rowNumber++) {
0483: ExecRow row = rowList[rowNumber];
0484: // insert the base row and get its new location
0485: heapController.insertAndFetchLocation(row.getRowArray(),
0486: heapLocation);
0487:
0488: for (int ictr = 0; ictr < indexCount; ictr++) {
0489: if (indexControllers[ictr] == null) {
0490: continue;
0491: }
0492:
0493: // Get an index row based on the base row
0494: indexableRow = getIndexRowFromHeapRow(
0495: getIndexRowGenerator(ictr), heapLocation, row);
0496:
0497: insertRetCode = indexControllers[ictr]
0498: .insert(indexableRow.getRowArray());
0499:
0500: if (insertRetCode == ConglomerateController.ROWISDUPLICATE) {
0501: retCode = rowNumber;
0502: }
0503: }
0504:
0505: } // end loop through rows on list
0506:
0507: // Close the open conglomerates
0508: for (int ictr = 0; ictr < indexCount; ictr++) {
0509: if (indexControllers[ictr] == null) {
0510: continue;
0511: }
0512:
0513: indexControllers[ictr].close();
0514: }
0515: heapController.close();
0516:
0517: return retCode;
0518: }
0519:
0520: /**
0521: * Given a key row, delete all matching heap rows and their index
0522: * rows.
0523: * <p>
0524: * LOCKING: row locking if there is a key; otherwise,
0525: * table locking.
0526: *
0527: * @param tc transaction controller
0528: * @param key key to delete by.
0529: * @param indexNumber Key is appropriate for this index.
0530: * @return the number of rows deleted. If key is not unique,
0531: * this may be more than one.
0532: * @exception StandardException Thrown on failure
0533: */
0534: int deleteRow(TransactionController tc, ExecIndexRow key,
0535: int indexNumber) throws StandardException {
0536: // Always row locking
0537: return deleteRows(tc, key, ScanController.GE, null, null, key,
0538: ScanController.GT, indexNumber, true);
0539: }
0540:
0541: int deleteRow(TransactionController tc, ExecIndexRow key,
0542: int indexNumber, boolean wait) throws StandardException {
0543: // Always row locking
0544: return deleteRows(tc, key, ScanController.GE, null, null, key,
0545: ScanController.GT, indexNumber, wait);
0546: }
0547:
0548: /**
0549: * Delete the set of rows defined by a scan on an index
0550: * from the table. Most of the parameters are simply passed
0551: * to TransactionController.openScan. Please refer to the
0552: * TransactionController documentation for details.
0553: * <p>
0554: * LOCKING: row locking if there is a start and a stop
0555: * key; otherwise, table locking
0556: *
0557: * @param tc transaction controller
0558: * @param startKey key to start the scan.
0559: * @param startOp operation to start the scan.
0560: * @param stopKey key to start the scan.
0561: * @param qualifier a qualifier for the scan.
0562: * @param filter filter on base rows
0563: * @param stopOp operation to start the scan.
0564: * @param indexNumber Key is appropriate for this index.
0565: * @return the number of rows deleted.
0566: * @exception StandardException Thrown on failure
0567: * @see TransactionController#openScan
0568: */
0569: int deleteRows(TransactionController tc, ExecIndexRow startKey,
0570: int startOp, Qualifier[][] qualifier, TupleFilter filter,
0571: ExecIndexRow stopKey, int stopOp, int indexNumber)
0572: throws StandardException {
0573: return deleteRows(tc, startKey, startOp, qualifier, filter,
0574: stopKey, stopOp, indexNumber, true);
0575: }
0576:
0577: /**
0578: * @inheritDoc
0579: */
0580: private int deleteRows(TransactionController tc,
0581: ExecIndexRow startKey, int startOp,
0582: Qualifier[][] qualifier, TupleFilter filter,
0583: ExecIndexRow stopKey, int stopOp, int indexNumber,
0584: boolean wait) throws StandardException {
0585: ConglomerateController heapCC;
0586: ScanController drivingScan;
0587: ExecIndexRow drivingIndexRow;
0588: RowLocation baseRowLocation;
0589: RowChanger rc;
0590: ExecRow baseRow = crf.makeEmptyRow();
0591: int rowsDeleted = 0;
0592: boolean passedFilter = true;
0593:
0594: rc = getRowChanger(tc, (int[]) null, baseRow);
0595:
0596: /*
0597: ** If we have a start and a stop key, then we are going to
0598: ** get row locks, otherwise, we are getting table locks.
0599: ** This may be excessive locking for the case where there
0600: ** is a start key and no stop key or vice versa.
0601: */
0602: int lockMode = ((startKey != null) && (stopKey != null)) ? tc.MODE_RECORD
0603: : tc.MODE_TABLE;
0604:
0605: /*
0606: ** Don't use level 3 if we have the same start/stop key.
0607: */
0608: int isolation = ((startKey != null) && (stopKey != null) && (startKey == stopKey)) ? TransactionController.ISOLATION_REPEATABLE_READ
0609: : TransactionController.ISOLATION_SERIALIZABLE;
0610:
0611: // Row level locking
0612: rc.open(lockMode, wait);
0613:
0614: DataValueDescriptor[] startKeyRow = startKey == null ? null
0615: : startKey.getRowArray();
0616:
0617: DataValueDescriptor[] stopKeyRow = stopKey == null ? null
0618: : stopKey.getRowArray();
0619:
0620: /* Open the heap conglomerate */
0621: heapCC = tc.openConglomerate(getHeapConglomerate(), false,
0622: (TransactionController.OPENMODE_FORUPDATE | ((wait) ? 0
0623: : TransactionController.OPENMODE_LOCK_NOWAIT)),
0624: lockMode,
0625: TransactionController.ISOLATION_REPEATABLE_READ);
0626:
0627: drivingScan = tc.openScan(
0628: getIndexConglomerate(indexNumber), // conglomerate to open
0629: false, // don't hold open across commit
0630: (TransactionController.OPENMODE_FORUPDATE | ((wait) ? 0
0631: : TransactionController.OPENMODE_LOCK_NOWAIT)),
0632: lockMode, isolation, (FormatableBitSet) null, // all fields as objects
0633: startKeyRow, // start position - first row
0634: startOp, // startSearchOperation
0635: qualifier, //scanQualifier
0636: stopKeyRow, // stop position - through last row
0637: stopOp); // stopSearchOperation
0638:
0639: // Get an index row based on the base row
0640: drivingIndexRow = getIndexRowFromHeapRow(
0641: getIndexRowGenerator(indexNumber), heapCC
0642: .newRowLocationTemplate(), crf.makeEmptyRow());
0643:
0644: while (drivingScan.fetchNext(drivingIndexRow.getRowArray())) {
0645: baseRowLocation = (RowLocation) drivingIndexRow
0646: .getColumn(drivingIndexRow.nColumns());
0647:
0648: boolean base_row_exists = heapCC.fetch(baseRowLocation,
0649: baseRow.getRowArray(), (FormatableBitSet) null);
0650:
0651: if (SanityManager.DEBUG) {
0652: // it can not be possible for heap row to disappear while
0653: // holding scan cursor on index at ISOLATION_REPEATABLE_READ.
0654: SanityManager.ASSERT(base_row_exists,
0655: "base row not found");
0656: }
0657:
0658: // only delete rows which pass the base-row filter
0659: if (filter != null) {
0660: passedFilter = filter.execute(baseRow).equals(true);
0661: }
0662: if (passedFilter) {
0663: rc.deleteRow(baseRow, baseRowLocation);
0664: rowsDeleted++;
0665: }
0666: }
0667:
0668: heapCC.close();
0669: drivingScan.close();
0670: rc.close();
0671:
0672: return rowsDeleted;
0673: }
0674:
0675: /**
0676: * Given a key row, return the first matching heap row.
0677: * <p>
0678: * LOCKING: shared row locking.
0679: *
0680: * @param tc transaction controller
0681: * @param key key to read by.
0682: * @param indexNumber Key is appropriate for this index.
0683: * @exception StandardException Thrown on failure
0684: */
0685: ExecRow getRow(TransactionController tc, ExecIndexRow key,
0686: int indexNumber) throws StandardException {
0687: ConglomerateController heapCC;
0688:
0689: /* Open the heap conglomerate */
0690: heapCC = tc.openConglomerate(getHeapConglomerate(), false,
0691: 0, // for read only
0692: TransactionController.MODE_RECORD,
0693: TransactionController.ISOLATION_REPEATABLE_READ);
0694:
0695: try {
0696: return getRow(tc, heapCC, key, indexNumber);
0697: } finally {
0698: heapCC.close();
0699: }
0700: }
0701:
0702: /**
0703: * Given an index row and index number return the RowLocation
0704: * in the heap of the first matching row.
0705: * Used by the autoincrement code to get the RowLocation in
0706: * syscolumns given a <tablename, columname> pair.
0707: *
0708: * @see DataDictionaryImpl#computeRowLocation(TransactionController, TableDescriptor, String)
0709: *
0710: * @param tc Transaction Controller to use.
0711: * @param key Index Row to search in the index.
0712: * @param indexNumber Identifies the index to use.
0713: *
0714: * @exception StandardException thrown on failure.
0715: */
0716: RowLocation getRowLocation(TransactionController tc,
0717: ExecIndexRow key, int indexNumber) throws StandardException {
0718: ConglomerateController heapCC;
0719: heapCC = tc.openConglomerate(getHeapConglomerate(), false,
0720: 0, // for read only
0721: TransactionController.MODE_RECORD,
0722: TransactionController.ISOLATION_REPEATABLE_READ);
0723:
0724: try {
0725: RowLocation rl[] = new RowLocation[1];
0726: ExecRow notUsed = getRowInternal(tc, heapCC, key,
0727: indexNumber, rl);
0728: return rl[0];
0729: } finally {
0730: heapCC.close();
0731: }
0732: }
0733:
0734: /**
0735: * Given a key row, return the first matching heap row.
0736: * <p>
0737: * LOCKING: shared row locking.
0738: *
0739: * @param tc transaction controller
0740: * @param heapCC heap to look in
0741: * @param key key to read by.
0742: * @param indexNumber Key is appropriate for this index.
0743: * @exception StandardException Thrown on failure
0744: */
0745: ExecRow getRow(TransactionController tc,
0746: ConglomerateController heapCC, ExecIndexRow key,
0747: int indexNumber)
0748:
0749: throws StandardException {
0750: RowLocation rl[] = new RowLocation[1];
0751: return getRowInternal(tc, heapCC, key, indexNumber, rl);
0752: }
0753:
0754: /**
0755: * @exception StandardException Thrown on failure
0756: */
0757: private ExecRow getRowInternal(TransactionController tc,
0758: ConglomerateController heapCC, ExecIndexRow key,
0759: int indexNumber, RowLocation rl[])
0760:
0761: throws StandardException {
0762: ScanController drivingScan;
0763: ExecIndexRow drivingIndexRow;
0764: RowLocation baseRowLocation;
0765: ExecRow baseRow = crf.makeEmptyRow();
0766:
0767: drivingScan = tc.openScan(
0768: getIndexConglomerate(indexNumber),
0769: // conglomerate to open
0770: false, // don't hold open across commit
0771: 0, // open for read
0772: TransactionController.MODE_RECORD,
0773: TransactionController.ISOLATION_REPEATABLE_READ,
0774: (FormatableBitSet) null, // all fields as objects
0775: key.getRowArray(), // start position - first row
0776: ScanController.GE, // startSearchOperation
0777: null, //scanQualifier
0778: key.getRowArray(), // stop position - through last row
0779: ScanController.GT); // stopSearchOperation
0780:
0781: // Get an index row based on the base row
0782: drivingIndexRow = getIndexRowFromHeapRow(
0783: getIndexRowGenerator(indexNumber), heapCC
0784: .newRowLocationTemplate(), crf.makeEmptyRow());
0785:
0786: try {
0787: if (drivingScan.fetchNext(drivingIndexRow.getRowArray())) {
0788: rl[0] = baseRowLocation = (RowLocation) drivingIndexRow
0789: .getColumn(drivingIndexRow.nColumns());
0790: boolean base_row_exists = heapCC.fetch(baseRowLocation,
0791: baseRow.getRowArray(), (FormatableBitSet) null);
0792:
0793: if (SanityManager.DEBUG) {
0794: // it can not be possible for heap row to disappear while
0795: // holding scan cursor on index at ISOLATION_REPEATABLE_READ.
0796: SanityManager.ASSERT(base_row_exists,
0797: "base row not found");
0798: }
0799:
0800: return baseRow;
0801: } else {
0802: return null;
0803: }
0804: }
0805:
0806: finally {
0807: drivingScan.close();
0808: }
0809: }
0810:
0811: /**
0812: * Updates a base row in a catalog and updates all the corresponding
0813: * index rows.
0814: *
0815: * @param key key row
0816: * @param newRow new version of the row
0817: * @param indexNumber index that key operates
0818: * @param indicesToUpdate array of booleans, one for each index on the catalog.
0819: * if a boolean is true, that means we must update the
0820: * corresponding index because changes in the newRow
0821: * affect it.
0822: * @param colsToUpdate array of ints indicating which columns (1 based)
0823: * to update. If null, do all.
0824: * @param tc transaction controller
0825: *
0826: * @exception StandardException Thrown on failure
0827: */
0828: void updateRow(ExecIndexRow key, ExecRow newRow, int indexNumber,
0829: boolean[] indicesToUpdate, int[] colsToUpdate,
0830: TransactionController tc) throws StandardException {
0831: updateRow(key, newRow, indexNumber, indicesToUpdate,
0832: colsToUpdate, tc, true);
0833: }
0834:
0835: /**
0836: * Updates a base row in a catalog and updates all the corresponding
0837: * index rows.
0838: *
0839: * @param key key row
0840: * @param newRow new version of the row
0841: * @param indexNumber index that key operates
0842: * @param indicesToUpdate array of booleans, one for each index on the catalog.
0843: * if a boolean is true, that means we must update the
0844: * corresponding index because changes in the newRow
0845: * affect it.
0846: * @param colsToUpdate array of ints indicating which columns (1 based)
0847: * to update. If null, do all.
0848: * @param tc transaction controller
0849: * @param wait If true, then the caller wants to wait for locks. False will be
0850: * when we using a nested user xaction - we want to timeout right away if the parent
0851: * holds the lock. (bug 4821)
0852: *
0853: * @exception StandardException Thrown on failure
0854: */
0855: void updateRow(ExecIndexRow key, ExecRow newRow, int indexNumber,
0856: boolean[] indicesToUpdate, int[] colsToUpdate,
0857: TransactionController tc, boolean wait)
0858: throws StandardException {
0859: ExecRow[] newRows = new ExecRow[1];
0860: newRows[0] = newRow;
0861: updateRow(key, newRows, indexNumber, indicesToUpdate,
0862: colsToUpdate, tc, wait);
0863: }
0864:
0865: /**
0866: * Updates a set of base rows in a catalog with the same key on an index
0867: * and updates all the corresponding index rows.
0868: *
0869: * @param key key row
0870: * @param newRows new version of the array of rows
0871: * @param indexNumber index that key operates
0872: * @param indicesToUpdate array of booleans, one for each index on the catalog.
0873: * if a boolean is true, that means we must update the
0874: * corresponding index because changes in the newRow
0875: * affect it.
0876: * @param colsToUpdate array of ints indicating which columns (1 based)
0877: * to update. If null, do all.
0878: * @param tc transaction controller
0879: *
0880: * @exception StandardException Thrown on failure
0881: */
0882: void updateRow(ExecIndexRow key, ExecRow[] newRows,
0883: int indexNumber, boolean[] indicesToUpdate,
0884: int[] colsToUpdate, TransactionController tc)
0885: throws StandardException {
0886: updateRow(key, newRows, indexNumber, indicesToUpdate,
0887: colsToUpdate, tc, true);
0888: }
0889:
0890: /**
0891: * Updates a set of base rows in a catalog with the same key on an index
0892: * and updates all the corresponding index rows. If parameter wait is true,
0893: * then the caller wants to wait for locks. When using a nested user xaction
0894: * we want to timeout right away if the parent holds the lock.
0895: *
0896: * @param key key row
0897: * @param newRows new version of the array of rows
0898: * @param indexNumber index that key operates
0899: * @param indicesToUpdate array of booleans, one for each index on the catalog.
0900: * if a boolean is true, that means we must update the
0901: * corresponding index because changes in the newRow
0902: * affect it.
0903: * @param colsToUpdate array of ints indicating which columns (1 based)
0904: * to update. If null, do all.
0905: * @param tc transaction controller
0906: * @param wait If true, then the caller wants to wait for locks. When
0907: * using a nested user xaction we want to timeout right away
0908: * if the parent holds the lock. (bug 4821)
0909: *
0910: * @exception StandardException Thrown on failure
0911: */
0912: private void updateRow(ExecIndexRow key, ExecRow[] newRows,
0913: int indexNumber, boolean[] indicesToUpdate,
0914: int[] colsToUpdate, TransactionController tc, boolean wait)
0915: throws StandardException {
0916: ConglomerateController heapCC;
0917: ScanController drivingScan;
0918: ExecIndexRow drivingIndexRow;
0919: RowLocation baseRowLocation;
0920: ExecIndexRow templateRow;
0921: ExecRow baseRow = crf.makeEmptyRow();
0922:
0923: if (SanityManager.DEBUG) {
0924: SanityManager.ASSERT(indicesToUpdate.length == crf
0925: .getNumIndexes(), "Wrong number of indices.");
0926: }
0927:
0928: RowChanger rc = getRowChanger(tc, colsToUpdate, baseRow);
0929:
0930: // Row level locking
0931: rc.openForUpdate(indicesToUpdate,
0932: TransactionController.MODE_RECORD, wait);
0933:
0934: /* Open the heap conglomerate */
0935: heapCC = tc.openConglomerate(getHeapConglomerate(), false,
0936: (TransactionController.OPENMODE_FORUPDATE | ((wait) ? 0
0937: : TransactionController.OPENMODE_LOCK_NOWAIT)),
0938: TransactionController.MODE_RECORD,
0939: TransactionController.ISOLATION_REPEATABLE_READ);
0940:
0941: drivingScan = tc.openScan(
0942: getIndexConglomerate(indexNumber), // conglomerate to open
0943: false, // don't hold open across commit
0944: (TransactionController.OPENMODE_FORUPDATE | ((wait) ? 0
0945: : TransactionController.OPENMODE_LOCK_NOWAIT)),
0946: TransactionController.MODE_RECORD,
0947: TransactionController.ISOLATION_REPEATABLE_READ,
0948: (FormatableBitSet) null, // all fields as objects
0949: key.getRowArray(), // start position - first row
0950: ScanController.GE, // startSearchOperation
0951: null, //scanQualifier
0952: key.getRowArray(), // stop position - through last row
0953: ScanController.GT); // stopSearchOperation
0954:
0955: // Get an index row based on the base row
0956: drivingIndexRow = getIndexRowFromHeapRow(
0957: getIndexRowGenerator(indexNumber), heapCC
0958: .newRowLocationTemplate(), crf.makeEmptyRow());
0959:
0960: int rowNum = 0;
0961: while (drivingScan.fetchNext(drivingIndexRow.getRowArray())) {
0962: baseRowLocation = (RowLocation) drivingIndexRow
0963: .getColumn(drivingIndexRow.nColumns());
0964: boolean base_row_exists = heapCC.fetch(baseRowLocation,
0965: baseRow.getRowArray(), (FormatableBitSet) null);
0966:
0967: if (SanityManager.DEBUG) {
0968: // it can not be possible for heap row to disappear while
0969: // holding scan cursor on index at ISOLATION_REPEATABLE_READ.
0970: SanityManager.ASSERT(base_row_exists,
0971: "base row not found");
0972: }
0973:
0974: rc.updateRow(baseRow,
0975: (rowNum == newRows.length - 1) ? newRows[rowNum]
0976: : newRows[rowNum++], baseRowLocation);
0977: }
0978: rc.finish();
0979: heapCC.close();
0980: drivingScan.close();
0981: rc.close();
0982: }
0983:
0984: /**
0985: * Get the Properties associated with creating the heap.
0986: *
0987: * @return The Properties associated with creating the heap.
0988: */
0989: Properties getCreateHeapProperties() {
0990: return crf.getCreateHeapProperties();
0991: }
0992:
0993: /**
0994: * Get the Properties associated with creating the specified index.
0995: *
0996: * @param indexNumber The specified index number.
0997: *
0998: * @return The Properties associated with creating the specified index.
0999: */
1000: Properties getCreateIndexProperties(int indexNumber) {
1001: return crf.getCreateIndexProperties(indexNumber);
1002: }
1003:
1004: /**
1005: * Gets a row changer for this catalog.
1006: *
1007: * @param tc transaction controller
1008: * @param changedCols the columns to change (1 based), may be null
1009: * @param baseRow used to detemine column types at creation time
1010: * only. The row changer does ***Not*** keep a referance to
1011: * this row or change it in any way.
1012: *
1013: * @return a row changer for this catalog.
1014: * @exception StandardException Thrown on failure
1015: */
1016: private RowChanger getRowChanger(TransactionController tc,
1017: int[] changedCols, ExecRow baseRow)
1018: throws StandardException {
1019: RowChanger rc;
1020: int indexCount = crf.getNumIndexes();
1021: IndexRowGenerator[] irgs = new IndexRowGenerator[indexCount];
1022: long[] cids = new long[indexCount];
1023:
1024: if (SanityManager.DEBUG) {
1025: if (changedCols != null) {
1026: for (int i = changedCols.length - 1; i >= 0; i--) {
1027: SanityManager.ASSERT(changedCols[i] != 0,
1028: "Column id is 0, but should be 1 based");
1029: }
1030: }
1031: }
1032:
1033: for (int ictr = 0; ictr < indexCount; ictr++) {
1034: irgs[ictr] = getIndexRowGenerator(ictr);
1035: cids[ictr] = getIndexConglomerate(ictr);
1036: }
1037:
1038: rc = crf.getExecutionFactory()
1039: .getRowChanger(getHeapConglomerate(),
1040: (StaticCompiledOpenConglomInfo) null,
1041: (DynamicCompiledOpenConglomInfo) null, irgs,
1042: cids, (StaticCompiledOpenConglomInfo[]) null,
1043: (DynamicCompiledOpenConglomInfo[]) null,
1044: crf.getHeapColumnCount(), tc, changedCols,
1045: getStreamStorableHeapColIds(baseRow),
1046: (Activation) null);
1047: return rc;
1048: }
1049:
1050: private boolean computedStreamStorableHeapColIds = false;
1051: private int[] streamStorableHeapColIds;
1052:
1053: private int[] getStreamStorableHeapColIds(ExecRow baseRow)
1054: throws StandardException {
1055: if (!computedStreamStorableHeapColIds) {
1056: int sshcidLen = 0;
1057: //
1058: //Compute the length of streamStorableHeapColIds
1059: //One entry for each column id.
1060: DataValueDescriptor[] ra = baseRow.getRowArray();
1061: for (int ix = 0; ix < ra.length; ix++)
1062: if (ra[ix] instanceof StreamStorable)
1063: sshcidLen++;
1064:
1065: //
1066: //If we have some streamStorableHeapColIds we
1067: //allocate an array to remember them and fill in
1068: //the array with the 0 based column ids. If we
1069: //have none leave streamStorableHeapColIds Null.
1070: if (sshcidLen > 0) {
1071: streamStorableHeapColIds = new int[sshcidLen];
1072: int sshcidOffset = 0;
1073: for (int ix = 0; ix < ra.length; ix++)
1074: if (ra[ix] instanceof StreamStorable)
1075: streamStorableHeapColIds[sshcidOffset++] = ix;
1076: }
1077: computedStreamStorableHeapColIds = true;
1078: }
1079: return streamStorableHeapColIds;
1080: }
1081:
1082: /**
1083: * Get an index row based on a row from the heap.
1084: *
1085: * @param irg IndexRowGenerator to use
1086: * @param rl RowLocation for heap
1087: * @param heapRow Row from the heap
1088: *
1089: * @return ExecIndexRow Index row.
1090: *
1091: * @exception StandardException Thrown on error
1092: */
1093: private ExecIndexRow getIndexRowFromHeapRow(IndexRowGenerator irg,
1094: RowLocation rl, ExecRow heapRow) throws StandardException {
1095: ExecIndexRow indexRow;
1096:
1097: indexRow = irg.getIndexRowTemplate();
1098: // Get an index row based on the base row
1099: irg.getIndexRow(heapRow, rl, indexRow, (FormatableBitSet) null);
1100:
1101: return indexRow;
1102: }
1103:
1104: public String toString() {
1105: if (SanityManager.DEBUG) {
1106: return "name: " + this .getTableName()
1107: + "\n\theapCongolomerate: " + heapConglomerate
1108: + "\n\tnumIndexes: "
1109: + ((indexes != null) ? indexes.length : 0)
1110: + "\n\tnumIndexesSet: " + numIndexesSet
1111: + "\n\theapSet: " + heapSet + "\n";
1112: } else {
1113: return "";
1114: }
1115: }
1116: }
|