/** * Insert the given row into the given conglomerate and check for duplicate key error. * * @param row The row to insert * @exception StandardException Thrown on duplicate key error */ private void insertAndCheckDups(ExecIndexRow row) throws StandardException { openIndexCC(); int insertStatus = indexCC.insert(row.getRowArray()); if (insertStatus == ConglomerateController.ROWISDUPLICATE) { /* ** We have a duplicate key error. */ String indexOrConstraintName = indexName; // now get table name, and constraint name if needed LanguageConnectionContext lcc = activation.getLanguageConnectionContext(); DataDictionary dd = lcc.getDataDictionary(); // get the descriptors ConglomerateDescriptor cd = dd.getConglomerateDescriptor(indexCID); UUID tableID = cd.getTableID(); TableDescriptor td = dd.getTableDescriptor(tableID); String tableName = td.getName(); if (indexOrConstraintName == null) // no index name passed in { ConstraintDescriptor conDesc = dd.getConstraintDescriptor(td, cd.getUUID()); indexOrConstraintName = conDesc.getConstraintName(); } throw StandardException.newException( SQLState.LANG_DUPLICATE_KEY_CONSTRAINT, indexOrConstraintName, tableName); } if (SanityManager.DEBUG) { if (insertStatus != 0) { SanityManager.THROWASSERT("Unknown insert status " + insertStatus); } } }
static void debugLock(String type, CompatibilitySpace compatibilitySpace, Object group) { if (SanityManager.DEBUG) { SanityManager.DEBUG(Constants.LOCK_TRACE, type + debugLockString(compatibilitySpace, group)); } }
/** * Finish doing the changes for this index. This is intended for deferred inserts for unique * indexes. It has no effect unless we are doing an update of a unique index. * * @exception StandardException Thrown on error */ public void finish() throws StandardException { ExecRow deferredRow; /* Deferred processing only necessary for unique indexes */ if (rowHolder != null) { CursorResultSet rs = rowHolder.getResultSet(); try { rs.open(); while ((deferredRow = rs.getNextRow()) != null) { if (SanityManager.DEBUG) { if (!(deferredRow instanceof ExecIndexRow)) { SanityManager.THROWASSERT( "deferredRow isn't an instance " + "of ExecIndexRow as expected. " + "It is an " + deferredRow.getClass().getName()); } } insertAndCheckDups((ExecIndexRow) deferredRow); } } finally { rs.close(); /* ** If row holder was passed in, let the ** client of this method clean it up. */ if (!rowHolderPassedIn) { rowHolder.close(); } } } }
static void debugAddThreadInfo(StringBuffer sb) { if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(Constants.LOCK_TRACE_ADD_THREAD_INFO)) { debugAppendObject(sb, " Thread=", Thread.currentThread()); } } }
/** * Create a new {@code FileInfoDescriptor} using the supplied arguments. * * <p>id unique id to be used for the new file descriptor sd schema of the new file to be stored * in the database SQLName the SQL name of the new schema object representing the file * generationID version numberof the file the descriptor describes * * @return the newly created file info descriptor */ public FileInfoDescriptor newFileInfoDescriptor( UUID id, SchemaDescriptor sd, String sqlName, long generationId) { if (SanityManager.DEBUG) { SanityManager.ASSERT(id != null); } return new FileInfoDescriptor(dataDictionary, id, sd, sqlName, generationId); }
/** * Read an integer previously written by writeInt(). * * @exception IOException an exception was thrown by a method on in. */ public static final int readInt(DataInput in) throws IOException { int value = in.readUnsignedByte(); if ((value & ~0x3f) == 0) { // length is stored in this byte, we also know that the 0x80 bit // was not set, so no need to mask off the sign extension from // the byte to int conversion. // account for 1 byte stored length of field + 1 for all returns return (value); } else if ((value & 0x80) == 0) { // length is stored in 2 bytes. only use low 6 bits from 1st byte. if (SanityManager.DEBUG) { SanityManager.ASSERT((value & 0x40) == 0x40); } // top 8 bits of 2 byte length is stored in this byte, we also // know that the 0x80 bit was not set, so no need to mask off the // sign extension from the 1st byte to int conversion. Need to // mask the byte in data[offset + 1] to account for possible sign // extension. return (((value & 0x3f) << 8) | in.readUnsignedByte()); } else { // length is stored in 4 bytes. only use low 7 bits from 1st byte. if (SanityManager.DEBUG) { SanityManager.ASSERT((value & 0x80) == 0x80); } // top 8 bits of 4 byte length is stored in this byte, we also // know that the 0x80 bit was set, so need to mask off the // sign extension from the 1st byte to int conversion. Need to // mask the bytes from the next 3 bytes data[offset + 1,2,3] to // account for possible sign extension. // return (((value & 0x7f) << 24) | (in.readUnsignedByte() << 16) | (in.readUnsignedByte() << 8) | (in.readUnsignedByte())); } }
public static final int readInt(byte[] data, int offset) { int value = data[offset++]; if ((value & ~0x3f) == 0) { // length is stored in this byte, we also know that the 0x80 bit // was not set, so no need to mask off the sign extension from // the byte to int conversion. return (value); } else if ((value & 0x80) == 0) { // length is stored in 2 bytes. only use low 6 bits from 1st byte. if (SanityManager.DEBUG) { SanityManager.ASSERT((value & 0x40) == 0x40); } // top 8 bits of 2 byte length is stored in this byte, we also // know that the 0x80 bit was not set, so no need to mask off the // sign extension from the 1st byte to int conversion. Need to // mask the byte in data[offset + 1] to account for possible sign // extension. return (((value & 0x3f) << 8) | (data[offset] & 0xff)); } else { // length is stored in 4 bytes. only use low 7 bits from 1st byte. if (SanityManager.DEBUG) { SanityManager.ASSERT((value & 0x80) == 0x80); } // top 8 bits of 4 byte length is stored in this byte, we also // know that the 0x80 bit was set, so need to mask off the // sign extension from the 1st byte to int conversion. Need to // mask the bytes from the next 3 bytes data[offset + 1,2,3] to // account for possible sign extension. // return (((value & 0x7f) << 24) | ((data[offset++] & 0xff) << 16) | ((data[offset++] & 0xff) << 8) | ((data[offset] & 0xff))); } }
String getOperatorName() { switch (opType) { case INTERSECT_OP: return "INTERSECT"; case EXCEPT_OP: return "EXCEPT"; } if (SanityManager.DEBUG) SanityManager.THROWASSERT("Invalid intersectOrExcept opType: " + opType); return "?"; }
static void debugLock( String type, CompatibilitySpace compatibilitySpace, Object group, Lockable ref, Object qualifier, int timeout) { if (SanityManager.DEBUG) { SanityManager.DEBUG( Constants.LOCK_TRACE, type + debugLockString(compatibilitySpace, group, ref, qualifier, timeout)); } }
/** * Create an IndexChanger * * @param irg the IndexRowGenerator for the index. * @param indexCID the conglomerate id for the index. * @param indexSCOCI the SCOCI for the idexes. * @param indexDCOCI the DCOCI for the idexes. * @param baseCC the ConglomerateController for the base table. * @param tc The TransactionController * @param lockMode The lock mode (granularity) to use * @param baseRowReadMap Map of columns read in. 1 based. * @param isolationLevel Isolation level to use. * @param activation Current activation * @exception StandardException Thrown on error */ public IndexChanger( IndexRowGenerator irg, long indexCID, StaticCompiledOpenConglomInfo indexSCOCI, DynamicCompiledOpenConglomInfo indexDCOCI, String indexName, ConglomerateController baseCC, TransactionController tc, int lockMode, FormatableBitSet baseRowReadMap, int isolationLevel, Activation activation) throws StandardException { this.irg = irg; this.indexCID = indexCID; this.indexSCOCI = indexSCOCI; this.indexDCOCI = indexDCOCI; this.baseCC = baseCC; this.tc = tc; this.lockMode = lockMode; this.baseRowReadMap = baseRowReadMap; this.rowHolderPassedIn = false; this.isolationLevel = isolationLevel; this.activation = activation; this.indexName = indexName; // activation will be null when called from DataDictionary if (activation != null && activation.getIndexConglomerateNumber() == indexCID) { ownIndexSC = false; } if (SanityManager.DEBUG) { SanityManager.ASSERT(tc != null, "TransactionController argument to constructor is null"); SanityManager.ASSERT(irg != null, "IndexRowGenerator argument to constructor is null"); } }
double getRowCountEstimate(double leftRowCount, double rightRowCount) { switch (opType) { case INTERSECT_OP: // The result has at most min( leftRowCount, rightRowCount). Estimate the actual row count // at // half that. return Math.min(leftRowCount, rightRowCount) / 2; case EXCEPT_OP: // The result has at most leftRowCount rows and at least // max(0, leftRowCount - rightRowCount) rows. Use the mean // of those two as the estimate. return (leftRowCount + Math.max(0, leftRowCount - rightRowCount)) / 2; } if (SanityManager.DEBUG) SanityManager.THROWASSERT("Invalid intersectOrExcept opType: " + opType); return 1.0; } // end of getRowCountEstimate
/** * Initialize the class. * * <p>Save away pointers to the base table template row, and the rowlocation class. Build default * map of base columns to key columns, this map can be changed with setMap(). * * <p> * * @param template The template for the base table row. * @param rowlocation The template for the row location. * @param numkeys The total number of columns in the secondary index including the rowlocation * column. * @exception StandardException Standard exception policy. */ public void init(DataValueDescriptor[] template, RowLocation rowlocation, int numkeys) throws StandardException { if (SanityManager.DEBUG) { if (numkeys != (template.length + 1)) SanityManager.THROWASSERT("numkeys = " + numkeys + " template.length = " + template.length); } init_rowlocation = rowlocation; /* create new object array for the row, and copy all object references * from template row to new secondary index row. */ row = new DataValueDescriptor[numkeys]; System.arraycopy(template, 0, row, 0, template.length); /* add the reference to the row location column as the last column */ row[row.length - 1] = rowlocation; }
/** * Make a SYSCONTRAINTS row * * @throws StandardException thrown on failure * @return Row suitable for inserting into SYSCONTRAINTS. */ public ExecRow makeRow(TupleDescriptor td, TupleDescriptor parent) throws StandardException { DataValueDescriptor col; ExecRow row; int constraintIType; UUID oid; String constraintSType = null; String constraintID = null; String tableID = null; String constraintName = null; String schemaID = null; boolean isEnabled = true; int referenceCount = 0; if (td != null) { ConstraintDescriptor constraint = (ConstraintDescriptor) td; /* ** We only allocate a new UUID if the descriptor doesn't already have one. ** For descriptors replicated from a Source system, we already have an UUID. */ oid = constraint.getUUID(); constraintID = oid.toString(); oid = constraint.getTableId(); tableID = oid.toString(); constraintName = constraint.getConstraintName(); constraintIType = constraint.getConstraintType(); switch (constraintIType) { case DataDictionary.PRIMARYKEY_CONSTRAINT: constraintSType = "P"; break; case DataDictionary.UNIQUE_CONSTRAINT: constraintSType = "U"; break; case DataDictionary.CHECK_CONSTRAINT: constraintSType = "C"; break; case DataDictionary.FOREIGNKEY_CONSTRAINT: constraintSType = "F"; break; default: if (SanityManager.DEBUG) { SanityManager.THROWASSERT("invalid constraint type"); } } schemaID = constraint.getSchemaDescriptor().getUUID().toString(); isEnabled = constraint.isEnabled(); referenceCount = constraint.getReferenceCount(); } /* Insert info into sysconstraints */ /* RESOLVE - It would be nice to require less knowledge about sysconstraints * and have this be more table driven. */ /* Build the row to insert */ row = getExecutionFactory().getValueRow(SYSCONSTRAINTS_COLUMN_COUNT); /* 1st column is CONSTRAINTID (UUID - char(36)) */ row.setColumn(SYSCONSTRAINTS_CONSTRAINTID, new SQLChar(constraintID)); /* 2nd column is TABLEID (UUID - char(36)) */ row.setColumn(SYSCONSTRAINTS_TABLEID, new SQLChar(tableID)); /* 3rd column is NAME (varchar(128)) */ row.setColumn(SYSCONSTRAINTS_CONSTRAINTNAME, new SQLVarchar(constraintName)); /* 4th column is TYPE (char(1)) */ row.setColumn(SYSCONSTRAINTS_TYPE, new SQLChar(constraintSType)); /* 5th column is SCHEMAID (UUID - char(36)) */ row.setColumn(SYSCONSTRAINTS_SCHEMAID, new SQLChar(schemaID)); /* 6th column is STATE (char(1)) */ row.setColumn(SYSCONSTRAINTS_STATE, new SQLChar(isEnabled ? "E" : "D")); /* 7th column is REFERENCED */ row.setColumn(SYSCONSTRAINTS_REFERENCECOUNT, new SQLInteger(referenceCount)); return row; }
/** * Make a ConstraintDescriptor out of a SYSCONSTRAINTS row * * @param row a SYSCONSTRAINTS row * @param parentTupleDescriptor Subconstraint descriptor with auxiliary info. * @param dd dataDictionary * @throws StandardException thrown on failure */ public TupleDescriptor buildDescriptor( ExecRow row, TupleDescriptor parentTupleDescriptor, DataDictionary dd) throws StandardException { ConstraintDescriptor constraintDesc = null; if (SanityManager.DEBUG) { SanityManager.ASSERT( row.nColumns() == SYSCONSTRAINTS_COLUMN_COUNT, "Wrong number of columns for a SYSCONSTRAINTS row"); } DataValueDescriptor col; ConglomerateDescriptor conglomDesc; DataDescriptorGenerator ddg; TableDescriptor td = null; int constraintIType = -1; int[] keyColumns = null; UUID constraintUUID; UUID schemaUUID; UUID tableUUID; UUID referencedConstraintId = null; SchemaDescriptor schema; String tableUUIDString; String constraintName; String constraintSType; String constraintStateStr; boolean constraintEnabled; int referenceCount; String constraintUUIDString; String schemaUUIDString; SubConstraintDescriptor scd; if (SanityManager.DEBUG) { if (!(parentTupleDescriptor instanceof SubConstraintDescriptor)) { SanityManager.THROWASSERT( "parentTupleDescriptor expected to be instanceof " + "SubConstraintDescriptor, not " + parentTupleDescriptor.getClass().getName()); } } scd = (SubConstraintDescriptor) parentTupleDescriptor; ddg = dd.getDataDescriptorGenerator(); /* 1st column is CONSTRAINTID (UUID - char(36)) */ col = row.getColumn(SYSCONSTRAINTS_CONSTRAINTID); constraintUUIDString = col.getString(); constraintUUID = getUUIDFactory().recreateUUID(constraintUUIDString); /* 2nd column is TABLEID (UUID - char(36)) */ col = row.getColumn(SYSCONSTRAINTS_TABLEID); tableUUIDString = col.getString(); tableUUID = getUUIDFactory().recreateUUID(tableUUIDString); /* Get the TableDescriptor. * It may be cached in the SCD, * otherwise we need to go to the * DD. */ if (scd != null) { td = scd.getTableDescriptor(); } if (td == null) { td = dd.getTableDescriptor(tableUUID); } /* 3rd column is NAME (varchar(128)) */ col = row.getColumn(SYSCONSTRAINTS_CONSTRAINTNAME); constraintName = col.getString(); /* 4th column is TYPE (char(1)) */ col = row.getColumn(SYSCONSTRAINTS_TYPE); constraintSType = col.getString(); if (SanityManager.DEBUG) { SanityManager.ASSERT(constraintSType.length() == 1, "Fourth column type incorrect"); } boolean typeSet = false; switch (constraintSType.charAt(0)) { case 'P': constraintIType = DataDictionary.PRIMARYKEY_CONSTRAINT; typeSet = true; // fall through case 'U': if (!typeSet) { constraintIType = DataDictionary.UNIQUE_CONSTRAINT; typeSet = true; } // fall through case 'F': if (!typeSet) constraintIType = DataDictionary.FOREIGNKEY_CONSTRAINT; if (SanityManager.DEBUG) { if (!(parentTupleDescriptor instanceof SubKeyConstraintDescriptor)) { SanityManager.THROWASSERT( "parentTupleDescriptor expected to be instanceof " + "SubKeyConstraintDescriptor, not " + parentTupleDescriptor.getClass().getName()); } } conglomDesc = td.getConglomerateDescriptor( ((SubKeyConstraintDescriptor) parentTupleDescriptor).getIndexId()); /* Take care the rare case of conglomDesc being null. The * reason is that our "td" is out of date. Another thread * which was adding a constraint committed between the moment * we got the table descriptor (conglomerate list) and the * moment we scanned and got the constraint desc list. Since * that thread just added a new row to SYSCONGLOMERATES, * SYSCONSTRAINTS, etc. We wouldn't have wanted to lock the * system tables just to prevent other threads from adding new * rows. */ if (conglomDesc == null) { // we can't be getting td from cache because if we are // here, we must have been in dd's ddl mode (that's why // the ddl thread went through), we are not done yet, the // dd ref count is not 0, hence it couldn't have turned // into COMPILE_ONLY mode td = dd.getTableDescriptor(tableUUID); if (scd != null) scd.setTableDescriptor(td); // try again now conglomDesc = td.getConglomerateDescriptor( ((SubKeyConstraintDescriptor) parentTupleDescriptor).getIndexId()); } if (SanityManager.DEBUG) { SanityManager.ASSERT( conglomDesc != null, "conglomDesc is expected to be non-null for backing index"); } referencedConstraintId = ((SubKeyConstraintDescriptor) parentTupleDescriptor).getKeyConstraintId(); keyColumns = conglomDesc.getIndexDescriptor().baseColumnPositions(); break; case 'C': constraintIType = DataDictionary.CHECK_CONSTRAINT; if (SanityManager.DEBUG) { if (!(parentTupleDescriptor instanceof SubCheckConstraintDescriptor)) { SanityManager.THROWASSERT( "parentTupleDescriptor expected to be instanceof " + "SubCheckConstraintDescriptor, not " + parentTupleDescriptor.getClass().getName()); } } break; default: if (SanityManager.DEBUG) { SanityManager.THROWASSERT("Fourth column value invalid"); } } /* 5th column is SCHEMAID (UUID - char(36)) */ col = row.getColumn(SYSCONSTRAINTS_SCHEMAID); schemaUUIDString = col.getString(); schemaUUID = getUUIDFactory().recreateUUID(schemaUUIDString); schema = dd.getSchemaDescriptor(schemaUUID, null); /* 6th column is STATE (char(1)) */ col = row.getColumn(SYSCONSTRAINTS_STATE); constraintStateStr = col.getString(); if (SanityManager.DEBUG) { SanityManager.ASSERT(constraintStateStr.length() == 1, "Sixth column (state) type incorrect"); } switch (constraintStateStr.charAt(0)) { case 'E': constraintEnabled = true; break; case 'D': constraintEnabled = false; break; default: constraintEnabled = true; if (SanityManager.DEBUG) { SanityManager.THROWASSERT( "Invalidate state value '" + constraintStateStr + "' for constraint"); } } /* 7th column is REFERENCECOUNT, boolean */ col = row.getColumn(SYSCONSTRAINTS_REFERENCECOUNT); referenceCount = col.getInt(); /* now build and return the descriptor */ switch (constraintIType) { case DataDictionary.PRIMARYKEY_CONSTRAINT: constraintDesc = ddg.newPrimaryKeyConstraintDescriptor( td, constraintName, false, // deferable, false, // initiallyDeferred, keyColumns, // genReferencedColumns(dd, td), //int referencedColumns[], constraintUUID, ((SubKeyConstraintDescriptor) parentTupleDescriptor).getIndexId(), schema, constraintEnabled, referenceCount); break; case DataDictionary.UNIQUE_CONSTRAINT: constraintDesc = ddg.newUniqueConstraintDescriptor( td, constraintName, false, // deferable, false, // initiallyDeferred, keyColumns, // genReferencedColumns(dd, td), //int referencedColumns[], constraintUUID, ((SubKeyConstraintDescriptor) parentTupleDescriptor).getIndexId(), schema, constraintEnabled, referenceCount); break; case DataDictionary.FOREIGNKEY_CONSTRAINT: if (SanityManager.DEBUG) { SanityManager.ASSERT( referenceCount == 0, "REFERENCECOUNT column is nonzero for fk constraint"); } constraintDesc = ddg.newForeignKeyConstraintDescriptor( td, constraintName, false, // deferable, false, // initiallyDeferred, keyColumns, // genReferencedColumns(dd, td), //int referencedColumns[], constraintUUID, ((SubKeyConstraintDescriptor) parentTupleDescriptor).getIndexId(), schema, referencedConstraintId, constraintEnabled, ((SubKeyConstraintDescriptor) parentTupleDescriptor).getRaDeleteRule(), ((SubKeyConstraintDescriptor) parentTupleDescriptor).getRaUpdateRule()); break; case DataDictionary.CHECK_CONSTRAINT: if (SanityManager.DEBUG) { SanityManager.ASSERT( referenceCount == 0, "REFERENCECOUNT column is nonzero for check constraint"); } constraintDesc = ddg.newCheckConstraintDescriptor( td, constraintName, false, // deferable, false, // initiallyDeferred, constraintUUID, ((SubCheckConstraintDescriptor) parentTupleDescriptor).getConstraintText(), ((SubCheckConstraintDescriptor) parentTupleDescriptor) .getReferencedColumnsDescriptor(), schema, constraintEnabled); break; } return constraintDesc; }