use of org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl in project derby by apache.
the class SYSTRIGGERSRowFactory method makeRow.
/**
* Helper method that contains common logic for {@code makeRow()} and
* {@code makeEmptyRowForCurrentVersion()}. Creates a row for the
* SYSTRIGGERS conglomerate.
*
* @param td the {@code TriggerDescriptor} to create a row from (can be
* {@code null} if the returned row should be empty)
* @param columnCount the number of columns in the returned row (used for
* trimming off columns in soft upgrade mode to match the format in
* the old dictionary version)
* @return a row for the SYSTRIGGERS conglomerate
* @throws StandardException if an error happens when creating the row
*/
private ExecRow makeRow(TupleDescriptor td, int columnCount) throws StandardException {
String name = null;
UUID uuid = null;
// schema
UUID suuid = null;
// referenced table
UUID tuuid = null;
// action sps uuid string
UUID actionSPSID = null;
// when clause sps uuid string
UUID whenSPSID = null;
Timestamp createTime = null;
String event = null;
String time = null;
String type = null;
String enabled = null;
String triggerDefinition = null;
String oldReferencingName = null;
String newReferencingName = null;
ReferencedColumns rcd = null;
boolean referencingOld = false;
boolean referencingNew = false;
String whenClauseText = null;
if (td != null) {
TriggerDescriptor triggerDescriptor = (TriggerDescriptor) td;
name = triggerDescriptor.getName();
uuid = triggerDescriptor.getUUID();
suuid = triggerDescriptor.getSchemaDescriptor().getUUID();
createTime = triggerDescriptor.getCreationTimestamp();
// for now we are assuming that a trigger can only listen to a single event
event = triggerDescriptor.listensForEvent(TriggerDescriptor.TRIGGER_EVENT_UPDATE) ? "U" : triggerDescriptor.listensForEvent(TriggerDescriptor.TRIGGER_EVENT_DELETE) ? "D" : "I";
time = triggerDescriptor.isBeforeTrigger() ? "B" : "A";
type = triggerDescriptor.isRowTrigger() ? "R" : "S";
enabled = triggerDescriptor.isEnabled() ? "E" : "D";
tuuid = triggerDescriptor.getTableDescriptor().getUUID();
int[] refCols = triggerDescriptor.getReferencedCols();
int[] refColsInTriggerAction = triggerDescriptor.getReferencedColsInTriggerAction();
rcd = (refCols != null || refColsInTriggerAction != null) ? new ReferencedColumnsDescriptorImpl(refCols, refColsInTriggerAction) : null;
actionSPSID = triggerDescriptor.getActionId();
whenSPSID = triggerDescriptor.getWhenClauseId();
triggerDefinition = triggerDescriptor.getTriggerDefinition();
referencingOld = triggerDescriptor.getReferencingOld();
referencingNew = triggerDescriptor.getReferencingNew();
oldReferencingName = triggerDescriptor.getOldReferencingName();
newReferencingName = triggerDescriptor.getNewReferencingName();
whenClauseText = triggerDescriptor.getWhenClauseText();
}
/* Build the row to insert */
ExecRow row = getExecutionFactory().getValueRow(columnCount);
/* 1st column is TRIGGERID */
row.setColumn(1, new SQLChar((uuid == null) ? null : uuid.toString()));
/* 2nd column is TRIGGERNAME */
row.setColumn(2, new SQLVarchar(name));
/* 3rd column is SCHEMAID */
row.setColumn(3, new SQLChar((suuid == null) ? null : suuid.toString()));
/* 4th column is CREATIONTIMESTAMP */
SQLTimestamp creationTimestamp = (createTime == null) ? new SQLTimestamp(null) : new SQLTimestamp(createTime, getCalendarForCreationTimestamp());
row.setColumn(4, creationTimestamp);
/* 5th column is EVENT */
row.setColumn(5, new SQLChar(event));
/* 6th column is FIRINGTIME */
row.setColumn(6, new SQLChar(time));
/* 7th column is TYPE */
row.setColumn(7, new SQLChar(type));
/* 8th column is STATE */
row.setColumn(8, new SQLChar(enabled));
/* 9th column is TABLEID */
row.setColumn(9, new SQLChar((tuuid == null) ? null : tuuid.toString()));
/* 10th column is WHENSTMTID */
row.setColumn(10, new SQLChar((whenSPSID == null) ? null : whenSPSID.toString()));
/* 11th column is ACTIONSTMTID */
row.setColumn(11, new SQLChar((actionSPSID == null) ? null : actionSPSID.toString()));
/* 12th column is REFERENCEDCOLUMNS
* (user type org.apache.derby.catalog.ReferencedColumns)
*/
row.setColumn(12, new UserType(rcd));
/* 13th column is TRIGGERDEFINITION */
row.setColumn(13, dvf.getLongvarcharDataValue(triggerDefinition));
/* 14th column is REFERENCINGOLD */
row.setColumn(14, new SQLBoolean(referencingOld));
/* 15th column is REFERENCINGNEW */
row.setColumn(15, new SQLBoolean(referencingNew));
/* 16th column is OLDREFERENCINGNAME */
row.setColumn(16, new SQLVarchar(oldReferencingName));
/* 17th column is NEWREFERENCINGNAME */
row.setColumn(17, new SQLVarchar(newReferencingName));
/* 18th column is WHENCLAUSETEXT */
if (row.nColumns() >= 18) {
// This column is present only if the data dictionary version is
// 10.11 or higher.
row.setColumn(18, dvf.getLongvarcharDataValue(whenClauseText));
}
return row;
}
use of org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl in project derby by apache.
the class HashTableNode method generateMinion.
/**
* Logic shared by generate() and generateResultSet().
*
* @param acb The ExpressionClassBuilder for the class being built
* @param mb the method the expression will go into
*
* @exception StandardException Thrown on error
*/
private void generateMinion(ExpressionClassBuilder acb, MethodBuilder mb, boolean genChildResultSet) throws StandardException {
MethodBuilder userExprFun;
ValueNode searchClause = null;
ValueNode equijoinClause = null;
/* The tableProperties, if non-null, must be correct to get this far.
* We simply call verifyProperties to set initialCapacity and
* loadFactor.
*/
verifyProperties(getDataDictionary());
/* Put the predicates back into the tree */
if (searchPredicateList != null) {
// Remove any redundant predicates before restoring
searchPredicateList.removeRedundantPredicates();
searchClause = searchPredicateList.restorePredicates();
/* Allow the searchPredicateList to get garbage collected now
* that we're done with it.
*/
searchPredicateList = null;
}
// for the single table predicates, we generate an exprFun
// that evaluates the expression of the clause
// against the current row of the child's result.
// if the restriction is empty, simply pass null
// to optimize for run time performance.
// generate the function and initializer:
// Note: Boolean lets us return nulls (boolean would not)
// private Boolean exprN()
// {
// return <<searchClause.generate(ps)>>;
// }
// static Method exprN = method pointer to exprN;
// Map the result columns to the source columns
ResultColumnList.ColumnMapping mappingArrays = getResultColumns().mapSourceColumns();
int[] mapArray = mappingArrays.mapArray;
int mapArrayItem = acb.addItem(new ReferencedColumnsDescriptorImpl(mapArray));
// Save the hash key columns
FormatableIntHolder[] fihArray = FormatableIntHolder.getFormatableIntHolders(hashKeyColumns());
FormatableArrayHolder hashKeyHolder = new FormatableArrayHolder(fihArray);
int hashKeyItem = acb.addItem(hashKeyHolder);
/* Generate the HashTableResultSet:
* arg1: childExpress - Expression for childResultSet
* arg2: searchExpress - Expression for single table predicates
* arg3 : equijoinExpress - Qualifier[] for hash table look up
* arg4: projectExpress - Expression for projection, if any
* arg5: resultSetNumber
* arg6: mapArrayItem - item # for mapping of source columns
* arg7: reuseResult - whether or not the result row can be reused
* (ie, will it always be the same)
* arg8: hashKeyItem - item # for int[] of hash column #s
* arg9: removeDuplicates - don't remove duplicates in hash table (for now)
* arg10: maxInMemoryRowCount - max row size for in-memory hash table
* arg11: initialCapacity - initialCapacity for java.util.Hashtable
* arg12 : loadFactor - loadFactor for java.util.Hashtable
* arg13: estimated row count
* arg14: estimated cost
* arg15: close method
*/
acb.pushGetResultSetFactoryExpression(mb);
if (genChildResultSet)
childResult.generateResultSet(acb, mb);
else
childResult.generate((ActivationClassBuilder) acb, mb);
/* Get the next ResultSet #, so that we can number this ResultSetNode, its
* ResultColumnList and ResultSet.
*/
assignResultSetNumber();
/* Set the point of attachment in all subqueries attached
* to this node.
*/
if (pSubqueryList != null && pSubqueryList.size() > 0) {
pSubqueryList.setPointOfAttachment(getResultSetNumber());
if (SanityManager.DEBUG) {
SanityManager.ASSERT(pSubqueryList.size() == 0, "pSubqueryList.size() expected to be 0");
}
}
if (rSubqueryList != null && rSubqueryList.size() > 0) {
rSubqueryList.setPointOfAttachment(getResultSetNumber());
if (SanityManager.DEBUG) {
SanityManager.ASSERT(rSubqueryList.size() == 0, "rSubqueryList.size() expected to be 0");
}
}
// Get the final cost estimate based on child's cost.
setCostEstimate(childResult.getFinalCostEstimate());
// if there is no searchClause, we just want to pass null.
if (searchClause == null) {
mb.pushNull(ClassName.GeneratedMethod);
} else {
// this sets up the method and the static field.
// generates:
// DataValueDescriptor userExprFun { }
userExprFun = acb.newUserExprFun();
// searchClause knows it is returning its value;
/* generates:
* return <searchClause.generate(acb)>;
* and adds it to userExprFun
* NOTE: The explicit cast to DataValueDescriptor is required
* since the searchClause may simply be a boolean column or subquery
* which returns a boolean. For example:
* where booleanColumn
*/
searchClause.generateExpression(acb, userExprFun);
userExprFun.methodReturn();
/* PUSHCOMPILER
userSB.newReturnStatement(searchClause.generateExpression(acb, userSB));
*/
// we are done modifying userExprFun, complete it.
userExprFun.complete();
// searchClause is used in the final result set as an access of the new static
// field holding a reference to this new method.
// generates:
// ActivationClass.userExprFun
// which is the static field that "points" to the userExprFun
// that evaluates the where clause.
acb.pushMethodReference(mb, userExprFun);
}
/* Generate the qualifiers for the look up into
* the hash table.
*/
joinPredicateList.generateQualifiers(acb, mb, (Optimizable) childResult, false);
/* Determine whether or not reflection is needed for the projection.
* Reflection is not needed if all of the columns map directly to source
* columns.
*/
if (reflectionNeededForProjection()) {
// for the resultColumns, we generate a userExprFun
// that creates a new row from expressions against
// the current row of the child's result.
// (Generate optimization: see if we can simply
// return the current row -- we could, but don't, optimize
// the function call out and have execution understand
// that a null function pointer means take the current row
// as-is, with the performance trade-off as discussed above.)
/* Generate the Row function for the projection */
getResultColumns().generateCore(acb, mb, false);
} else {
mb.pushNull(ClassName.GeneratedMethod);
}
mb.push(getResultSetNumber());
mb.push(mapArrayItem);
mb.push(getResultColumns().reusableResult());
mb.push(hashKeyItem);
mb.push(false);
mb.push(-1L);
mb.push(initialCapacity);
mb.push(loadFactor);
mb.push(getCostEstimate().singleScanRowCount());
mb.push(getCostEstimate().getEstimatedCost());
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getHashTableResultSet", ClassName.NoPutResultSet, 14);
}
use of org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl in project derby by apache.
the class CreateConstraintConstantAction method executeConstantAction.
// INTERFACE METHODS
/**
* This is the guts of the Execution-time logic for CREATE CONSTRAINT.
* <P>
* A constraint is represented as:
* <UL>
* <LI> ConstraintDescriptor.
* </UL>
* If a backing index is required then the index will
* be created through an CreateIndexConstantAction setup
* by the compiler.
* <BR>
* Dependencies are created as:
* <UL>
* <LI> ConstraintDescriptor depends on all the providers collected
* at compile time and passed into the constructor.
* <LI> For a FOREIGN KEY constraint ConstraintDescriptor depends
* on the ConstraintDescriptor for the referenced constraints
* and the privileges required to create the constraint.
* </UL>
*
* @see ConstraintDescriptor
* @see CreateIndexConstantAction
* @see ConstantAction#executeConstantAction
*
* @exception StandardException Thrown on failure
*/
public void executeConstantAction(Activation activation) throws StandardException {
ConglomerateDescriptor conglomDesc = null;
ConglomerateDescriptor[] conglomDescs = null;
ConstraintDescriptor conDesc = null;
TableDescriptor td = null;
UUID indexId = null;
String uniqueName;
String backingIndexName;
/* RESOLVE - blow off not null constraints for now (and probably for ever) */
if (constraintType == DataDictionary.NOTNULL_CONSTRAINT) {
return;
}
LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
DataDictionary dd = lcc.getDataDictionary();
DependencyManager dm = dd.getDependencyManager();
TransactionController tc = lcc.getTransactionExecute();
cf = lcc.getLanguageConnectionFactory().getClassFactory();
/*
** Inform the data dictionary that we are about to write to it.
** There are several calls to data dictionary "get" methods here
** that might be done in "read" mode in the data dictionary, but
** it seemed safer to do this whole operation in "write" mode.
**
** We tell the data dictionary we're done writing at the end of
** the transaction.
*/
dd.startWriting(lcc);
/* Table gets locked in AlterTableConstantAction */
/*
** If the schema descriptor is null, then
** we must have just read ourselves in.
** So we will get the corresponding schema
** descriptor from the data dictionary.
*/
SchemaDescriptor sd = dd.getSchemaDescriptor(schemaName, tc, true);
/* Try to get the TableDescriptor from
* the Activation. We will go to the
* DD if not there. (It should always be
* there except when in a target.)
*/
td = activation.getDDLTableDescriptor();
if (td == null) {
/* tableId will be non-null if adding a
* constraint to an existing table.
*/
if (tableId != null) {
td = dd.getTableDescriptor(tableId);
} else {
td = dd.getTableDescriptor(tableName, sd, tc);
}
if (td == null) {
throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, tableName);
}
activation.setDDLTableDescriptor(td);
}
/* Generate the UUID for the backing index. This will become the
* constraint's name, if no name was specified.
*/
UUIDFactory uuidFactory = dd.getUUIDFactory();
UUID constrId = uuidFactory.createUUID();
/* Create the index, if there's one for this constraint */
if (indexAction != null) {
if (indexAction.getIndexName() == null) {
/* Set the index name */
backingIndexName = uuidFactory.createUUID().toString();
indexAction.setIndexName(backingIndexName);
} else {
backingIndexName = indexAction.getIndexName();
}
indexAction.setConstraintID(constrId);
/* Create the index */
indexAction.executeConstantAction(activation);
/* Get the conglomerate descriptor for the backing index */
conglomDescs = td.getConglomerateDescriptors();
for (int index = 0; index < conglomDescs.length; index++) {
conglomDesc = conglomDescs[index];
/* Check for conglomerate being an index first, since
* name is null for heap.
*/
if (conglomDesc.isIndex() && backingIndexName.equals(conglomDesc.getConglomerateName())) {
break;
}
}
if (SanityManager.DEBUG) {
SanityManager.ASSERT(conglomDesc != null, "conglomDesc is expected to be non-null after search for backing index");
SanityManager.ASSERT(conglomDesc.isIndex(), "conglomDesc is expected to be indexable after search for backing index");
SanityManager.ASSERT(conglomDesc.getConglomerateName().equals(backingIndexName), "conglomDesc name expected to be the same as backing index name after search for backing index");
}
indexId = conglomDesc.getUUID();
}
boolean[] defaults = new boolean[] { ConstraintDefinitionNode.DEFERRABLE_DEFAULT, ConstraintDefinitionNode.INITIALLY_DEFERRED_DEFAULT, ConstraintDefinitionNode.ENFORCED_DEFAULT };
for (int i = 0; i < characteristics.length; i++) {
if (characteristics[i] != defaults[i]) {
dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_11, "DEFERRED CONSTRAINTS");
if (constraintType == DataDictionary.NOTNULL_CONSTRAINT || !characteristics[2]) /* not enforced */
{
// Remove when feature DERBY-532 is completed
if (!PropertyUtil.getSystemProperty("derby.constraintsTesting", "false").equals("true")) {
throw StandardException.newException(SQLState.NOT_IMPLEMENTED, "non-default constraint characteristics");
}
}
}
}
/* Now, lets create the constraint descriptor */
DataDescriptorGenerator ddg = dd.getDataDescriptorGenerator();
switch(constraintType) {
case DataDictionary.PRIMARYKEY_CONSTRAINT:
conDesc = ddg.newPrimaryKeyConstraintDescriptor(td, constraintName, // deferable,
characteristics[0], // initiallyDeferred,
characteristics[1], // int[],
genColumnPositions(td, false), constrId, indexId, sd, characteristics[2], // referenceCount
0);
dd.addConstraintDescriptor(conDesc, tc);
break;
case DataDictionary.UNIQUE_CONSTRAINT:
conDesc = ddg.newUniqueConstraintDescriptor(td, constraintName, // deferable,
characteristics[0], // initiallyDeferred,
characteristics[1], // int[],
genColumnPositions(td, false), constrId, indexId, sd, characteristics[2], // referenceCount
0);
dd.addConstraintDescriptor(conDesc, tc);
break;
case DataDictionary.CHECK_CONSTRAINT:
conDesc = ddg.newCheckConstraintDescriptor(td, constraintName, // deferable,
characteristics[0], // initiallyDeferred,
characteristics[1], constrId, constraintText, // int[],
new ReferencedColumnsDescriptorImpl(genColumnPositions(td, false)), sd, characteristics[2]);
dd.addConstraintDescriptor(conDesc, tc);
storeConstraintDependenciesOnPrivileges(activation, conDesc, null, providerInfo);
break;
case DataDictionary.FOREIGNKEY_CONSTRAINT:
ReferencedKeyConstraintDescriptor referencedConstraint = DDUtils.locateReferencedConstraint(dd, td, constraintName, columnNames, otherConstraintInfo);
DDUtils.validateReferentialActions(dd, td, constraintName, otherConstraintInfo, columnNames);
conDesc = ddg.newForeignKeyConstraintDescriptor(td, constraintName, // deferable,
characteristics[0], // initiallyDeferred,
characteristics[1], // int[],
genColumnPositions(td, false), constrId, indexId, sd, referencedConstraint, characteristics[2], otherConstraintInfo.getReferentialActionDeleteRule(), otherConstraintInfo.getReferentialActionUpdateRule());
// try to create the constraint first, because it
// is expensive to do the bulk check, find obvious
// errors first
dd.addConstraintDescriptor(conDesc, tc);
/* No need to do check if we're creating a
* table.
*/
if ((!forCreateTable) && dd.activeConstraint(conDesc)) {
validateFKConstraint(activation, tc, dd, (ForeignKeyConstraintDescriptor) conDesc, referencedConstraint, ((CreateIndexConstantAction) indexAction).getIndexTemplateRow());
}
/* Create stored dependency on the referenced constraint */
dm.addDependency(conDesc, referencedConstraint, lcc.getContextManager());
// store constraint's dependency on REFERENCES privileges in the dependeny system
storeConstraintDependenciesOnPrivileges(activation, conDesc, referencedConstraint.getTableId(), providerInfo);
break;
case DataDictionary.MODIFY_CONSTRAINT:
throw StandardException.newException(SQLState.NOT_IMPLEMENTED, "ALTER CONSTRAINT");
default:
if (SanityManager.DEBUG) {
SanityManager.THROWASSERT("contraintType (" + constraintType + ") has unexpected value");
}
break;
}
/* Create stored dependencies for each provider */
if (providerInfo != null) {
for (int ix = 0; ix < providerInfo.length; ix++) {
Provider provider = null;
/* We should always be able to find the Provider */
provider = (Provider) providerInfo[ix].getDependableFinder().getDependable(dd, providerInfo[ix].getObjectId());
dm.addDependency(conDesc, provider, lcc.getContextManager());
}
}
/* Finally, invalidate off of the table descriptor(s)
* to ensure that any dependent statements get
* re-compiled.
*/
if (!forCreateTable) {
dm.invalidateFor(td, DependencyManager.CREATE_CONSTRAINT, lcc);
}
if (constraintType == DataDictionary.FOREIGNKEY_CONSTRAINT) {
if (SanityManager.DEBUG) {
SanityManager.ASSERT(conDesc != null, "conDesc expected to be non-null");
if (!(conDesc instanceof ForeignKeyConstraintDescriptor)) {
SanityManager.THROWASSERT("conDesc expected to be instance of ForeignKeyConstraintDescriptor, not " + conDesc.getClass().getName());
}
}
dm.invalidateFor(((ForeignKeyConstraintDescriptor) conDesc).getReferencedConstraint().getTableDescriptor(), DependencyManager.CREATE_CONSTRAINT, lcc);
}
this.constraintId = constrId;
}
use of org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl in project derby by apache.
the class AlterTableConstantAction method dropColumnFromTable.
/**
* Workhorse for dropping a column from a table.
*
* This routine drops a column from a table, taking care
* to properly handle the various related schema objects.
*
* The syntax which gets you here is:
*
* ALTER TABLE tbl DROP [COLUMN] col [CASCADE|RESTRICT]
*
* The keyword COLUMN is optional, and if you don't
* specify CASCADE or RESTRICT, the default is CASCADE
* (the default is chosen in the parser, not here).
*
* If you specify RESTRICT, then the column drop should be
* rejected if it would cause a dependent schema object
* to become invalid.
*
* If you specify CASCADE, then the column drop should
* additionally drop other schema objects which have
* become invalid.
*
* You may not drop the last (only) column in a table.
*
* Schema objects of interest include:
* - views
* - triggers
* - constraints
* - check constraints
* - primary key constraints
* - foreign key constraints
* - unique key constraints
* - not null constraints
* - privileges
* - indexes
* - default values
*
* Dropping a column may also change the column position
* numbers of other columns in the table, which may require
* fixup of schema objects (such as triggers and column
* privileges) which refer to columns by column position number.
*
* Indexes are a bit interesting. The official SQL spec
* doesn't talk about indexes; they are considered to be
* an imlementation-specific performance optimization.
* The current Derby behavior is that:
* - CASCADE/RESTRICT doesn't matter for indexes
* - when a column is dropped, it is removed from any indexes
* which contain it.
* - if that column was the only column in the index, the
* entire index is dropped.
*
* @param columnName the name of the column specfication in the ALTER
* statement-- currently we allow only one.
* @exception StandardException thrown on failure.
*/
private void dropColumnFromTable(String columnName) throws StandardException {
boolean cascade = (behavior == StatementType.DROP_CASCADE);
// drop any generated columns which reference this column
ColumnDescriptorList generatedColumnList = td.getGeneratedColumns();
int generatedColumnCount = generatedColumnList.size();
ArrayList<String> cascadedDroppedColumns = new ArrayList<String>();
for (int i = 0; i < generatedColumnCount; i++) {
ColumnDescriptor generatedColumn = generatedColumnList.elementAt(i);
String[] referencedColumnNames = generatedColumn.getDefaultInfo().getReferencedColumnNames();
int referencedColumnCount = referencedColumnNames.length;
for (int j = 0; j < referencedColumnCount; j++) {
if (columnName.equals(referencedColumnNames[j])) {
String generatedColumnName = generatedColumn.getColumnName();
// we're trying to drop
if (!cascade) {
//
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnName, "GENERATED COLUMN", generatedColumnName);
} else {
cascadedDroppedColumns.add(generatedColumnName);
}
}
}
}
DataDescriptorGenerator ddg = dd.getDataDescriptorGenerator();
int cascadedDrops = cascadedDroppedColumns.size();
int sizeAfterCascadedDrops = td.getColumnDescriptorList().size() - cascadedDrops;
// can NOT drop a column if it is the only one in the table
if (sizeAfterCascadedDrops == 1) {
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), "THE *LAST* COLUMN " + columnName, "TABLE", td.getQualifiedName());
}
// now drop dependent generated columns
for (int i = 0; i < cascadedDrops; i++) {
String generatedColumnName = cascadedDroppedColumns.get(i);
activation.addWarning(StandardException.newWarning(SQLState.LANG_GEN_COL_DROPPED, generatedColumnName, td.getName()));
//
// We can only recurse 2 levels since a generation clause cannot
// refer to other generated columns.
//
dropColumnFromTable(generatedColumnName);
}
/*
* Cascaded drops of dependent generated columns may require us to
* rebuild the table descriptor.
*/
td = dd.getTableDescriptor(tableId);
ColumnDescriptor columnDescriptor = td.getColumnDescriptor(columnName);
// We already verified this in bind, but do it again
if (columnDescriptor == null) {
throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, columnName, td.getQualifiedName());
}
int size = td.getColumnDescriptorList().size();
droppedColumnPosition = columnDescriptor.getPosition();
FormatableBitSet toDrop = new FormatableBitSet(size + 1);
toDrop.set(droppedColumnPosition);
td.setReferencedColumnMap(toDrop);
dm.invalidateFor(td, (cascade ? DependencyManager.DROP_COLUMN : DependencyManager.DROP_COLUMN_RESTRICT), lcc);
// If column has a default we drop the default and any dependencies
if (columnDescriptor.getDefaultInfo() != null) {
dm.clearDependencies(lcc, columnDescriptor.getDefaultDescriptor(dd));
}
// then we need to drop the system-generated sequence backing it.
if (columnDescriptor.isAutoincrement() && dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_11, null)) {
DropTableConstantAction.dropIdentitySequence(dd, td, activation);
}
// columns which are used through REFERENCING clause
for (TriggerDescriptor trd : dd.getTriggerDescriptors(td)) {
// If we find that the trigger is dependent on the column being
// dropped because column is part of trigger columns list, then
// we will give a warning or drop the trigger based on whether
// ALTER TABLE DROP COLUMN is RESTRICT or CASCADE. In such a
// case, no need to check if the trigger action columns referenced
// through REFERENCING clause also used the column being dropped.
boolean triggerDroppedAlready = false;
int[] referencedCols = trd.getReferencedCols();
if (referencedCols != null) {
int refColLen = referencedCols.length, j;
boolean changed = false;
for (j = 0; j < refColLen; j++) {
if (referencedCols[j] > droppedColumnPosition) {
// Trigger is not defined on the column being dropped
// but the column position of trigger column is changing
// because the position of the column being dropped is
// before the the trigger column
changed = true;
} else if (referencedCols[j] == droppedColumnPosition) {
// the trigger is defined on the column being dropped
if (cascade) {
trd.drop(lcc);
triggerDroppedAlready = true;
activation.addWarning(StandardException.newWarning(SQLState.LANG_TRIGGER_DROPPED, trd.getName(), td.getName()));
} else {
// otherwsie there would be unexpected behaviors
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnName, "TRIGGER", trd.getName());
}
break;
}
}
// drop column.
if (j == refColLen && changed) {
dd.dropTriggerDescriptor(trd, tc);
for (j = 0; j < refColLen; j++) {
if (referencedCols[j] > droppedColumnPosition)
referencedCols[j]--;
}
trd.setReferencedCols(referencedCols);
dd.addDescriptor(trd, sd, DataDictionary.SYSTRIGGERS_CATALOG_NUM, false, tc);
}
}
// loop above, then move to next trigger
if (triggerDroppedAlready)
continue;
// Column being dropped is not one of trigger columns. Check if
// that column is getting used inside the trigger action through
// REFERENCING clause. This can be tracked only for triggers
// created in 10.7 and higher releases. Derby releases prior to
// that did not keep track of trigger action columns used
// through the REFERENCING clause.
int[] referencedColsInTriggerAction = trd.getReferencedColsInTriggerAction();
if (referencedColsInTriggerAction != null) {
int refColInTriggerActionLen = referencedColsInTriggerAction.length, j;
boolean changedColPositionInTriggerAction = false;
for (j = 0; j < refColInTriggerActionLen; j++) {
if (referencedColsInTriggerAction[j] > droppedColumnPosition) {
changedColPositionInTriggerAction = true;
} else if (referencedColsInTriggerAction[j] == droppedColumnPosition) {
if (cascade) {
trd.drop(lcc);
triggerDroppedAlready = true;
activation.addWarning(StandardException.newWarning(SQLState.LANG_TRIGGER_DROPPED, trd.getName(), td.getName()));
} else {
// we'd better give an error if don't drop it,
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnName, "TRIGGER", trd.getName());
}
break;
}
}
// column has been actually dropped from the table descriptor.
if (j == refColInTriggerActionLen && changedColPositionInTriggerAction) {
dd.dropTriggerDescriptor(trd, tc);
for (j = 0; j < refColInTriggerActionLen; j++) {
if (referencedColsInTriggerAction[j] > droppedColumnPosition)
referencedColsInTriggerAction[j]--;
}
trd.setReferencedColsInTriggerAction(referencedColsInTriggerAction);
dd.addDescriptor(trd, sd, DataDictionary.SYSTRIGGERS_CATALOG_NUM, false, tc);
}
}
}
ConstraintDescriptorList csdl = dd.getConstraintDescriptors(td);
int csdl_size = csdl.size();
ArrayList<ConstantAction> newCongloms = new ArrayList<ConstantAction>();
// we want to remove referenced primary/unique keys in the second
// round. This will ensure that self-referential constraints will
// work OK.
int tbr_size = 0;
ConstraintDescriptor[] toBeRemoved = new ConstraintDescriptor[csdl_size];
// let's go downwards, don't want to get messed up while removing
for (int i = csdl_size - 1; i >= 0; i--) {
ConstraintDescriptor cd = csdl.elementAt(i);
int[] referencedColumns = cd.getReferencedColumns();
int numRefCols = referencedColumns.length, j;
boolean changed = false;
for (j = 0; j < numRefCols; j++) {
if (referencedColumns[j] > droppedColumnPosition)
changed = true;
if (referencedColumns[j] == droppedColumnPosition)
break;
}
if (// column not referenced
j == numRefCols) {
if ((cd instanceof CheckConstraintDescriptor) && changed) {
dd.dropConstraintDescriptor(cd, tc);
for (j = 0; j < numRefCols; j++) {
if (referencedColumns[j] > droppedColumnPosition)
referencedColumns[j]--;
}
((CheckConstraintDescriptor) cd).setReferencedColumnsDescriptor(new ReferencedColumnsDescriptorImpl(referencedColumns));
dd.addConstraintDescriptor(cd, tc);
}
continue;
}
if (!cascade) {
//
throw StandardException.newException(SQLState.LANG_PROVIDER_HAS_DEPENDENT_OBJECT, dm.getActionString(DependencyManager.DROP_COLUMN), columnName, "CONSTRAINT", cd.getConstraintName());
}
if (cd instanceof ReferencedKeyConstraintDescriptor) {
// restrict will raise an error in invalidate if referenced
toBeRemoved[tbr_size++] = cd;
continue;
}
// drop now in all other cases
dm.invalidateFor(cd, DependencyManager.DROP_CONSTRAINT, lcc);
dropConstraint(cd, td, newCongloms, activation, lcc, true);
activation.addWarning(StandardException.newWarning(SQLState.LANG_CONSTRAINT_DROPPED, cd.getConstraintName(), td.getName()));
}
for (int i = tbr_size - 1; i >= 0; i--) {
ConstraintDescriptor cd = toBeRemoved[i];
dropConstraint(cd, td, newCongloms, activation, lcc, false);
activation.addWarning(StandardException.newWarning(SQLState.LANG_CONSTRAINT_DROPPED, cd.getConstraintName(), td.getName()));
if (cascade) {
ConstraintDescriptorList fkcdl = dd.getForeignKeys(cd.getUUID());
for (ConstraintDescriptor fkcd : fkcdl) {
dm.invalidateFor(fkcd, DependencyManager.DROP_CONSTRAINT, lcc);
dropConstraint(fkcd, td, newCongloms, activation, lcc, true);
activation.addWarning(StandardException.newWarning(SQLState.LANG_CONSTRAINT_DROPPED, fkcd.getConstraintName(), fkcd.getTableDescriptor().getName()));
}
}
dm.invalidateFor(cd, DependencyManager.DROP_CONSTRAINT, lcc);
dm.clearDependencies(lcc, cd);
}
/* If there are new backing conglomerates which must be
* created to replace a dropped shared conglomerate
* (where the shared conglomerate was dropped as part
* of a "drop constraint" call above), then create them
* now. We do this *after* dropping all dependent
* constraints because we don't want to waste time
* creating a new conglomerate if it's just going to be
* dropped again as part of another "drop constraint".
*/
createNewBackingCongloms(newCongloms, (long[]) null);
/*
* The work we've done above, specifically the possible
* dropping of primary key, foreign key, and unique constraints
* and their underlying indexes, may have affected the table
* descriptor. By re-reading the table descriptor here, we
* ensure that the compressTable code is working with an
* accurate table descriptor. Without this line, we may get
* conglomerate-not-found errors and the like due to our
* stale table descriptor.
*/
td = dd.getTableDescriptor(tableId);
compressTable();
ColumnDescriptorList tab_cdl = td.getColumnDescriptorList();
// drop the column from syscolumns
dd.dropColumnDescriptor(td.getUUID(), columnName, tc);
ColumnDescriptor[] cdlArray = new ColumnDescriptor[size - columnDescriptor.getPosition()];
//
for (int i = columnDescriptor.getPosition(), j = 0; i < size; i++, j++) {
ColumnDescriptor cd = tab_cdl.elementAt(i);
dd.dropColumnDescriptor(td.getUUID(), cd.getColumnName(), tc);
cd.setPosition(i);
if (cd.isAutoincrement()) {
cd.setAutoinc_create_or_modify_Start_Increment(ColumnDefinitionNode.CREATE_AUTOINCREMENT);
}
cdlArray[j] = cd;
}
dd.addDescriptorArray(cdlArray, td, DataDictionary.SYSCOLUMNS_CATALOG_NUM, false, tc);
// By this time, the column has been removed from the table descriptor.
// Now, go through all the triggers and regenerate their trigger action
// SPS and rebind the generated trigger action sql. If the trigger
// action is using the dropped column, it will get detected here. If
// not, then we will have generated the internal trigger action sql
// which matches the trigger action sql provided by the user.
//
// eg of positive test case
// create table atdc_16_tab1 (a1 integer, b1 integer, c1 integer);
// create table atdc_16_tab2 (a2 integer, b2 integer, c2 integer);
// create trigger atdc_16_trigger_1
// after update of b1 on atdc_16_tab1
// REFERENCING NEW AS newt
// for each row
// update atdc_16_tab2 set c2 = newt.c1
// The internal representation for the trigger action before the column
// is dropped is as follows
// update atdc_16_tab2 set c2 =
// org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().
// getONewRow().getInt(3)
// After the drop column shown as below
// alter table DERBY4998_SOFT_UPGRADE_RESTRICT drop column c11
// The above internal representation of tigger action sql is not
// correct anymore because column position of c1 in atdc_16_tab1 has
// now changed from 3 to 2. Following while loop will regenerate it and
// change it to as follows
// update atdc_16_tab2 set c2 =
// org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().
// getONewRow().getInt(2)
//
// We could not do this before the actual column drop, because the
// rebind would have still found the column being dropped in the
// table descriptor and hence use of such a column in the trigger
// action rebind would not have been caught.
// For the table on which ALTER TABLE is getting performed, find out
// all the SPSDescriptors that use that table as a provider. We are
// looking for SPSDescriptors that have been created internally for
// trigger action SPSes. Through those SPSDescriptors, we will be
// able to get to the triggers dependent on the table being altered
// Following will get all the dependent objects that are using
// ALTER TABLE table as provider
List<DependencyDescriptor> depsOnAlterTableList = dd.getProvidersDescriptorList(td.getObjectID().toString());
for (DependencyDescriptor depOnAT : depsOnAlterTableList) {
// Go through all the dependent objects on the table being altered
DependableFinder dependent = depOnAT.getDependentFinder();
// stored prepared statement.
if (dependent.getSQLObjectType().equals(Dependable.STORED_PREPARED_STATEMENT)) {
// Look for all the dependent objects that are using this
// stored prepared statement as provider. We are only
// interested in dependents that are triggers.
List<DependencyDescriptor> depsTrigger = dd.getProvidersDescriptorList(depOnAT.getUUID().toString());
for (DependencyDescriptor depsTriggerDesc : depsTrigger) {
DependableFinder providerIsTrigger = depsTriggerDesc.getDependentFinder();
// it is a trigger
if (providerIsTrigger.getSQLObjectType().equals(Dependable.TRIGGER)) {
// Drop and recreate the trigger after regenerating
// it's trigger action plan. If the trigger action
// depends on the column being dropped, it will be
// caught here.
TriggerDescriptor trdToBeDropped = dd.getTriggerDescriptor(depsTriggerDesc.getUUID());
// First check for dependencies in the trigger's WHEN
// clause, if there is one.
UUID whenClauseId = trdToBeDropped.getWhenClauseId();
boolean gotDropped = false;
if (whenClauseId != null) {
gotDropped = columnDroppedAndTriggerDependencies(trdToBeDropped, whenClauseId, true, cascade, columnName);
}
// dependencies.
if (!gotDropped) {
columnDroppedAndTriggerDependencies(trdToBeDropped, trdToBeDropped.getActionId(), false, cascade, columnName);
}
}
}
}
}
// Adjust the column permissions rows in SYSCOLPERMS to reflect the
// changed column positions due to the dropped column:
dd.updateSYSCOLPERMSforDropColumn(td.getUUID(), tc, columnDescriptor);
// remove column descriptor from table descriptor. this fixes up the
// list in case we were called recursively in order to cascade-drop a
// dependent generated column.
tab_cdl.remove(td.getColumnDescriptor(columnName));
}
use of org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl in project derby by apache.
the class ProjectRestrictNode method generateMinion.
/**
* Logic shared by generate() and generateResultSet().
*
* @param acb The ExpressionClassBuilder for the class being built
* @param mb The method the expression will go into
*
* @exception StandardException Thrown on error
*/
private void generateMinion(ExpressionClassBuilder acb, MethodBuilder mb, boolean genChildResultSet) throws StandardException {
/* If this ProjectRestrict doesn't do anything, bypass its generation.
* (Remove any true and true predicates first, as they could be left
* by the like transformation.)
*/
if (restrictionList != null && restrictionList.size() > 0) {
restrictionList.eliminateBooleanTrueAndBooleanTrue();
}
if (nopProjectRestrict()) {
generateNOPProjectRestrict();
if (genChildResultSet)
childResult.generateResultSet(acb, mb);
else
childResult.generate((ActivationClassBuilder) acb, mb);
setCostEstimate(childResult.getFinalCostEstimate());
return;
}
/* Put the predicates back into the tree */
if (restrictionList != null) {
constantRestriction = restrictionList.restoreConstantPredicates();
// Remove any redundant predicates before restoring
restrictionList.removeRedundantPredicates();
restriction = restrictionList.restorePredicates();
/* Allow the restrictionList to get garbage collected now
* that we're done with it.
*/
restrictionList = null;
}
// for the restriction, we generate an exprFun
// that evaluates the expression of the clause
// against the current row of the child's result.
// if the restriction is empty, simply pass null
// to optimize for run time performance.
// generate the function and initializer:
// Note: Boolean lets us return nulls (boolean would not)
// private Boolean exprN()
// {
// return <<restriction.generate(ps)>>;
// }
// static Method exprN = method pointer to exprN;
// Map the result columns to the source columns
ResultColumnList.ColumnMapping mappingArrays = getResultColumns().mapSourceColumns();
int[] mapArray = mappingArrays.mapArray;
boolean[] cloneMap = mappingArrays.cloneMap;
int mapArrayItem = acb.addItem(new ReferencedColumnsDescriptorImpl(mapArray));
int cloneMapItem = acb.addItem(cloneMap);
/* Will this node do a projection? */
boolean doesProjection = true;
/* Does a projection unless same # of columns in same order
* as child.
*/
if ((!reflectionNeededForProjection()) && mapArray != null && mapArray.length == childResult.getResultColumns().size()) {
/* mapArray entries are 1-based */
int index = 0;
for (; index < mapArray.length; index++) {
if (mapArray[index] != index + 1) {
break;
}
}
if (index == mapArray.length) {
doesProjection = false;
}
}
/* Generate the ProjectRestrictSet:
* arg1: childExpress - Expression for childResultSet
* arg2: Activation
* arg3: restrictExpress - Expression for restriction
* arg4: projectExpress - Expression for projection
* arg5: resultSetNumber
* arg6: constantExpress - Expression for constant restriction
* (for example, where 1 = 2)
* arg7: mapArrayItem - item # for mapping of source columns
* arg8: cloneMapItem - item # for mapping of columns that need cloning
* arg9: reuseResult - whether or not the result row can be reused
* (ie, will it always be the same)
* arg10: doesProjection - does this node do a projection
* arg11: estimated row count
* arg12: estimated cost
* arg13: close method
*/
acb.pushGetResultSetFactoryExpression(mb);
if (genChildResultSet)
childResult.generateResultSet(acb, mb);
else
childResult.generate((ActivationClassBuilder) acb, mb);
/* Get the next ResultSet #, so that we can number this ResultSetNode, its
* ResultColumnList and ResultSet.
*/
assignResultSetNumber();
/* Set the point of attachment in all subqueries attached
* to this node.
*/
if (projectSubquerys != null && projectSubquerys.size() > 0) {
projectSubquerys.setPointOfAttachment(getResultSetNumber());
}
if (restrictSubquerys != null && restrictSubquerys.size() > 0) {
restrictSubquerys.setPointOfAttachment(getResultSetNumber());
}
// Load our final cost estimate.
setCostEstimate(getFinalCostEstimate());
// if there is no restriction, we just want to pass null.
if (restriction == null) {
mb.pushNull(ClassName.GeneratedMethod);
} else {
// this sets up the method and the static field.
// generates:
// Object userExprFun { }
MethodBuilder userExprFun = acb.newUserExprFun();
// restriction knows it is returning its value;
/* generates:
* return <restriction.generate(acb)>;
* and adds it to userExprFun
* NOTE: The explicit cast to DataValueDescriptor is required
* since the restriction may simply be a boolean column or subquery
* which returns a boolean. For example:
* where booleanColumn
*/
restriction.generateExpression(acb, userExprFun);
userExprFun.methodReturn();
// we are done modifying userExprFun, complete it.
userExprFun.complete();
// restriction is used in the final result set as an access of the new static
// field holding a reference to this new method.
// generates:
// ActivationClass.userExprFun
// which is the static field that "points" to the userExprFun
// that evaluates the where clause.
acb.pushMethodReference(mb, userExprFun);
}
/* Determine whether or not reflection is needed for the projection.
* Reflection is not needed if all of the columns map directly to source
* columns.
*/
if (reflectionNeededForProjection()) {
// for the resultColumns, we generate a userExprFun
// that creates a new row from expressions against
// the current row of the child's result.
// (Generate optimization: see if we can simply
// return the current row -- we could, but don't, optimize
// the function call out and have execution understand
// that a null function pointer means take the current row
// as-is, with the performance trade-off as discussed above.)
/* Generate the Row function for the projection */
getResultColumns().generateCore(acb, mb, false);
} else {
mb.pushNull(ClassName.GeneratedMethod);
}
mb.push(getResultSetNumber());
// if there is no constant restriction, we just want to pass null.
if (constantRestriction == null) {
mb.pushNull(ClassName.GeneratedMethod);
} else {
// this sets up the method and the static field.
// generates:
// userExprFun { }
MethodBuilder userExprFun = acb.newUserExprFun();
// restriction knows it is returning its value;
/* generates:
* return <restriction.generate(acb)>;
* and adds it to userExprFun
* NOTE: The explicit cast to DataValueDescriptor is required
* since the restriction may simply be a boolean column or subquery
* which returns a boolean. For example:
* where booleanColumn
*/
constantRestriction.generateExpression(acb, userExprFun);
userExprFun.methodReturn();
// we are done modifying userExprFun, complete it.
userExprFun.complete();
// restriction is used in the final result set as an access
// of the new static field holding a reference to this new method.
// generates:
// ActivationClass.userExprFun
// which is the static field that "points" to the userExprFun
// that evaluates the where clause.
acb.pushMethodReference(mb, userExprFun);
}
mb.push(mapArrayItem);
mb.push(cloneMapItem);
mb.push(getResultColumns().reusableResult());
mb.push(doesProjection);
mb.push(validatingCheckConstraints);
if (validatingBaseTableUUIDString == null) {
mb.push(UUID.NULL);
} else {
mb.push(validatingBaseTableUUIDString);
}
mb.push(getCostEstimate().rowCount());
mb.push(getCostEstimate().getEstimatedCost());
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getProjectRestrictResultSet", ClassName.NoPutResultSet, 13);
}
Aggregations