Diff for /ZSQLExtend/importFMPXML.py between versions 1.20 and 1.29

version 1.20, 2008/01/09 14:23:26 version 1.29, 2009/02/10 17:54:00
Line 12  from amara import saxtools Line 12  from amara import saxtools
   
 try:  try:
     import psycopg2 as psycopg      import psycopg2 as psycopg
       import psycopg2.extensions
       # switch to unicode
       psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
     psyco = 2      psyco = 2
 except:  except:
     import psycopg      import psycopg
Line 19  except: Line 22  except:
   
 fm_ns = 'http://www.filemaker.com/fmpxmlresult'  fm_ns = 'http://www.filemaker.com/fmpxmlresult'
   
 version_string = "V0.5.1 ROC 9.1.2008"  version_string = "V0.6.3 ROC 10.2.2009"
   
 def unicodify(str, withNone=False):  def unicodify(text, withNone=False):
     """decode str (utf-8 or latin-1 representation) into unicode object"""      """decode str (utf-8 or latin-1 representation) into unicode object"""
     if withNone and str is None:      if withNone and text is None:
         return None          return None
     if not str:      if not text:
         return u""          return u""
     if type(str) is StringType:      if isinstance(text, str):
         try:          try:
             return str.decode('utf-8')              return text.decode('utf-8')
         except:          except:
             return str.decode('latin-1')              return text.decode('latin-1')
     else:      else:
         return str          return text
   
 def utf8ify(str, withNone=False):  def utf8ify(text, withNone=False):
     """encode unicode object or string into byte string in utf-8 representation"""      """encode unicode object or string into byte string in utf-8 representation"""
     if withNone and str is None:      if withNone and text is None:
         return None          return None
     if not str:      if not text:
         return ""          return ""
     if type(str) is StringType:      if isinstance(text, unicode):
         return str          return text.encode('utf-8')
     else:      else:
         return str.encode('utf-8')          return text
   
 def getTextFromNode(nodename):  def getTextFromNode(nodename):
     """get the cdata content of a node"""      """get the cdata content of a node"""
Line 143  class xml_handler: Line 146  class xml_handler:
                   
         # connect database          # connect database
         self.dbCon = psycopg.connect(options.dsn)          self.dbCon = psycopg.connect(options.dsn)
           logging.debug("DB encoding: %s"%getattr(self.dbCon, 'encoding', 'UNKNOWN'))
         self.db = self.dbCon.cursor()          self.db = self.dbCon.cursor()
         assert self.db, "AIIEE no db cursor for %s!!"%options.dsn          assert self.db, "AIIEE no db cursor for %s!!"%options.dsn
           
Line 155  class xml_handler: Line 159  class xml_handler:
         self.ascii_db = getattr(options,"ascii_db",None)          self.ascii_db = getattr(options,"ascii_db",None)
         self.replace_table = getattr(options,"replace_table",None)          self.replace_table = getattr(options,"replace_table",None)
         self.backup_table = getattr(options,"backup_table",None)          self.backup_table = getattr(options,"backup_table",None)
           self.read_before_update = getattr(options,"read_before_update",None)
           self.debug_data = getattr(options,"debug_data",None)
   
         self.logger.debug("dsn: "+repr(getattr(options,"dsn",None)))          self.logger.debug("dsn: "+repr(getattr(options,"dsn",None)))
         self.logger.debug("table: "+repr(self.table))          self.logger.debug("table: "+repr(self.table))
Line 166  class xml_handler: Line 172  class xml_handler:
         self.logger.debug("ascii_db: "+repr(self.ascii_db))          self.logger.debug("ascii_db: "+repr(self.ascii_db))
         self.logger.debug("replace_table: "+repr(self.replace_table))          self.logger.debug("replace_table: "+repr(self.replace_table))
         self.logger.debug("backup_table: "+repr(self.backup_table))          self.logger.debug("backup_table: "+repr(self.backup_table))
           self.logger.debug("read_before_update: "+repr(self.read_before_update))
           self.logger.debug("debug_data: "+repr(self.debug_data))
                   
         self.dbIDs = {}          self.dbIDs = {}
         self.rowcnt = 0          self.rowcnt = 0
