Skip to content

Commit fce5b8d

Browse files
committed
Release 0.9.1 first commit
Former-commit-id: 1ff96bf
1 parent 2cb4e89 commit fce5b8d

9 files changed

Lines changed: 181 additions & 101 deletions

File tree

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2014 Jon Carlson
3+
Copyright (c) 2016 Jon Carlson
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# pgdiff - PostgreSQL schema diff
22

3-
An important feature of this utility is that it never modifies any database directly. You are solely responsible for verifying the generated SQL *before* running it against your database. Now that you know about that, it should give you confidence that it is safe to try out and see what SQL gets generated.
3+
pgdiff compares the schema between two PostgreSQL databases and generates alter statements to be *manually* run against the second database. The provided pgdiff.sh script helps automate the process. At the moment, not everything in the schema is compared, but the things considered important are: roles, sequences, tables, columns (and their default values), primary keys, unique constraints, foreign keys, roles, ownership information, and grants.
44

5-
Written in GoLang, pgdiff compares the schema between two PostgreSQL databases and generates alter statements to be *manually* run against the second database. At the moment, not everything in the schema is compared, but the things considered important are: roles, sequences, tables, columns (and their default values), primary keys, unique constraints, foreign keys, roles, ownership information, and grants.
5+
An important feature is that pgdiff never modifies a database directly. You alone are responsible for verifying the generated SQL *before* running it against your database, so you can have confidence this is safe to try and see what SQL gets generated.
66

77
It is written to be easy to add and improve the accuracy of the diff. If you find something that seems wrong and you want me to look at it, please send me two schema-only database dumps that I can test with (Use the --schema-only option with pg\_dump)
88

@@ -17,20 +17,25 @@ It is written to be easy to add and improve the accuracy of the diff. If you fi
1717

1818
### usage
1919

20-
pgdiff [database flags] <schemaType>
20+
pgdiff [options] <schemaType>
2121

2222

23-
program flags | Explanation
24-
-------------: | ------------------------------------
25-
-U1 | first db postgres user
26-
-pw1 | first db password
27-
-h1 | first db host -- default is localhost
28-
-p1 | first db port number. defaults to 5432
29-
-d1 | first db name
30-
-U2 | second db postgres user
31-
-pw2 | second db password
32-
-h2 | second db host -- default is localhost
33-
-p2 | second db port number. defaults to 5432
34-
-d2 | second db name
23+
### options
3524

36-
&lt;schemaType&gt; the type of objects in the schema to compare: ALL, ROLE, SEQUENCE, TABLE, COLUMN, INDEX, FOREIGN_KEY, OWNER, GRANT_RELATIONSHIP, GRANT_ATTRIBUTE
25+
options | explanation
26+
----------------: | ------------------------------------
27+
-V, --version | prints the version of pgdiff being used
28+
-?, --help | displays helpful usage information
29+
-U, --user1 | first postgres user
30+
-u, --user2 | second postgres user
31+
-W, --password1 | first db password
32+
-w, --password2 | second db password
33+
-H, --host1 | first db host. default is localhost
34+
-h, --host2 | second db host. default is localhost
35+
-P, --port1 | first db port number. default is 5432
36+
-p, --port2 | second db port number. default is 5432
37+
-D, --dbname1 | first db name
38+
-d, --dbname2 | second db name
39+
40+
41+
&lt;schemaType&gt; can be: ROLE, SEQUENCE, TABLE, COLUMN, INDEX, FOREIGN_KEY, OWNER, GRANT_RELATIONSHIP, GRANT_ATTRIBUTE

flags.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
//
22
// Copyright (c) 2014 Jon Carlson. All rights reserved.
3-
// Use of this source code is governed by an MIT-style
3+
// Use of this source code is governed by the MIT
44
// license that can be found in the LICENSE file.
55
//
66

77
package main
88

9-
import "flag"
10-
import "github.com/joncrlsn/pgutil"
9+
import (
10+
"github.com/joncrlsn/pgutil"
11+
flag "github.com/ogier/pflag"
12+
)
1113

