Skip to content

Commit 2d60b3e

Browse files
committed
Added sorting to columng.go and index.go
Former-commit-id: d96c4a7
1 parent 8aa08a9 commit 2d60b3e

3 files changed

Lines changed: 147 additions & 81 deletions

File tree

column.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package main
22

3+
import "sort"
34
import "fmt"
45
import "strconv"
56
import "strings"
@@ -12,22 +13,24 @@ import "github.com/joncrlsn/pgutil"
1213
type ColumnRows []map[string]string
1314

1415
func (slice ColumnRows) Len() int {
15-
return len(slice)
16+
return len(slice)
1617
}
1718

1819
func (slice ColumnRows) Less(i, j int) bool {
19-
if slice[i]["table_name"] < slice[j]["table_name"] {
20-
return true
20+
//fmt.Printf("--Less %s:%s with %s:%s", slice[i]["table_name"], slice[i]["column_name"], slice[j]["table_name"], slice[j]["column_name"])
21+
if slice[i]["table_name"] == slice[j]["table_name"] {
22+
return slice[i]["column_name"] < slice[j]["column_name"]
2123
}
22-
return slice[i]["column_name"] < slice[j]["column_name"]
24+
return slice[i]["table_name"] < slice[j]["table_name"]
2325
}
2426

2527
func (slice ColumnRows) Swap(i, j int) {
26-
slice[i], slice[j] = slice[j], slice[i]
28+
fmt.Printf("--Swapping %d/%s:%s with %d/%s:%s \n", i, slice[i]["table_name"], slice[i]["column_name"], j, slice[j]["table_name"], slice[j]["column_name"])
29+
slice[i], slice[j] = slice[j], slice[i]
2730
}
2831

2932
// ==================================
30-
// ColumnSchema definition
33+
// ColumnSchema definition
3134
// (implements Schema -- defined in pgdiff.go)
3235
// ==================================
3336

@@ -180,22 +183,25 @@ SELECT table_name
180183
FROM information_schema.columns
181184
WHERE table_schema = 'public'
182185
AND is_updatable = 'YES'
183-
ORDER by table_name, column_name COLLATE "C" ASC;`
186+
-- We do not depend on this sorting correctly
187+
ORDER BY table_name, column_name COLLATE "C" ASC;`
184188

185189
rowChan1, _ := pgutil.QueryStrings(conn1, sql)
186190
rowChan2, _ := pgutil.QueryStrings(conn2, sql)
187191

188192
//rows1 := make([]map[string]string, 500)
189-
rows1 := make(ColumnRows, 500)
193+
rows1 := make(ColumnRows, 0)
190194
for row := range rowChan1 {
191195
rows1 = append(rows1, row)
192196
}
197+
sort.Sort(rows1)
193198

194199
//rows2 := make([]map[string]string, 500)
195-
rows2 := make(ColumnRows, 500)
200+
rows2 := make(ColumnRows, 0)
196201
for row := range rowChan2 {
197202
rows2 = append(rows2, row)
198203
}
204+
sort.Sort(&rows2)
199205

200206
// We have to explicitly type this as Schema here for some unknown reason
201207
var schema1 Schema = &ColumnSchema{rows: rows1, rowNum: -1}

index.go

Lines changed: 129 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,188 @@
11
package main
22

3+
import "sort"
34
import "fmt"
45
import "strings"
56
import "database/sql"
67
import "github.com/joncrlsn/pgutil"
78

8-
// IndexSchema holds a channel that streams index metadata from one of the databases.
9-
// It also holds a reference to the current row of data we're viewing.
10-
//
11-
// IndexSchema implements the Schema interface defined in pgdiff.go
9+
// ==================================
10+
// IndexRows definition
11+
// ==================================
12+
type IndexRows []map[string]string
13+
14+
func (slice IndexRows) Len() int {
15+
return len(slice)
16+
}
17+
18+
func (slice IndexRows) Less(i, j int) bool {
19+
//fmt.Printf("--Less %s:%s with %s:%s", slice[i]["table_name"], slice[i]["column_name"], slice[j]["table_name"], slice[j]["column_name"])
20+
if slice[i]["table_name"] == slice[j]["table_name"] {
21+
return slice[i]["index_name"] < slice[j]["index_name"]
22+
}
23+
return slice[i]["table_name"] < slice[j]["table_name"]
24+
}
25+
26+
func (slice IndexRows) Swap(i, j int) {
27+
//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"])
28+
slice[i], slice[j] = slice[j], slice[i]
29+
}
30+
31+
// ==================================
32+
// IndexSchema definition
33+
// (implements Schema -- defined in pgdiff.go)
34+
// ==================================
35+
36+
// IndexSchema holds a slice of rows from one of the databases as well as
37+
// a reference to the current row of data we're viewing.
1238
type IndexSchema struct {
13-
channel chan map[string]string
14-
row map[string]string
15-
done bool
39+
rows IndexRows
40+
rowNum int
41+
done bool
42+
}
43+
44+
// get returns the value from the current row for the given key
45+
func (c *IndexSchema) get(key string) string {
46+
if c.rowNum >= len(c.rows) {
47+
return ""
48+
}
49+
return c.rows[c.rowNum][key]
1650
}
1751

18-
// NextRow reads from the channel and tells you if there are (probably) more or not
52+
// get returns the current row for the given key
53+
func (c *IndexSchema) getRow() map[string]string {
54+
if c.rowNum >= len(c.rows) {
55+
return make(map[string]string)
56+
}
57+
return c.rows[c.rowNum]
58+
}
59+
60+
// NextRow increments the rowNum and tells you whether or not there are more
1961
func (c *IndexSchema) NextRow() bool {
20-
c.row = <-c.channel
21-
if len(c.row) == 0 {
62+
if c.rowNum >= len(c.rows)-1 {
2263
c.done = true
2364
}
65+
c.rowNum = c.rowNum + 1
2466
return !c.done
2567
}
2668

2769
// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
2870
func (c *IndexSchema) Compare(obj interface{}) int {
2971
c2, ok := obj.(*IndexSchema)
3072
if !ok {
31-
fmt.Println("Error!!!, Change(...) needs a IndexSchema instance", c2)
32-
return +999
73+
fmt.Println("Error!!!, change needs a IndexSchema instance", c2)
3374
}
3475

35-
//fmt.Printf("Comparing %s with %s", c.row["table_name"], c2.row["table_name"])
36-
val := _compareString(c.row["table_name"], c2.row["table_name"])
76+
if len(c.get("table_name")) == 0 || len(c.get("index_name")) == 0 {
77+
fmt.Printf("--Comparing (table_name or index_name is empty): %v\n-- %v\n", c.getRow(), c2.getRow())
78+
}
79+
80+
val := _compareString(c.get("table_name"), c2.get("table_name"))
3781
if val != 0 {
82+
// Table name differed so return that value
3883
return val
3984
}
4085

41-
val = _compareString(c.row["index_name"], c2.row["index_name"])
86+
// Table name was the same so compare index name
87+
val = _compareString(c.get("index_name"), c2.get("index_name"))
4288
return val
4389
}
4490

45-
// Add generates SQL to add the constraint/index
46-
func (c IndexSchema) Add() {
47-
fmt.Println("--\n--Add\n--")
91+
// Add prints SQL to add the column
92+
func (c *IndexSchema) Add() {
93+
//fmt.Println("--\n--Add\n--")
4894

4995
// Assertion
50-
if c.row["index_def"] == "null" {
51-
fmt.Printf("-- Unexpected situation in index.go: there is no index_def for %s %s\n", c.row["table_name"], c.row["index_name"])
96+
if c.get("index_def") == "null" || len(c.get("index_def")) == 0 {
97+
fmt.Printf("-- Add Unexpected situation in index.go: there is no index_def for %s %s\n", c.get("table_name"), c.get("index_name"))
5298
return
5399
}
54100

55-
// Create the index
56-
fmt.Printf("%s;\n", c.row["index_def"])
101+
// Create the index first
102+
fmt.Printf("%s;\n", c.get("index_def"))
57103

58-
if c.row["constraint_def"] != "null" {
104+
if c.get("constraint_def") != "null" {
59105
// Create the constraint using the index we just created
60-
if c.row["pk"] == "true" {
106+
if c.get("pk") == "true" {
61107
// Add primary key using the index
62-
fmt.Printf("ALTER TABLE ONLY %s ADD CONSTRAINT %s PRIMARY KEY USING INDEX %s;\n", c.row["table_name"], c.row["index_name"], c.row["index_name"])
63-
} else if c.row["uq"] == "true" {
108+
fmt.Printf("ALTER TABLE ONLY %s ADD CONSTRAINT %s PRIMARY KEY USING INDEX %s;\n", c.get("table_name"), c.get("index_name"), c.get("index_name"))
109+
} else if c.get("uq") == "true" {
64110
// Add unique constraint using the index
65-
fmt.Printf("ALTER TABLE ONLY %s ADD CONSTRAINT %s UNIQUE USING INDEX %s;\n", c.row["table_name"], c.row["index_name"], c.row["index_name"])
111+
fmt.Printf("ALTER TABLE ONLY %s ADD CONSTRAINT %s UNIQUE USING INDEX %s;\n", c.get("table_name"), c.get("index_name"), c.get("index_name"))
66112
}
67113
}
68114
}
69115

70-
// Drop generates SQL to drop the index and/or the constraint related to it
71-
func (c IndexSchema) Drop() {
72-
fmt.Println("--\n--Drop\n--")
73-
if c.row["constraint_def"] != "null" {
116+
// Drop prints SQL to drop the column
117+
func (c *IndexSchema) Drop() {
118+
//fmt.Println("--\n--Drop\n--")
119+
if c.get("constraint_def") != "null" {
74120
fmt.Println("-- Warning, this may drop foreign keys pointing at this column. Make sure you re-run the FOREIGN_KEY diff after running this SQL.")
75-
//fmt.Printf("ALTER TABLE ONLY %s DROP CONSTRAINT IF EXISTS %s CASCADE; -- %s\n", c.row["table_name"], c.row["index_name"], c.row["constraint_def"])
76-
fmt.Printf("ALTER TABLE ONLY %s DROP CONSTRAINT IF EXISTS %s CASCADE;\n", c.row["table_name"], c.row["index_name"])
121+
//fmt.Printf("ALTER TABLE ONLY %s DROP CONSTRAINT IF EXISTS %s CASCADE; -- %s\n", c.get("table_name"), c.get("index_name"), c.get("constraint_def"))
122+
fmt.Printf("ALTER TABLE ONLY %s DROP CONSTRAINT IF EXISTS %s CASCADE;\n", c.get("table_name"), c.get("index_name"))
77123
}
78124
// The second line has no index_def
79-
//fmt.Printf("DROP INDEX IF EXISTS %s; -- %s \n", c.row["index_name"], c.row["index_def"])
80-
fmt.Printf("DROP INDEX IF EXISTS %s;\n", c.row["index_name"])
125+
//fmt.Printf("DROP INDEX IF EXISTS %s; -- %s \n", c.get("index_name"), c.get("index_def"))
126+
fmt.Printf("DROP INDEX IF EXISTS %s;\n", c.get("index_name"))
81127
}
82128

83-
// Change handles the case where the table and index name match, but the details do not
84-
func (c IndexSchema) Change(obj interface{}) {
129+
// Change handles the case where the table and column match, but the details do not
130+
func (c *IndexSchema) Change(obj interface{}) {
85131
c2, ok := obj.(*IndexSchema)
86132
if !ok {
87133
fmt.Println("-- Error!!!, change needs an IndexSchema instance", c2)
88134
}
89135
// Table and constraint name matches... We need to make sure the details match
90136

91137
// NOTE that there should always be an index_def for both c and c2 (but we're checking below anyway)
92-
if len(c.row["index_def"]) == 0 {
93-
fmt.Printf("-- Unexpected situation in index.go: index_def is empty for %v\n", c.row)
138+
if len(c.get("index_def")) == 0 {
139+
fmt.Printf("-- Change: Unexpected situation in index.go: index_def is empty for 1: %v 2:%v\n", c.getRow(), c2.getRow())
94140
return
95141
}
96-
if len(c2.row["index_def"]) == 0 {
97-
fmt.Printf("-- Unexpected situation in index.go: index_def is empty for %v\n", c2.row)
142+
if len(c2.get("index_def")) == 0 {
143+
fmt.Printf("-- Change: Unexpected situation in index.go: index_def is empty for 2: %v 1: %v\n", c2.getRow(), c.getRow())
98144
return
99145
}
100146

101-
if c.row["constraint_def"] != c2.row["constraint_def"] {
102-
fmt.Println("--\n--CHANGE: constraint defs different\n--")
147+
if c.get("constraint_def") != c2.get("constraint_def") {
103148
// c1.constraint and c2.constraint are just different
104-
fmt.Printf("-- Different defs:\n-- %s\n-- %s\n", c.row["constraint_def"], c2.row["constraint_def"])
105-
if c.row["constraint_def"] == "null" {
149+
fmt.Printf("-- CHANGE: Different defs:\n-- %s\n-- %s\n", c.get("constraint_def"), c2.get("constraint_def"))
150+
if c.get("constraint_def") == "null" {
106151
// c1.constraint does not exist, c2.constraint does, so
107152
// Drop constraint
108-
fmt.Printf("DROP INDEX IF EXISTS %s; -- %s \n", c2.row["index_name"], c2.row["index_def"])
109-
} else if c2.row["constraint_def"] == "null" {
153+
fmt.Printf("DROP INDEX IF EXISTS %s; -- %s \n", c2.get("index_name"), c2.get("index_def"))
154+
} else if c2.get("constraint_def") == "null" {
110155
// c1.constraint exists, c2.constraint does not, so
111156
// Add constraint
112-
if c.row["index_def"] == c2.row["index_def"] {
157+
if c.get("index_def") == c2.get("index_def") {
113158
// Indexes match, so
114159
// Add constraint using the index
115-
if c.row["pk"] == "true" {
160+
if c.get("pk") == "true" {
116161
// Add primary key using the index
117-
fmt.Printf("ALTER TABLE %s ADD CONSTRAINT %s PRIMARY KEY USING INDEX %s;\n", c.row["table_name"], c.row["index_name"], c.row["index_name"])
118-
} else if c.row["uq"] == "true" {
162+
fmt.Printf("ALTER TABLE %s ADD CONSTRAINT %s PRIMARY KEY USING INDEX %s;\n", c.get("table_name"), c.get("index_name"), c.get("index_name"))
163+
} else if c.get("uq") == "true" {
119164
// Add unique constraint using the index
120-
fmt.Printf("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE USING INDEX %s;\n", c.row["table_name"], c.row["index_name"], c.row["index_name"])
165+
fmt.Printf("ALTER TABLE %s ADD CONSTRAINT %s UNIQUE USING INDEX %s;\n", c.get("table_name"), c.get("index_name"), c.get("index_name"))
121166
} else {
122167

123168
}
124169
} else {
125170
// Drop the c2 index, create a copy of the c1 index
126-
fmt.Printf("DROP INDEX IF EXISTS %s; -- %s \n", c2.row["index_name"], c2.row["index_def"])
171+
fmt.Printf("DROP INDEX IF EXISTS %s; -- %s \n", c2.get("index_name"), c2.get("index_def"))
127172
}
128173
// WIP
129-
//fmt.Printf("ALTER TABLE %s ADD CONSTRAINT %s %s;\n", c.row["table_name"], c.row["index_name"], c.row["constraint_def"])
174+
//fmt.Printf("ALTER TABLE %s ADD CONSTRAINT %s %s;\n", c.get("table_name"), c.get("index_name"), c.get("constraint_def"))
130175

131-
} else if c.row["index_def"] != c2.row["index_def"] {
176+
} else if c.get("index_def") != c2.get("index_def") {
132177
// The constraints match
133178
}
134-
135-
} else if c.row["index_def"] != c2.row["index_def"] {
136-
if !strings.HasPrefix(c.row["index_def"], c2.row["index_def"]) &&
137-
!strings.HasPrefix(c2.row["index_def"], c.row["index_def"]) {
179+
} else if c.get("index_def") != c2.get("index_def") {
180+
if !strings.HasPrefix(c.get("index_def"), c2.get("index_def")) &&
181+
!strings.HasPrefix(c2.get("index_def"), c.get("index_def")) {
138182
fmt.Println("--\n--Change index defs different\n--")
139183
// Remember, if we are here, then the two constraint_defs match (both may be empty)
140184
// The indexes do not match, but the constraints do
141-
fmt.Printf("--CHANGE: Different index defs:\n-- %s\n-- %s\n", c.row["index_def"], c2.row["index_def"])
185+
fmt.Printf("--CHANGE: Different index defs:\n-- %s\n-- %s\n", c.get("index_def"), c2.get("index_def"))
142186

143187
// Drop the index (and maybe the constraint) so we can recreate the index
144188
c.Drop()
@@ -150,12 +194,16 @@ func (c IndexSchema) Change(obj interface{}) {
150194

151195
}
152196

197+
// ==================================
198+
// Functions
199+
// ==================================
200+
153201
/*
154-
* Compare the indexes in the two databases
202+
* Compare the columns in the two databases
155203
*/
156204
func compareIndexes(conn1 *sql.DB, conn2 *sql.DB) {
157205
// This SQL was generated with psql -E -c "\d t_org"
158-
// The magic is in pg_get_indexdef and pg_get_constraint
206+
// The "magic" is in pg_get_indexdef and pg_get_constraint
159207
sql := `
160208
SELECT c.relname AS table_name
161209
, c2.relname AS index_name
@@ -166,20 +214,31 @@ SELECT c.relname AS table_name
166214
, con.contype AS typ
167215
FROM pg_catalog.pg_index AS i
168216
JOIN pg_catalog.pg_class AS c ON (c.oid = i.indrelid)
169-
JOIN pg_catalog.pg_class AS c2 ON (c2.oid = i.indexrelid)
170-
LEFT JOIN pg_catalog.pg_constraint con
217+
JOIN pg_catalog.pg_class AS c2 ON (c2.oid = i.indexrelid)
218+
LEFT JOIN pg_catalog.pg_constraint con
171219
ON (con.conrelid = i.indrelid AND con.conindid = i.indexrelid AND con.contype IN ('p','u','x'))
172220
WHERE c.relname NOT LIKE 'pg_%'
173-
AND c.relname = 't_org'
174-
ORDER BY c.relname, c2.relname;
221+
--AND c.relname = 't_org'
222+
--ORDER BY c.relname, c2.relname;
175223
`
176-
177224
rowChan1, _ := pgutil.QueryStrings(conn1, sql)
178225
rowChan2, _ := pgutil.QueryStrings(conn2, sql)
179226

180-
// We have to explicitly type this as Schema for some reason
181-
var schema1 Schema = &IndexSchema{channel: rowChan1}
182-
var schema2 Schema = &IndexSchema{channel: rowChan2}
227+
rows1 := make(IndexRows, 0)
228+
for row := range rowChan1 {
229+
rows1 = append(rows1, row)
230+
}
231+
sort.Sort(rows1)
232+
233+
rows2 := make(IndexRows, 0)
234+
for row := range rowChan2 {
235+
rows2 = append(rows2, row)
236+
}
237+
sort.Sort(rows2)
238+
239+
// We have to explicitly type this as Schema here for some unknown reason
240+
var schema1 Schema = &IndexSchema{rows: rows1, rowNum: -1}
241+
var schema2 Schema = &IndexSchema{rows: rows2, rowNum: -1}
183242

184243
// Compare the columns
185244
doDiff(schema1, schema2)

pgdiff.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/bin/bash
2+
# pgdiff -U1 c42 -pw1 c422006 -d1 prd-cpc -o1 sslmode=disable -U2 c42 -pw2 c422006 -d2 cp_staging -o2 sslmode=disable COLUMN
23

34
USER1=c42
45
PASS1=c422006
@@ -9,7 +10,7 @@ OPT1="sslmode=disable"
910
USER2=c42
1011
PASS2=c422006
1112
HOST2=localhost
12-
NAME2=cp_staging
13+
NAME2=stg-cpc
1314
OPT2="sslmode=disable"
1415

1516
function rundiff() {
@@ -28,6 +29,6 @@ rundiff SEQUENCE
2829
rundiff TABLE
2930
rundiff COLUMN
3031
rundiff INDEX
31-
rundiff FOREIGN_KEY
32+
#rundiff FOREIGN_KEY
3233
#rundiff ROLE
3334

0 commit comments

Comments
 (0)