protected override void ExecuteStatement(ExecutionContext context)
{
//if (!context.User.CanAlterTable(TableName))
// throw new InvalidAccessException(context.Request.UserName(), TableName);
var table = context.Request.Access().GetTable(TableName);
if (table == null)
throw new ObjectNotFoundException(TableName);
var tableInfo = table.TableInfo;
var newTableInfo = new TableInfo(tableInfo.TableName);
var checker = ColumnChecker.Default(context.Request, TableName);
bool tableAltered = false;
bool markDropped = false;
for (int n = 0; n < tableInfo.ColumnCount; ++n) {
var column = tableInfo[n];
string columnName = column.ColumnName;
var columnType = column.ColumnType;
var defaultExpression = column.DefaultExpression;
if (Action.ActionType == AlterTableActionType.SetDefault &&
CheckColumnNamesMatch(context.Request, ((SetDefaultAction)Action).ColumnName, columnName)) {
var exp = ((SetDefaultAction)Action).DefaultExpression;
exp = checker.CheckExpression(exp);
defaultExpression = exp;
tableAltered = true;
} else if (Action.ActionType == AlterTableActionType.DropDefault &&
CheckColumnNamesMatch(context.Request, ((DropDefaultAction)Action).ColumnName, columnName)) {
defaultExpression = null;
tableAltered = true;
} else if (Action.ActionType == AlterTableActionType.DropColumn &&
CheckColumnNamesMatch(context.Request, ((DropColumnAction)Action).ColumnName, columnName)) {
// Check there are no referential links to this column
var refs = context.Request.Access().QueryTableImportedForeignKeys(TableName);
foreach (var reference in refs) {
CheckColumnConstraint(columnName, reference.ForeignColumnNames, reference.ForeignTable, reference.ConstraintName);
}
// Or from it
refs = context.Request.Access().QueryTableForeignKeys(TableName);
foreach (var reference in refs) {
CheckColumnConstraint(columnName, reference.ColumnNames, reference.TableName, reference.ConstraintName);
}
// Or that it's part of a primary key
var primaryKey = context.Request.Access().QueryTablePrimaryKey(TableName);
if (primaryKey != null)
CheckColumnConstraint(columnName, primaryKey.ColumnNames, TableName, primaryKey.ConstraintName);
// Or that it's part of a unique set
var uniques = context.Request.Access().QueryTableUniqueKeys(TableName);
foreach (var unique in uniques) {
CheckColumnConstraint(columnName, unique.ColumnNames, TableName, unique.ConstraintName);
}
markDropped = true;
tableAltered = true;
}
var newColumn = new ColumnInfo(columnName, columnType);
if (defaultExpression != null)
newColumn.DefaultExpression = defaultExpression;
newColumn.IndexType = column.IndexType;
newColumn.IsNotNull = column.IsNotNull;
// If not dropped then add to the new table definition.
if (!markDropped) {
newTableInfo.AddColumn(newColumn);
}
}
if (Action.ActionType == AlterTableActionType.AddColumn) {
var col = ((AddColumnAction)Action).Column;
checker.CheckExpression(col.DefaultExpression);
var columnName = col.ColumnName;
var columnType = col.ColumnType;
// If column name starts with [table_name]. then strip it off
columnName = checker.StripTableName(TableName.Name, columnName);
if (tableInfo.IndexOfColumn(col.ColumnName) != -1)
throw new InvalidOperationException("The column '" + col.ColumnName + "' is already in the table '" + tableInfo.TableName + "'.");
var newColumn = new ColumnInfo(columnName, columnType) {
IsNotNull = col.IsNotNull,
DefaultExpression = col.DefaultExpression
};
newTableInfo.AddColumn(newColumn);
tableAltered = true;
}
if (Action.ActionType == AlterTableActionType.DropConstraint) {
string constraintName = ((DropConstraintAction)Action).ConstraintName;
int dropCount = context.Request.Access().DropTableConstraint(TableName, constraintName);
if (dropCount == 0)
throw new InvalidOperationException("Named constraint to drop on table " + TableName + " was not found: " + constraintName);
} else if (Action.ActionType == AlterTableActionType.DropPrimaryKey) {
if (!context.Request.Access().DropTablePrimaryKey(TableName, null))
throw new InvalidOperationException("No primary key to delete on table " + TableName);
}
if (Action.ActionType == AlterTableActionType.AddConstraint) {
var constraint = ((AddConstraintAction)Action).Constraint;
bool foreignConstraint = (constraint.ConstraintType == ConstraintType.ForeignKey);
ObjectName refTname = null;
if (foreignConstraint) {
refTname = context.Request.Access().ResolveTableName(constraint.ReferenceTable);
}
var columnNames = checker.StripColumnList(TableName.FullName, constraint.Columns);
columnNames = checker.StripColumnList(constraint.ReferenceTable, columnNames);
var expression = checker.CheckExpression(constraint.CheckExpression);
columnNames = checker.CheckColumns(columnNames);
IEnumerable<string> refCols = null;
if (foreignConstraint && constraint.ReferenceColumns != null) {
var referencedChecker = ColumnChecker.Default(context.Request, refTname);
refCols = referencedChecker.CheckColumns(constraint.ReferenceColumns);
}
var newConstraint = new ConstraintInfo(constraint.ConstraintName, constraint.ConstraintType, TableName, columnNames.ToArray());
if (foreignConstraint) {
if (refCols == null)
throw new InvalidOperationException("Could not create a Foreign Key constraint with no reference columns");
newConstraint.ForeignTable = refTname;
newConstraint.ForeignColumnNames = refCols.ToArray();
newConstraint.OnDelete = constraint.OnDelete;
newConstraint.OnUpdate = constraint.OnUpdate;
}
if (constraint.ConstraintType == ConstraintType.Check)
newConstraint.CheckExpression = expression;
context.Request.Access().AddConstraint(TableName, newConstraint);
}
// Alter the existing table to the new format...
if (tableAltered) {
if (newTableInfo.ColumnCount == 0)
throw new InvalidOperationException("Can not ALTER table to have 0 columns.");
context.DirectAccess.AlterObject(newTableInfo);
} else {
// If the table wasn't physically altered, check the constraints.
// Calling this method will also make the transaction check all
// deferred constraints during the next commit.
context.Request.Access().CheckConstraintViolations(TableName);
}
}