From 711ecbbe8d24dbb3b317ad3930b356344a894fbc Mon Sep 17 00:00:00 2001 From: Aaron L Date: Fri, 6 Jan 2017 17:45:32 -0800 Subject: [PATCH] Use pg-specific schema tables for fkey detection - Postgres doesn't care about names for uniqueness of keys unlike mysql because internally it keeps "oid" values to keep track of everything. Unfortunately this means that the information_schema standard is inadequate to differentiate between constraints that are named the same (which isn't possible in mysql, but is in pg). Hence we have to dip into the pg specific schemas for better or worse. - Fix naming of the sample schema in the README since it would fail for mysql due to duplicate naming. - Mark test schema up so we don't fix the bad names so we catch regressions here. - Fix #85 --- README.md | 6 +++--- bdb/drivers/postgres.go | 21 ++++++++++++--------- testdata/postgres_test_schema.sql | 2 ++ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a272fc28c..ac8159ab7 100644 --- a/README.md +++ b/README.md @@ -356,7 +356,7 @@ CREATE TABLE jets ( ); ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id); -ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id); +ALTER TABLE jets ADD CONSTRAINT jet_pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id); CREATE TABLE languages ( id integer NOT NULL, @@ -373,8 +373,8 @@ CREATE TABLE pilot_languages ( -- Composite primary key ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id); -ALTER TABLE pilot_languages ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id); -ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id); +ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id); +ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id); ``` The generated model structs for this schema look like the following. Note that we've included the relationship diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go index ce9456118..5ae0283f1 100644 --- a/bdb/drivers/postgres.go +++ b/bdb/drivers/postgres.go @@ -264,15 +264,18 @@ func (p *PostgresDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.Foreign query := ` select - tc.constraint_name, - kcu.table_name as source_table, - kcu.column_name as source_column, - ccu.table_name as dest_table, - ccu.column_name as dest_column - from information_schema.table_constraints as tc - inner join information_schema.key_column_usage as kcu ON tc.constraint_name = kcu.constraint_name and tc.constraint_schema = kcu.constraint_schema - inner join information_schema.constraint_column_usage as ccu ON tc.constraint_name = ccu.constraint_name and tc.constraint_schema = ccu.constraint_schema - where tc.table_name = $1 and tc.constraint_type = 'FOREIGN KEY' and tc.table_schema = $2;` + pgcon.conname, + pgc.relname as source_table, + pgasrc.attname as source_column, + dstlookupname.relname as dest_table, + pgadst.attname as dest_column + from pg_namespace pgn + inner join pg_class pgc on pgn.oid = pgc.relnamespace and pgc.relkind = 'r' + inner join pg_constraint pgcon on pgn.oid = pgcon.connamespace and pgc.oid = pgcon.conrelid + inner join pg_class dstlookupname on pgcon.confrelid = dstlookupname.oid + inner join pg_attribute pgasrc on pgc.oid = pgasrc.attrelid and pgasrc.attnum = ANY(pgcon.conkey) + inner join pg_attribute pgadst on pgcon.confrelid = pgadst.attrelid and pgadst.attnum = ANY(pgcon.confkey) + where pgn.nspname = $2 and pgc.relname = $1 and pgcon.contype = 'f'` var rows *sql.Rows var err error diff --git a/testdata/postgres_test_schema.sql b/testdata/postgres_test_schema.sql index 52f33e4bb..e0a043c10 100644 --- a/testdata/postgres_test_schema.sql +++ b/testdata/postgres_test_schema.sql @@ -400,6 +400,7 @@ CREATE TABLE jets ( ); ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id); +-- The following fkey remains poorly named to avoid regressions related to psql naming ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id); CREATE TABLE languages ( @@ -417,5 +418,6 @@ CREATE TABLE pilot_languages ( -- Composite primary key ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id); +-- The following fkey remains poorly named to avoid regressions related to psql naming ALTER TABLE pilot_languages ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id); ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);