/** * restore the before image of the page * * @exception StandardException Standard Derby Error Policy * @exception IOException problem reading the complete log record from the input stream */ public void restoreMe( Transaction xact, BasePage undoPage, LogInstant CLRInstant, LimitObjectInput in) throws StandardException, IOException { int slot = undoPage.findRecordById(recordId, Page.FIRST_SLOT_NUMBER); if (SanityManager.DEBUG) { if (!getPageId().equals(undoPage.getPageId())) SanityManager.THROWASSERT( "restoreMe cannot restore to a different page. " + "doMe page:" + getPageId() + " undoPage:" + undoPage.getPageId()); if (slot != doMeSlot) SanityManager.THROWASSERT( "restoreMe cannot restore to a different slot. " + "doMe slot:" + doMeSlot + " undoMe slot: " + slot + " recordId:" + recordId); } undoPage.skipField(in); // skip the after image of the column undoPage.storeField(CLRInstant, slot, fieldId, in); undoPage.setAuxObject(null); }
/** * Get a BigDecimal representing the value of a DataValueDescriptor * * @param value Non-null value to be converted * @return BigDecimal value * @throws StandardException Invalid conversion or out of range. */ public static BigDecimal getBigDecimal(DataValueDescriptor value) throws StandardException { if (SanityManager.DEBUG) { if (value.isNull()) SanityManager.THROWASSERT("NULL value passed to SQLDecimal.getBigDecimal"); } switch (value.typeToBigDecimal()) { case Types.DECIMAL: return (BigDecimal) value.getObject(); case Types.CHAR: try { return new BigDecimal(value.getString().trim()); } catch (NumberFormatException nfe) { throw StandardException.newException( SQLState.LANG_FORMAT_EXCEPTION, "java.math.BigDecimal"); } case Types.BIGINT: return BigDecimal.valueOf(value.getLong()); default: if (SanityManager.DEBUG) SanityManager.THROWASSERT( "invalid return from " + value.getClass() + ".typeToBigDecimal() " + value.typeToBigDecimal()); return null; } }
/** * Restore field to its old value. * * @exception IOException Can be thrown by any of the methods of ObjectInput. * @exception StandardException Standard Derby policy. * @see LogicalPageOperation#undoMe */ public void undoMe( Transaction xact, BasePage undoPage, int undoRecordId, LogInstant CLRInstant, LimitObjectInput in) throws StandardException, IOException { int slot = undoPage.findRecordById(undoRecordId, Page.FIRST_SLOT_NUMBER); if (SanityManager.DEBUG) { // if the record Id has changed, the page had better changed // this can only happen during recovery since in run time undo, // this resetRecordHandle gets called and this object have the new // page number and recordId if (undoRecordId != this.recordId) if (undoPage.getPageNumber() == getPageId().getPageNumber()) SanityManager.THROWASSERT( "recordId changed from " + this.recordId + " to " + undoRecordId + " but page number did not change " + undoPage.getPageNumber()); if (slot == -1) SanityManager.THROWASSERT( "recordId " + undoRecordId + " not found on page " + undoPage.getPageNumber()); } undoPage.skipField((java.io.ObjectInput) in); // skip the after image of the column undoPage.storeField(CLRInstant, slot, fieldId, in); undoPage.setAuxObject(null); }
String nullMethodName() { int formatId = getStoredFormatIdFromTypeId(); switch (formatId) { case StoredFormatIds.DECIMAL_TYPE_ID: return "getNullDecimal"; case StoredFormatIds.DOUBLE_TYPE_ID: return "getNullDouble"; case StoredFormatIds.INT_TYPE_ID: return "getNullInteger"; case StoredFormatIds.LONGINT_TYPE_ID: return "getNullLong"; case StoredFormatIds.REAL_TYPE_ID: return "getNullFloat"; case StoredFormatIds.SMALLINT_TYPE_ID: return "getNullShort"; case StoredFormatIds.TINYINT_TYPE_ID: return "getNullByte"; default: if (SanityManager.DEBUG) { SanityManager.THROWASSERT("unexpected formatId in nullMethodName() - " + formatId); } return null; } }
/** * Get the method name for getting out the corresponding primitive Java type. * * @return String The method call name for getting the corresponding primitive Java type. */ public String getPrimitiveMethodName() { int formatId = getStoredFormatIdFromTypeId(); switch (formatId) { case StoredFormatIds.DOUBLE_TYPE_ID: return "getDouble"; case StoredFormatIds.INT_TYPE_ID: return "getInt"; case StoredFormatIds.LONGINT_TYPE_ID: return "getLong"; case StoredFormatIds.REAL_TYPE_ID: return "getFloat"; case StoredFormatIds.SMALLINT_TYPE_ID: return "getShort"; case StoredFormatIds.TINYINT_TYPE_ID: return "getByte"; case StoredFormatIds.DECIMAL_TYPE_ID: default: if (SanityManager.DEBUG) { SanityManager.THROWASSERT( "unexpected formatId in getPrimitiveMethodName() - " + formatId); } return null; } }
/** * Get the method name for getting out the corresponding primitive Java type. * * @return String The method call name for getting the corresponding primitive Java type. */ public String getPrimitiveMethodName() { if (SanityManager.DEBUG) { SanityManager.THROWASSERT( "getPrimitiveMethodName not applicable for " + getClass().toString()); } return null; }
/** @see TypeCompiler#getCorrespondingPrimitiveTypeName */ public String getCorrespondingPrimitiveTypeName() { /* Only numerics and booleans get mapped to Java primitives */ int formatId = getStoredFormatIdFromTypeId(); switch (formatId) { case StoredFormatIds.DOUBLE_TYPE_ID: return "double"; case StoredFormatIds.INT_TYPE_ID: return "int"; case StoredFormatIds.LONGINT_TYPE_ID: return "long"; case StoredFormatIds.REAL_TYPE_ID: return "float"; case StoredFormatIds.SMALLINT_TYPE_ID: return "short"; case StoredFormatIds.TINYINT_TYPE_ID: return "byte"; case StoredFormatIds.DECIMAL_TYPE_ID: default: if (SanityManager.DEBUG) { SanityManager.THROWASSERT( "unexpected formatId in getCorrespondingPrimitiveTypeName() - " + formatId); } return null; } }
/** @see TypeCompiler#getCastToCharWidth */ public int getCastToCharWidth(DataTypeDescriptor dts) { int formatId = getStoredFormatIdFromTypeId(); switch (formatId) { case StoredFormatIds.DECIMAL_TYPE_ID: // Need to have space for '-' and decimal point. return dts.getPrecision() + 2; case StoredFormatIds.DOUBLE_TYPE_ID: return TypeCompiler.DOUBLE_MAXWIDTH_AS_CHAR; case StoredFormatIds.INT_TYPE_ID: return TypeCompiler.INT_MAXWIDTH_AS_CHAR; case StoredFormatIds.LONGINT_TYPE_ID: return TypeCompiler.LONGINT_MAXWIDTH_AS_CHAR; case StoredFormatIds.REAL_TYPE_ID: return TypeCompiler.REAL_MAXWIDTH_AS_CHAR; case StoredFormatIds.SMALLINT_TYPE_ID: return TypeCompiler.SMALLINT_MAXWIDTH_AS_CHAR; case StoredFormatIds.TINYINT_TYPE_ID: return TypeCompiler.TINYINT_MAXWIDTH_AS_CHAR; default: if (SanityManager.DEBUG) { SanityManager.THROWASSERT("unexpected formatId in getCastToCharWidth() - " + formatId); } return 0; } }
/** * Called when setting a DECIMAL value internally or from through a procedure or function. Handles * long in addition to BigDecimal to handle identity being stored as a long but returned as a * DECIMAL. */ public void setValue(Number theValue) throws StandardException { if (SanityManager.ASSERT) { if (theValue != null && !(theValue instanceof java.math.BigDecimal) && !(theValue instanceof java.lang.Long)) SanityManager.THROWASSERT("SQLDecimal.setValue(Number) passed a " + theValue.getClass()); } if (theValue instanceof BigDecimal || theValue == null) setCoreValue((BigDecimal) theValue); else setValue(theValue.longValue()); }
/** * Flatten this FSqry into the outer query block. The steps in flattening are: o Mark all * ResultColumns as redundant, so that they are "skipped over" at generate(). o Append the * wherePredicates to the outer list. o Return the fromList so that the caller will merge the 2 * lists RESOLVE - FSqrys with subqueries are currently not flattenable. Some of them can be * flattened, however. We need to merge the subquery list when we relax this restriction. * * <p>NOTE: This method returns NULL when flattening RowResultSetNodes (the node for a VALUES * clause). The reason is that no reference is left to the RowResultSetNode after flattening is * done - the expressions point directly to the ValueNodes in the RowResultSetNode's * ResultColumnList. * * @param rcl The RCL from the outer query * @param outerPList PredicateList to append wherePredicates to. * @param sql The SubqueryList from the outer query * @param gbl The group by list, if any * @param havingClause The HAVING clause, if any * @return FromList The fromList from the underlying SelectNode. * @exception StandardException Thrown on error */ public FromList flatten( ResultColumnList rcl, PredicateList outerPList, SubqueryList sql, GroupByList gbl, ValueNode havingClause) throws StandardException { FromList fromList = null; SelectNode selectNode; resultColumns.setRedundant(); subquery.getResultColumns().setRedundant(); /* ** RESOLVE: Each type of result set should know how to remap itself. */ if (subquery instanceof SelectNode) { selectNode = (SelectNode) subquery; fromList = selectNode.getFromList(); // selectNode.getResultColumns().setRedundant(); if (selectNode.getWherePredicates().size() > 0) { outerPList.destructiveAppend(selectNode.getWherePredicates()); } if (selectNode.getWhereSubquerys().size() > 0) { sql.destructiveAppend(selectNode.getWhereSubquerys()); } } else if (!(subquery instanceof RowResultSetNode)) { if (SanityManager.DEBUG) { SanityManager.THROWASSERT( "subquery expected to be either a SelectNode or a RowResultSetNode, but is a " + subquery.getClass().getName()); } } /* Remap all ColumnReferences from the outer query to this node. * (We replace those ColumnReferences with clones of the matching * expression in the SELECT's RCL. */ rcl.remapColumnReferencesToExpressions(); outerPList.remapColumnReferencesToExpressions(); if (gbl != null) { gbl.remapColumnReferencesToExpressions(); } if (havingClause != null) { havingClause.remapColumnReferencesToExpressions(); } return fromList; }
/** * Write the old column value and and new column value as optional data. If logical undo, writes * out the entire row's before image. * * @exception IOException Can be thrown by any of the methods of ObjectOutput. * @exception StandardException Standard Derby policy. */ private void writeOptionalDataToBuffer(RawTransaction t, Object column) throws StandardException, IOException { if (SanityManager.DEBUG) { SanityManager.ASSERT(this.page != null); } DynamicByteArrayOutputStream logBuffer = t.getLogBuffer(); int optionalDataStart = logBuffer.getPosition(); if (SanityManager.DEBUG) { SanityManager.ASSERT( optionalDataStart == 0, "Buffer for writing optional data should start at position 0"); } this.page.logColumn(doMeSlot, fieldId, column, logBuffer, 100); // the after image of the column this.page.logField(doMeSlot, fieldId, logBuffer); // the BI of the column if (undo != null) { // RESOLVE: we want the AFTER image of the row, not the BEFORE // image. This works for now because only btree needs a logical // undoable updateField and it always update only the pointer field // to point to something else. // // But in the future, it needs to be changed. this.page.logRecord( doMeSlot, BasePage.LOG_RECORD_DEFAULT, recordId, (FormatableBitSet) null, logBuffer, (RecordHandle) null); // log the BI of the entire row } int optionalDataLength = logBuffer.getPosition() - optionalDataStart; if (SanityManager.DEBUG) { if (optionalDataLength != logBuffer.getUsed()) SanityManager.THROWASSERT( "wrong optional data length, optionalDataLength = " + optionalDataLength + ", logBuffer.getUsed() = " + logBuffer.getUsed()); } // set the position to the beginning of the buffer logBuffer.setPosition(optionalDataStart); this.preparedLog = new ByteArray(logBuffer.getByteArray(), optionalDataStart, optionalDataLength); }
/** * Restore the in-memory representation from the stream. * * <p> * * @exception ClassNotFoundException Thrown if the stored representation is serialized and a class * named in the stream could not be found. * @see java.io.Externalizable#readExternal */ private final void localReadExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); baseConglomerateId = in.readLong(); rowLocationColumn = in.readInt(); // read the column sort order info FormatableBitSet ascDescBits = new FormatableBitSet(); ascDescBits.readExternal(in); ascDescInfo = new boolean[ascDescBits.getLength()]; for (int i = 0; i < ascDescBits.getLength(); i++) ascDescInfo[i] = ascDescBits.isSet(i); // In memory maintain a collation id per column in the template. collation_ids = new int[format_ids.length]; if (SanityManager.DEBUG) { SanityManager.ASSERT(!hasCollatedTypes); } // initialize all the entries to COLLATION_TYPE_UCS_BASIC, // and then reset as necessary. For version ACCESS_B2I_V3_ID, // this is the default and no resetting is necessary. for (int i = 0; i < format_ids.length; i++) collation_ids[i] = StringDataValue.COLLATION_TYPE_UCS_BASIC; // initialize the unique with null setting to false, to be reset // below when read from disk. For version ACCESS_B2I_V3_ID and // ACCESS_B2I_V4_ID, this is the default and no resetting is necessary. setUniqueWithDuplicateNulls(false); if (conglom_format_id == StoredFormatIds.ACCESS_B2I_V4_ID || conglom_format_id == StoredFormatIds.ACCESS_B2I_V5_ID) { // current format id, read collation info from disk if (SanityManager.DEBUG) { // length must include row location column and at least // one other field. SanityManager.ASSERT(collation_ids.length >= 2, "length = " + collation_ids.length); } hasCollatedTypes = ConglomerateUtil.readCollationIdArray(collation_ids, in); } else if (conglom_format_id != StoredFormatIds.ACCESS_B2I_V3_ID) { // Currently only V3, V4 and V5 should be possible in a Derby DB. // Actual work for V3 is handled by default code above, so no // special work is necessary. if (SanityManager.DEBUG) { SanityManager.THROWASSERT("Unexpected format id: " + conglom_format_id); } } if (conglom_format_id == StoredFormatIds.ACCESS_B2I_V5_ID) { setUniqueWithDuplicateNulls(in.readBoolean()); } }
/** * Distill the BigDecimal to a byte array and write out: * * <UL> * <LI>scale (zero or positive) as a byte * <LI>length of byte array as a byte * <LI>the byte array * </UL> */ public void writeExternal(ObjectOutput out) throws IOException { // never called when value is null if (SanityManager.DEBUG) SanityManager.ASSERT(!isNull()); int scale; byte[] byteArray; if (value != null) { scale = value.scale(); // J2SE 5.0 introduced negative scale value for BigDecimals. // In previouse Java releases a negative scale was not allowed // (threw an exception on setScale and the constructor that took // a scale). // // Thus the Derby format for DECIMAL implictly assumed a // positive or zero scale value, and thus now must explicitly // be positive. This is to allow databases created under J2SE 5.0 // to continue to be supported under JDK 1.3/JDK 1.4, ie. to continue // the platform independence, independent of OS/cpu and JVM. // // If the scale is negative set the scale to be zero, this results // in an unchanged value with a new scale. A BigDecimal with a // negative scale by definition is a whole number. // e.g. 1000 can be represented by: // a BigDecimal with scale -3 (unscaled value of 1) // or a BigDecimal with scale 0 (unscaled value of 1000) if (scale < 0) { scale = 0; value = value.setScale(0); } BigInteger bi = value.unscaledValue(); byteArray = bi.toByteArray(); } else { scale = rawScale; byteArray = rawData; } if (SanityManager.DEBUG) { if (scale < 0) SanityManager.THROWASSERT( "DECIMAL scale at writeExternal is negative " + scale + " value " + toString()); } out.writeByte(scale); out.writeByte(byteArray.length); out.write(byteArray); }
/** * Initializer for a CreateTableNode for a base table * * @param newObjectName The name of the new object being created (ie base table) * @param tableElementList The elements of the table: columns, constraints, etc. * @param properties The optional list of properties associated with the table. * @param lockGranularity The lock granularity. * @exception StandardException Thrown on error */ public void init( Object newObjectName, Object tableElementList, Object properties, Object lockGranularity) throws StandardException { tableType = TableDescriptor.BASE_TABLE_TYPE; this.lockGranularity = ((Character) lockGranularity).charValue(); implicitCreateSchema = true; if (SanityManager.DEBUG) { if (this.lockGranularity != TableDescriptor.TABLE_LOCK_GRANULARITY && this.lockGranularity != TableDescriptor.ROW_LOCK_GRANULARITY) { SanityManager.THROWASSERT("Unexpected value for lockGranularity = " + this.lockGranularity); } } initAndCheck(newObjectName); this.tableElementList = (TableElementList) tableElementList; this.properties = (Properties) properties; }
private int getDefaultAccessLevel() throws StandardException { PersistentSet tc = lcc.getTransactionExecute(); String modeS = (String) PropertyUtil.getServiceProperty(tc, Property.DEFAULT_CONNECTION_MODE_PROPERTY); if (modeS == null) return FULL_ACCESS; else if (StringUtil.SQLEqualsIgnoreCase(modeS, Property.NO_ACCESS)) return NO_ACCESS; else if (StringUtil.SQLEqualsIgnoreCase(modeS, Property.READ_ONLY_ACCESS)) return READ_ACCESS; else if (StringUtil.SQLEqualsIgnoreCase(modeS, Property.FULL_ACCESS)) return FULL_ACCESS; else { if (SanityManager.DEBUG) SanityManager.THROWASSERT( "Invalid value for property " + Property.DEFAULT_CONNECTION_MODE_PROPERTY + " " + modeS); return FULL_ACCESS; } }
/** * Initializer for a CreateTableNode for a global temporary table * * @param newObjectName The name of the new object being declared (ie temporary table) * @param tableElementList The elements of the table: columns, constraints, etc. * @param properties The optional list of properties associated with the table. * @param onCommitDeleteRows If true, on commit delete rows else on commit preserve rows of * temporary table. * @param onRollbackDeleteRows If true, on rollback, delete rows from temp tables which were * logically modified. true is the only supported value * @exception StandardException Thrown on error */ public void init( Object newObjectName, Object tableElementList, Object properties, Object onCommitDeleteRows, Object onRollbackDeleteRows) throws StandardException { tableType = TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE; newObjectName = tempTableSchemaNameCheck(newObjectName); this.onCommitDeleteRows = ((Boolean) onCommitDeleteRows).booleanValue(); this.onRollbackDeleteRows = ((Boolean) onRollbackDeleteRows).booleanValue(); initAndCheck(newObjectName); this.tableElementList = (TableElementList) tableElementList; this.properties = (Properties) properties; if (SanityManager.DEBUG) { if (this.onRollbackDeleteRows == false) { SanityManager.THROWASSERT( "Unexpected value for onRollbackDeleteRows = " + this.onRollbackDeleteRows); } } }
/** * Does this trigger need to fire on this type of DML? * * @param stmtType the type of DML * (StatementType.INSERT|StatementType.UPDATE|StatementType.DELETE) * @param modifiedCols the columns modified, or null for all * @return true/false * @exception StandardException on error */ public boolean needsToFire(int stmtType, int[] modifiedCols) throws StandardException { if (SanityManager.DEBUG) { if (!((stmtType == StatementType.INSERT) || (stmtType == StatementType.BULK_INSERT_REPLACE) || (stmtType == StatementType.UPDATE) || (stmtType == StatementType.DELETE))) { SanityManager.THROWASSERT("invalid statement type " + stmtType); } } /* ** If we are disabled, we never fire */ if (!isEnabled) { return false; } if (stmtType == StatementType.INSERT) { return (eventMask & TRIGGER_EVENT_INSERT) == eventMask; } if (stmtType == StatementType.DELETE) { return (eventMask & TRIGGER_EVENT_DELETE) == eventMask; } // this is a temporary restriction, but it may not be lifted // anytime soon. if (stmtType == StatementType.BULK_INSERT_REPLACE) { throw StandardException.newException( SQLState.LANG_NO_BULK_INSERT_REPLACE_WITH_TRIGGER, getTableDescriptor().getQualifiedName(), name); } // if update, only relevant if columns intersect return ((eventMask & TRIGGER_EVENT_UPDATE) == eventMask) && ConstraintDescriptor.doColumnsIntersect(modifiedCols, referencedCols); }
/** * Get the constraint type out of the row. * * @param row The row from sysconstraints * @return int The constraint type as an int * @exception StandardException thrown on failure */ protected int getConstraintType(ExecRow row) throws StandardException { DataValueDescriptor col; int constraintIType; String constraintSType; /* 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"); } switch (constraintSType.charAt(0)) { case 'P': constraintIType = DataDictionary.PRIMARYKEY_CONSTRAINT; break; case 'U': constraintIType = DataDictionary.UNIQUE_CONSTRAINT; break; case 'C': constraintIType = DataDictionary.CHECK_CONSTRAINT; break; case 'F': constraintIType = DataDictionary.FOREIGNKEY_CONSTRAINT; break; default: if (SanityManager.DEBUG) { SanityManager.THROWASSERT("Fourth column value invalid"); } constraintIType = -1; } return constraintIType; }
/** * @see Authorizer#authorize * @exception StandardException Thrown if the operation is not allowed */ public void authorize(Activation activation, int operation) throws StandardException { int sqlAllowed = lcc.getStatementContext().getSQLAllowed(); switch (operation) { case Authorizer.SQL_ARBITARY_OP: case Authorizer.SQL_CALL_OP: if (sqlAllowed == RoutineAliasInfo.NO_SQL) throw externalRoutineException(operation, sqlAllowed); break; case Authorizer.SQL_SELECT_OP: if (sqlAllowed > RoutineAliasInfo.READS_SQL_DATA) throw externalRoutineException(operation, sqlAllowed); break; // SQL write operations case Authorizer.SQL_WRITE_OP: case Authorizer.PROPERTY_WRITE_OP: if (isReadOnlyConnection()) throw StandardException.newException(SQLState.AUTH_WRITE_WITH_READ_ONLY_CONNECTION); if (sqlAllowed > RoutineAliasInfo.MODIFIES_SQL_DATA) throw externalRoutineException(operation, sqlAllowed); break; // SQL DDL operations case Authorizer.JAR_WRITE_OP: case Authorizer.SQL_DDL_OP: if (isReadOnlyConnection()) throw StandardException.newException(SQLState.AUTH_DDL_WITH_READ_ONLY_CONNECTION); if (sqlAllowed > RoutineAliasInfo.MODIFIES_SQL_DATA) throw externalRoutineException(operation, sqlAllowed); break; default: if (SanityManager.DEBUG) SanityManager.THROWASSERT("Bad operation code " + operation); } if (activation != null) { List requiredPermissionsList = activation.getPreparedStatement().getRequiredPermissionsList(); DataDictionary dd = lcc.getDataDictionary(); // Database Owner can access any object. Ignore // requiredPermissionsList for Database Owner if (requiredPermissionsList != null && !requiredPermissionsList.isEmpty() && !authorizationId.equals(dd.getAuthorizationDatabaseOwner())) { int ddMode = dd.startReading(lcc); /* * The system may need to read the permission descriptor(s) * from the system table(s) if they are not available in the * permission cache. So start an internal read-only nested * transaction for this. * * The reason to use a nested transaction here is to not hold * locks on system tables on a user transaction. e.g.: when * attempting to revoke an user, the statement may time out * since the user-to-be-revoked transaction may have acquired * shared locks on the permission system tables; hence, this * may not be desirable. * * All locks acquired by StatementPermission object's check() * method will be released when the system ends the nested * transaction. * * In Derby, the locks from read nested transactions come from * the same space as the parent transaction; hence, they do not * conflict with parent locks. */ lcc.beginNestedTransaction(true); try { try { // perform the permission checking for (Iterator iter = requiredPermissionsList.iterator(); iter.hasNext(); ) { ((StatementPermission) iter.next()).check(lcc, authorizationId, false, activation); } } finally { dd.doneReading(ddMode, lcc); } } finally { // make sure we commit; otherwise, we will end up with // mismatch nested level in the language connection context. lcc.commitNestedTransaction(); } } } }
/** * Make a ConstraintDescriptor out of a SYSCONSTRAINTS row * * @param row a SYSCONSTRAINTS row * @param parentTupleDescriptor Subconstraint descriptor with auxiliary info. * @param dd dataDictionary * @exception 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"); } keyColumns = conglomDesc.getIndexDescriptor().baseColumnPositions(); 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; }
/** * ************************************************************************ Private methods of * B2I, arranged alphabetically. * ************************************************************************* */ private void traverseRight() { // RESOLVE - Do I have to do this??????????????? if (SanityManager.DEBUG) SanityManager.THROWASSERT("not implemented."); }
/** * Make a SYSCONTRAINTS row * * @return Row suitable for inserting into SYSCONTRAINTS. * @exception StandardException thrown on failure */ 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, dvf.getDataValue(referenceCount)); return row; }
/** * Create an empty secondary index b-tree, using the generic b-tree to do the generic part of the * creation process. * * <p>This routine opens the newly created container, adds a single page, and makes this page the * root by inserting a LeafControlRow onto this page at slot 0 and marking in that control row * that the page is a root page. * * <p>The following properties are specific to the b-tree secondary index: * * <UL> * <LI>"baseConglomerateId" (integer). The conglomerate id of the base conglomerate is never * actually accessed by the b-tree secondary index implementation, it only serves as a * namespace for row locks. This property is required. * <LI>"rowLocationColumn" (integer). The zero-based index into the row which the b-tree * secondary index will assume holds a @see RowLocation of the base row in the base * conglomerate. This value will be used for acquiring locks. In this implementation * RowLocationColumn must be the last key column. This property is required. * </UL> * * A secondary index i (a, b) on table t (a, b, c) would have rows which looked like (a, b, * row_location). baseConglomerateId is set to the conglomerate id of t. rowLocationColumns is set * to 2. allowsDuplicates would be set to false, @see BTree#create. To create a unique secondary * index set uniquenessColumns to 2, this means that the btree code will compare the key values * but not the row id when determing uniqueness. To create a nonunique secondary index set * uniquenessColumns to 3, this would mean that the uniqueness test would include the row location * and since all row locations will be unique all rows inserted into the index will be * differentiated (at least) by row location. * * @see BTree#create * @exception StandardException Standard exception policy. */ public void create( TransactionManager xact_manager, int segmentId, long input_conglomid, DataValueDescriptor[] template, ColumnOrdering[] columnOrder, int[] collationIds, Properties properties, int temporaryFlag) throws StandardException { String property_value = null; Transaction rawtran = xact_manager.getRawStoreXact(); if (properties == null) { throw (StandardException.newException( SQLState.BTREE_PROPERTY_NOT_FOUND, PROPERTY_BASECONGLOMID)); } // Get baseConglomerateId // property_value = properties.getProperty(PROPERTY_BASECONGLOMID); if (property_value == null) { throw (StandardException.newException( SQLState.BTREE_PROPERTY_NOT_FOUND, PROPERTY_BASECONGLOMID)); } if (SanityManager.DEBUG) { if (property_value == null) SanityManager.THROWASSERT(PROPERTY_BASECONGLOMID + "property not passed to B2I.create()"); } baseConglomerateId = Long.parseLong(property_value); // Get rowLocationColumn // property_value = properties.getProperty(PROPERTY_ROWLOCCOLUMN); if (SanityManager.DEBUG) { if (property_value == null) SanityManager.THROWASSERT(PROPERTY_ROWLOCCOLUMN + "property not passed to B2I.create()"); } if (property_value == null) { throw (StandardException.newException( SQLState.BTREE_PROPERTY_NOT_FOUND, PROPERTY_BASECONGLOMID)); } rowLocationColumn = Integer.parseInt(property_value); // Currently the row location column must be the last column (makes) // comparing the columns in the index easier. if (SanityManager.DEBUG) { SanityManager.ASSERT( rowLocationColumn == template.length - 1, "rowLocationColumn is not the last column in the index"); SanityManager.ASSERT(template[rowLocationColumn] instanceof RowLocation); // There must be at least one key column if (rowLocationColumn < 1) SanityManager.THROWASSERT( "rowLocationColumn (" + rowLocationColumn + ") expected to be >= 1"); } /* convert the sorting order information into a boolean array map. * If the sorting order for the columns is not provided, we * assign the default as Ascending Order. * array length is equal to template length, because column order * length changes whether it is unique or is non unique. store assumes * template length arrays. So, we make template length array and make * the last column as ascending instead of having lot of execeptions * code. */ ascDescInfo = new boolean[template.length]; for (int i = 0; i < ascDescInfo.length; i++) { if (columnOrder != null && i < columnOrder.length) ascDescInfo[i] = columnOrder[i].getIsAscending(); else ascDescInfo[i] = true; // default values - ascending order } // get collation ids from input collation ids, store it in the // conglom state. collation_ids = ConglomerateUtil.createCollationIds(template.length, collationIds); hasCollatedTypes = hasCollatedColumns(collation_ids); // Do the generic part of creating the b-tree. super.create( rawtran, segmentId, input_conglomid, template, properties, getTypeFormatId(), temporaryFlag); // open the base conglomerate - to get the lock ConglomerateController base_cc = xact_manager.openConglomerate( baseConglomerateId, false, TransactionController.OPENMODE_FOR_LOCK_ONLY, TransactionController.MODE_TABLE, TransactionController.ISOLATION_SERIALIZABLE); OpenBTree open_btree = new OpenBTree(); BTreeLockingPolicy b2i_locking_policy = new B2ITableLocking3( rawtran, TransactionController.MODE_TABLE, rawtran.newLockingPolicy( LockingPolicy.MODE_CONTAINER, TransactionController.ISOLATION_SERIALIZABLE, true), base_cc, open_btree); // The following call will "open" the new btree. Create is // an interesting case. What we really want is read only table lock // on the base conglomerate and update locks on the index. For now // just get the update lock on the base table, this is done by the // lockTable() call made by base class. open_btree.init( (TransactionManager) xact_manager, // current user xact (TransactionManager) xact_manager, // current xact (ContainerHandle) null, // have init open the container. rawtran, false, (ContainerHandle.MODE_FORUPDATE), TransactionController.MODE_TABLE, b2i_locking_policy, // get table level lock. this, (LogicalUndo) null, // no logical undo necessary, as // initEmptyBtree() // work will be done single user and // rows will not move. (DynamicCompiledOpenConglomInfo) null); // Open the newly created container, and insert the first control row. LeafControlRow.initEmptyBtree(open_btree); open_btree.close(); base_cc.close(); }