Skip to content

Commit

Permalink
Use pg-specific schema tables for fkey detection
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
aarondl committed Jan 7, 2017
1 parent fac1a7f commit 711ecbb
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 12 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down
21 changes: 12 additions & 9 deletions bdb/drivers/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions testdata/postgres_test_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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);

0 comments on commit 711ecbb

Please sign in to comment.