11package main
22
3+ import "sort"
34import "fmt"
45import "database/sql"
56import "github.com/joncrlsn/pgutil"
67
7- // ForeignKeySchema holds a channel streaming foreign key data from one of the databases as well as
8+ // ==================================
9+ // ForeignKeyRows definition
10+ // ==================================
11+ type ForeignKeyRows []map [string ]string
12+
13+ func (slice ForeignKeyRows ) Len () int {
14+ return len (slice )
15+ }
16+
17+ func (slice ForeignKeyRows ) Less (i , j int ) bool {
18+ //fmt.Printf("--Less %s:%s with %s:%s", slice[i]["table_name"], slice[i]["column_name"], slice[j]["table_name"], slice[j]["column_name"])
19+ if slice [i ]["table_name" ] == slice [j ]["table_name" ] {
20+ return slice [i ]["constraint_def" ] < slice [j ]["constraint_def" ]
21+ }
22+ return slice [i ]["table_name" ] < slice [j ]["table_name" ]
23+ }
24+
25+ func (slice ForeignKeyRows ) Swap (i , j int ) {
26+ //fmt.Printf("--Swapping %d/%s:%s with %d/%s:%s \n", i, slice[i]["table_name"], slice[i]["index_name"], j, slice[j]["table_name"], slice[j]["index_name"])
27+ slice [i ], slice [j ] = slice [j ], slice [i ]
28+ }
29+
30+ // ==================================
31+ // ForeignKeySchema definition
32+ // (implements Schema -- defined in pgdiff.go)
33+ // ==================================
34+
35+ // ForeignKeySchema holds a slice of rows from one of the databases as well as
836// a reference to the current row of data we're viewing.
9- //
10- // ForeignKeySchema implements the Schema interface defined in pgdiff.go
1137type ForeignKeySchema struct {
12- channel chan map [ string ] string
13- row map [ string ] string
38+ rows ForeignKeyRows
39+ rowNum int
1440 done bool
1541}
1642
43+ // get returns the value from the current row for the given key
44+ func (c * ForeignKeySchema ) get (key string ) string {
45+ if c .rowNum >= len (c .rows ) {
46+ return ""
47+ }
48+ return c.rows [c.rowNum ][key ]
49+ }
50+
51+ // get returns the current row for the given key
52+ func (c * ForeignKeySchema ) getRow () map [string ]string {
53+ if c .rowNum >= len (c .rows ) {
54+ return make (map [string ]string )
55+ }
56+ return c .rows [c .rowNum ]
57+ }
58+
1759// NextRow reads from the channel and tells you if there are (probably) more or not
1860func (c * ForeignKeySchema ) NextRow () bool {
19- c . row = <- c . channel
20- if len ( c . row ) == 0 {
21- c . done = true
22- }
23- return ! c .done
61+ if c . rowNum >= len ( c . rows ) - 1 {
62+ c . done = true
63+ }
64+ c . rowNum = c . rowNum + 1
65+ return ! c .done
2466}
2567
2668// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
@@ -31,28 +73,28 @@ func (c *ForeignKeySchema) Compare(obj interface{}) int {
3173 return + 999
3274 }
3375
34- //fmt.Printf("Comparing %s with %s", c.row[ "table_name"] , c2.row[ "table_name"] )
35- val := _compareString (c .row [ "table_name" ] , c2 .row [ "table_name" ] )
76+ //fmt.Printf("Comparing %s with %s", c.get( "table_name") , c2.get( "table_name") )
77+ val := _compareString (c .get ( "table_name" ) , c2 .get ( "table_name" ) )
3678 if val != 0 {
3779 return val
3880 }
3981
40- val = _compareString (c .row [ "constraint_def" ] , c2 .row [ "constraint_def" ] )
82+ val = _compareString (c .get ( "constraint_def" ) , c2 .get ( "constraint_def" ) )
4183 return val
4284}
4385
4486// Add returns SQL to add the foreign key
45- func (c ForeignKeySchema ) Add () {
46- fmt .Printf ("ALTER TABLE %s ADD CONSTRAINT %s %s;\n " , c .row [ "table_name" ] , c .row [ "constraint_name" ] , c .row [ "constraint_def" ] )
87+ func (c * ForeignKeySchema ) Add () {
88+ fmt .Printf ("ALTER TABLE %s ADD CONSTRAINT %s %s;\n " , c .get ( "table_name" ) , c .get ( "fk_name" ) , c .get ( "constraint_def" ) )
4789}
4890
4991// Drop returns SQL to drop the foreign key
5092func (c ForeignKeySchema ) Drop () {
51- fmt .Printf ("ALTER TABLE %s DROP CONSTRAINT %s; -- %s\n " , c .row [ "table_name" ] , c .row [ "constraint_name" ] , c .row [ "constraint_def" ] )
93+ fmt .Printf ("ALTER TABLE %s DROP CONSTRAINT %s; -- %s\n " , c .get ( "table_name" ) , c .get ( "fk_name" ) , c .get ( "constraint_def" ) )
5294}
5395
5496// Change handles the case where the table and foreign key name, but the details do not
55- func (c ForeignKeySchema ) Change (obj interface {}) {
97+ func (c * ForeignKeySchema ) Change (obj interface {}) {
5698 c2 , ok := obj .(* ForeignKeySchema )
5799 if ! ok {
58100 fmt .Println ("Error!!!, change needs a ForeignKeySchema instance" , c2 )
@@ -65,22 +107,31 @@ func (c ForeignKeySchema) Change(obj interface{}) {
65107 */
66108func compareForeignKeys (conn1 * sql.DB , conn2 * sql.DB ) {
67109 sql := `
68- SELECT c.conname AS constraint_name
69- , c.contype AS constraint_type
110+ SELECT c.conname AS fk_name
70111 , cl.relname AS table_name
71112 , pg_catalog.pg_get_constraintdef(c.oid, true) as constraint_def
72113FROM pg_catalog.pg_constraint c
73114INNER JOIN pg_class AS cl ON (c.conrelid = cl.oid)
74- WHERE c.contype = 'f'
75- ORDER BY cl.relname::varchar, pg_catalog.pg_get_constraintdef(c.oid, true) COLLATE "C" ASC;
115+ WHERE c.contype = 'f';
76116`
77-
78117 rowChan1 , _ := pgutil .QueryStrings (conn1 , sql )
79118 rowChan2 , _ := pgutil .QueryStrings (conn2 , sql )
80119
81- // We have to explicitly type this as Schema for some reason
82- var schema1 Schema = & ForeignKeySchema {channel : rowChan1 }
83- var schema2 Schema = & ForeignKeySchema {channel : rowChan2 }
120+ rows1 := make (ForeignKeyRows , 0 )
121+ for row := range rowChan1 {
122+ rows1 = append (rows1 , row )
123+ }
124+ sort .Sort (rows1 )
125+
126+ rows2 := make (ForeignKeyRows , 0 )
127+ for row := range rowChan2 {
128+ rows2 = append (rows2 , row )
129+ }
130+ sort .Sort (rows2 )
131+
132+ // We have to explicitly type this as Schema here for some unknown reason
133+ var schema1 Schema = & ForeignKeySchema {rows : rows1 , rowNum : - 1 }
134+ var schema2 Schema = & ForeignKeySchema {rows : rows2 , rowNum : - 1 }
84135
85136 // Compare the columns
86137 doDiff (schema1 , schema2 )
0 commit comments