dabo Commit
Revision 5524
Date: 2009-11-14 10:36:52 -0800 (Sat, 14 Nov 2009)
Author: Ed
Trac: http://trac.dabodev.com/changeset/5524
Changed:
U trunk/dabo/db/dBackend.py
U trunk/dabo/db/dCursorMixin.py
U trunk/dabo/db/dbSQLite.py
Log:
*MAJOR* change to the underlying cursor engine. This will need to be tested!
I looked into the problems with binary values not being able to be saved, and
was surprised to find that internally, we are still doing string substitution
to build our SQL statements to be executed. I thought that Carl Karsten had
re-written all of this years ago, but apparently not.
dCursorMixin now passes field values as parameters to the dbapi's execute,
instead of trying to create a fully-substituted string that incorporates the
field values. This was the primary reason that Dabo was not able to handle
binary values correctly.
I've added a backend-customizable attribute called 'paramPlaceholder', which is
the character to be used for parameterized execution. The default in dBackend
is '%s', and I've overridden it in dbSQLite to be '?'. Please update any other
backends that don't use '%s' for parameters.
Diff:
Modified: trunk/dabo/db/dBackend.py
===================================================================
--- trunk/dabo/db/dBackend.py 2009-11-14 18:32:01 UTC (rev 5523)
+++ trunk/dabo/db/dBackend.py 2009-11-14 18:36:52 UTC (rev 5524)
@@ -21,6 +21,8 @@
# When enclosing table or field names that contain spaces, what
# character is used? Default to double quote.
nameEnclosureChar = '"'
+ # The character used in sql to represent parameters to be substituted
+ paramPlaceholder = "%s"
def __init__(self):
self._baseClass = dBackend
Modified: trunk/dabo/db/dCursorMixin.py
===================================================================
--- trunk/dabo/db/dCursorMixin.py 2009-11-14 18:32:01 UTC (rev 5523)
+++ trunk/dabo/db/dCursorMixin.py 2009-11-14 18:36:52 UTC (rev 5524)
@@ -290,14 +290,17 @@
sql = sql.encode(self.Encoding)
# Some backends, notably Firebird, require that fields be
specially marked.
sql = self.processFields(sql)
-
try:
if params:
res = self.superCursor.execute(self, sql,
params)
if not self.IsPrefCursor:
- dabo.dbActivityLog.write("SQL: %s,
PARAMS: %s" % (
-
sql.decode(self.Encoding).replace("\n", " "),
- ', '.join("%s" % p for
p in params)))
+ try:
+ dabo.dbActivityLog.write("SQL:
%s, PARAMS: %s" % (
+
sql.decode(self.Encoding).replace("\n", " "),
+ ', '.join("%s"
% p for p in params)))
+ except StandardError:
+ # A problem with writing to the
log, most likely due to encoding issues
+
dabo.dbActivityLog.write("FAILED SQL: %s")
else:
res = self.superCursor.execute(self, sql)
if not self.IsPrefCursor:
@@ -310,9 +313,13 @@
if errorClass is not None and isinstance(e, errorClass):
raise e
if params:
- dabo.dbActivityLog.write("FAILED SQL: %s,
PARAMS: %s" % (
-
sql.decode(self.Encoding).replace("\n", " "),
- ', '.join("%s" % p for p in
params)))
+ try:
+ dabo.dbActivityLog.write("FAILED SQL:
%s, PARAMS: %s" % (
+
sql.decode(self.Encoding).replace("\n", " "),
+ ', '.join("%s" % p for
p in params)))
+ except StandardError:
+ # A problem with writing to the log,
most likely due to encoding issues
+ dabo.dbActivityLog.write("FAILED SQL:
%s")
else:
dabo.dbActivityLog.write("FAILED SQL: %s" % (
sql.decode(self.Encoding).replace("\n", " "),))
@@ -1334,7 +1341,7 @@
if diff:
if newrec:
flds = ""
- vals = ""
+ vals = []
kf = self.KeyField
for kk, vv in diff.items():
if self.AutoPopulatePK:
@@ -1356,29 +1363,29 @@
flds += ", " +
self.BackendObject.encloseNames(kk, aq)
# add value to expression
fieldType = [ds[1] for ds in
self.DataStructure if ds[0] == kk][0]
- vals += ", %s" %
(self.formatForQuery(vv[1], fieldType))
+ vals.append(self.formatForQuery(vv[1],
fieldType))
- # Trim leading comma-space from the strings
+ # Trim leading comma-space from the 'flds'
string
flds = flds[2:]
- vals = vals[2:]
if not flds:
# Some backends (sqlite) require
non-empty field clauses. We already
# know that we are expecting the
backend to generate the PK, so send
# NULL as the PK Value:
flds = self.KeyField
vals = "NULL"
- sql = "insert into %s (%s) values (%s) " % (
-
self.BackendObject.encloseNames(self.Table, aq), flds, vals)
+ nms =
self.BackendObject.encloseNames(self.Table, aq)
+ sql = "insert into %s (%s) values (%s) " %
(nms, flds, self.BackendObject.paramPlaceholder)
+ params = tuple(vals)
else:
pkWhere = self.makePkWhere(row)
- updClause = self.makeUpdClause(diff)
+ updClause, params = self.makeUpdClause(diff)
sql = "update %s set %s where %s" %
(self.BackendObject.encloseNames(self.Table, aq),
updClause, pkWhere)
#run the update
aux = self.AuxCursor
- res = aux.execute(sql)
+ res = aux.execute(sql, params)
if newrec and self.AutoPopulatePK and (newPKVal is
None):
# Call the database backend-specific code to
retrieve the
@@ -1933,8 +1940,12 @@
def makeUpdClause(self, diff):
- """ Create the 'set field=val' section of the Update statement.
"""
- ret = ""
+ """Create the 'set field=val' section of the Update statement.
Return a 2-tuple
+ containing the sql portion as the first element, and the
parameters for the
+ values as the second.
+ """
+ retSql = ""
+ retParams = []
bo = self.BackendObject
aq = self.AutoQuoteNames
tblPrefix = bo.getUpdateTablePrefix(self.Table, autoQuote=aq)
@@ -1947,8 +1958,12 @@
if ret:
ret += ", "
fieldType = [ds[1] for ds in self.DataStructure if
ds[0] == fld][0]
- ret += tblPrefix + bo.encloseNames(fld, aq) + " = " +
self.formatForQuery(new_val, fieldType)
- return ret
+ nms = bo.encloseNames(fld, aq)
+ retSql = "%s%s%s = %s" % (retSql, tblPrefix, nms,
self.BackendObject.paramPlaceholder)
+ print "CURS FT", fieldType
+ thisVal =self.formatForQuery(new_val, fieldType)
+ retParams.append(thisVal)
+ return (retSql, tuple(retParams))
def processFields(self, txt):
Modified: trunk/dabo/db/dbSQLite.py
===================================================================
--- trunk/dabo/db/dbSQLite.py 2009-11-14 18:32:01 UTC (rev 5523)
+++ trunk/dabo/db/dbSQLite.py 2009-11-14 18:36:52 UTC (rev 5524)
@@ -15,6 +15,7 @@
def __init__(self):
dBackend.__init__(self)
self.dbModuleName = "pysqlite2"
+ self.paramPlaceholder = "?"
try:
from pysqlite2 import dbapi2 as dbapi
except ImportError:
_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-dev
Searchable Archives: http://leafe.com/archives/search/dabo-dev
This message:
http://leafe.com/archives/byMID/[email protected]