#!/usr/bin/python # pg_diff v0.2 # Utility to display differences between PostgreSQL databases __author__ = "Anoop Menon " __license__ = "GPL" __version__ = "0.2" __date__ = "07/07/2007" import sys import os import pg import commands from sets import * def showUsage(): print """ pg_diff v%s (%s) %s, Copyright 2007. pg_diff is a program that displays the table differences between two PostgreSQL databases. By default, it will print out the list of tables that are different between the two databases. It can optionally also print out the exact differences in schema. It does NOT compare the data in the tables. Usage: pg_diff [options] -s Also print table creation SQL (uses pg_dump) -d Search for differences in the attributes (used for finding column additions or deletions) NOTE: currently it defaults to username 'postgres' and hostname 'localhost' for both databases. """ % (__version__, __author__, __date__) class PGDiff: def __init__(self, db1, db2, u1="postgres", u2="postgres", p1=None, p2=None, h1="localhost", h2="localhost", sql=0): self._db1name = db1 self._db2name = db2 self._db1user = u1 self._db2user = u2 self._db1pass = p1 self._db2pass = p2 self._db1host = h1 self._db2host = h2 self._db1 = pg.DB(dbname=self._db1name, host=self._db1host, user=self._db1user) self._db2 = pg.DB(dbname=self._db2name, host=self._db2host, user=self._db2user) self._sql = sql def printTableAttrDiff(self, db1, db2, table): att1 = db1.get_attnames(table) att2 = db2.get_attnames(table) a1diff = dict() a2diff = dict() for a in att1.items(): if a not in att2.items(): a1diff[a[0]] = a[1] for a in att2.items(): if a not in att1.items(): a2diff[a[0]] = a[1] if len(a2diff)>0 or len(a1diff)>0: print "\nThere are differences in the table '%s'" % table head = "-".ljust(67).replace(" ", "-") print head print "| %s | %s |" % (self._db1name.ljust(30), self._db2name.ljust(30)) print head if len(a1diff)>0: right = "|".rjust(34) for aname,atype in a1diff.items(): print str("| "+aname+": "+atype).ljust(33)+"|"+"|".rjust(33) if len(a2diff)>0: left = "| ".rjust(34) for aname,atype in a2diff.items(): print "|"+left+str(aname+": "+atype).ljust(31)+"|" print head return def printTableAttr(self, db, table): attr = db.get_attnames(table) attnsize = 0 atttsize = 0 for attname,atttype in attr.items(): if len(attname)>attnsize: attnsize = len(attname) if len(atttype)>atttsize: atttsize = len(atttype) attnsize+=2 atttsize+=2 hsize = attnsize+atttsize+7 head = "" for a in range(0,hsize): head+="-" print head for attname,atttype in attr.items(): print "| %s | %s |" %(attname.ljust(attnsize), atttype.rjust(atttsize)) print head def printTableSQL(self, db, table): cmd = "pg_dump -O -U postgres %s -s -t %s" % (db, table) (st,out) = commands.getstatusoutput(cmd) print out def printDiffTables(self, deep=0): s1 = Set(self._db1.get_tables()) s2 = Set(self._db2.get_tables()) d1 = [ a for a in s1-s2 ] d2 = [ a for a in s2-s1 ] head ="" if len(d1)>0: msg = "Tables in '%s' that are not in '%s'" % (self._db1name,self._db2name) head = "" for a in range(0,len(msg)): head+="=" print head print msg print head,"\n" for t in d1: print "***************************************" print "* %s *" % t.center(35) print "***************************************" self.printTableAttr(self._db1, t) print "" if self._sql: print "Table creating SQL:" self.printTableSQL(self._db1name, t) if len(d2)>0: msg = "Tables in '%s' that are not in '%s'" % (self._db2name,self._db1name) print head print msg print head,"\n" for t in d2: print "***************************************" print "* %s *" % t.center(35) print "***************************************" self.printTableAttr(self._db2, t) print "" if self._sql: print "Table creating SQL:" self.printTableSQL(self._db2name, t) if deep: msg = " Tables that are in both databases but have different attributes" head = "=================================================================" print head print msg print head d = s1.intersection(s2) #common tables for t in d: self.printTableAttrDiff(self._db1, self._db2, t) def main(argv): try: db1 = argv[1] db2 = argv[2] except: showUsage() return showsql = 0 deep = 0 try: for a in argv[3:]: if a=="-s": showsql = 1 if a=="-d": deep = 1 except: pass try: pgdiff = PGDiff(db1, db2, sql=showsql) print "" pgdiff.printDiffTables(deep) print "" except Exception,e: print str(e) if __name__=="__main__": main(sys.argv)