Line 255  class xml_handler: Line 263  class xml_handler:
         qstr="select attname, format_type(pg_attribute.atttypid, pg_attribute.atttypmod) from pg_attribute, pg_class where attrelid = pg_class.oid and pg_attribute.attnum > 0 and relname = '%s'"          qstr="select attname, format_type(pg_attribute.atttypid, pg_attribute.atttypmod) from pg_attribute, pg_class where attrelid = pg_class.oid and pg_attribute.attnum > 0 and relname = '%s'"
         self.sql_fields={}          self.sql_fields={}
         for f in SimpleSearch(self.db, qstr%self.table):          for f in SimpleSearch(self.db, qstr%self.table):
             n = f[0]              fn = f[0]
             t = f[1]              ft = f[1]
             #print "SQL fields: %s (%s)"%(n,t)              #print "SQL fields: %s (%s)"%(n,t)
             self.sql_fields[n] = TableColumn(n,t)              self.sql_fields[fn] = TableColumn(fn,ft)
                   
         # translate id_field (SQL-name) to XML-name          # translate id_field (SQL-name) to XML-name
         self.xml_id = self.sql_field_map.get(self.id_field, None)          self.xml_id = self.sql_field_map.get(self.id_field, None)
Line 307  class xml_handler: Line 315  class xml_handler:
                         self.logger.debug("field %s has different type (%s vs %s)"%(f,f.getType(),sf.getType()))                          self.logger.debug("field %s has different type (%s vs %s)"%(f,f.getType(),sf.getType()))
                 elif uf is not None:                  elif uf is not None:
                     # add field to table                      # add field to table
                     qstr="alter table %s add %s %s"%(self.table,uf.getName(),uf.getType())                      fn = uf.getName()
                       ft = uf.getType()
                       qstr="alter table %s add \"%s\" %s"%(self.table,fn,ft)
                     self.logger.info("db add field:"+qstr)                      self.logger.info("db add field:"+qstr)
                                           
                     if self.ascii_db and type(qstr)==types.UnicodeType:                      if self.ascii_db and type(qstr)==types.UnicodeType:
Line 315  class xml_handler: Line 325  class xml_handler:
                                                   
                     self.db.execute(qstr)                      self.db.execute(qstr)
                     self.dbCon.commit()                      self.dbCon.commit()
                       # add field to field list
                       self.sql_fields[fn] = TableColumn(fn, ft)
                                   
         # prepare sql statements for update (do not update id_field)          # prepare sql statements for update (do not update id_field)
         setStr=string.join(["%s = %%s"%self.xml_field_map[f] for f in self.xml_update_list if f != self.xml_id], ', ')          setStr=string.join(["\"%s\" = %%s"%self.xml_field_map[f] for f in self.xml_update_list if f != self.xml_id], ', ')
         self.updQuery="UPDATE %s SET %s WHERE %s = %%s"%(self.table,setStr,self.id_field)          self.updQuery="UPDATE %s SET %s WHERE \"%s\" = %%s"%(self.table,setStr,self.id_field)
           # and select (for update check)
           selStr=string.join([self.xml_field_map[f].getName() for f in self.xml_update_list if f != self.xml_id], ', ')
           self.selQuery="SELECT %s FROM %s WHERE \"%s\" = %%s"%(selStr,self.table,self.id_field)
         # and insert          # and insert
         fields=string.join([self.xml_field_map[x].getName() for x in self.xml_update_list], ',')          fields=string.join(["\"%s\""%self.xml_field_map[x].getName() for x in self.xml_update_list], ',')
         values=string.join(['%s' for f in self.xml_update_list], ',')          values=string.join(['%s' for f in self.xml_update_list], ',')
         self.addQuery="INSERT INTO %s (%s) VALUES (%s)"%(self.table,fields,values)          self.addQuery="INSERT INTO %s (%s) VALUES (%s)"%(self.table,fields,values)
         self.logger.debug("update-query: "+self.updQuery)          self.logger.debug("update-query: "+self.updQuery)
           self.logger.debug("sel-query: "+self.selQuery)
         self.logger.debug("add-query: "+self.addQuery)          self.logger.debug("add-query: "+self.addQuery)
         return          return
   