1214
func parseFlags() (pgutil.DbInfo, pgutil.DbInfo) {
1315

14-
var dbUser1 = flag.String("U1", "", "db user")
15-
var dbPass1 = flag.String("pw1", "", "db password")
16-
var dbHost1 = flag.String("h1", "localhost", "db host")
17-
var dbPort1 = flag.Int("p1", 5432, "db port")
18-
var dbName1 = flag.String("d1", "", "db name")
19-
var dbOptions1 = flag.String("o1", "", "db options (eg. sslmode=disable)")
20-
21-
var dbUser2 = flag.String("U2", "", "db user")
22-
var dbPass2 = flag.String("pw2", "", "db password")
23-
var dbHost2 = flag.String("h2", "localhost", "db host")
24-
var dbPort2 = flag.Int("p2", 5432, "db port")
25-
var dbName2 = flag.String("d2", "", "db name")
26-
var dbOptions2 = flag.String("o2", "", "db options (eg. sslmode=disable)")
16+
var dbUser1 = flag.StringP("user1", "U", "", "db user")
17+
var dbPass1 = flag.StringP("password1", "W", "", "db password")
18+
var dbHost1 = flag.StringP("host1", "H", "localhost", "db host")
19+
var dbPort1 = flag.IntP("port1", "P", 5432, "db port")
20+
var dbName1 = flag.StringP("dbname1", "D", "", "db name")
21+
var dbOptions1 = flag.StringP("options1", "O", "", "db options (eg. sslmode=disable)")
22+
23+
var dbUser2 = flag.StringP("user2", "u", "", "db user")
24+
var dbPass2 = flag.StringP("password2", "w", "", "db password")
25+
var dbHost2 = flag.StringP("host2", "h", "localhost", "db host")
26+
var dbPort2 = flag.IntP("port2", "p", 5432, "db port")
27+
var dbName2 = flag.StringP("dbname2", "d", "", "db name")
28+
var dbOptions2 = flag.StringP("options2", "o", "", "db options (eg. sslmode=disable)")
2729

2830
flag.Parse()
2931

index.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import "fmt"
1111
import "strings"
1212
import "database/sql"
1313
import "github.com/joncrlsn/pgutil"
14+
import "github.com/joncrlsn/misc"
1415

1516
// ==================================
1617
// IndexRows definition
@@ -86,14 +87,14 @@ func (c *IndexSchema) Compare(obj interface{}) int {
8687
fmt.Printf("--Comparing (table_name or index_name is empty): %v\n-- %v\n", c.getRow(), c2.getRow())
8788
}
8889

89-
val := _compareString(c.get("table_name"), c2.get("table_name"))
90+
val := misc.CompareStrings(c.get("table_name"), c2.get("table_name"))
9091
if val != 0 {
9192
// Table name differed so return that value
9293
return val
9394
}
9495

9596
// Table name was the same so compare index name
96-
val = _compareString(c.get("index_name"), c2.get("index_name"))
97+
val = misc.CompareStrings(c.get("index_name"), c2.get("index_name"))
9798
return val
9899
}
99100

owner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func (c OwnerSchema) Add() {
8686
if c.get("type") == "TABLE" || c.get("type") == "SEQUENCE" {
8787
fmt.Printf("-- Notice, db2 has no %s. You probably need to run pgdiff with the %s option first.\n", c.get("relationship_name"), c.get("type"))
8888
} else if c.get("type") == "VIEW" {
89-
fmt.Printf("-- Notice, db2 has no view named %s. pgdiff does not yet compare view definitions.\n", c.get("relationship_name"))
89+
fmt.Printf("-- Notice, db2 has no view named %s. Cannot compare owners. (pgdiff does not (yet?) generate view definitions)\n", c.get("relationship_name"))
9090
}
9191
}
9292

@@ -95,7 +95,7 @@ func (c OwnerSchema) Drop() {
9595
if c.get("type") == "TABLE" || c.get("type") == "SEQUENCE" {
9696
fmt.Printf("-- Notice, db2 has a %s that db1 does not: %s. \n", c.get("type"), c.get("relationship_name"))
9797
} else if c.get("type") == "VIEW" {
98-
fmt.Printf("-- Notice, db2 has a view that db1 does not: %s. pgdiff does not yet compare view definitions.\n", c.get("relationship_name"))
98+
fmt.Printf("-- Notice, db2 has a view that db1 does not: %s. Cannot compare owners.\n", c.get("relationship_name"))
9999
}
100100
}
101101

pgdiff.go

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
//
2-
// Copyright (c) 2014 Jon Carlson. All rights reserved.
3-
// Use of this source code is governed by an MIT-style
2+
// Copyright (c) 2016 Jon Carlson. All rights reserved.
3+
// Use of this source code is governed by the MIT
44
// license that can be found in the LICENSE file.
55
//
66

77
package main
88

