66
77package main
88
9- import "sort"
10- import "fmt"
11- import "strconv"
12- import "strings"
13- import "database/sql"
14- import "github.com/joncrlsn/pgutil"
15- import "github.com/joncrlsn/misc"
9+ import (
10+ "sort"
11+ "fmt"
12+ "strconv"
13+ "strings"
14+ "database/sql"
15+ "github.com/joncrlsn/pgutil"
16+ "github.com/joncrlsn/misc"
17+ "text/template"
18+ "bytes"
19+ )
20+
21+ var (
22+ columnSqlTemplate = initColumnSqlTemplate ()
23+ )
24+
25+ // Initializes the Sql template
26+ func initColumnSqlTemplate () * template.Template {
27+ sql := `
28+ SELECT table_schema
29+ , {{if eq $.DbSchema "*" }}table_schema || '.' || {{end}}table_name AS compare_name
30+ , table_name
31+ , column_name
32+ , data_type
33+ , is_nullable
34+ , column_default
35+ , character_maximum_length
36+ FROM information_schema.columns
37+ WHERE is_updatable = 'YES'
38+ {{if eq $.DbSchema "*" }}
39+ AND table_schema NOT LIKE 'pg_%'
40+ AND table_schema <> 'information_schema'
41+ {{else}}
42+ AND table_schema = '{{$.DbSchema}}'
43+ {{end}}
44+ ORDER BY compare_name, column_name;
45+ `
46+ t := template .New ("ColumnSqlTmpl" )
47+ template .Must (t .Parse (sql ))
48+ return t
49+ }
50+
1651
1752// ==================================
1853// Column Rows definition
@@ -26,8 +61,8 @@ func (slice ColumnRows) Len() int {
2661}
2762
2863func (slice ColumnRows ) Less (i , j int ) bool {
29- if slice [i ]["table_name " ] != slice [j ]["table_name " ] {
30- return slice [i ]["table_name " ] < slice [j ]["table_name " ]
64+ if slice [i ]["compare_name " ] != slice [j ]["compare_name " ] {
65+ return slice [i ]["column_name " ] < slice [j ]["compare_name " ]
3166 }
3267 return slice [i ]["column_name" ] < slice [j ]["column_name" ]
3368}
@@ -73,7 +108,7 @@ func (c *ColumnSchema) Compare(obj interface{}) int {
73108 fmt .Println ("Error!!!, Compare needs a ColumnSchema instance" , c2 )
74109 }
75110
76- val := misc .CompareStrings (c .get ("table_name " ), c2 .get ("table_name " ))
111+ val := misc .CompareStrings (c .get ("compare_name " ), c2 .get ("compare_name " ))
77112 if val != 0 {
78113 // Table name differed so return that value
79114 return val
@@ -85,19 +120,24 @@ func (c *ColumnSchema) Compare(obj interface{}) int {
85120}
86121
87122// Add prints SQL to add the column
88- func (c * ColumnSchema ) Add () {
123+ func (c * ColumnSchema ) Add (obj interface {}) {
124+ c2 , ok := obj .(* ColumnSchema )
125+ if ! ok {
126+ fmt .Println ("Error!!!, ColumnSchema.Add(obj) needs a ColumnSchema instance" , c2 )
127+ }
128+
89129 if c .get ("data_type" ) == "character varying" {
90130 maxLength , valid := getMaxLength (c .get ("character_maximum_length" ))
91131 if ! valid {
92- fmt .Printf ("ALTER TABLE %s ADD COLUMN %s character varying" , c .get ("table_name" ), c .get ("column_name" ))
132+ fmt .Printf ("ALTER TABLE %s.%s ADD COLUMN %s character varying" , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ))
93133 } else {
94- fmt .Printf ("ALTER TABLE %s ADD COLUMN %s character varying(%s)" , c .get ("table_name" ), c .get ("column_name" ), maxLength )
134+ fmt .Printf ("ALTER TABLE %s.%s ADD COLUMN %s character varying(%s)" , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ), maxLength )
95135 }
96136 } else {
97137 if c .get ("data_type" ) == "ARRAY" {
98138 fmt .Println ("-- Note that adding of array data types are not yet generated properly." )
99139 }
100- fmt .Printf ("ALTER TABLE %s ADD COLUMN %s %s" , c .get ("table_name" ), c .get ("column_name" ), c .get ("data_type" ))
140+ fmt .Printf ("ALTER TABLE %s.%s ADD COLUMN %s %s" , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ), c .get ("data_type" ))
101141 }
102142
103143 if c .get ("is_nullable" ) == "NO" {
@@ -110,9 +150,13 @@ func (c *ColumnSchema) Add() {
110150}
111151
112152// Drop prints SQL to drop the column
113- func (c * ColumnSchema ) Drop () {
153+ func (c * ColumnSchema ) Drop (obj interface {}) {
154+ c2 , ok := obj .(* ColumnSchema )
155+ if ! ok {
156+ fmt .Println ("Error!!!, ColumnSchema.Drop(obj) needs a ColumnSchema instance" , c2 )
157+ }
114158 // if dropping column
115- fmt .Printf ("ALTER TABLE %s DROP COLUMN IF EXISTS %s;\n " , c .get ("table_name" ), c .get ("column_name" ))
159+ fmt .Printf ("ALTER TABLE %s.%s DROP COLUMN IF EXISTS %s;\n " , c2 .get ("table_schema" ), c2 . get ( " table_name" ), c2 .get ("column_name" ))
116160}
117161
118162// Change handles the case where the table and column match, but the details do not
@@ -122,7 +166,7 @@ func (c *ColumnSchema) Change(obj interface{}) {
122166 fmt .Println ("Error!!!, ColumnSchema.Change(obj) needs a ColumnSchema instance" , c2 )
123167 }
124168
125- // Detect column type change (mostly varchar length, or number size increase)
169+ // Detect column type change (mostly varchar length, or number size increase)
126170 // (integer to/from bigint is OK)
127171 if c .get ("data_type" ) == c2 .get ("data_type" ) {
128172 if c .get ("data_type" ) == "character varying" {
@@ -141,8 +185,8 @@ func (c *ColumnSchema) Change(obj interface{}) {
141185 if max1Int < max2Int {
142186 fmt .Println ("-- WARNING: The next statement will shorten a character varying column, which may result in data loss." )
143187 }
144- fmt .Printf ("-- max1Valid: %v max2Valid: %v " , max1Valid , max2Valid )
145- fmt .Printf ("ALTER TABLE %s ALTER COLUMN %s TYPE character varying(%s);\n " , c .get ("table_name" ), c .get ("column_name" ), max1 )
188+ fmt .Printf ("-- max1Valid: %v max2Valid: %v \n " , max1Valid , max2Valid )
189+ fmt .Printf ("ALTER TABLE %s.%s ALTER COLUMN %s TYPE character varying(%s);\n " , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ), max1 )
146190 }
147191 }
148192 }
@@ -155,27 +199,27 @@ func (c *ColumnSchema) Change(obj interface{}) {
155199 if ! max1Valid {
156200 fmt .Println ("-- WARNING: varchar column has no maximum length. Setting to 1024" )
157201 }
158- 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 )
202+ fmt .Printf ("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s(%s);\n " , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ), c .get ("data_type" ), max1 )
159203 } else {
160- fmt .Printf ("ALTER TABLE %s ALTER COLUMN %s TYPE %s;\n " , c .get ("table_name" ), c .get ("column_name" ), c .get ("data_type" ))
204+ fmt .Printf ("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s;\n " , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ), c .get ("data_type" ))
161205 }
162206 }
163207
164208 // Detect column default change (or added, dropped)
165209 if c .get ("column_default" ) == "null" {
166210 if c .get ("column_default" ) != "null" {
167- fmt .Printf ("ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT;\n " , c .get ("table_name" ), c .get ("column_name" ))
211+ fmt .Printf ("ALTER TABLE %s.%s ALTER COLUMN %s DROP DEFAULT;\n " , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ))
168212 }
169213 } else if c .get ("column_default" ) != c2 .get ("column_default" ) {
170- fmt .Printf ("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT %s;\n " , c .get ("table_name" ), c .get ("column_name" ), c .get ("column_default" ))
214+ fmt .Printf ("ALTER TABLE %s.%s ALTER COLUMN %s SET DEFAULT %s;\n " , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ), c .get ("column_default" ))
171215 }
172216
173217 // Detect not-null and nullable change
174218 if c .get ("is_nullable" ) != c2 .get ("is_nullable" ) {
175219 if c .get ("is_nullable" ) == "YES" {
176- fmt .Printf ("ALTER TABLE %s ALTER COLUMN %s DROP NOT NULL;\n " , c .get ("table_name" ), c .get ("column_name" ))
220+ fmt .Printf ("ALTER TABLE %s.%s ALTER COLUMN %s DROP NOT NULL;\n " , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ))
177221 } else {
178- fmt .Printf ("ALTER TABLE %s ALTER COLUMN %s SET NOT NULL;\n " , c .get ("table_name" ), c .get ("column_name" ))
222+ fmt .Printf ("ALTER TABLE %s.%s ALTER COLUMN %s SET NOT NULL;\n " , c2 . get ( "table_schema" ) , c .get ("table_name" ), c .get ("column_name" ))
179223 }
180224 }
181225}
@@ -188,21 +232,15 @@ func (c *ColumnSchema) Change(obj interface{}) {
188232 * Compare the columns in the two databases
189233 */
190234func compareColumns (conn1 * sql.DB , conn2 * sql.DB ) {
191- sql := `
192- SELECT table_schema || '.' || table_name AS table_name
193- , column_name
194- , data_type
195- , is_nullable
196- , column_default
197- , character_maximum_length
198- FROM information_schema.columns
199- WHERE table_schema NOT LIKE 'pg_%'
200- AND table_schema <> 'information_schema'
201- AND is_updatable = 'YES'
202- ORDER BY table_name, column_name;`
235+
236+ buf1 := new (bytes.Buffer )
237+ columnSqlTemplate .Execute (buf1 , dbInfo1 )
203238
204- rowChan1 , _ := pgutil .QueryStrings (conn1 , sql )
205- rowChan2 , _ := pgutil .QueryStrings (conn2 , sql )
239+ buf2 := new (bytes.Buffer )
240+ columnSqlTemplate .Execute (buf2 , dbInfo2 )
241+
242+ rowChan1 , _ := pgutil .QueryStrings (conn1 , buf1 .String ())
243+ rowChan2 , _ := pgutil .QueryStrings (conn2 , buf2 .String ())
206244
207245 //rows1 := make([]map[string]string, 500)
208246 rows1 := make (ColumnRows , 0 )
@@ -218,6 +256,15 @@ ORDER BY table_name, column_name;`
218256 }
219257 sort .Sort (& rows2 )
220258
259+ //for _, val := range rows1 {
260+ //fmt.Println("list1: ", val["table_schema"], val["compare_name"], val["column_name"], val["character_maximum_length"] )
261+ //}
262+ //fmt.Println()
263+
264+ //for _, val := range rows2 {
265+ //fmt.Println("list2: ", val["table_schema"], val["compare_name"], val["column_name"], val["character_maximum_length"])
266+ //}
267+
221268 // We have to explicitly type this as Schema here for some unknown reason
222269 var schema1 Schema = & ColumnSchema {rows : rows1 , rowNum : - 1 }
223270 var schema2 Schema = & ColumnSchema {rows : rows2 , rowNum : - 1 }
0 commit comments