DependencyManager dm = dd.getDependencyManager();
TransactionController tc = lcc.getTransactionExecute();
boolean cascade = (behavior == StatementType.DROP_CASCADE);
// drop any generated columns which reference this column
ColumnDescriptorList generatedColumnList = td.getGeneratedColumns();
int generatedColumnCount = generatedColumnList.size();
ArrayList cascadedDroppedColumns = new ArrayList();
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();
// ok, the current generated column references the column
// we're trying to drop
if (! cascade)
{
// Reject the DROP COLUMN, because there exists a
// generated column which references this column.
//
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 = (String) 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( activation, 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));
}
// need to deal with triggers if has referencedColumns
GenericDescriptorList tdl = dd.getTriggerDescriptors(td);
Enumeration descs = tdl.elements();
while (descs.hasMoreElements())
{
TriggerDescriptor trd = (TriggerDescriptor) descs.nextElement();
int[] referencedCols = trd.getReferencedCols();
if (referencedCols == null)
continue;
int refColLen = referencedCols.length, j;
boolean changed = false;
for (j = 0; j < refColLen; j++)
{
if (referencedCols[j] > droppedColumnPosition)
{
changed = true;
}
else if (referencedCols[j] == droppedColumnPosition)
{
if (cascade)
{
trd.drop(lcc);
activation.addWarning(
StandardException.newWarning(
SQLState.LANG_TRIGGER_DROPPED,
trd.getName(), td.getName()));
}
else
{ // we'd better give an error if don't drop it,
// 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;
}
}
// change triggers to refer to columns in new positions
if (j == refColLen && changed)
{
dd.dropTriggerDescriptor(trd, tc);
for (j = 0; j < refColLen; j++)
{
if (referencedCols[j] > droppedColumnPosition)
referencedCols[j]--;
}
dd.addDescriptor(trd, sd,
DataDictionary.SYSTRIGGERS_CATALOG_NUM,
false, tc);
}
}
ConstraintDescriptorList csdl = dd.getConstraintDescriptors(td);
int csdl_size = csdl.size();
ArrayList newCongloms = new ArrayList();
// 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 (j == numRefCols) // column not referenced
{
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)
{
// Reject the DROP COLUMN, because there exists a constraint
// which references this column.
//
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 (int j = 0; j < fkcdl.size(); j++)
{
ConstraintDescriptor fkcd =
(ConstraintDescriptor) fkcdl.elementAt(j);
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, activation, dd);
/*
* 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(activation);
ColumnDescriptorList tab_cdl = td.getColumnDescriptorList();
// drop the column from syscolumns
dd.dropColumnDescriptor(td.getUUID(), columnName, tc);
ColumnDescriptor[] cdlArray =
new ColumnDescriptor[size - columnDescriptor.getPosition()];
// For each column in this table with a higher column position,
// drop the entry from SYSCOLUMNS, but hold on to the column
// descriptor and reset its position to adjust for the dropped
// column. Then, re-add all those adjusted column descriptors
// back to SYSCOLUMNS
//
for (int i = columnDescriptor.getPosition(), j = 0; i < size; i++, j++)
{
ColumnDescriptor cd = (ColumnDescriptor) 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);
List deps = dd.getProvidersDescriptorList(td.getObjectID().toString());
for (Iterator depsIterator = deps.listIterator();
depsIterator.hasNext();)
{
DependencyDescriptor depDesc =
(DependencyDescriptor) depsIterator.next();
DependableFinder finder = depDesc.getProviderFinder();
if (finder instanceof DDColumnDependableFinder)
{
DDColumnDependableFinder colFinder =
(DDColumnDependableFinder) finder;
FormatableBitSet oldColumnBitMap =
new FormatableBitSet(colFinder.getColumnBitMap());
FormatableBitSet newColumnBitMap =
new FormatableBitSet(oldColumnBitMap);
newColumnBitMap.clear();
int bitLen = oldColumnBitMap.getLength();
for (int i = 0; i < bitLen; i++)
{
if (i < droppedColumnPosition && oldColumnBitMap.isSet(i))
newColumnBitMap.set(i);
if (i > droppedColumnPosition && oldColumnBitMap.isSet(i))
newColumnBitMap.set(i - 1);
}
if (newColumnBitMap.equals(oldColumnBitMap))
continue;
dd.dropStoredDependency(depDesc, tc);
colFinder.setColumnBitMap(newColumnBitMap.getByteArray());
dd.addDescriptor(depDesc, null,
DataDictionary.SYSDEPENDS_CATALOG_NUM,
true, tc);
}
}
// 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 ) );
}