99
import "fmt"
1010
import "log"
11-
import "flag"
11+
import flag "github.com/ogier/pflag"
1212
import "os"
1313
import "strings"
1414
import _ "github.com/lib/pq"
@@ -24,10 +24,16 @@ type Schema interface {
2424
NextRow() bool
2525
}
2626

27-
var args []string
28-
var dbInfo1 pgutil.DbInfo
29-
var dbInfo2 pgutil.DbInfo
30-
var schemaType string
27+
const (
28+
version = "0.9.1"
29+
)
30+
31+
var (
32+
args []string
33+
dbInfo1 pgutil.DbInfo
34+
dbInfo2 pgutil.DbInfo
35+
schemaType string
36+
)
3137

3238
/*
3339
* Initialize anything needed later
@@ -40,18 +46,36 @@ func init() {
4046
*/
4147
func main() {
4248

49+
var helpPtr = flag.BoolP("help", "?", false, "print help information")
50+
var versionPtr = flag.BoolP("version", "V", false, "print version information")
51+
4352
dbInfo1, dbInfo2 = parseFlags()
44-
fmt.Println("-- db1:", dbInfo1)
45-
fmt.Println("-- db2:", dbInfo2)
46-
fmt.Println("-- Run the following SQL againt db2:")
4753

4854
// Remaining args:
4955
args = flag.Args()
56+
57+
if *helpPtr {
58+
usage()
59+
}
60+
61+
if *versionPtr {
62+
fmt.Fprintf(os.Stderr, "%s - version %s\n", os.Args[0], version)
63+
fmt.Fprintln(os.Stderr, "Copyright (c) 2016 Jon Carlson. All rights reserved.")
64+
fmt.Fprintln(os.Stderr, "Use of this source code is governed by the MIT license")
65+
fmt.Fprintln(os.Stderr, "that can be found here: http://opensource.org/licenses/MIT")
66+
os.Exit(1)
67+
}
68+
5069
if len(args) == 0 {
5170
fmt.Println("The required first argument is SchemaType: ROLE, SEQUENCE, TABLE, COLUMN, INDEX, FOREIGN_KEY, OWNER, GRANT_RELATIONSHIP, GRANT_ATTRIBUTE")
5271
os.Exit(1)
5372
}
5473
schemaType = strings.ToUpper(args[0])
74+
fmt.Println("-- schemaType:", schemaType)
75+
76+
fmt.Println("-- db1:", dbInfo1)
77+
fmt.Println("-- db2:", dbInfo2)
78+
fmt.Println("-- Run the following SQL againt db2:")
5579

5680
conn1, err := dbInfo1.Open()
5781
check("opening database 1", err)
@@ -135,24 +159,26 @@ func doDiff(db1 Schema, db2 Schema) {
135159
}
136160

137161
func usage() {
138-
fmt.Fprintf(os.Stderr, "usage: %s [database flags] <schemaType> \n", os.Args[0])
162+
fmt.Fprintf(os.Stderr, "%s - version %s\n", os.Args[0], version)
163+
fmt.Fprintf(os.Stderr, "usage: %s [<options>] <schemaType> \n", os.Args[0])
139164
fmt.Fprintln(os.Stderr, `
140165
Compares the schema between two PostgreSQL databases and generates alter statements
141-
to be *manually* run against the second database.
142-
143-
[database flags]: (optional)
144-
-U1 : postgres user (matches psql flag)
145-
-h1 : database host -- default is localhost (matches psql flag)
146-
-p1 : port. defaults to 5432 (matches psql flag)
147-
-d1 : database name (matches psql flag)
148-
-pw1 : password for the postgres user (otherwise you'll be prompted)
149-
-U2 : postgres user (matches psql flag)
150-
-h2 : database host -- default is localhost (matches psql flag)
151-
-p2 : port. defaults to 5432 (matches psql flag)
152-
-d2 : database name (matches psql flag)
153-
-pw2 : password for the postgres user (otherwise you'll be prompted)
154-
155-
<schemaTpe> : type of schema to check: TABLE, COLUMN, FOREIGN_KEY (soon: CONSTRAINT, ROLE)
166+
that can be *manually* run against the second database.
167+
168+
Options:
169+
-?, --help : print help information
170+
-V, --version : print version information
171+
-v, --verbose : print extra run information
172+
-U, --user1 : first postgres user
173+
-u, --user2 : second postgres user
174+
-H, --host1 : first database host. default is localhost
175+
-h, --host2 : second database host. default is localhost
176+
-P, --port1 : first port. default is 5432
177+
-p, --port2 : second port. default is 5432
178+
-D, --dbname1 : first database name
179+
-d, --dbname2 : second database name
180+
181+
<schemaTpe> can be: ROLE, SEQUENCE, TABLE, COLUMN, INDEX, FOREIGN_KEY, OWNER, GRANT_RELATIONSHIP, GRANT_ATTRIBUTE
156182
`)
157183

158184
os.Exit(2)
@@ -163,13 +189,3 @@ func check(msg string, err error) {
163189
log.Fatal("Error "+msg, err)
164190
}
165191
}
166-
167-
func _compareString(s1 string, s2 string) int {
168-
if s1 == s2 {
169-
return 0
170-
} else if s1 < s2 {
171-
return -1
172-
} else {
173-
return +1
174-
}
175-
}

pgdiff.sh

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,51 @@
11
#!/bin/bash
22
#
3-
# pgdiff.sh runs a compare on each database type in the proper order. At each step you are allowed to review
3+
# pgdiff.sh runs a compare on each schema type in the proper order. At each step you are allowed to review
44
# and optionally change and/or run the generated SQL.
55
#
66
# If you convert this to a windows batch file, please share it.
77
#
8-
# pgdiff -U1 postgres -pw1 supersecret -d1 maindb -o1 sslmode=disable -U2 postgres -pw2 supersecret -d2 stagingdb -o2 sslmode=disable COLUMN
8+
# pgdiff -U postgres -W supersecret -D maindb -O sslmode=disable -u postgres -w supersecret -d stagingdb -o sslmode=disable COLUMN
99
#
1010

11-
USER1=c42
12-
HOST1=dbwan
13-
NAME1=crashplan
14-
OPT1=
11+
[[ -z $USER1 ]] && USER1=c42
12+
[[ -z $HOST1 ]] && HOST1=localhost
13+
[[ -z $NAME1 ]] && NAME1=cp
14+
[[ -z $OPT1 ]] && OPT1='sslmode=disable'
1515

16-
USER2=c42
17-
HOST2=fkd-msp
18-
NAME2=cp_staging
19-
OPT2=
16+
[[ -z $USER2 ]] && USER2=c42
17+
[[ -z $HOST2 ]] && HOST2=localhost
18+
[[ -z $NAME2 ]] && NAME2=cp-pentest
19+
[[ -z $OPT2 ]] && OPT2='sslmode=disable'
2020

21-
echo -n "Enter password: "; read passw
21+
echo "This is the reference database:"
22+
echo " ${USER1}@${HOST1}/$NAME1"
23+
read -sp "Enter DB password: " passw
2224
PASS1=$passw
2325
PASS2=$passw
2426

27+
echo
28+
echo "This database may be changed (if you choose):"
29+
echo " ${USER2}@${HOST2}/$NAME2"
30+
read -sp "Enter DB password (defaults to previous password): " passw
31+
[[ -n $passw ]] && PASS2=$passw
32+
echo
33+
34+
let i=0
2535
function rundiff() {
36+
((i++))
2637
local TYPE=$1
27-
echo "Generating diff for $TYPE..."
28-
pgdiff -U1 $USER1 -pw1 $PASS1 -h1 $HOST1 -d1 $NAME1 -o1 "$OPT1" -U2 $USER2 -pw2 $PASS2 -h2 $HOST2 -d2 $NAME2 -o2 "$OPT2" $TYPE > "${TYPE}.sql"
38+
local sqlFile="${i}-${TYPE}.sql"
39+
echo "Generating diff for $TYPE... $PASS1"
40+
./pgdiff -U "$USER1" -W "$PASS1" -H "$HOST1" -D "$NAME1" -O "$OPT1" \
41+
-u "$USER2" -w "$PASS2" -h "$HOST2" -d "$NAME2" -o "$OPT2" \
42+
$TYPE > "$sqlFile"
2943
RC=$? && [[ $RC != 0 ]] && exit $RC
3044
echo -n "Press Enter to review the generated output: "; read x
31-
vi "${TYPE}.sql"
45+
vi "$sqlFile"
3246
echo -n "Do you wish to run this against ${NAME2}? [yN]: "; read x
33-
if [[ $x =~ y ]]; then
34-
pgrun -U $USER2 -pw $PASS2 -h $HOST2 -d $NAME2 -o "$OPT2" -f "${TYPE}.sql"
47+
if [[ $x =~ ^y ]]; then
48+
PGPASSWORD="$PASS2" pgrun -U $USER2 -h $HOST2 -d $NAME2 -O "$OPT2" -f "$sqlFile"
3549
fi
3650
echo
3751
}

0 commit comments

Comments
 (0)