Skip to content

Commit 1e95a4c

Browse files
committed
WIP - Column data internal sort
1 parent 5e7dfb1 commit 1e95a4c

1 file changed

Lines changed: 97 additions & 50 deletions

File tree

column.go

Lines changed: 97 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,83 +6,114 @@ import "strings"
66
import "database/sql"
77
import "github.com/joncrlsn/pgutil"
88

9-
// ColumnSchema holds a channel streaming column data from one of the databases as well as
9+
// ==================================
10+
// ColumnRows definition
11+
// ==================================
12+
type ColumnRows []map[string]string
13+
14+
func (slice ColumnRows) Len() int {
15+
return len(slice)
16+
}
17+
18+
func (slice ColumnRows) Less(i, j int) bool {
19+
if slice[i]["table_name"] < slice[j]["table_name"] {
20+
return true
21+
}
22+
return slice[i]["column_name"] < slice[j]["column_name"]
23+
}
24+
25+
func (slice ColumnRows) Swap(i, j int) {
26+
slice[i], slice[j] = slice[j], slice[i]
27+
}
28+
29+
// ==================================
30+
// ColumnSchema definition
31+
// (implements Schema -- defined in pgdiff.go)
32+
// ==================================
33+
34+
// ColumnSchema holds a slice of rows from one of the databases as well as
1035
// a reference to the current row of data we're viewing.
11-
//
12-
// ColumnSchema implements the Schema interface defined in pgdiff.go
1336
type ColumnSchema struct {
14-
channel chan map[string]string
15-
row map[string]string
16-
done bool
37+
rows ColumnRows
38+
rowNum int
39+
done bool
1740
}
1841

