public ExpressionChecker(ColumnChecker checker)
 {
     this.checker = checker;
 }
        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);
            }
        }
Example #3
0
 public ExpressionChecker(ColumnChecker checker)
 {
     this.checker = checker;
 }