[DB-SIG] Towards a single parameter style

Matthew T. Kromer matt@zope.com
Mon, 17 Feb 2003 12:26:12 -0500


M.-A. Lemburg wrote:

>
> Now this would be hard to agree on and it will also break existing
> code, so I think we should just make the preferred paramstyle
> a suggestion in the DB-API. I'd vote for the simplest of them
> all: the 'qmark' style.


Qmark is the  style that's probably the hardest to cope with for 
binding, as well.  To do it fast you'd need a C extension just to rip 
the SQL apart to find non-escaped or quoted question marks.

The dictionary modes or string substitution modes would be easier to 
deal with, but still pose problems for purely positional parameter binds.

Consider the following:

   sql, args = transform( 'SELECT FROM FOO WHERE BLA=%(bla)s AND 
OOG=%(oog)s', {'bla': bla, 'oog': oog})

A simple translator might try:

    args = []
    c = dict.copy()
    for key, value in c.items():
        args.append(value)
        c[key] = '?'

    sql = statment % c
    return sql, args

Yet this would be dependant on the order of keys()!  It would 
conceivably alter the oder of BLA and OOG (in fact,  in my test case, I 
think it does).

Here's another example:  Oracle's positional parameter binds use a 
notation like :1, :2, :3 etc.  But as near as I can see, it doesn't 
actually CARE what the number is -- the first one to appear in the 
expression is 1, the second is 2, etc -- so an expression that is 
'SELECT FROM FOO WHERE BLA=:2 and OOG=:1' is identical to 'SELECT FROM 
FOO WHERE BLA=:1 and OOG=:2' -- the number in the format string is 
meaningless, only its position matters.  Fortunately, Oracle has named 
binds as well as positional binds -- but not all databases do.

As awful as it is, the style that's probably MOST univeral is "SELECT  * 
FROM FOO WHERE BLA=%s AND OOG=%s", (bla, oog) since this preserves the 
order of the parameters at the sake of losing their names (but synthetic 
names can be conjured for databases that need named binds).  A qmark or 
positional binder can easily substitute in '?' or ':1', ':2' etc and 
return the argument list as the bind parameters, and a named binder can 
substitute in ':p1', ':p2' etc and return a dictionary of {'p1': param1, 
...} as the argument vector.  The only case that isn't handled properly 
that I can see is those drivers that support NO binding at all -- but 
even those can guess at their format based on the type of the argument 
(ie quote strings but don't quote numbers).