From b806297afe99f0d62fca65a6e44c975a127912cf Mon Sep 17 00:00:00 2001 From: Haotian Date: Mon, 1 May 2023 12:40:10 -0700 Subject: [PATCH] style(db): rename constraint names to follow sql style guide (#2973) * programatically rename unique and foreign key constraints to enforce 'tablename_uq' and 'reftable_fkey' patterns * manually rename unique constraints for names over 63 characters * update changed constraint names in db update testcases --- .../postgres/33/01_static_credential.up.sql | 1 + .../39/01_static_ssh_private_key_creds.up.sql | 1 + .../postgres/67/01_rename_constraints.up.sql | 108 ++++++++++++++++++ internal/iam/group_test.go | 2 +- internal/iam/role_test.go | 2 +- internal/iam/user_test.go | 2 +- sql-style-guide.md | 3 + 7 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 internal/db/schema/migrations/oss/postgres/67/01_rename_constraints.up.sql diff --git a/internal/db/schema/migrations/oss/postgres/33/01_static_credential.up.sql b/internal/db/schema/migrations/oss/postgres/33/01_static_credential.up.sql index a2969c0df..c0bdecf49 100644 --- a/internal/db/schema/migrations/oss/postgres/33/01_static_credential.up.sql +++ b/internal/db/schema/migrations/oss/postgres/33/01_static_credential.up.sql @@ -88,6 +88,7 @@ begin; -- is 68 characters. -- -- https://www.postgresql.org/docs/current/limits.html + -- Constraint renamed in 67/01_rename_constraints.up.sql constraint credential_static_username_password_store_id_public_id_uq unique(store_id, public_id) ); diff --git a/internal/db/schema/migrations/oss/postgres/39/01_static_ssh_private_key_creds.up.sql b/internal/db/schema/migrations/oss/postgres/39/01_static_ssh_private_key_creds.up.sql index 8d9bf8dd9..6ad746170 100644 --- a/internal/db/schema/migrations/oss/postgres/39/01_static_ssh_private_key_creds.up.sql +++ b/internal/db/schema/migrations/oss/postgres/39/01_static_ssh_private_key_creds.up.sql @@ -63,6 +63,7 @@ begin; -- is 67 characters. -- -- https://www.postgresql.org/docs/current/limits.html + -- Constraint renamed in 67/01_rename_constraints.up.sql constraint credential_static_ssh_private_key_store_id_public_id_uq unique(store_id, public_id) ); diff --git a/internal/db/schema/migrations/oss/postgres/67/01_rename_constraints.up.sql b/internal/db/schema/migrations/oss/postgres/67/01_rename_constraints.up.sql new file mode 100644 index 000000000..4393b9679 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/67/01_rename_constraints.up.sql @@ -0,0 +1,108 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: MPL-2.0 + +begin; + + -- procedurally rename unique constraints to follow style guide `tablename_col1_colx_uq` + -- if constraint name format is under 63 characters + do $$ + declare + const record; + i int; + begin + for const in + select pc.conname as constraint_name, + pgc.relname as table_name, + pgc.relname || '_' || ( + select string_agg(attname, '_') + from ( + select pa.attname + from pg_catalog.pg_attribute pa + where pa.attrelid = pc.conrelid + and pa.attnum = any(pc.conkey) + order by pa.attname asc + ) as attname + ) || '_uq' as new_name, + pc.conrelid as table_num, + pc.conkey as attr_keys, + regexp_replace(regexp_replace(pc.conname, '^' || pgc.relname || '_', ''), 'uq$', '') as attrs_concat + from pg_catalog.pg_constraint pc + join pg_catalog.pg_class pgc on pc.conrelid = pgc.oid + where pgc.relname not like 'pg_%' + and contype = 'u' + order by pgc.relname, pc.conname + loop foreach i in array const.attr_keys + loop const.attrs_concat := regexp_replace( + const.attrs_concat, + concat(( + select pa.attname + from pg_catalog.pg_attribute pa + where pa.attnum = i + and pa.attrelid = const.table_num + ), '_'), ''); + end loop; + if length(const.attrs_concat) > 0 and length(const.new_name) <= 63 + then + execute format('alter table %I rename constraint %I to %I', const.table_name, const.constraint_name, const.new_name); + end if; + end loop; + end; + $$ language plpgsql; + + -- manually rename unique constraints to follow style guide if constraint name format exceeds 63 characters + alter table auth_password_argon2_conf rename constraint auth_password_argon2_conf_password_method_id_iterations_mem_key + to auth_password_argon2_conf_iters_thrds_mem_pm_id_key_salt_len_uq; + alter table auth_password_credential rename constraint auth_password_credential_password_method_id_password_conf_i_key + to auth_password_credential_password_method_conf_account_ids_uq; + -- Renames credential from 33/01_static_credential.up.sql + alter table credential_static_username_password_credential rename constraint credential_static_username_password_store_id_public_id_uq + to credential_static_username_password_credential_store_pub_ids_uq; + -- Renames credential from 39/01_static_ssh_private_key_creds.up.sql + alter table credential_static_ssh_private_key_credential rename constraint credential_static_ssh_private_key_store_id_public_id_uq + to credential_static_ssh_private_key_credential_store_pub_ids_uq; + + -- procedurally rename foreign key constraints to follow style guide 'reftable_fkey' + -- if constraint name format is under 63 characters + do $$ + declare + const record; + i int; + begin + for const in + select pc.conname as constraint_name, + pgc.relname as table_name, + pgc.relname || '_' as new_name, + pc.conrelid as conrelid, + pc.conkey as conkey, + pgc2.relname as con_table + from pg_catalog.pg_constraint pc + join pg_catalog.pg_class pgc on pc.confrelid = pgc.oid + join pg_catalog.pg_class pgc2 on pc.conrelid = pgc2.oid + where pgc.relname not like 'pg_%' + and contype = 'f' + and (pc.conname !~ ('^' || pgc.relname || '_') + or pc.conname !~ 'fkey[1]?$') + order by pgc.relname, pc.conname + loop + i = ( + select max(x) + from unnest(const.conkey) as x + ); + const.new_name = const.new_name || ( + select pa.attname + from pg_catalog.pg_attribute pa + where const.conrelid = pa.attrelid + and pa.attnum = i + ) || '_fkey'; + if length(const.new_name) <= 63 + then + begin + execute format('alter table if exists %I rename constraint %I to %I', const.con_table, const.constraint_name, const.new_name); + exception when others then + end; + end if; + end loop; + end; + $$ language plpgsql; + +commit; diff --git a/internal/iam/group_test.go b/internal/iam/group_test.go index 13754cace..de131e424 100644 --- a/internal/iam/group_test.go +++ b/internal/iam/group_test.go @@ -282,7 +282,7 @@ func Test_GroupUpdate(t *testing.T) { }, wantErr: true, wantDup: true, - wantErrMsg: `db.Update: duplicate key value violates unique constraint "iam_group_name_scope_id_key": unique constraint violation: integrity violation: error #1002`, + wantErrMsg: `db.Update: duplicate key value violates unique constraint "iam_group_name_scope_id_uq": unique constraint violation: integrity violation: error #1002`, }, { name: "set description null", diff --git a/internal/iam/role_test.go b/internal/iam/role_test.go index 2eddd35d5..7a0282c7e 100644 --- a/internal/iam/role_test.go +++ b/internal/iam/role_test.go @@ -287,7 +287,7 @@ func Test_RoleUpdate(t *testing.T) { }, wantErr: true, wantDup: true, - wantErrMsg: `db.Update: duplicate key value violates unique constraint "iam_role_name_scope_id_key": unique constraint violation: integrity violation: error #1002`, + wantErrMsg: `db.Update: duplicate key value violates unique constraint "iam_role_name_scope_id_uq": unique constraint violation: integrity violation: error #1002`, }, { name: "set description null", diff --git a/internal/iam/user_test.go b/internal/iam/user_test.go index f30c69ed0..7e8f4741e 100644 --- a/internal/iam/user_test.go +++ b/internal/iam/user_test.go @@ -205,7 +205,7 @@ func Test_UserUpdate(t *testing.T) { }, wantErr: true, wantDup: true, - wantErrMsg: `db.Update: duplicate key value violates unique constraint "iam_user_name_scope_id_key": unique constraint violation: integrity violation: error #1002`, + wantErrMsg: `db.Update: duplicate key value violates unique constraint "iam_user_name_scope_id_uq": unique constraint violation: integrity violation: error #1002`, }, { name: "modified-scope", diff --git a/sql-style-guide.md b/sql-style-guide.md index b02f53e70..e312682eb 100644 --- a/sql-style-guide.md +++ b/sql-style-guide.md @@ -66,6 +66,9 @@ For `create table` statements: - The naming pattern for unique constraints is `tablename_col1_colx_uq` where `tablename` is the name of the table and `col1_colx` is the name of each column in the unique constraint. +- The naming pattern for unique constraint names which would be over 63 characters + in length is to prioritize keeping the full 'tablename_uq' pattern intact and + abbreviate the names of the columns. ### Functions