--- ZSQLExtend/ZSQLExtend.py 2006/11/17 16:04:26 1.97 +++ ZSQLExtend/ZSQLExtend.py 2007/02/01 14:48:59 1.101 @@ -1,4 +1,3 @@ - from OFS.Folder import Folder from Acquisition import Implicit from Globals import DTMLFile,package_home,Persistent @@ -15,12 +14,20 @@ from Products.ZSQLMethods.SQL import SQL from xml.sax.saxutils import escape from types import * import Shared.DC.ZRDB.DA -import zLOG +import logging import os.path import os import copy import unicodedata +import logging + +#ersetzt logging +def logger(txt,method,txt2): + """logging""" + logging.info(txt+ txt2) + + from OFS.SimpleItem import SimpleItem def getTextFromNode(nodename): @@ -162,7 +169,7 @@ class ZSQLExtendFolder(Folder,Persistent #from xml.dom.minidom import parseString,parse from Ft.Xml import Parse - zLOG.LOG("import xsd",zLOG.INFO,"called") + logger("import xsd",logging.INFO,"called") #fh=file("/tmp/fmpxml.xml") import bz2 import base64 @@ -172,16 +179,16 @@ class ZSQLExtendFolder(Folder,Persistent if data: data=bz2.decompress(base64.decodestring(data)) - #zLOG.LOG("import xsd",zLOG.INFO,"received file") + #logger("import xsd",logging.INFO,"received file") doc=Parse(data) - #zLOG.LOG("import xsd",zLOG.INFO,"parsed file") + #logger("import xsd",logging.INFO,"parsed file") elif filename: fh=file(filename) txt=fh.read() doc=Parse(txt) - #zLOG.LOG("import xsd",zLOG.INFO,"parsed file") + #logger("import xsd",logging.INFO,"parsed file") Nss={'xsd':'http://www.w3.org/2001/XMLSchema'} @@ -200,7 +207,7 @@ class ZSQLExtendFolder(Folder,Persistent else: create=False - zLOG.LOG("update xsd: fieldnames",zLOG.INFO,repr(fieldNames)) + logger("update xsd: fieldnames",logging.INFO,repr(fieldNames)) qstr="""select attname from pg_attribute, pg_class where attrelid = pg_class.oid and relname = '%s' """ columns=[x.attname for x in self.ZSQLSimpleSearch(qstr%table)] @@ -215,7 +222,7 @@ class ZSQLExtendFolder(Folder,Persistent for fieldName in fieldNames: if type(fieldName) is UnicodeType: fieldName=fieldName.encode('utf-8') - zLOG.LOG("update xml: fieldname",zLOG.INFO,repr(fieldName)) + logging.LOG("update xml: fieldname",logging.INFO,repr(fieldName)) if fieldName.lower() not in columns: if create:# table does not exist therefore create with one column @@ -225,7 +232,7 @@ class ZSQLExtendFolder(Folder,Persistent qstr="""alter table %s add %s %s""" self.ZSQLSimpleSearch(qstr%(table,fieldName,'text')) - zLOG.LOG("update xsd: fieldname add",zLOG.INFO,qstr%(table,fieldName,'text')) + logging.LOG("update xsd: fieldname add",logging.INFO,qstr%(table,fieldName,'text')) def importXMLFileAccess(self,table,container,data=None,identify=None,filename=None,RESPONSE=None): @@ -239,7 +246,7 @@ class ZSQLExtendFolder(Folder,Persistent ''' from xml.dom.pulldom import parseString,parse - zLOG.LOG("import xml",zLOG.INFO,"called") + logging.LOG("import xml",logging.INFO,"called") #fh=file("/tmp/fmpxml.xml") import bz2 import base64 @@ -248,14 +255,14 @@ class ZSQLExtendFolder(Folder,Persistent if data: data=bz2.decompress(base64.decodestring(data)) - zLOG.LOG("import xml",zLOG.INFO,"received file") + logging.LOG("import xml",logging.INFO,"received file") doc=parseString(data) - zLOG.LOG("import xml",zLOG.INFO,"parsed file") + logging.LOG("import xml",logging.INFO,"parsed file") elif filename: fh=file(filename) doc=parse(fh) - zLOG.LOG("import xml",zLOG.INFO,"parsed file") + logging.LOG("import xml",logging.INFO,"parsed file") while 1: node=doc.getEvent() @@ -278,7 +285,7 @@ class ZSQLExtendFolder(Folder,Persistent field=dataSet[identify] searchStr="""select %s from %s where %s = '%s'"""%(identify,table,identify,field) - zLOG.LOG("import xml",zLOG.INFO,searchStr) + logging.LOG("import xml",logging.INFO,searchStr) search=self.ZSQLSimpleSearch(searchStr) if search: update=True @@ -292,7 +299,7 @@ class ZSQLExtendFolder(Folder,Persistent field=dataSet[identify] queryStr="""UPDATE %s SET %s WHERE %s = '%s' """%(table,setStr,identify,field) - zLOG.LOG("update xml",zLOG.INFO,queryStr) + logging.LOG("update xml",logging.INFO,queryStr) self.ZSQLSimpleSearch(queryStr) ret+="ud: %s \n"%field else: @@ -304,7 +311,7 @@ class ZSQLExtendFolder(Folder,Persistent queryStr="""INSERT INTO %s (%s) VALUES (%s)"""%(table,fields,values) self.ZSQLSimpleSearch(queryStr) - zLOG.LOG("update xml",zLOG.INFO,queryStr) + logging.LOG("update xml",logging.INFO,queryStr) @@ -345,7 +352,7 @@ class ZSQLExtendFolder(Folder,Persistent field=dataSet[nr] searchStr="""select %s from %s where %s = '%s'"""%(identify,table,identify,field) - zLOG.LOG("import xml",zLOG.INFO,searchStr) + logging.LOG("import xml",logging.INFO,searchStr) search=self.ZSQLSimpleSearch(searchStr) if search: update=True @@ -359,7 +366,7 @@ class ZSQLExtendFolder(Folder,Persistent field=dataSet[nr] queryStr="""UPDATE %s SET %s WHERE %s = '%s' """%(table,setStr,identify,field) - zLOG.LOG("update xml",zLOG.INFO,queryStr) + logging.LOG("update xml",logging.INFO,queryStr) self.ZSQLSimpleSearch(queryStr) ret+="ud: %s \n"%field else: @@ -371,7 +378,7 @@ class ZSQLExtendFolder(Folder,Persistent queryStr="""INSERT INTO %s (%s) VALUES (%s)"""%(table,fields,values) self.ZSQLSimpleSearch(queryStr) - zLOG.LOG("update xml",zLOG.INFO,queryStr) + logging.LOG("update xml",logging.INFO,queryStr) ret+="ad: %s \n"%field elif node[1].nodeName=="METADATA": @@ -383,21 +390,164 @@ class ZSQLExtendFolder(Folder,Persistent for name in names: fieldNames.append(name.getAttribute('NAME')) - zLOG.LOG("update xml: fieldnames",zLOG.INFO,repr(fieldNames)) + logging.LOG("update xml: fieldnames",logging.INFO,repr(fieldNames)) qstr="""select attname from pg_attribute, pg_class where attrelid = pg_class.oid and relname = '%s' """ columns=[x.attname for x in self.ZSQLSimpleSearch(qstr%table)] for fieldName in fieldNames: - zLOG.LOG("update xml: fieldname",zLOG.INFO,repr(fieldName)) + logging.LOG("update xml: fieldname",logging.INFO,repr(fieldName)) if fieldName not in columns: qstr="""alter table %s add %s %s""" self.ZSQLSimpleSearch(qstr%(table,fieldName,'text')) - zLOG.LOG("update xml: fieldname add",zLOG.INFO,qstr%(table,fieldName,'text')) + logging.LOG("update xml: fieldname add",logging.INFO,qstr%(table,fieldName,'text')) #fn=node[1].getAttribute("xml:id") #nf=file("xtf/"+fn+".xtf",'w') #nf.write(""""""+node[1].toxml()+"") #print "wrote: %s"%fn + + + def importXMLFileFMP(self,table,data=None,filename=None,update_fields=None,id_field=None,sync_mode=False,RESPONSE=None): + ''' + Import FileMaker XML file (FMPXMLRESULT format) into the table. + @param table: name of the table the xml shall be imported into + @param data: xml data as bz2 string + @param filename: xmlfile filename + @param update_fields: (optional) list of fields to update; default is to create all fields + @param id_field: (optional) field which uniquely identifies an entry for updating purposes. + @param sync_mode: (optional) really synchronise, i.e. delete entries not in XML file + @param RESPONSE: (optional) + ''' + from xml.dom.pulldom import parseString,parse + import transaction + + ret = "" + + if data: + data=bz2.decompress(base64.decodestring(data)) + zLOG.LOG("fmpxml",zLOG.INFO,"received file") + doc=parseString(data) + zLOG.LOG("fmpxml",zLOG.INFO,"parsed file") + + elif filename: + fh=file(filename) + zLOG.LOG("fmpxml",zLOG.INFO,"reading file") + doc=parse(fh) + zLOG.LOG("fmpxml",zLOG.INFO,"parsed file") + + dbIDs = {} + rowcnt = 0 + + if id_field is not None: + # prepare a list of ids for sync mode + qstr="select %s from %s"%(id_field,table) + for id in self.ZSQLSimpleSearch(qstr): + # value 0: not updated + dbIDs[id[0]] = 0; + rowcnt += 1 + zLOG.LOG("fmpxml",zLOG.INFO,"%d entries in DB to sync"%rowcnt) + + fieldNames = [] + rowcnt = 0 + id_val = '' + + while 1: + node=doc.getEvent() + + if node is None: + break; + + # METADATA tag defines number and names of fields in FMPXMLRESULT + if node[1].nodeName == 'METADATA': + doc.expandNode(node[1]) + + names=node[1].getElementsByTagName('FIELD') + + for name in names: + fn = name.getAttribute('NAME') + fieldNames.append(fn) + + if update_fields is None: + # update all fields + update_fields = fieldNames + + zLOG.LOG("fmpxml fieldnames:",zLOG.INFO,repr(fieldNames)) + # get list of fields in db table + qstr="""select attname from pg_attribute, pg_class where attrelid = pg_class.oid and relname = '%s'""" + columns=[x.attname for x in self.ZSQLSimpleSearch(qstr%table)] + + # adjust db table to fields in XML and fieldlist + for fieldName in fieldNames: + zLOG.LOG("fmpxml fieldname:",zLOG.INFO,repr(fieldName)) + if (fieldName not in columns) and (fieldName in update_fields): + qstr="""alter table %s add %s %s""" + self.ZSQLSimpleSearch(qstr%(table,fieldName,'text')) + zLOG.LOG("fmpxml add field:",zLOG.INFO,qstr%(table,fieldName,'text')) + + # ROW tags (in RESULTSET tag) hold data + elif node[1].nodeName == 'ROW': + rowcnt += 1 + + doc.expandNode(node[1]) + cols=node[1].getElementsByTagName('COL') + dataSet={} + i = 0 + # populate with data + for col in cols: + data=col.getElementsByTagName('DATA') + dataSet[fieldNames[i]] = getTextFromNode(data[0]) + i += 1 + + update=False + + # synchronize by id_field + if id_field: + id_val=dataSet[id_field] + if id_val in dbIDs: + dbIDs[id_val] += 1 + update=True + + if update: + # update existing row (by id_field) + setvals=[] + for fieldName in update_fields: + setvals.append("%s = %s"%(fieldName,self.ZSQLQuote(dataSet[fieldName]))) + setStr=string.join(setvals, ',') + id_val=dataSet[id_field] + qstr="""UPDATE %s SET %s WHERE %s = '%s' """%(table,setStr,id_field,id_val) + #zLOG.LOG("fmpxml update:",zLOG.INFO,queryStr) + self.ZSQLSimpleSearch(qstr) + ret+="up: %s \n"%id_val + else: + # create new row + fields=string.join(update_fields, ',') + values=string.join([" %s "%self.ZSQLQuote(dataSet[x]) for x in update_fields], ',') + qstr="""INSERT INTO %s (%s) VALUES (%s)"""%(table,fields,values) + self.ZSQLSimpleSearch(qstr) + #zLOG.LOG("fmpxml: insert",zLOG.INFO,queryStr) + ret+="ad: %s \n"%dataSet.get(id_field, rowcnt) + + #zLOG.LOG("fmpxml row:",zLOG.INFO,"%d (%s)"%(rowcnt,id_val)) + if (rowcnt % 10) == 0: + zLOG.LOG("fmpxml row:",zLOG.INFO,"%d (%s)"%(rowcnt,id_val)) + transaction.commit() + + transaction.commit() + if sync_mode: + # delete unmatched entries in db + for id in dbIDs.keys(): + # find all not-updated fields + if dbIDs[id] == 0: + zLOG.LOG("fmpxml delete:",zLOG.INFO,id) + qstr = "DELETE FROM %s WHERE %s = '%s'" + self.ZSQLSimpleSearch(qstr%(table,id_field,id)) + + elif dbIDs[id] > 1: + zLOG.LOG("fmpxml sync:",zLOG.INFO,"id used more than once?"+id) + + transaction.commit() + + return ret def generateIndex(self,field,index_name,table,RESPONSE=None): """erzeuge index aus feld""" @@ -705,7 +855,8 @@ class ZSQLExtendFolder(Folder,Persistent #print "INLINE:",argv for a in argTmp.keys(): - qs.append(a+"="+urllib.quote(str(argTmp[a]))) + aFiltered=re.sub(r"^-","_",a) # beginning of a command should always be "_" + qs.append(aFiltered+"="+urllib.quote(str(argTmp[a]))) #return [] ret = self.parseQueryString(string.join(qs,","),"_",storename=storename) @@ -734,6 +885,8 @@ class ZSQLExtendFolder(Folder,Persistent ret[field[0]]=(self.ZSQLInlineSearch(storename=storename,args=argTmp2),field[3],field[4],field[5],field[6]) return ret + + def ZSQLInlineSearch(self,storename=None,args=None,**argv): """inlinesearch""" @@ -753,11 +906,9 @@ class ZSQLExtendFolder(Folder,Persistent #print "INLINE:",argv for a in argTmp.keys(): - try: - qs.append(a+"="+urllib.quote(str(argTmp[a]))) - except: - import urllib - qs.append(a+"="+urllib.quote(str(argTmp[a]))) + aFiltered=re.sub(r"^-","_",a) # beginning of a command should always be "_" + qs.append(aFiltered+"="+urllib.quote(str(argTmp[a]))) + #return [] @@ -776,11 +927,11 @@ class ZSQLExtendFolder(Folder,Persistent try: self.getConnectionObj().manage_close_connection() except: - zLOG.LOG("ZSQLResetConnection",zLOG.ERROR, '%s %s'%sys.exc_info()[:2]) + logging.LOG("ZSQLResetConnection",logging.ERROR, '%s %s'%sys.exc_info()[:2]) try: self.getConnectionObj().manage_open_connection() except: - zLOG.LOG("ZSQLResetConnection",zLOG.ERROR, '%s %s'%sys.exc_info()[:2]) + logging.LOG("ZSQLResetConnection",logging.ERROR, '%s %s'%sys.exc_info()[:2]) def ZSQLSimpleSearch(self,query=None,max_rows=1000000): """simple search""" @@ -803,7 +954,7 @@ class ZSQLExtendFolder(Folder,Persistent try: self.getConnectionObj().manage_open_connection() except: - zLOG.LOG("ZSQLSimpleSearch",zLOG.ERROR, '%s %s'%sys.exc_info()[:2]) + logging.LOG("ZSQLSimpleSearch",logging.ERROR, '%s %s'%sys.exc_info()[:2]) else: try: @@ -816,7 +967,7 @@ class ZSQLExtendFolder(Folder,Persistent try: self.getConnectionObj().manage_open_connection() except: - zLOG.LOG("ZSQLSimpleSearch",zLOG.ERROR, '%s %s'%sys.exc_info()[:2]) + logging.LOG("ZSQLSimpleSearch",logging.ERROR, '%s %s'%sys.exc_info()[:2]) def getConnectionObj(self): if hasattr(self,'connection_id'): @@ -954,7 +1105,7 @@ class ZSQLExtendFolder(Folder,Persistent changeString=string.join(changeList,",") queryString="UPDATE %s SET %s WHERE %s"%(table,changeString,identify) - zLOG.LOG("ZSQLExtend",zLOG.INFO,"CHANGE: "+queryString) + logging.LOG("ZSQLExtend",logging.INFO,"CHANGE: "+queryString) self.ZSQLSimpleSearch(queryString) @@ -1499,7 +1650,7 @@ class ZSQLExtendFolder(Folder,Persistent def ZSQLQuery(self,query,debug=None): """query""" if debug: - zLOG.LOG("ZSQLQuery", zLOG.INFO, query) + logging.LOG("ZSQLQuery", logging.INFO, query) return self.ZSQLSimpleSearch(query) @@ -1527,7 +1678,7 @@ class ZSQLExtendFolder(Folder,Persistent self.REQUEST.SESSION['query']=string.join(self.REQUEST['QUERY_STRING'].split("&"),",") self.REQUEST.SESSION['come_from_search']="yes" - return self.REQUEST.RESPONSE.redirect(urllib.unquote(formatfile)) + return self.REQUEST.RESPONSE.redirect(urllib.unquote(formatfile)+"?"+rq) def ZSQLint(self,string):