0001: /*
0002:
0003: Derby - Class org.apache.derby.iapi.sql.dictionary.TableDescriptor
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.iapi.sql.dictionary;
0023:
0024: import org.apache.derby.iapi.services.context.ContextManager;
0025:
0026: import org.apache.derby.iapi.error.StandardException;
0027:
0028: import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList;
0029:
0030: import org.apache.derby.iapi.sql.depend.Provider;
0031:
0032: import org.apache.derby.iapi.sql.execute.ExecRow;
0033: import org.apache.derby.catalog.UUID;
0034: import org.apache.derby.catalog.DependableFinder;
0035: import org.apache.derby.iapi.services.io.FormatableBitSet;
0036: import org.apache.derby.iapi.sql.StatementType;
0037: import org.apache.derby.iapi.services.io.StoredFormatIds;
0038:
0039: import org.apache.derby.iapi.types.DataValueDescriptor;
0040: import org.apache.derby.iapi.sql.depend.Provider;
0041: import org.apache.derby.iapi.sql.execute.ExecRow;
0042: import org.apache.derby.iapi.sql.execute.ExecutionContext;
0043:
0044: import org.apache.derby.iapi.reference.SQLState;
0045: import org.apache.derby.catalog.Dependable;
0046: import org.apache.derby.iapi.services.sanity.SanityManager;
0047:
0048: import java.util.Vector;
0049: import java.util.Enumeration;
0050: import java.util.List;
0051: import java.util.Iterator;
0052:
0053: /**
0054: * This class represents a table descriptor. The external interface to this
0055: * class is:
0056: <p>
0057: <ol>
0058: <li>external interface </li>
0059: <li>public String getSchemaName();</li>
0060: <li>public String getQualifiedName();</li>
0061: <li>public int getTableType();</li>
0062: <li>public long getHeapConglomerateId() throws StandardException;</li>
0063: <li>public int getNumberOfColumns(); </li>
0064: <li>public FormatableBitSet getReferencedColumnMap();</li>
0065: <li>public void setReferencedColumnMap(FormatableBitSet referencedColumnMap);</li>
0066: <li>public int getMaxColumnID() throws StandardException;</li>
0067: <li>public void setUUID(UUID uuid);</li>
0068: <li>public char getLockGranularity();</li>
0069: <li>public void setTableName(String newTableName);</li>
0070: <li>public void setLockGranularity(char lockGranularity);</li>
0071: <li>public ExecRow getEmptyExecRow( ContextManager cm) throws StandardException;</li>
0072: <li>public boolean tableNameEquals(String otherSchemaName, String otherTableName);</li>
0073: <li>public ReferencedKeyConstraintDescriptor getPrimaryKey() throws StandardException;</li>
0074: <li>public void removeConglomerateDescriptor(ConglomerateDescriptor cd) throws StandardException;</li>
0075: <li>public void removeConstraintDescriptor(ConstraintDescriptor cd) throws StandardException;</li>
0076: <li>public void getAffectedIndexes(...) throws StandardException;</li>
0077: <li>public void getAllRelevantTriggers(...) throws StandardException;</li>
0078: <li>public void getAllRelevantConstraints(...) throws StandardException</li>
0079: <li>public ColumnDescriptorList getColumnDescriptorList();</li>
0080: <li> public String[] getColumnNamesArray();</li>
0081: <li>public long[] getAutoincIncrementArray();</li>
0082: <li>public ColumnDescriptor getColumnDescriptor(String columnName);</li>
0083: <li>public ColumnDescriptor getColumnDescriptor(int columnNumber);</li>
0084: <li>public ConglomerateDescriptor[] getConglomerateDescriptors() throws StandardException;</li>
0085: <li>public ConglomerateDescriptor getConglomerateDescriptor(long conglomerateNumber) throws StandardException;</li>
0086: <li>public ConglomerateDescriptor getConglomerateDescriptor(UUID conglomerateUUID) throws StandardException;</li>
0087: <li>public IndexLister getIndexLister() throws StandardException;</li>
0088: <li>public ViewDescriptor getViewDescriptor();</li>
0089: <li>public boolean tableHasAutoincrement();</li>
0090: <li>public boolean statisticsExist(ConglomerateDescriptor cd) throws StandardException;</li>
0091: <li>public double selectivityForConglomerate(...)throws StandardException;</li>
0092: </ol>
0093: <p>
0094: *
0095: * @author Jeff Lichtman
0096: */
0097:
0098: public class TableDescriptor extends TupleDescriptor implements
0099: UniqueSQLObjectDescriptor, Provider {
0100: public static final int BASE_TABLE_TYPE = 0;
0101: public static final int SYSTEM_TABLE_TYPE = 1;
0102: public static final int VIEW_TYPE = 2;
0103: public static final int GLOBAL_TEMPORARY_TABLE_TYPE = 3;
0104: public static final int SYNONYM_TYPE = 4;
0105: public static final int VTI_TYPE = 5;
0106:
0107: public static final char ROW_LOCK_GRANULARITY = 'R';
0108: public static final char TABLE_LOCK_GRANULARITY = 'T';
0109: public static final char DEFAULT_LOCK_GRANULARITY = ROW_LOCK_GRANULARITY;
0110:
0111: /**
0112: */
0113:
0114: // implementation
0115: private char lockGranularity;
0116: private boolean onCommitDeleteRows; //true means on commit delete rows, false means on commit preserve rows of temporary table.
0117: private boolean onRollbackDeleteRows; //true means on rollback delete rows. This is the only value supported.
0118: SchemaDescriptor schema;
0119: String tableName;
0120: UUID oid;
0121: int tableType;
0122: long heapConglomNumber = -1;
0123: ColumnDescriptorList columnDescriptorList;
0124: ConglomerateDescriptorList conglomerateDescriptorList;
0125: ConstraintDescriptorList constraintDescriptorList;
0126: private GenericDescriptorList triggerDescriptorList;
0127: ViewDescriptor viewDescriptor;
0128: FormatableBitSet referencedColumnMap;
0129:
0130: /** A list of statistics pertaining to this table--
0131: */
0132: private List statisticsDescriptorList;
0133:
0134: /**
0135: * Constructor for a TableDescriptor (this is for a temporary table).
0136: *
0137: * @param dataDictionary The data dictionary that this descriptor lives in
0138: * @param tableName The name of the temporary table
0139: * @param schema The schema descriptor for this table.
0140: * @param tableType An integer identifier for the type of the table : declared global temporary table
0141: * @param onCommitDeleteRows If true, on commit delete rows else on commit preserve rows of temporary table.
0142: * @param onRollbackDeleteRows If true, on rollback, delete rows from temp tables which were logically modified. true is the only supported value
0143: */
0144:
0145: public TableDescriptor(DataDictionary dataDictionary,
0146: String tableName, SchemaDescriptor schema, int tableType,
0147: boolean onCommitDeleteRows, boolean onRollbackDeleteRows) {
0148: this (dataDictionary, tableName, schema, tableType, '\0');
0149:
0150: this .onCommitDeleteRows = onCommitDeleteRows;
0151: this .onRollbackDeleteRows = onRollbackDeleteRows;
0152: }
0153:
0154: /**
0155: * Constructor for a TableDescriptor.
0156: *
0157: * @param dataDictionary The data dictionary that this descriptor lives in
0158: * @param tableName The name of the table
0159: * @param schema The schema descriptor for this table.
0160: * @param tableType An integer identifier for the type of the table
0161: * (base table, view, etc.)
0162: * @param lockGranularity The lock granularity.
0163: */
0164:
0165: public TableDescriptor(DataDictionary dataDictionary,
0166: String tableName, SchemaDescriptor schema, int tableType,
0167: char lockGranularity) {
0168: super (dataDictionary);
0169:
0170: this .schema = schema;
0171: this .tableName = tableName;
0172: this .tableType = tableType;
0173: this .lockGranularity = lockGranularity;
0174:
0175: this .conglomerateDescriptorList = new ConglomerateDescriptorList();
0176: this .columnDescriptorList = new ColumnDescriptorList();
0177: this .constraintDescriptorList = new ConstraintDescriptorList();
0178: this .triggerDescriptorList = new GenericDescriptorList();
0179: }
0180:
0181: //
0182: // TableDescriptor interface
0183: //
0184:
0185: /**
0186: * Gets the name of the schema the table lives in.
0187: *
0188: * @return A String containing the name of the schema the table
0189: * lives in.
0190: */
0191: public String getSchemaName() {
0192: return schema.getSchemaName();
0193: }
0194:
0195: /**
0196: * Gets the SchemaDescriptor for this TableDescriptor.
0197: *
0198: * @return SchemaDescriptor The SchemaDescriptor.
0199: */
0200: public SchemaDescriptor getSchemaDescriptor() {
0201: return schema;
0202: }
0203:
0204: /**
0205: * Gets the name of the table.
0206: *
0207: * @return A String containing the name of the table.
0208: */
0209: public String getName() {
0210: return tableName;
0211: }
0212:
0213: /**
0214: * Sets the the table name in case of rename table.
0215: *
0216: * This is used only by rename table
0217: * @param newTableName The new table name.
0218: */
0219: public void setTableName(String newTableName) {
0220: this .tableName = newTableName;
0221: }
0222:
0223: /**
0224: * Gets the full, qualified name of the table.
0225: *
0226: * @return A String containing the name of the table.
0227: */
0228: public String getQualifiedName() {
0229: //quoteStringIfNecessary is for bug 3476. If the schemaName and/or tableName has
0230: //double quotes in it, this method will put them in quotes and replace every
0231: //double quote with 2 double quotes.
0232: return quoteStringIfNecessary(getSchemaName()) + "."
0233: + quoteStringIfNecessary(getName());
0234: }
0235:
0236: /**
0237: * If the name has double quotes in it, put two double quotes for every single
0238: * double quote.
0239: * For eg, if table name is m"n, return it as "m""n". For now, this is used
0240: * by DMLModStatementNode.parseCheckConstraint().
0241: *
0242: * @param name The String with or without double quotes
0243: *
0244: * @return The quoted String
0245: */
0246:
0247: private String quoteStringIfNecessary(String name) {
0248: String quotedString = name;
0249: int quotePos = name.indexOf("\"");
0250:
0251: if (quotePos == -1)
0252: return name;
0253:
0254: //string does have quotes in it.
0255: while (quotePos != -1) {
0256: quotedString = quotedString.substring(0, quotePos) + "\""
0257: + quotedString.substring(quotePos);
0258: quotePos = quotedString.indexOf("\"", quotePos + 2);
0259: }
0260: return "\"" + quotedString + "\"";
0261:
0262: }
0263:
0264: /**
0265: * Gets the UUID of the table.
0266: *
0267: * @return The UUID of the table.
0268: */
0269: public UUID getUUID() {
0270: return oid;
0271: }
0272:
0273: /**
0274: * Gets an identifier telling what type of table this is
0275: * (base table, declared global temporary table, view, etc.)
0276: *
0277: * @return An identifier telling what type of table this is.
0278: */
0279: public int getTableType() {
0280: return tableType;
0281: }
0282:
0283: /**
0284: * Gets the id for the heap conglomerate of the table.
0285: * There may also be keyed conglomerates, these are
0286: * stored separately in the conglomerates table.
0287: *
0288: * @return the id of the heap conglomerate for the table.
0289: *
0290: * @exception StandardException Thrown on error
0291: */
0292: public long getHeapConglomerateId() throws StandardException {
0293: DataDictionary dd = getDataDictionary();
0294:
0295: ConglomerateDescriptor cd = null;
0296:
0297: /* If we've already cached the heap conglomerate number, then
0298: * simply return it.
0299: */
0300: if (heapConglomNumber != -1) {
0301: return heapConglomNumber;
0302: }
0303:
0304: ConglomerateDescriptor[] cds = getConglomerateDescriptors();
0305:
0306: for (int index = 0; index < cds.length; index++) {
0307: cd = cds[index];
0308: if (!cd.isIndex())
0309: break;
0310: }
0311:
0312: if (SanityManager.DEBUG) {
0313: if (cd == null) {
0314: SanityManager
0315: .THROWASSERT("cd is expected to be non-null for "
0316: + tableName);
0317: }
0318:
0319: if (cd.isIndex()) {
0320: SanityManager
0321: .THROWASSERT("Did not find heap conglomerate for "
0322: + tableName);
0323: }
0324: }
0325:
0326: heapConglomNumber = cd.getConglomerateNumber();
0327:
0328: return heapConglomNumber;
0329: }
0330:
0331: /**
0332: * Gets the number of columns in the table.
0333: *
0334: * @return the number of columns in the table.
0335: *
0336: */
0337: public int getNumberOfColumns() {
0338: return getColumnDescriptorList().size();
0339: }
0340:
0341: /**
0342: * Get the referenced column map of the table.
0343: *
0344: * @return the referencedColumnMap of the table.
0345: *
0346: */
0347: public FormatableBitSet getReferencedColumnMap() {
0348: return referencedColumnMap;
0349: }
0350:
0351: /**
0352: * Set the referenced column map of the table.
0353: *
0354: * @param referencedColumnMap FormatableBitSet of referenced columns.
0355: *
0356: */
0357: public void setReferencedColumnMap(
0358: FormatableBitSet referencedColumnMap) {
0359: this .referencedColumnMap = referencedColumnMap;
0360: }
0361:
0362: /**
0363: * Gets the highest column id in the table. For now this is the same as
0364: * the number of columns. However, in the future, after we implement
0365: * ALTER TABLE DROP COLUMN, this correspondence won't hold any longer.
0366: *
0367: * @return the highest column ID in the table
0368: *
0369: * @exception StandardException Thrown on error
0370: */
0371: public int getMaxColumnID() throws StandardException {
0372: int maxColumnID = 1;
0373: int cdlSize = getColumnDescriptorList().size();
0374: for (int index = 0; index < cdlSize; index++) {
0375: ColumnDescriptor cd = (ColumnDescriptor) columnDescriptorList
0376: .elementAt(index);
0377: maxColumnID = Math.max(maxColumnID, cd.getPosition());
0378: }
0379:
0380: return maxColumnID;
0381: }
0382:
0383: /**
0384: * Sets the UUID of the table
0385: *
0386: * @param oid The UUID of the table to be set in the descriptor
0387: */
0388: public void setUUID(UUID oid) {
0389: this .oid = oid;
0390: }
0391:
0392: /**
0393: * Gets the lock granularity for the table.
0394: *
0395: * @return A char representing the lock granularity for the table.
0396: */
0397: public char getLockGranularity() {
0398: return lockGranularity;
0399: }
0400:
0401: /**
0402: * Sets the lock granularity for the table to the specified value.
0403: *
0404: * @param lockGranularity The new lockGranularity.
0405: */
0406: public void setLockGranularity(char lockGranularity) {
0407: this .lockGranularity = lockGranularity;
0408: }
0409:
0410: /**
0411: * Gets the on rollback behavior for the declared global temporary table.
0412: *
0413: * @return A boolean representing the on rollback behavior for the declared global temporary table.
0414: */
0415: public boolean isOnRollbackDeleteRows() {
0416: return onRollbackDeleteRows;
0417: }
0418:
0419: /**
0420: * Gets the on commit behavior for the declared global temporary table.
0421: *
0422: * @return A boolean representing the on commit behavior for the declared global temporary table.
0423: */
0424: public boolean isOnCommitDeleteRows() {
0425: return onCommitDeleteRows;
0426: }
0427:
0428: /**
0429: * Sets the heapConglomNumber to -1 for temporary table since the table was dropped and recreated at the commit time
0430: * and hence its conglomerate id has changed. This is used for temporary table descriptors only
0431: */
0432: public void resetHeapConglomNumber() {
0433: if (SanityManager.DEBUG) {
0434: if (tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
0435: SanityManager
0436: .THROWASSERT("tableType expected to be TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE, not "
0437: + tableType);
0438: }
0439: }
0440: heapConglomNumber = -1;
0441: }
0442:
0443: /**
0444: * Gets an ExecRow for rows stored in the table this describes.
0445: *
0446: * @param cm Current ContextManager
0447: *
0448: * @return the row.
0449: * @exception StandardException Thrown on failure
0450: */
0451: public ExecRow getEmptyExecRow(ContextManager cm)
0452: throws StandardException {
0453: int columnCount = getNumberOfColumns();
0454: ExecutionContext ec = (ExecutionContext) cm
0455: .getContext(ExecutionContext.CONTEXT_ID);
0456: ExecRow result = ec.getExecutionFactory().getValueRow(
0457: columnCount);
0458:
0459: for (int index = 0; index < columnCount; index++) {
0460: ColumnDescriptor cd = (ColumnDescriptor) columnDescriptorList
0461: .elementAt(index);
0462: //String name = column.getColumnName();
0463: DataValueDescriptor dataValue = cd.getType().getNull();
0464: result.setColumn(index + 1, dataValue);
0465: }
0466: return result;
0467: }
0468:
0469: /**
0470: * Gets the conglomerate descriptor list
0471: *
0472: * @return The conglomerate descriptor list for this table descriptor
0473: */
0474: public ConglomerateDescriptorList getConglomerateDescriptorList() {
0475: return conglomerateDescriptorList;
0476: }
0477:
0478: /**
0479: * Gets the view descriptor for this TableDescriptor.
0480: *
0481: * @return ViewDescriptor The ViewDescriptor, if any.
0482: */
0483: public ViewDescriptor getViewDescriptor() {
0484: return viewDescriptor;
0485: }
0486:
0487: /**
0488: * Set (cache) the view descriptor for this TableDescriptor
0489: *
0490: * @param viewDescriptor The view descriptor to cache.
0491: */
0492: public void setViewDescriptor(ViewDescriptor viewDescriptor) {
0493: if (SanityManager.DEBUG) {
0494: if (tableType != TableDescriptor.VIEW_TYPE) {
0495: SanityManager
0496: .THROWASSERT("tableType expected to be TableDescriptor.VIEW_TYPE, not "
0497: + tableType);
0498: }
0499: }
0500: this .viewDescriptor = viewDescriptor;
0501: }
0502:
0503: /**
0504: * Is this provider persistent? A stored dependency will be required
0505: * if both the dependent and provider are persistent.
0506: *
0507: * @return boolean Whether or not this provider is persistent.
0508: */
0509: public boolean isPersistent() {
0510: if (tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE)
0511: return false;
0512: else
0513: return (super .isPersistent());
0514: }
0515:
0516: /**
0517: * Is this descriptor represents a synonym?
0518: *
0519: * @return boolean Whether or not this represents a synonym
0520: */
0521: public boolean isSynonymDescriptor() {
0522: if (tableType == TableDescriptor.SYNONYM_TYPE)
0523: return true;
0524: return false;
0525: }
0526:
0527: /**
0528: * Gets the number of indexes on the table, including the backing indexes.
0529: *
0530: * @return the number of columns in the table.
0531: *
0532: */
0533: public int getTotalNumberOfIndexes() throws StandardException {
0534: int totalNumberOfIndexes = 0;
0535: ConglomerateDescriptor[] cds = getConglomerateDescriptors();
0536:
0537: for (int index = 0; index < cds.length; index++) {
0538: if (cds[index].isIndex()) {
0539: totalNumberOfIndexes++;
0540: }
0541: }
0542:
0543: return totalNumberOfIndexes;
0544: }
0545:
0546: /**
0547: * Builds a list of all triggers which are relevant to a
0548: * given statement type, given a list of updated columns.
0549: *
0550: * @param statementType defined in StatementType
0551: * @param changedColumnIds array of changed columns
0552: * @param relevantTriggers IN/OUT. Passed in as an empty list. Filled in as we go.
0553: *
0554: * @exception StandardException Thrown on error
0555: */
0556: public void getAllRelevantTriggers(int statementType,
0557: int[] changedColumnIds,
0558: GenericDescriptorList relevantTriggers)
0559: throws StandardException {
0560: if (SanityManager.DEBUG) {
0561: SanityManager
0562: .ASSERT(
0563: (statementType == StatementType.INSERT)
0564: || (statementType == StatementType.BULK_INSERT_REPLACE)
0565: || (statementType == StatementType.UPDATE)
0566: || (statementType == StatementType.DELETE),
0567: "invalid statement type " + statementType);
0568: }
0569:
0570: DataDictionary dd = getDataDictionary();
0571: Enumeration descs = dd.getTriggerDescriptors(this ).elements();
0572:
0573: while (descs.hasMoreElements()) {
0574: TriggerDescriptor tgr = (TriggerDescriptor) descs
0575: .nextElement();
0576:
0577: if (tgr.needsToFire(statementType, changedColumnIds)) {
0578: relevantTriggers.add(tgr);
0579: }
0580: }
0581: }
0582:
0583: /**
0584: * Gets all of the relevant constraints for a statement, given its
0585: * statement type and its list of updated columns.
0586: *
0587: * @param statementType As defined in StatementType.
0588: * @param skipCheckConstraints Skip check constraints
0589: * @param changedColumnIds If null, all columns being changed, otherwise array
0590: * of 1-based column ids for columns being changed
0591: * @param needsDeferredProcessing IN/OUT. true if the statement already needs
0592: * deferred processing. set while evaluating this
0593: * routine if a trigger or constraint requires
0594: * deferred processing
0595: * @param relevantConstraints IN/OUT. Empty list is passed in. We hang constraints on it as we go.
0596: *
0597: * @exception StandardException Thrown on error
0598: */
0599: public void getAllRelevantConstraints(int statementType,
0600: boolean skipCheckConstraints, int[] changedColumnIds,
0601: boolean[] needsDeferredProcessing,
0602: ConstraintDescriptorList relevantConstraints)
0603: throws StandardException {
0604: if (SanityManager.DEBUG) {
0605: SanityManager
0606: .ASSERT(
0607: (statementType == StatementType.INSERT)
0608: || (statementType == StatementType.BULK_INSERT_REPLACE)
0609: || (statementType == StatementType.UPDATE)
0610: || (statementType == StatementType.DELETE),
0611: "invalid statement type " + statementType);
0612: }
0613:
0614: DataDictionary dd = getDataDictionary();
0615: ConstraintDescriptorList cdl = dd
0616: .getConstraintDescriptors(this );
0617: int cdlSize = cdl.size();
0618:
0619: for (int index = 0; index < cdlSize; index++) {
0620: ConstraintDescriptor cd = cdl.elementAt(index);
0621:
0622: if (skipCheckConstraints
0623: && (cd.getConstraintType() == DataDictionary.CHECK_CONSTRAINT)) {
0624: continue;
0625: }
0626:
0627: /*
0628: ** For each constraint, figure out if it requires deferred processing.
0629: ** Note that we need to do this on constraints that don't
0630: ** necessarily need to fire -- e.g. for an insert into a
0631: ** a table with a self-referencing constraint, we don't
0632: ** need to check the primary key constraint (assuming it
0633: ** is only referenced by the self-referencing fk on the same
0634: ** table), but we have to run in deferred mode nonetheless
0635: ** (even though we aren't going to check the pk constraint).
0636: */
0637: if (!needsDeferredProcessing[0]
0638: && (cd instanceof ReferencedKeyConstraintDescriptor)
0639: && (statementType != StatementType.UPDATE && statementType != StatementType.BULK_INSERT_REPLACE)) {
0640: /* For insert (bulk or regular) on a non-published table,
0641: * we only need deferred mode if there is a
0642: * self-referencing foreign key constraint.
0643: */
0644: needsDeferredProcessing[0] = ((ReferencedKeyConstraintDescriptor) cd)
0645: .hasSelfReferencingFK(cdl,
0646: ConstraintDescriptor.ENABLED);
0647: }
0648:
0649: if (cd.needsToFire(statementType, changedColumnIds)) {
0650: /*
0651: ** For update, if we are updating a referenced key, then
0652: ** we have to do it in deferred mode (in case we update
0653: ** multiple rows).
0654: */
0655: if ((cd instanceof ReferencedKeyConstraintDescriptor)
0656: && (statementType == StatementType.UPDATE || statementType == StatementType.BULK_INSERT_REPLACE)) {
0657: needsDeferredProcessing[0] = true;
0658: }
0659:
0660: relevantConstraints.add(cd);
0661: }
0662: }
0663: }
0664:
0665: //
0666: // Provider interface
0667: //
0668:
0669: /**
0670: @return the stored form of this provider
0671:
0672: @see Dependable#getDependableFinder
0673: */
0674: public DependableFinder getDependableFinder() {
0675: if (referencedColumnMap == null)
0676: return getDependableFinder(StoredFormatIds.TABLE_DESCRIPTOR_FINDER_V01_ID);
0677: else
0678: return getColumnDependableFinder(
0679: StoredFormatIds.COLUMN_DESCRIPTOR_FINDER_V01_ID,
0680: referencedColumnMap.getByteArray());
0681: }
0682:
0683: /**
0684: * Return the name of this Provider. (Useful for errors.)
0685: *
0686: * @return String The name of this provider.
0687: */
0688: public String getObjectName() {
0689: if (referencedColumnMap == null)
0690: return tableName;
0691: else {
0692: String name = new String(tableName);
0693: boolean first = true;
0694: for (int i = 0; i < columnDescriptorList.size(); i++) {
0695: ColumnDescriptor cd = (ColumnDescriptor) columnDescriptorList
0696: .elementAt(i);
0697: if (referencedColumnMap.isSet(cd.getPosition())) {
0698: if (first) {
0699: name += "(" + cd.getColumnName();
0700: first = false;
0701: } else
0702: name += ", " + cd.getColumnName();
0703: }
0704: }
0705: if (!first)
0706: name += ")";
0707: return name;
0708: }
0709: }
0710:
0711: /**
0712: * Get the provider's UUID
0713: *
0714: * @return String The provider's UUID
0715: */
0716: public UUID getObjectID() {
0717: return oid;
0718: }
0719:
0720: /**
0721: * Get the provider's type.
0722: *
0723: * @return String The provider's type.
0724: */
0725: public String getClassType() {
0726: return Dependable.TABLE;
0727: }
0728:
0729: //
0730: // class interface
0731: //
0732:
0733: /**
0734: * Prints the contents of the TableDescriptor
0735: *
0736: * @return The contents as a String
0737: */
0738: public String toString() {
0739: if (SanityManager.DEBUG) {
0740: String tempString = "SCHEMA:\n" + schema + "\ntableName: "
0741: + tableName + "\n" + "oid: " + oid + " tableType: "
0742: + tableType + "\n" + "conglomerateDescriptorList: "
0743: + conglomerateDescriptorList + "\n"
0744: + "columnDescriptorList: " + columnDescriptorList
0745: + "\n" + "constraintDescriptorList: "
0746: + constraintDescriptorList + "\n"
0747: + "heapConglomNumber: " + heapConglomNumber + "\n";
0748: if (tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
0749: tempString = tempString + "onCommitDeleteRows: " + "\n"
0750: + onCommitDeleteRows + "\n";
0751: tempString = tempString + "onRollbackDeleteRows: "
0752: + "\n" + onRollbackDeleteRows + "\n";
0753: } else
0754: tempString = tempString + "lockGranularity: "
0755: + lockGranularity + "\n";
0756: return tempString;
0757: } else {
0758: return "";
0759: }
0760: }
0761:
0762: /**
0763: * Gets the column descriptor list
0764: *
0765: * @return The column descriptor list for this table descriptor
0766: *
0767: */
0768: public ColumnDescriptorList getColumnDescriptorList() {
0769: return columnDescriptorList;
0770: }
0771:
0772: /**
0773: * Gets the constraint descriptor list
0774: *
0775: * @return The constraint descriptor list for this table descriptor
0776: *
0777: * @exception StandardException Thrown on failure
0778: */
0779: public ConstraintDescriptorList getConstraintDescriptorList()
0780: throws StandardException {
0781: return constraintDescriptorList;
0782: }
0783:
0784: /**
0785: * Sets the constraint descriptor list
0786: *
0787: * @param newCDL The new constraint descriptor list for this table descriptor
0788: */
0789: public void setConstraintDescriptorList(
0790: ConstraintDescriptorList newCDL) {
0791: constraintDescriptorList = newCDL;
0792: }
0793:
0794: /**
0795: * Empty the constraint descriptor list
0796: *
0797: * @exception StandardException Thrown on failure
0798: */
0799: public void emptyConstraintDescriptorList()
0800: throws StandardException {
0801: // Easier just to get a new CDL then to clean out the current one
0802: this .constraintDescriptorList = new ConstraintDescriptorList();
0803: }
0804:
0805: /**
0806: * Gets the primary key, may return null if no primary key
0807: *
0808: * @return The priamry key or null
0809: *
0810: * @exception StandardException Thrown on failure
0811: */
0812: public ReferencedKeyConstraintDescriptor getPrimaryKey()
0813: throws StandardException {
0814: ConstraintDescriptorList cdl = getDataDictionary()
0815: .getConstraintDescriptors(this );
0816:
0817: return cdl.getPrimaryKey();
0818: }
0819:
0820: /**
0821: * Gets the trigger descriptor list
0822: *
0823: * @return The trigger descriptor list for this table descriptor
0824: *
0825: * @exception StandardException Thrown on failure
0826: */
0827: public GenericDescriptorList getTriggerDescriptorList()
0828: throws StandardException {
0829: return triggerDescriptorList;
0830: }
0831:
0832: /**
0833: * Sets the trigger descriptor list
0834: *
0835: * @param newCDL The new trigger descriptor list for this table descriptor
0836: */
0837: public void setTriggerDescriptorList(GenericDescriptorList newCDL) {
0838: triggerDescriptorList = newCDL;
0839: }
0840:
0841: /**
0842: * Empty the trigger descriptor list
0843: *
0844: * @exception StandardException Thrown on failure
0845: */
0846: public void emptyTriggerDescriptorList() throws StandardException {
0847: // Easier just to get a new CDL then to clean out the current one
0848: this .triggerDescriptorList = new GenericDescriptorList();
0849: }
0850:
0851: /**
0852: * Compare the tables descriptors based on the names.
0853: * Null schema names match.
0854: *
0855: * @param otherTableName the other table name
0856: * @param otherSchemaName the other schema name
0857: *
0858: * @return boolean Whether or not the 2 TableNames are equal.
0859: */
0860: public boolean tableNameEquals(String otherTableName,
0861: String otherSchemaName) {
0862: String schemaName = getSchemaName();
0863:
0864: if ((schemaName == null) || (otherSchemaName == null)) {
0865: return tableName.equals(otherTableName);
0866: } else {
0867: return schemaName.equals(otherSchemaName)
0868: && tableName.equals(otherTableName);
0869: }
0870: }
0871:
0872: /**
0873: * Remove this descriptor
0874: *
0875: * @param cd The conglomerate descriptor
0876: *
0877: * @exception StandardException on error
0878: */
0879: public void removeConglomerateDescriptor(ConglomerateDescriptor cd)
0880: throws StandardException {
0881: conglomerateDescriptorList.dropConglomerateDescriptor(
0882: getUUID(), cd);
0883: }
0884:
0885: /**
0886: * Remove this descriptor. Warning, removes by using object
0887: * reference, not uuid.
0888: *
0889: * @param cd constraint descriptor
0890: *
0891: * @exception StandardException on error
0892: */
0893: public void removeConstraintDescriptor(ConstraintDescriptor cd)
0894: throws StandardException {
0895: constraintDescriptorList.remove(cd);
0896: }
0897:
0898: /**
0899: * Get the descriptor for a column in the table,
0900: * either by the column name or by its ordinal position (column number).
0901: * Returns NULL for columns that do not exist.
0902: *
0903: * @param columnName A String containing the name of the column
0904: *
0905: * @return A ColumnDescriptor describing the column
0906: */
0907: public ColumnDescriptor getColumnDescriptor(String columnName) {
0908: return columnDescriptorList
0909: .getColumnDescriptor(oid, columnName);
0910: }
0911:
0912: /**
0913: * @param columnNumber The ordinal position of the column in the table
0914: *
0915: * @return A ColumnDescriptor describing the column
0916: */
0917: public ColumnDescriptor getColumnDescriptor(int columnNumber) {
0918: return columnDescriptorList.getColumnDescriptor(oid,
0919: columnNumber);
0920: }
0921:
0922: /**
0923: * Gets a ConglomerateDescriptor[] to loop through all the conglomerate descriptors
0924: * for the table.
0925: *
0926: * @return A ConglomerateDescriptor[] for looping through the table's conglomerates
0927: *
0928: * @exception StandardException Thrown on failure
0929: */
0930: public ConglomerateDescriptor[] getConglomerateDescriptors() {
0931:
0932: int size = conglomerateDescriptorList.size();
0933: ConglomerateDescriptor[] cdls = new ConglomerateDescriptor[size];
0934: conglomerateDescriptorList.toArray(cdls);
0935: return cdls;
0936: }
0937:
0938: /**
0939: * Gets a conglomerate descriptor for the given table and conglomerate number.
0940: *
0941: * @param conglomerateNumber The conglomerate number
0942: * we're interested in
0943: *
0944: * @return A ConglomerateDescriptor describing the requested
0945: * conglomerate. Returns NULL if no such conglomerate.
0946: *
0947: * @exception StandardException Thrown on failure
0948: */
0949: public ConglomerateDescriptor getConglomerateDescriptor(
0950: long conglomerateNumber) throws StandardException {
0951: return conglomerateDescriptorList
0952: .getConglomerateDescriptor(conglomerateNumber);
0953: }
0954:
0955: /**
0956: * Gets array of conglomerate descriptors for the given table and
0957: * conglomerate number. More than one descriptors if duplicate indexes
0958: * share one conglomerate.
0959: *
0960: * @param conglomerateNumber The conglomerate number
0961: * we're interested in
0962: *
0963: * @return Array of ConglomerateDescriptors with the requested
0964: * conglomerate number. Returns size 0 array if no such conglomerate.
0965: *
0966: * @exception StandardException Thrown on failure
0967: */
0968: public ConglomerateDescriptor[] getConglomerateDescriptors(
0969: long conglomerateNumber) throws StandardException {
0970: return conglomerateDescriptorList
0971: .getConglomerateDescriptors(conglomerateNumber);
0972: }
0973:
0974: /**
0975: * Gets a conglomerate descriptor for the given table and conglomerate UUID String.
0976: *
0977: * @param conglomerateUUID The UUID for the conglomerate
0978: * we're interested in
0979: *
0980: * @return A ConglomerateDescriptor describing the requested
0981: * conglomerate. Returns NULL if no such conglomerate.
0982: *
0983: * @exception StandardException Thrown on failure
0984: */
0985: public ConglomerateDescriptor getConglomerateDescriptor(
0986: UUID conglomerateUUID) throws StandardException {
0987: return conglomerateDescriptorList
0988: .getConglomerateDescriptor(conglomerateUUID);
0989: }
0990:
0991: /**
0992: * Gets array of conglomerate descriptors for the given table and
0993: * conglomerate UUID. More than one descriptors if duplicate indexes
0994: * share one conglomerate.
0995: *
0996: * @param conglomerateUUID The conglomerate UUID
0997: * we're interested in
0998: *
0999: * @return Array of ConglomerateDescriptors with the requested
1000: * conglomerate UUID. Returns size 0 array if no such conglomerate.
1001: *
1002: * @exception StandardException Thrown on failure
1003: */
1004: public ConglomerateDescriptor[] getConglomerateDescriptors(
1005: UUID conglomerateUUID) throws StandardException {
1006: return conglomerateDescriptorList
1007: .getConglomerateDescriptors(conglomerateUUID);
1008: }
1009:
1010: /**
1011: * Gets an object which lists out all the index row generators on a table together
1012: * with their conglomerate ids.
1013: *
1014: * @return An object to list out the index row generators.
1015: *
1016: * @exception StandardException Thrown on failure
1017: */
1018: public IndexLister getIndexLister() throws StandardException {
1019: return new IndexLister(this );
1020: }
1021:
1022: /**
1023: * Does the table have an autoincrement column or not?
1024: *
1025: * @return TRUE if the table has atleast one autoincrement column, false
1026: * otherwise
1027: */
1028: public boolean tableHasAutoincrement() {
1029: int cdlSize = getColumnDescriptorList().size();
1030: for (int index = 0; index < cdlSize; index++) {
1031: ColumnDescriptor cd = (ColumnDescriptor) columnDescriptorList
1032: .elementAt(index);
1033: if (cd.isAutoincrement())
1034: return true;
1035: }
1036: return false;
1037: }
1038:
1039: /**
1040: * Gets an array of column names.
1041: *
1042: * @return An array, filled with the column names in the table.
1043: *
1044: */
1045: public String[] getColumnNamesArray() {
1046: int size = getNumberOfColumns();
1047: String[] s = new String[size];
1048:
1049: for (int i = 0; i < size; i++)
1050: s[i] = getColumnDescriptor(i + 1).getColumnName();
1051:
1052: return s;
1053: }
1054:
1055: /**
1056: * gets an array of increment values for autoincrement columns in the target
1057: * table. If column is not an autoincrement column, then increment value is
1058: * 0. If table has no autoincrement columns, returns NULL.
1059: *
1060: * @return array containing the increment values of autoincrement
1061: * columns.
1062: *
1063: */
1064: public long[] getAutoincIncrementArray() {
1065: if (!tableHasAutoincrement())
1066: return null;
1067:
1068: int size = getNumberOfColumns();
1069: long[] inc = new long[size];
1070:
1071: for (int i = 0; i < size; i++) {
1072: ColumnDescriptor cd = getColumnDescriptor(i + 1);
1073: if (cd.isAutoincrement())
1074: inc[i] = cd.getAutoincInc();
1075: }
1076:
1077: return inc;
1078: }
1079:
1080: /** Returns a list of statistics for this table.
1081: */
1082: private synchronized List getStatistics() throws StandardException {
1083: // if table already has the statistics descriptors initialized
1084: // no need to do anything
1085: if (statisticsDescriptorList != null)
1086: return statisticsDescriptorList;
1087:
1088: DataDictionary dd = getDataDictionary();
1089: return statisticsDescriptorList = dd
1090: .getStatisticsDescriptors(this );
1091: }
1092:
1093: /**
1094: * Are there statistics for this particular conglomerate.
1095: *
1096: * @param cd Conglomerate/Index for which we want to check if statistics
1097: * exist. cd can be null in which case user wants to know if there are any
1098: * statistics at all on the table.
1099: */
1100: public boolean statisticsExist(ConglomerateDescriptor cd)
1101: throws StandardException {
1102: List sdl = getStatistics();
1103:
1104: if (cd == null)
1105: return (sdl.size() > 0);
1106:
1107: UUID cdUUID = cd.getUUID();
1108:
1109: for (Iterator li = sdl.iterator(); li.hasNext();) {
1110: StatisticsDescriptor statDesc = (StatisticsDescriptor) li
1111: .next();
1112: if (cdUUID.equals(statDesc.getReferenceID()))
1113: return true;
1114:
1115: }
1116:
1117: return false;
1118: }
1119:
1120: /**
1121: * For this conglomerate (index), return the selectivity of the first
1122: * numKeys. This basically returns the reciprocal of the number of unique
1123: * values in the leading numKey columns of the index. It is assumed that
1124: * statistics exist for the conglomerate if this function is called.
1125: *
1126: * @param cd ConglomerateDescriptor (Index) whose
1127: * cardinality we are interested in.
1128: * @param numKeys Number of leading columns of the index for which
1129: * cardinality is desired.
1130:
1131: */
1132: public double selectivityForConglomerate(ConglomerateDescriptor cd,
1133: int numKeys) throws StandardException {
1134: if (!statisticsExist(cd)) {
1135: if (SanityManager.DEBUG) {
1136: SanityManager
1137: .THROWASSERT("no statistics exist for conglomerate"
1138: + cd);
1139: } else {
1140: double selectivity = 0.1;
1141: for (int i = 0; i < numKeys; i++)
1142: selectivity *= 0.1;
1143: return selectivity;
1144: }
1145: }
1146:
1147: UUID referenceUUID = cd.getUUID();
1148:
1149: List sdl = getStatistics();
1150: for (Iterator li = sdl.iterator(); li.hasNext();) {
1151: StatisticsDescriptor statDesc = (StatisticsDescriptor) li
1152: .next();
1153:
1154: if (!referenceUUID.equals(statDesc.getReferenceID()))
1155: continue;
1156:
1157: if (statDesc.getColumnCount() != numKeys)
1158: continue;
1159:
1160: return statDesc.getStatistic().selectivity((Object[]) null);
1161: }
1162:
1163: if (SanityManager.DEBUG)
1164: SanityManager
1165: .THROWASSERT("Internal Error-- statistics not found in selectivityForConglomerate.\n cd = "
1166: + cd + "\nnumKeys = " + numKeys);
1167: return 0.1; // shouldn't come here.
1168: }
1169:
1170: /** @see TupleDescriptor#getDescriptorName */
1171: public String getDescriptorName() {
1172: return tableName;
1173: }
1174:
1175: /** @see TupleDescriptor#getDescriptorType */
1176: public String getDescriptorType() {
1177: return (tableType == TableDescriptor.SYNONYM_TYPE) ? "Synonym"
1178: : "Table/View";
1179: }
1180: }
|