Skip to content

Commit b8530d0

Browse files
committed
Support PG18 virtual generated columns
Closes #3568
1 parent 4bc916f commit b8530d0

File tree

3 files changed

+72
-164
lines changed

3 files changed

+72
-164
lines changed

src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,10 +1872,11 @@ protected override void ComputedColumnDefinition(
18721872
throw new NotSupportedException("Computed/generated columns aren't supported in PostgreSQL prior to version 12");
18731873
}
18741874

1875-
if (operation.IsStored != true)
1875+
if (operation.IsStored is not true && _postgresVersion < new Version(18, 0))
18761876
{
18771877
throw new NotSupportedException(
1878-
"Generated columns currently must be stored, specify 'stored: true' in "
1878+
"Virtual (non-stored) generated columns are only supported on PostgreSQL 18 and up. " +
1879+
"On older versions, specify 'stored: true' in "
18791880
+ $"'{nameof(RelationalPropertyBuilderExtensions.HasComputedColumnSql)}' in your context's OnModelCreating.");
18801881
}
18811882

@@ -1894,7 +1895,12 @@ protected override void ComputedColumnDefinition(
18941895
builder
18951896
.Append(" GENERATED ALWAYS AS (")
18961897
.Append(operation.ComputedColumnSql!)
1897-
.Append(") STORED");
1898+
.Append(")");
1899+
1900+
if (operation.IsStored is true)
1901+
{
1902+
builder.Append(" STORED");
1903+
}
18981904

18991905
if (!operation.IsNullable)
19001906
{

src/EFCore.PG/Scaffolding/Internal/NpgsqlDatabaseModelFactory.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -390,17 +390,22 @@ ORDER BY attnum
390390
continue;
391391
}
392392

393-
// Default values and PostgreSQL 12 generated columns
393+
// Default values and generated columns
394394
var defaultValueSql = record.GetValueOrDefault<string>("default");
395-
if (record.GetFieldValue<string>("attgenerated") == "s")
395+
switch (record.GetFieldValue<string>("attgenerated"))
396396
{
397-
column.ComputedColumnSql = defaultValueSql;
398-
column.IsStored = true;
399-
}
400-
else
401-
{
402-
column.DefaultValueSql = defaultValueSql;
403-
column.DefaultValue = ParseDefaultValueSql(systemTypeName, defaultValueSql);
397+
case "v":
398+
column.ComputedColumnSql = defaultValueSql;
399+
column.IsStored = false;
400+
break;
401+
case "s":
402+
column.ComputedColumnSql = defaultValueSql;
403+
column.IsStored = true;
404+
break;
405+
default:
406+
column.DefaultValueSql = defaultValueSql;
407+
column.DefaultValue = ParseDefaultValueSql(systemTypeName, defaultValueSql);
408+
break;
404409
}
405410

406411
// Identify IDENTITY columns, as well as SERIAL ones.

0 commit comments

Comments
 (0)