Line 370  class xml_handler: Line 386  class xml_handler:
         if self.sync_mode:          if self.sync_mode:
             # delete unmatched entries in db              # delete unmatched entries in db
             self.logger.info("deleting unmatched rows from db")              self.logger.info("deleting unmatched rows from db")
             delQuery = "DELETE FROM %s WHERE %s = %%s"%(self.table,self.id_field)              delQuery = "DELETE FROM %s WHERE \"%s\" = %%s"%(self.table,self.id_field)
             for id in self.dbIDs.keys():              for id in self.dbIDs.keys():
                 # find all not-updated fields                  # find all not-updated fields
                 if self.dbIDs[id] == 0:                  if self.dbIDs[id] == 0:
                     self.logger.info(" delete:"+id)                      self.logger.info(" delete: %s"%id)
                     SimpleSearch(self.db, delQuery, [id], ascii=self.ascii_db)                      SimpleSearch(self.db, delQuery, [id], ascii=self.ascii_db)
                     sys.exit(1)  
                                           
                 elif self.dbIDs[id] > 1:                  elif self.dbIDs[id] > 1:
                     self.logger.info(" sync: ID %s used more than once?"%id)                      self.logger.info(" sync: ID %s used more than once?"%id)
Line 423  class xml_handler: Line 438  class xml_handler:
         # synchronize by id_field          # synchronize by id_field
         if self.id_field:          if self.id_field:
             if self.id_type == 'integer':              if self.id_type == 'integer':
                   try:
                 id_val = int(self.xml_data[self.xml_id])                  id_val = int(self.xml_data[self.xml_id])
                   except:
                       pass
             else:              else:
                 id_val = self.xml_data[self.xml_id]                  id_val = self.xml_data[self.xml_id]
                                   
               if not id_val:
                   # abort update
                   self.logger.error("ERROR: unable to sync! emtpy id in row %s"%self.rowcnt)
                   return
                   
             if id_val in self.dbIDs:              if id_val in self.dbIDs:
                 self.dbIDs[id_val] += 1                  self.dbIDs[id_val] += 1
                 update=True                  update=True
Line 453  class xml_handler: Line 476  class xml_handler:
                                           
         if update:          if update:
             # update existing row (by id_field)              # update existing row (by id_field)
             # last argument is ID match              if self.read_before_update:
             args.append(id_val)                  # read data
                   if self.debug_data:
                       self.logger.debug("update check: %s = %s"%(id_val, args))
                   oldrow = SimpleSearch(self.db, self.selQuery, [id_val], ascii=self.ascii_db)
                   #i = 0
                   #for v in oldrow[0]:
                   #    logging.debug("v: %s = %s (%s)"%(v,args[i],v==args[i]))
                   #    i += 1
                   if tuple(oldrow[0]) != tuple(args):
                       # data has changed -- update
                       if self.debug_data:
                           self.logger.debug("really update: %s = %s"%(id_val, args))
                       args.append(id_val) # last arg is id
                       SimpleSearch(self.db, self.updQuery, args, ascii=self.ascii_db)
                       
               else:
                   # always update
                   if self.debug_data:
             self.logger.debug("update: %s = %s"%(id_val, args))              self.logger.debug("update: %s = %s"%(id_val, args))
                   args.append(id_val) # last arg is id
             SimpleSearch(self.db, self.updQuery, args, ascii=self.ascii_db)              SimpleSearch(self.db, self.updQuery, args, ascii=self.ascii_db)
   
         else:          else:
             # create new row              # create new row
               if self.debug_data:
             self.logger.debug("insert: %s"%args)              self.logger.debug("insert: %s"%args)
             SimpleSearch(self.db, self.addQuery, args, ascii=self.ascii_db)              SimpleSearch(self.db, self.addQuery, args, ascii=self.ascii_db)
   
Line 584  if __name__ == "__main__": Line 626  if __name__ == "__main__":
     opars.add_option("--backup", default=False, action="store_true",       opars.add_option("--backup", default=False, action="store_true", 
                      dest="backup_table",                        dest="backup_table", 
                      help="create backup of old table")                       help="create backup of old table")
       opars.add_option("--read-before-update", default=False, action="store_true", 
                        dest="read_before_update", 
                        help="read all data to check if it really changed")
     opars.add_option("-d", "--debug", default=False, action="store_true",       opars.add_option("-d", "--debug", default=False, action="store_true", 
                      dest="debug",                        dest="debug", 
                      help="debug mode (more output)")                       help="debug mode (more output)")
       opars.add_option("--debug-data", default=False, action="store_true", 
                        dest="debug_data", 
                        help="debug mode for data (even more output)")
           
     (options, args) = opars.parse_args()      (options, args) = opars.parse_args()
           

Removed from v.1.20  
changed lines
  Added in v.1.29


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>