diff options
| author | P. Christeas <p_christ@hol.gr> | 2010-07-01 20:51:33 +0300 |
|---|---|---|
| committer | P. Christeas <p_christ@hol.gr> | 2010-07-01 20:51:33 +0300 |
| commit | 7c26eb67fb646e02848435e768fd9c08a63529c9 (patch) | |
| tree | 6e661f4a60ce945bb2022ac5c943b72b02867cdb /addons/document | |
| parent | 2c5082001e8d6379fa36dd34cf070575ffcb31b1 (diff) | |
Document storage: the default db encoding is base64 in bytea
The storage class has to consider that. Also, prepare a class for raw bytea
storage.
bzr revid: p_christ@hol.gr-20100701175133-xxgu3cdlff0u7086
Diffstat (limited to 'addons/document')
| -rw-r--r-- | addons/document/document_storage.py | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/addons/document/document_storage.py b/addons/document/document_storage.py index 606600e17cb..290faac0229 100644 --- a/addons/document/document_storage.py +++ b/addons/document/document_storage.py @@ -115,7 +115,9 @@ class nodefd_db(StringIO, nodes.node_descriptor): mode = mode[:-1] if mode in ('r', 'r+'): - StringIO.__init__(self, ira_browse.db_datas) + cr.execute('SELECT db_datas FROM ir_attachment WHERE id = %s', ira_browse.id) + data = cr.fetchone()[0] + StringIO.__init__(self, data) elif mode in ('w', 'w+'): StringIO.__init__(self, None) # at write, we start at 0 (= overwrite), but have the original @@ -136,13 +138,13 @@ class nodefd_db(StringIO, nodes.node_descriptor): try: if self.mode in ('w', 'w+', 'r+'): out = self.getvalue() - cr.execute('UPDATE ir_attachment SET db_datas = %s, file_size=%d WHERE id = %s', + cr.execute("UPDATE ir_attachment SET db_datas = decode(%s,'escape'), file_size=%s WHERE id = %s", (out, len(out), par.file_id)) elif self.mode == 'a': out = self.getvalue() cr.execute("UPDATE ir_attachment " \ - "SET db_datas = COALESCE(db_datas,'') || %s, " \ - " file_size = COALESCE(file_size, 0) + %d " \ + "SET db_datas = COALESCE(db_datas,'') || decode(%s, 'escape'), " \ + " file_size = COALESCE(file_size, 0) + %s " \ " WHERE id = %s", (out, len(out), par.file_id)) cr.commit() @@ -153,6 +155,58 @@ class nodefd_db(StringIO, nodes.node_descriptor): cr.close() StringIO.close(self) +class nodefd_db64(StringIO, nodes.node_descriptor): + """ A descriptor to db data, base64 (the old way) + + It stores the data in base64 encoding at the db. Not optimal, but + the transparent compression of Postgres will save the day. + """ + def __init__(self, parent, ira_browse, mode): + nodes.node_descriptor.__init__(self, parent) + if mode.endswith('b'): + mode = mode[:-1] + + if mode in ('r', 'r+'): + StringIO.__init__(self, base64.decodestring(ira_browse.db_datas)) + elif mode in ('w', 'w+'): + StringIO.__init__(self, None) + # at write, we start at 0 (= overwrite), but have the original + # data available, in case of a seek() + elif mode == 'a': + StringIO.__init__(self, None) + else: + logging.getLogger('document.storage').error("Incorrect mode %s specified", mode) + raise IOError(errno.EINVAL, "Invalid file mode") + self.mode = mode + + def close(self): + # we now open a *separate* cursor, to update the data. + # FIXME: this may be improved, for concurrency handling + par = self._get_parent() + uid = par.context.uid + cr = pooler.get_db(par.context.dbname).cursor() + try: + if self.mode in ('w', 'w+', 'r+'): + out = self.getvalue() + cr.execute('UPDATE ir_attachment SET db_datas = %s::bytea, file_size=%s WHERE id = %s', + (base64.encodestring(out), len(out), par.file_id)) + elif self.mode == 'a': + out = self.getvalue() + # Yes, we're obviously using the wrong representation for storing our + # data as base64-in-bytea + cr.execute("UPDATE ir_attachment " \ + "SET db_datas = encode( (COALESCE(decode(encode(db_datas,'escape'),'base64'),'') || decode(%s, 'base64')),'base64')::bytea , " \ + " file_size = COALESCE(file_size, 0) + %s " \ + " WHERE id = %s", + (base64.encodestring(out), len(out), par.file_id)) + cr.commit() + except Exception, e: + logging.getLogger('document.storage').exception('Cannot update db file #%d for close:', par.file_id) + raise + finally: + cr.close() + StringIO.close(self) + class document_storage(osv.osv): """ The primary object for data storage. Each instance of this object is a storage media, in which our application @@ -239,7 +293,7 @@ class document_storage(osv.osv): # TODO: we need a better api for large files if self._debug: self._doclog.debug("Trying to obtain db_datas for ir.attachment[%d]", ira.id) - return nodefd_db(file_node, ira_browse=ira, mode=mode) + return nodefd_db64(file_node, ira_browse=ira, mode=mode) elif boo.type == 'realstore': if not ira.store_fname: |
