Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SetExistingRowsTo logic with system-versioned tables #1549

Open
jzabroski opened this issue Dec 13, 2021 · 0 comments
Open

SetExistingRowsTo logic with system-versioned tables #1549

jzabroski opened this issue Dec 13, 2021 · 0 comments
Labels
db:sql-server Microsoft SQL Server specific improvement Improvement of behavior or code quality

Comments

@jzabroski
Copy link
Collaborator

Describe the bug
If you use advanced database features, SetExistingRowsTo will only set values on the main table, not the history table.

Create.Table("Example")
                .InSchema("dbo")
                .WithColumn("ExampleId").AsInt64().NotNullable().PrimaryKey()
                .WithColumn("Version").AsRowVersion().NotNullable();
                .WithColumn("ValidFromInUTC").AsDateTime2()
                    .WithDefault(SystemMethods.CurrentUTCDateTime)
                .WithColumn("ValidToInUTC").AsDateTime2()
                    .WithDefaultValue("CONVERT(DATETIME2(7), '9999-12-31 23:59:59.9999999')");

// ExampleHistory is a near verbatim copy of Example, except for keys.
Create.Table("ExampleHistory")
                .InSchema("dbo")
                .WithColumn("ExampleId").AsInt64().NotNullable()
                .WithColumn("Version").AsRowVersion().NotNullable();
                .WithColumn("ValidFromInUTC").AsDateTime2()
                    .WithDefault(SystemMethods.CurrentUTCDateTime)
                .WithColumn("ValidToInUTC").AsDateTime2()
                    .WithDefaultValue("CONVERT(DATETIME2(7), '9999-12-31 23:59:59.9999999')");

var schema = "dbo";
var table = "Example";
var historySchema = "dbo";
var historyTable = table + "History";
var rowStartDateColumn = "ValidFromInUtc";
var rowEndDateColumn = "ValidToInUtc";
Execute.Sql("ALTER TABLE [" + schema + "].[" + table + "] ADD PERIOD FOR SYSTEM_TIME([" + rowStartDateColumn + "], [" + rowEndDateColumn + "]);");
Execute.Sql("ALTER TABLE [" + schema + "].[" + table + "] SET(SYSTEM_VERSIONING = ON(HISTORY_TABLE = [" + historySchema + "].[" + historyTable + "], DATA_CONSISTENCY_CHECK = ON))");

// Due to semantics of how T-SQL works, any changes to dbo.Example table will flow through to dbo.ExampleHistory
Alter.Table("Example")
                .InSchema("dbo")
                .AddColumn("IsEnabled").AsBoolean().Nullable().SetExistingRowsTo(false);

// This will fail with an error
Alter.Column("IsEnabled")
                .OnTable("Example")
                .InSchema("dbo")
                .AsBoolean().NotNullable();

To Reproduce
Observe the following error:

ALTER TABLE [dbo].[Example] ALTER COLUMN [IsEnabled] BIT NOT NULL
The error was Cannot insert the value NULL into column 'IsEnabled', table 'FluentMigratorTests_John.Zabroski.dbo.ExampleHistory'; column does not allow nulls. UPDATE fails.
The statement has been terminated.

Expected behavior
Should be in-line with Microsoft documented behavior in article Changing the Schema of a System-Versioned Temporal Table (or, at minimum, the Remarks visible in IntelliSense of FluentMigrator should call out this gotcha):

If you add a non-nullable column or alter existing column to become non-nullable, you must specify the default value for existing rows. The system will generate an additional default with the same value and apply it to the history table. Adding DEFAULT to a non-empty table is a size of data operation on all editions other than SQL Server Enterprise Edition (on which it is a metadata operation).

We can also look at what Postgres does.

Information (please complete the following information):
FluentMigrator 3.3.1

Additional context
Add any other context about the problem here.

@schambers schambers added the improvement Improvement of behavior or code quality label Mar 17, 2024
@jzabroski jzabroski added the db:sql-server Microsoft SQL Server specific label Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
db:sql-server Microsoft SQL Server specific improvement Improvement of behavior or code quality
Projects
None yet
Development

No branches or pull requests

2 participants