Skip to content

Commit

Permalink
Quote postgres table and column names as reserved keywords
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticmind authored and jeremydmiller committed Dec 17, 2024
1 parent fd08c20 commit df8d26e
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 7 deletions.
23 changes: 23 additions & 0 deletions src/Weasel.Postgresql.Tests/Tables/creating_tables_in_database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,27 @@ bool withDistinctNulls
(await table.ExistsInDatabaseAsync(theConnection))
.ShouldBeTrue();
}

[Fact]
public async Task create_table_with_name_and_column_using_reserved_keyword()
{
await theConnection.OpenAsync();

await theConnection.ResetSchemaAsync("tables");

var table = new Table("order");
table.AddColumn<int>("id").AsPrimaryKey();
table.AddColumn<string>("first_name");
table.AddColumn<string>("last_name");
table.AddColumn<int>("order");

await CreateSchemaObjectInDatabase(table);

(await table.ExistsInDatabaseAsync(theConnection))
.ShouldBeTrue();

await theConnection.CreateCommand(
"insert into \"order\" (id, first_name, last_name, \"order\") values (1, 'Elton', 'John',1)")
.ExecuteNonQueryAsync();
}
}
2 changes: 2 additions & 0 deletions src/Weasel.Postgresql/PostgresqlObjectName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ namespace Weasel.Postgresql;

public class PostgresqlObjectName: DbObjectName
{
protected override string QuotedQualifiedName => $"{SchemaUtils.QuoteName(Schema)}.{SchemaUtils.QuoteName(Name)}";

public PostgresqlObjectName(string schema, string name)
: base(schema, name, PostgresqlProvider.Instance.ToQualifiedName(schema, name))
{
Expand Down
20 changes: 20 additions & 0 deletions src/Weasel.Postgresql/SchemaUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,25 @@ private static async Task<bool> dropSchema(string connectionString, string schem
throw;
}
}

public static string QuoteName(string name)
{
return ReservedKeywords.Contains(name, StringComparer.InvariantCultureIgnoreCase) ? $"\"{name}\"" : name;
}

private static readonly string[] ReservedKeywords =
[
"ALL", "ANALYSE", "ANALYZE", "AND", "ANY", "ARRAY", "AS", "ASC", "ASYMMETRIC", "AUTHORIZATION",
"BINARY", "BOTH", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "CONCURRENTLY", "CONSTRAINT",
"CREATE", "CROSS", "CURRENT_CATALOG", "CURRENT_DATE", "CURRENT_ROLE", "CURRENT_SCHEMA",
"CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "DEFAULT", "DEFERRABLE", "DESC", "DISTINCT",
"DO", "ELSE", "END", "EXCEPT", "FALSE", "FETCH", "FOR", "FOREIGN", "FREEZE", "FROM", "FULL",
"GRANT", "GROUP", "HAVING", "ILIKE", "IN", "INITIALLY", "INNER", "INTERSECT", "INTO", "IS",
"ISNULL", "JOIN", "LATERAL", "LEADING", "LEFT", "LIKE", "LIMIT", "LOCALTIME", "LOCALTIMESTAMP",
"NATURAL", "NOT", "NOTNULL", "NULL", "OFFSET", "ON", "ONLY", "OR", "ORDER", "OUTER", "OVERLAPS",
"PLACING", "PRIMARY", "REFERENCES", "RETURNING", "RIGHT", "SELECT", "SESSION_USER", "SIMILAR",
"SOME", "SYMMETRIC", "TABLE", "THEN", "TO", "TRAILING", "TRUE", "UNION", "UNIQUE", "USER",
"USING", "VARIADIC", "VERBOSE", "WHEN", "WHERE", "WINDOW", "WITH"
];
}

4 changes: 2 additions & 2 deletions src/Weasel.Postgresql/Tables/Table.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ public void WriteCreateStatement(Migrator migrator, TextWriter writer)

if (migrator.Formatting == SqlFormatting.Pretty)
{
var columnLength = Columns.Max(x => x.Name.Length) + 4;
var columnLength = Columns.Max(x => x.QuotedName.Length) + 4;
var typeLength = Columns.Max(x => x.Type.Length) + 4;

var lines = Columns.Select(column =>
$" {column.Name.PadRight(columnLength)}{column.Type.PadRight(typeLength)}{column.Declaration()}")
$" {column.QuotedName.PadRight(columnLength)}{column.Type.PadRight(typeLength)}{column.Declaration()}")
.ToList();

if (PrimaryKeyColumns.Any())
Expand Down
12 changes: 7 additions & 5 deletions src/Weasel.Postgresql/Tables/TableColumn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public TableColumn(string name, string type)

public string Name { get; }

public string QuotedName => SchemaUtils.QuoteName(Name);

public string RawType()
{
return Type.Split('(')[0].Trim();
Expand All @@ -59,7 +61,7 @@ public string Declaration()

protected bool Equals(TableColumn other)
{
return string.Equals(Name, other.Name) &&
return string.Equals(QuotedName, other.QuotedName) &&
string.Equals(PostgresqlProvider.Instance.ConvertSynonyms(RawType()),
PostgresqlProvider.Instance.ConvertSynonyms(other.RawType()));
}
Expand Down Expand Up @@ -97,8 +99,8 @@ public string ToDeclaration()
var declaration = Declaration();

return declaration.IsEmpty()
? $"{Name} {Type}"
: $"{Name} {Type} {declaration}";
? $"{QuotedName} {Type}"
: $"{QuotedName} {Type} {declaration}";
}

public override string ToString()
Expand All @@ -109,12 +111,12 @@ public override string ToString()

public virtual string AlterColumnTypeSql(Table table, TableColumn changeActual)
{
return $"alter table {table.Identifier} alter column {Name.PadRight(Name.Length)} type {Type};";
return $"alter table {table.Identifier} alter column {QuotedName.PadRight(QuotedName.Length)} type {Type};";
}

public string DropColumnSql(Table table)
{
return $"alter table {table.Identifier} drop column {Name};";
return $"alter table {table.Identifier} drop column {QuotedName};";
}


Expand Down

0 comments on commit df8d26e

Please sign in to comment.