case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE:
case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE:
case NodeTypes.MODIFY_COLUMN_TYPE_NODE: {
ModifyColumnNode modNode = (ModifyColumnNode)node;
String columnName = modNode.getColumnName();
Column column = origTable.getColumn(columnName);
if(Column.isInternalName(columnName) || (column == null)) {
skipOrThrow(context, modNode.getExistenceCheck(), null, new NoSuchColumnException(columnName));
} else {
// Special case: The only requested change is RESTART WITH.
// Cannot go through the current ALTER flow as the new value may appear to be the same,
// triggering NONE change, but should still take affect as values may have been allocated.
if((elements.size() == 1) && isRestartWithNode(modNode)) {
Sequence curSeq = column.getIdentityGenerator();
if(curSeq == null) {
throw new ColumnNotGeneratedException(column);
}
AkibanInformationSchema aisCopy = new AkibanInformationSchema();
Sequence newSeq = Sequence.create(aisCopy,
curSeq.getSchemaName(),
curSeq.getSequenceName().getTableName(),
modNode.getAutoincrementStart(),
curSeq.getIncrement(),
curSeq.getMinValue(),
curSeq.getMaxValue(),
curSeq.isCycle());
ddl.alterSequence(session, curSeq.getSequenceName(), newSeq);
return ChangeLevel.METADATA;
} else {
columnChanges.add(TableChange.createModify(columnName, columnName));
columnDefNodes.add((ColumnDefinitionNode)node);
}
}
} break;
case NodeTypes.FK_CONSTRAINT_DEFINITION_NODE: {
FKConstraintDefinitionNode fkNode = (FKConstraintDefinitionNode) node;
if(fkNode.getConstraintType() == ConstraintType.DROP) {
if(fkNode.isGrouping()) {
if(origTable.getParentJoin() == null) {
skipOrThrow(context, fkNode.getExistenceCheck(), null, new NoSuchGroupingFKException(origTable.getName()));
fkNode = null;
}
} else {
if(fkNode.getConstraintName() == null) {
Collection<ForeignKey> fkeys = origTable.getReferencingForeignKeys();
if(fkeys.size() == 0) {
skipOrThrow(context, fkNode.getExistenceCheck(), null, new UnsupportedFKIndexException());
fkNode = null;
} else if(fkeys.size() != 1) {
throw new UnsupportedFKIndexException();
} else {
try {
fkNode.setConstraintName(fkeys.iterator().next().getConstraintName().getTableName());
} catch(StandardException ex) {
throw new SQLParserInternalException(ex);
}
}
} else if(origTable.getReferencingForeignKey(fkNode.getConstraintName().getTableName()) == null) {
skipOrThrow(context,
fkNode.getExistenceCheck(),
null,
new NoSuchForeignKeyException(fkNode.getConstraintName().getTableName(), origTable.getName()));
fkNode = null;
}
if(fkNode != null) {
// Also drop the referencing index.
indexChanges.add(TableChange.createDrop(fkNode.getConstraintName().getTableName()));
}
}
}
if(fkNode != null) {
fkDefNodes.add(fkNode);
}
} break;
case NodeTypes.CONSTRAINT_DEFINITION_NODE: {
ConstraintDefinitionNode cdn = (ConstraintDefinitionNode) node;
if(cdn.getConstraintType() == ConstraintType.DROP) {
String name = cdn.getName();
switch(cdn.getVerifyType()) {
case PRIMARY_KEY:
if(origTable.getPrimaryKey() == null) {
skipOrThrow(context, cdn.getExistenceCheck(),
null,
new NoSuchConstraintException(origTable.getName(), Index.PRIMARY));
name = null;
} else {
name = origTable.getPrimaryKey().getIndex().getIndexName().getName();
}
break;
case DROP:
boolean found = false;
String indexName = indexNameForConstrainName(origTable, name);
if (indexName != null) {
found = true;
name = indexName;
} else if (origTable.getReferencingForeignKey(name) != null) {
fkDefNodes.add(newFKDropNode(node, name, Boolean.FALSE));
found = true;
} else if (origTable.getParentJoin() != null && origTable.getParentJoin().getName().equals(name)) {
fkDefNodes.add(newFKDropNode(node, name, Boolean.TRUE));
found = true;
name = null;
}
if(!found) {
skipOrThrow(context,
cdn.getExistenceCheck(),
null,
new NoSuchConstraintException(origTable.getName(), name));
name = null;
}
break;
case UNIQUE:
Index index = origTable.getIndex(name);
if(index == null || !index.isUnique()) {
skipOrThrow(context,
cdn.getExistenceCheck(),
null,
new NoSuchUniqueException(origTable.getName(), cdn.getName()));
name = null;
}
break;
case CHECK:
throw new UnsupportedCheckConstraintException();
}
if (name != null) {
indexChanges.add(TableChange.createDrop(name));
}
} else if (cdn.getConstraintType() == ConstraintType.PRIMARY_KEY) {
if (origTable.getPrimaryKeyIncludingInternal().isAkibanPK())
{
columnChanges.add(TableChange.createDrop(Column.ROW_ID_NAME));
String indexName = origTable.getPrimaryKeyIncludingInternal().getIndex().getIndexName().getName();
indexChanges.add(TableChange.createDrop(indexName));
}
conDefNodes.add(cdn);
} else {
conDefNodes.add(cdn);
}
} break;
case NodeTypes.INDEX_DEFINITION_NODE:
IndexDefinitionNode idn = (IndexDefinitionNode)node;
if(idn.getJoinType() != null) {
throw new UnsupportedSQLException("ALTER ADD INDEX containing group index");
}
indexDefNodes.add(idn);
break;
case NodeTypes.AT_DROP_INDEX_NODE: {
AlterDropIndexNode dropIndexNode = (AlterDropIndexNode)node;
String name = dropIndexNode.getIndexName();
if(origTable.getIndex(name) == null) {
skipOrThrow(context, dropIndexNode.getExistenceCheck(), null, new NoSuchIndexException(name));
} else {
indexChanges.add(TableChange.createDrop(name));
}
}
break;
case NodeTypes.AT_RENAME_NODE:
TableName newName = DDLHelper.convertName(defaultSchema,
((AlterTableRenameNode)node).newName());
TableName oldName = origTable.getName();
ddl.renameTable(session, oldName, newName);
return ChangeLevel.METADATA;
case NodeTypes.AT_RENAME_COLUMN_NODE:
AlterTableRenameColumnNode alterRenameCol = (AlterTableRenameColumnNode) node;
String oldColName = alterRenameCol.getName();
String newColName = alterRenameCol.newName();
final Column oldCol = origTable.getColumn(oldColName);
if (oldCol == null) {
throw new NoSuchColumnException(oldColName);
}
columnChanges.add(TableChange.createModify(oldColName, newColName));
break;
default:
return null; // Something unsupported
}
}
for (ForeignKey foreignKey : origTable.getForeignKeys()) {
if (foreignKey.getReferencingTable() == origTable) {
checkForeignKeyAlterColumns(columnChanges, foreignKey.getReferencingColumns(),
foreignKey, origTable);
}
if (foreignKey.getReferencedTable() == origTable) {
checkForeignKeyAlterColumns(columnChanges, foreignKey.getReferencedColumns(),
foreignKey, origTable);
}
}
final AkibanInformationSchema origAIS = origTable.getAIS();
final Table tableCopy = copyTable(ddl.getAISCloner(), origTable, columnChanges);
final AkibanInformationSchema aisCopy = tableCopy.getAIS();
TableDDL.cloneReferencedTables(defaultSchema, ddl.getAISCloner(), origAIS, aisCopy, elements);
final TypesTranslator typesTranslator = ddl.getTypesTranslator();
final AISBuilder builder = new AISBuilder(aisCopy);
builder.getNameGenerator().mergeAIS(origAIS);
int pos = tableCopy.getColumnsIncludingInternal().size();
for(ColumnDefinitionNode cdn : columnDefNodes) {
if(cdn instanceof ModifyColumnNode) {
ModifyColumnNode modNode = (ModifyColumnNode) cdn;
handleModifyColumnNode(modNode, builder, tableCopy, typesTranslator);
} else {
TableDDL.addColumn(builder, typesTranslator, cdn, origTable.getName().getSchemaName(), origTable.getName().getTableName(), pos++);
}
}
// Ensure that internal columns stay at the end
// because there's a bunch of places that assume that they are
// (e.g. they assume getColumns() have indexes (1...getColumns().size()))
// If the original table had a primary key, the hidden pk is added a bit farther down
for (Column origColumn : origTable.getColumnsIncludingInternal()) {
if (origColumn.isInternalColumn()) {
String newName = findNewName(columnChanges, origColumn.getName());
if (newName != null) {
Column.create(tableCopy, origColumn, newName, pos++);
}
}
}
copyTableIndexes(origTable, tableCopy, columnChanges, indexChanges);
IndexNameGenerator indexNamer = DefaultIndexNameGenerator.forTable(tableCopy);
TableName newName = tableCopy.getName();
for(ConstraintDefinitionNode cdn : conDefNodes) {
assert cdn.getConstraintType() != ConstraintType.DROP : cdn;
String name = TableDDL.addIndex(indexNamer, builder, cdn, newName.getSchemaName(), newName.getTableName(), context);
indexChanges.add(TableChange.createAdd(name));
// This is required as the addIndex() for a primary key constraint
// *may* alter the NULL->NOT NULL status
// of the columns in the primary key
if (name.equals(Index.PRIMARY)) {
for (IndexColumn col : tableCopy.getIndex(name).getKeyColumns())
{
String columnName = col.getColumn().getName();
// Check if the column was added in the same alter as creating the index:
// ALTER TABLE c ADD COLUMN n SERIAL PRIMARY KEY
// You can't add and modify the column, so assume the add does the correct thing.
boolean columnAdded = false;
for (TableChange change : columnChanges) {
if (change.getChangeType() == ChangeType.ADD && columnName.equals(change.getNewName()))
columnAdded = true;
}
if (!columnAdded)
columnChanges.add(TableChange.createModify(columnName, columnName));
}
}
}
for(IndexDefinitionNode idn : indexDefNodes) {
String name = TableDDL.addIndex(indexNamer, builder, idn, newName.getSchemaName(), newName.getTableName(), context, ddl);
indexChanges.add(TableChange.createAdd(name));
}
// Correctly adds the Hidden PK (including sequence).
if (tableCopy.getPrimaryKeyIncludingInternal() == null) {
if (origTable.getPrimaryKeyIncludingInternal().isAkibanPK()) {
Column origColumn = origTable.getPrimaryKeyIncludingInternal().getColumns().get(0);
Column.create(tableCopy, origColumn, Column.ROW_ID_NAME, tableCopy.getColumns().size());
} else {
tableCopy.addHiddenPrimaryKey(builder.getNameGenerator());
columnChanges.add(TableChange.createAdd(Column.ROW_ID_NAME));
}