19-
// NextRow reads from the channel and tells you if there are (probably) more or not
42+
// get returns the value from the current row for the given key
43+
func (c *ColumnSchema) get(key string) string {
44+
if c.rowNum >= len(c.rows) {
45+
return ""
46+
}
47+
return c.rows[c.rowNum][key]
48+
}
49+
50+
// NextRow increments the rowNum and tells you whether or not there are more
2051
func (c *ColumnSchema) NextRow() bool {
21-
c.row = <-c.channel
22-
if len(c.row) == 0 {
52+
if c.rowNum >= len(c.rows)-1 {
2353
c.done = true
2454
}
55+
c.rowNum = c.rowNum + 1
2556
return !c.done
2657
}
2758

2859
// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
29-
func (c ColumnSchema) Compare(obj interface{}) int {
60+
func (c *ColumnSchema) Compare(obj interface{}) int {
3061
c2, ok := obj.(*ColumnSchema)
3162
if !ok {
3263
fmt.Println("Error!!!, change needs a ColumnSchema instance", c2)
3364
}
3465

35-
val := _compareString(c.row["table_name"], c2.row["table_name"])
66+
val := _compareString(c.get("table_name"), c2.get("table_name"))
3667
if val != 0 {
3768
// Table name differed so return that value
3869
return val
3970
}
4071

4172
// Table name was the same so compare column name
42-
val = _compareString(c.row["column_name"], c2.row["column_name"])
73+
val = _compareString(c.get("column_name"), c2.get("column_name"))
4374
return val
4475
}
4576

46-
// Add returns SQL to add the column
47-
func (c ColumnSchema) Add() {
48-
if c.row["data_type"] == "character varying" {
49-
maxLength, valid := getMaxLength(c.row["character_maximum_length"])
77+
// Add prints SQL to add the column
78+
func (c *ColumnSchema) Add() {
79+
if c.get("data_type") == "character varying" {
80+
maxLength, valid := getMaxLength(c.get("character_maximum_length"))
5081
if !valid {
5182
fmt.Println("-- WARNING: varchar column has no maximum length. Set to 1024")
5283
}
53-
fmt.Printf("ALTER TABLE %s ADD COLUMN %s %s(%s)", c.row["table_name"], c.row["column_name"], c.row["data_type"], maxLength)
84+
fmt.Printf("ALTER TABLE %s ADD COLUMN %s %s(%s)", c.get("table_name"), c.get("column_name"), c.get("data_type"), maxLength)
5485
} else {
55-
fmt.Printf("ALTER TABLE %s ADD COLUMN %s %s", c.row["table_name"], c.row["column_name"], c.row["data_type"])
86+
fmt.Printf("ALTER TABLE %s ADD COLUMN %s %s", c.get("table_name"), c.get("column_name"), c.get("data_type"))
5687
}
5788

58-
if c.row["is_nullable"] == "NO" {
89+
if c.get("is_nullable") == "NO" {
5990
fmt.Printf(" NOT NULL")
6091
}
61-
if c.row["column_default"] != "null" {
62-
fmt.Printf(" DEFAULT %s", c.row["column_default"])
92+
if c.get("column_default") != "null" {
93+
fmt.Printf(" DEFAULT %s", c.get("column_default"))
6394
}
6495
fmt.Printf(";\n")
6596
}
6697

67-
// Drop returns SQL to drop the column
68-
func (c ColumnSchema) Drop() {
98+
// Drop prints SQL to drop the column
99+
func (c *ColumnSchema) Drop() {
69100
// if dropping column
70-
fmt.Printf("ALTER TABLE %s DROP COLUMN IF EXISTS %s;\n", c.row["table_name"], c.row["column_name"])
101+
fmt.Printf("ALTER TABLE %s DROP COLUMN IF EXISTS %s;\n", c.get("table_name"), c.get("column_name"))
71102
}
72103

73104
// Change handles the case where the table and column match, but the details do not
74-
func (c ColumnSchema) Change(obj interface{}) {
105+
func (c *ColumnSchema) Change(obj interface{}) {
75106
c2, ok := obj.(*ColumnSchema)
76107
if !ok {
77108
fmt.Println("Error!!!, ColumnSchema.Change(obj) needs a ColumnSchema instance", c2)
78109
}
79110

80111
// Detect column type change (mostly varchar length, or number size increase) (integer to/from bigint is OK)
81-
if c.row["data_type"] == c2.row["data_type"] {
82-
if c.row["data_type"] == "character varying" {
83-
max1, max1Valid := getMaxLength(c.row["character_maximum_length"])
84-
max2, max2Valid := getMaxLength(c2.row["character_maximum_length"])
85-
if (max1Valid || !max2Valid) && (max1 != c2.row["character_maximum_length"]) {
112+
if c.get("data_type") == c2.get("data_type") {
113+
if c.get("data_type") == "character varying" {
114+
max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
115+
max2, max2Valid := getMaxLength(c2.get("character_maximum_length"))
116+
if (max1Valid || !max2Valid) && (max1 != c2.get("character_maximum_length")) {
86117
if !max1Valid {
87118
fmt.Println("-- WARNING: varchar column has no maximum length. Setting to 1024")
88119
}
@@ -93,44 +124,48 @@ func (c ColumnSchema) Change(obj interface{}) {
93124
if max1Int < max2Int {
94125
fmt.Println("-- WARNING: The next statement will shorten a character varying column.")
95126
}
96-
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s TYPE character varying(%s);\n", c.row["table_name"], c.row["column_name"], max1)
127+
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s TYPE character varying(%s);\n", c.get("table_name"), c.get("column_name"), max1)
97128
}
98129
}
99130
}
100131

101132
// TODO: Code and test a column change from integer to bigint
102-
if c.row["data_type"] != c2.row["data_type"] {
103-
fmt.Printf("-- WARNING: This type change may not work well: (%s to %s).\n", c2.row["data_type"], c.row["data_type"])
104-
if strings.HasPrefix(c.row["data_type"], "character") {
105-
max1, max1Valid := getMaxLength(c.row["character_maximum_length"])
133+
if c.get("data_type") != c2.get("data_type") {
134+
fmt.Printf("-- WARNING: This type change may not work well: (%s to %s).\n", c2.get("data_type"), c.get("data_type"))
135+
if strings.HasPrefix(c.get("data_type"), "character") {
136+
max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
106137
if !max1Valid {
107138
fmt.Println("-- WARNING: varchar column has no maximum length. Setting to 1024")
108139
}
109-
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s TYPE %s(%s);\n", c.row["table_name"], c.row["column_name"], c.row["data_type"], max1)
140+
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s TYPE %s(%s);\n", c.get("table_name"), c.get("column_name"), c.get("data_type"), max1)
110141
} else {
111-
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s TYPE %s;\n", c.row["table_name"], c.row["column_name"], c.row["data_type"])
142+
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s TYPE %s;\n", c.get("table_name"), c.get("column_name"), c.get("data_type"))
112143
}
113144
}
114145

115146
// Detect column default change (or added, dropped)
116-
if c.row["column_default"] == "null" {
117-
if c.row["column_default"] != "null" {
118-
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT;\n", c.row["table_name"], c.row["column_name"])
147+
if c.get("column_default") == "null" {
148+
if c.get("column_default") != "null" {
149+
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT;\n", c.get("table_name"), c.get("column_name"))
119150
}
120-
} else if c.row["column_default"] != c2.row["column_default"] {
121-
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT %s;\n", c.row["table_name"], c.row["column_name"], c.row["column_default"])
151+
} else if c.get("column_default") != c2.get("column_default") {
152+
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT %s;\n", c.get("table_name"), c.get("column_name"), c.get("column_default"))
122153
}
123154

124155
// TODO Detect not-null and nullable change
125-
if c.row["is_nullable"] != c2.row["is_nullable"] {
126-
if c.row["is_nullable"] == "YES" {
127-
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s DROP NOT NULL;\n", c.row["table_name"], c.row["column_name"])
156+
if c.get("is_nullable") != c2.get("is_nullable") {
157+
if c.get("is_nullable") == "YES" {
158+
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s DROP NOT NULL;\n", c.get("table_name"), c.get("column_name"))
128159
} else {
129-
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s SET NOT NULL;\n", c.row["table_name"], c.row["column_name"])
160+
fmt.Printf("ALTER TABLE %s ALTER COLUMN %s SET NOT NULL;\n", c.get("table_name"), c.get("column_name"))
130161
}
131162
}
132163
}
133164

165+
// ==================================
166+
// Functions
167+
// ==================================
168+
134169
/*
135170
* Compare the columns in the two databases
136171
*/
@@ -150,15 +185,27 @@ ORDER by table_name, column_name COLLATE "C" ASC;`
150185
rowChan1, _ := pgutil.QueryStrings(conn1, sql)
151186
rowChan2, _ := pgutil.QueryStrings(conn2, sql)
152187

153-
// We have to explicitly type this as Schema for some reason
154-
var schema1 Schema = &ColumnSchema{channel: rowChan1}
155-
var schema2 Schema = &ColumnSchema{channel: rowChan2}
188+
//rows1 := make([]map[string]string, 500)
189+
rows1 := make(ColumnRows, 500)
190+
for row := range rowChan1 {
191+
rows1 = append(rows1, row)
192+
}
193+
194+
//rows2 := make([]map[string]string, 500)
195+
rows2 := make(ColumnRows, 500)
196+
for row := range rowChan2 {
197+
rows2 = append(rows2, row)
198+
}
199+
200+
// We have to explicitly type this as Schema here for some unknown reason
201+
var schema1 Schema = &ColumnSchema{rows: rows1, rowNum: -1}
202+
var schema2 Schema = &ColumnSchema{rows: rows2, rowNum: -1}
156203

157204
// Compare the columns
158205
doDiff(schema1, schema2)
159206
}
160207

161-
// getMaxLength returns the maximum length and whether or not it is valie
208+
// getMaxLength returns the maximum length and whether or not it is valid
162209
func getMaxLength(maxLength string) (string, bool) {
163210

164211
if maxLength == "null" {

0 commit comments

Comments
 (0)