[DB-SIG] pyformat Parameter Style
Magnus Lyckå
magnus at thinkware.se
Tue May 13 15:02:22 EDT 2003
At 11:31 2003-05-13 +0200, M.-A. Lemburg wrote:
>Looks like I ought to update the PEP then. Can you suggest
>a wording ?
I can try! :)
----
paramstyle
String constant stating the type of parameter marker
formatting expected by the interface. Possible values are
[2]:
'qmark' Question mark style
'numeric' Numeric, positional style
'named' Named style
'format' All ANSI C printf format codes
'pyformat' All Python extended format codes
See .execute below for examples.
----
IIRC there has also been discussions on whether
execute("... x=%i AND y=%s", 1, 2)
is correct, or whether it should be
execute("... x=%i AND y=%s", (1, 2))
or perhaps either.
I think a clarification on execute is good as well, and honestly,
now that I look at it, I feel uncertain, but I assume it should
be just .execute(s, p), where p is a sequence or a mapping, i.e.
the second example above. From a BNF etc p.o.v. I guess "parameters"
is *one* argument, containing all the parameters for the SQL operation.
----
.execute(operation[,parameters])
Prepare and execute a database operation (query or
command). Parameters may be provided as sequence or
mapping and will be bound to variables in the operation.
Variables are specified in a database-specific notation
(see the module's paramstyle attribute for details). [5]
...
Return values are not defined.
Code examples with different paramstyles:
'qmark':
sql = 'SELECT * FROM table WHERE age>=? AND name=?'
cur.execute(sql, (15, 'Guido'))
'numeric':
sql = 'SELECT * FROM table WHERE age>=:1 AND name=:2'
cur.execute(sql, (15, 'Guido'))
'named':
sql = 'SELECT * FROM table WHERE age>=:min_age AND name=:name'
cur.execute(sql, {'min_age': 15, 'name': 'Guido'})
'format':
sql = 'SELECT * FROM table WHERE age>=%d AND name=%s'
cur.execute(sql, (15, 'Guido'))
'pyformat':
sql = 'SELECT * FROM table WHERE age>%(min_age)d AND
name=%(name)'
cur.execute(sql, {'min_age': 15, 'name': 'Guido'})
----
As far as I understand,
sql = 'SELECT * FROM table WHERE age>=:2 AND name=:1'
cur.execute(sql, (15, 'Guido'))
will do exactly the same thing as the example above, and not the same
thing as
sql = 'SELECT * FROM table WHERE age>=:2 AND name=:1'
cur.execute(sql, ('Guido', 15))
which is what I had expected. I don't know if that should be mentioned in the
spec.
>You probably mean: floats into strings.
You are probably right. :)
>I think the reason is that those drivers don't support binding
>in the sense that the SQL statement and the data are sent to
>the database as two separate entities.
Right. They perform the "SQL % parameters" in Python after turning
all parameters into strings, and that's where the exceptions come
from. At least for pysqlite and the related PostgreSQL driver.
>However, I don't understand why the current implementations
>don't use Python's wealth of format characters (and it's formatting
>implementation).
Right. It's as simple as to not do anything with numeric types,
rather than to call repr() on them. And that will still work
if people write %s in their SQL even for numeric values.
Actually, using repr() on a float will probably lead to a
few surprises that %f or %s on the actual float prevents:
>>> "%s %f %s" % (0.1, 0.1, repr(0.1))
'0.1 0.100000 0.10000000000000001'
The backend might well be able to store an exact decimal
representation, and then it's a bit silly to store the
Python float approximation.
>That said, I still think that positional binding is by far
>the easiest to use and understand way of binding variables.
A mapping is obviously useful if we have the same value
several times in the SQL statement.
--
Magnus Lycka (It's really Lyckå), magnus at thinkware.se
Thinkware AB, Sweden, www.thinkware.se
I code Python ~ The shortest path from thought to working program
More information about the DB-SIG
mailing list