protected override void Generate(CreateTableOperation operation, IModel model, MigrationCommandListBuilder builder, bool terminate)
        {
            base.Generate(operation, model, builder, false);
            if (terminate)
            {
                builder.Append(Dependencies.SqlGenerationHelper.StatementTerminator);
                EndStatement(builder);

                var columns = operation.Columns.Where(p => !p.IsNullable && string.IsNullOrWhiteSpace(p.DefaultValueSql) && p.DefaultValue == null);
                foreach (var column in columns)
                {
                    var columnAnnotation = column.FindAnnotation(FbAnnotationNames.ValueGenerationStrategy);
                    if (columnAnnotation != null)
                    {
                        var valueGenerationStrategy = columnAnnotation.Value as FbValueGenerationStrategy?;
                        if (valueGenerationStrategy == FbValueGenerationStrategy.SequenceTrigger)
                        {
                            _behavior.CreateIdentityForColumn(column.Name, column.Table, builder);
                        }
                    }
                }
            }
        }
        protected virtual IEnumerable <MigrationStatement> Generate(AlterColumnOperation operation)
        {
            var column     = operation.Column;
            var tableName  = CheckName(ExtractName(operation.Table));
            var columnName = CheckName(column.Name);

            // drop NOT NULL first, either it will be recreated or it was to drop
            using (var writer = SqlWriter())
            {
                writer.WriteLine("EXECUTE BLOCK");
                writer.WriteLine("AS");
                writer.WriteLine("declare constraint_name type of column rdb$relation_constraints.rdb$constraint_name;");
                writer.WriteLine("BEGIN");
                writer.Indent++;
                writer.WriteLine("select rc.rdb$constraint_name");
                writer.WriteLine("from rdb$relation_constraints rc");
                writer.WriteLine("join rdb$check_constraints cc on rc.rdb$constraint_name = cc.rdb$constraint_name");
                writer.Write("where rc.rdb$constraint_type = 'NOT NULL' and rc.rdb$relation_name = '");
                writer.Write(tableName);
                writer.Write("' and cc.rdb$trigger_name  = '");
                writer.Write(columnName);
                writer.Write("'");
                writer.WriteLine();
                writer.WriteLine("into :constraint_name;");
                writer.WriteLine("if (constraint_name is not null) then");
                writer.WriteLine("begin");
                writer.Indent++;
                writer.Write("execute statement 'alter table ");
                writer.Write(Quote(tableName));
                writer.Write(" drop constraint ' || :constraint_name;");
                writer.WriteLine();
                writer.Indent--;
                writer.WriteLine("end");
                writer.Indent--;
                writer.Write("END");
                yield return(Statement(writer));
            }
            // drop identity trigger first, either it will be recreated or it was to drop
            foreach (var item in _behavior.DropIdentityForColumn(columnName, tableName))
            {
                yield return(Statement(item));
            }

            using (var writer = SqlWriter())
            {
                writer.Write("ALTER TABLE ");
                writer.Write(Quote(tableName));
                writer.Write(" ALTER COLUMN ");
                writer.Write(Quote(columnName));
                writer.Write(" TYPE ");
                writer.Write(BuildPropertyType(column));
                // possible NOT NULL drop was dropped with statement above
                if (column.IsNullable != null && !column.IsNullable.Value)
                {
                    writer.Write(" NOT NULL");
                }
                if (column.Type == PrimitiveTypeKind.Boolean)
                {
                    writer.Write(" CHECK(");
                    writer.Write(Quote(columnName));
                    writer.Write(" IN (0,1))");
                }
                yield return(Statement(writer));
            }

            if (column.DefaultValue != null || !string.IsNullOrWhiteSpace(column.DefaultValueSql))
            {
                using (var writer = SqlWriter())
                {
                    writer.Write("ALTER TABLE ");
                    writer.Write(Quote(tableName));
                    writer.Write(" ALTER COLUMN ");
                    writer.Write(Quote(columnName));
                    writer.Write(" DROP DEFAULT");
                    yield return(Statement(writer));
                }

                using (var writer = SqlWriter())
                {
                    writer.Write("ALTER TABLE ");
                    writer.Write(Quote(tableName));
                    writer.Write(" ALTER COLUMN ");
                    writer.Write(Quote(columnName));
                    writer.Write(" SET DEFAULT ");
                    writer.Write(column.DefaultValue != null ? WriteValue((dynamic)column.DefaultValue) : column.DefaultValueSql);
                    yield return(Statement(writer));
                }
            }

            if (column.IsIdentity)
            {
                // possible identity drop was dropped with statement above
                foreach (var item in _behavior.CreateIdentityForColumn(columnName, tableName))
                {
                    yield return(Statement(item));
                }
            }
        }
        protected virtual IEnumerable <MigrationStatement> Generate(AddColumnOperation operation)
        {
            var tableName = ExtractName(operation.Table);

            using (var writer = SqlWriter())
            {
                writer.Write("ALTER TABLE ");
                writer.Write(Quote(tableName));
                writer.Write(" ADD ");
                var column = operation.Column;

                var builder            = new StringBuilder();
                var additionalCommands = new List <string>();

                var columnType = BuildPropertyType(column);
                builder.Append(Quote(column.Name));
                builder.Append(" ");
                builder.Append(columnType);

                if (column.IsIdentity)
                {
                    var identity = behavior.CreateIdentityForColumn(column.Name, tableName);
                    additionalCommands.AddRange(identity.Where(x => !string.IsNullOrWhiteSpace(x)));
                }

                if (column.ClrType == typeof(bool))
                {
                    const string format = "ALTER TABLE \"{0}\" ADD CHECK (\"{1}\" IN (1,0));";
                    additionalCommands.Add(string.Format(format, tableName, column.Name));
                }

                var columnData = Tuple.Create(builder.ToString(), additionalCommands.AsEnumerable());

                writer.Write(columnData.Item1);

                if (column.DefaultValue != null)
                {
                    writer.Write(" DEFAULT ");
                    writer.Write(WriteValue((dynamic)column.DefaultValue));
                }
                else if (!string.IsNullOrWhiteSpace(column.DefaultValueSql))
                {
                    writer.Write(" DEFAULT ");
                    writer.Write(column.DefaultValueSql);
                }
                else if (column.IsNullable != null &&
                         !column.IsNullable.Value &&
                         column.DefaultValue == null &&
                         string.IsNullOrWhiteSpace(column.DefaultValueSql) &&
                         !column.IsIdentity &&
                         !column.IsTimestamp)
                {
                    writer.Write(" DEFAULT ");
                    if (column.ClrType == typeof(bool))
                    {
                        writer.Write(WriteValue(Convert.ToInt16(column.ClrDefaultValue)));
                    }
                    else
                    {
                        writer.Write(WriteValue((dynamic)column.ClrDefaultValue));
                    }
                }

                if ((column.IsNullable != null) &&
                    !column.IsNullable.Value)
                {
                    writer.Write(" NOT NULL");
                }

                yield return(Statement(writer));
            }
        }