Skip to content

Commit 8ad98ea

Browse files
committed
Enforce that non-string types can't have collations applied.
1 parent 6ade313 commit 8ad98ea

3 files changed

Lines changed: 48 additions & 20 deletions

File tree

src/Rezoom.SQL.Compiler/Error.fs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,10 @@ let tableAlreadyHasPrimaryKey table =
145145
sprintf "SQ061: ``%O`` already has ``%O`` as its primary key constraint" table
146146
let cannotDropLastColumn table columnName =
147147
sprintf "SQ062: ``%O`` can't be dropped because it is the last column remaining in table ``%O``" columnName table
148-
148+
let cannotCollateType typeName =
149+
sprintf "SQ063: A column of type ``%O`` cannot have a collation applied" typeName
150+
let cannotAlterPrimaryKeyColumn columnName =
151+
sprintf "SQ064: Cannot alter the column ``%O`` because it is part of the table's primary key" columnName
149152

150153
let tableNameNotSuitableForPG =
151154
"SQ069: Table name is not suitable for PG (maybe you thought you were writing R?)"

src/Rezoom.SQL.Compiler/ModelOps.fs

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ let addTableColumn (tableName : QualifiedObjectName WithSource) (column : Adding
127127
let! table = getRequiredTable tableName
128128
match table.Columns |> Map.tryFind column.Name.Value with
129129
| None ->
130+
match column.Collation with
131+
| None -> ()
132+
| Some _ ->
133+
if not column.TypeName.SupportsCollation then
134+
failAt column.Name.Source <| Error.cannotCollateType column.TypeName
130135
let schemaColumn =
131136
{ TableName = tableName.Value
132137
ColumnName = column.Name.Value
@@ -423,17 +428,19 @@ let changeColumnType tableName (columnName : Name WithSource) newType =
423428
| None ->
424429
failAt columnName.Source <| Error.noSuchColumn columnName.Value
425430
| Some col ->
431+
if col.PrimaryKey then
432+
failAt columnName.Source <| Error.cannotAlterPrimaryKeyColumn columnName.Value
426433
if col.ColumnTypeName = newType then
427434
failAt columnName.Source <| Error.columnTypeIsAlready columnName.Value newType
428-
else
429-
// FUTURE validate that referencing FKs have compatible type? default value has compatible type?
430-
let newColumn =
431-
{ col with
432-
ColumnType = ColumnType.OfTypeName(newType, col.ColumnType.Nullable)
433-
ColumnTypeName = newType
434-
}
435-
let table = { table with Columns = table.Columns |> Map.add columnName.Value newColumn }
436-
return! putObject tableName (SchemaTable table)
435+
// FUTURE validate that referencing FKs have compatible type? default value has compatible type?
436+
let newColumn =
437+
{ col with
438+
ColumnType = ColumnType.OfTypeName(newType, col.ColumnType.Nullable)
439+
ColumnTypeName = newType
440+
Collation = if newType.SupportsCollation then col.Collation else None
441+
}
442+
let table = { table with Columns = table.Columns |> Map.add columnName.Value newColumn }
443+
return! putObject tableName (SchemaTable table)
437444
}
438445

439446
let changeColumnNullability tableName (columnName : Name WithSource) newNullable =
@@ -443,13 +450,14 @@ let changeColumnNullability tableName (columnName : Name WithSource) newNullable
443450
| None ->
444451
failAt columnName.Source <| Error.noSuchColumn columnName.Value
445452
| Some col ->
453+
if col.PrimaryKey then
454+
failAt columnName.Source <| Error.cannotAlterPrimaryKeyColumn columnName.Value
446455
if col.ColumnType.Nullable = newNullable then
447456
failAt columnName.Source <| Error.columnNullabilityIsAlready columnName.Value newNullable
448-
else
449-
let newColumn =
450-
{ col with ColumnType = { col.ColumnType with Nullable = newNullable } }
451-
let table = { table with Columns = table.Columns |> Map.add columnName.Value newColumn }
452-
return! putObject tableName (SchemaTable table)
457+
let newColumn =
458+
{ col with ColumnType = { col.ColumnType with Nullable = newNullable } }
459+
let table = { table with Columns = table.Columns |> Map.add columnName.Value newColumn }
460+
return! putObject tableName (SchemaTable table)
453461
}
454462

455463
let changeColumnCollation tableName (columnName : Name WithSource) newCollation =
@@ -459,11 +467,14 @@ let changeColumnCollation tableName (columnName : Name WithSource) newCollation
459467
| None ->
460468
failAt columnName.Source <| Error.noSuchColumn columnName.Value
461469
| Some col ->
470+
if col.PrimaryKey then
471+
failAt columnName.Source <| Error.cannotAlterPrimaryKeyColumn columnName.Value
462472
if col.Collation = Some newCollation then
463473
failAt columnName.Source <| Error.columnCollationIsAlready columnName.Value newCollation
464-
else
465-
let newColumn =
466-
{ col with Collation = Some newCollation }
467-
let table = { table with Columns = table.Columns |> Map.add columnName.Value newColumn }
468-
return! putObject tableName (SchemaTable table)
474+
if not col.ColumnTypeName.SupportsCollation then
475+
failAt columnName.Source <| Error.cannotCollateType col.ColumnTypeName
476+
let newColumn =
477+
{ col with Collation = Some newCollation }
478+
let table = { table with Columns = table.Columns |> Map.add columnName.Value newColumn }
479+
return! putObject tableName (SchemaTable table)
469480
}

src/Rezoom.SQL.Test/TestAlterTable.fs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,18 @@ let ``can't drop last column`` () =
8383
{ defaultTest with
8484
Migration = "create table Foo(x int); alter table Foo drop column x"
8585
Expect = BadMigration <| Error.cannotDropLastColumn "main.Foo" "x"
86+
} |> assertSimple
87+
88+
[<Test>]
89+
let ``can't alter pk column`` () =
90+
{ defaultTest with
91+
Migration = "create table Foo(x int primary key); alter table Foo alter column x int64"
92+
Expect = BadMigration <| Error.cannotAlterPrimaryKeyColumn "x"
93+
} |> assertSimple
94+
95+
[<Test>]
96+
let ``can't collate guid`` () =
97+
{ defaultTest with
98+
Migration = "create table Foo(x guid collate foo);"
99+
Expect = BadMigration <| Error.cannotCollateType "GUID"
86100
} |> assertSimple

0 commit comments

Comments
 (0)