Re: [pysqlite] database locked

Gerhard Häring <[email protected]> Fri, 06 Feb 2009 20:33:47 +0100
Newsgroups gmane.comp.python.db.pysqlite.user
Message-ID <[email protected]>
Eric S. Johansson wrote:
> Dennis Lee Bieber wrote:
>> On Fri, 06 Feb 2009 00:24:01 -0500, "Eric S. Johansson"
>> <[email protected]> declaimed the following in
>> gmane.comp.python.db.pysqlite.user:
>>
>>
>>>            selection_command = selection_command +  " limit ?"
>> 	<snip>
>>> pysqlite2.dbapi2.OperationalError: near "?": syntax error
>>>
>> 	I suspect you need to fill in the limit using regular % string
>> interpolation.
> 
> it doesn't bark at me for limit but does bark at me for ? substitution for the
> table name.  this is in part why I asked is there anything I can use to see the
> end result of the ? substitution process.

There any substitution process happening with the ?. It's more like a 
function that's being compiled by SQLite for its own virtual machine 
that is then called with parameters (see attachments).

According to the docs, there are nice pragmas like vdbe_listing, 
vdbe_trace, etc., but I couldn't get them to work.

> [...] 
>> 	Visualize, just for example, a statement like:
>>
>> select * from ? where ? = ?
>>
> ...
>> 	On the other side of the equation, you are putting quotes around the
>> ?s for real data values... You don't need the quotes! Again, the purpose
>> of parameterized queries is that the database interface, itself, ensures
>> that the contents which take the place of the ? will be properly quoted
>> and escaped to fill the role of "data item".
> 
> I think I understand.  Maybe what I need to use is a limited set of values and
> types to protect against SQL injection attacks. i.e. limit and offset are only
> integers and order by argument would be limited to a finite number of possible
> that I use.  Then I could use string substitution and get the quoting right
> without worrying about injection attacks. [...]

As noted before, the numbers for LIMIT and OFFSET work fine as bound 
parameters:

 >>> import sqlite3
 >>> con = sqlite3.connect(":memory:")
 >>> con.execute("select * from (select 1 union select 2 union select 3) 
limit ?", (1,)).fetchall()
[(1,)]
 >>>

If you think you must use string substitution to dynamically create SQL, 
you could write your own quote() function. But then you must make sure 
that you *always* use it.

If I really needed that, I'd probably use an existing SQL generation 
framework, like the one from SQLAlchemy. It's perfectly possible to use 
SQLAlchemy for just that and not use the rest of it.

-- Gerhard

_______________________________________________
list-pysqlite mailing list
list-pysqlite-FR6EJeJVuqdwc357pe9rcyQmJico6nz3epZhswDD4dQ@public.gmane.org
http://itsystementwicklung.de/cgi-bin/mailman/listinfo/list-pysqlite
vdbetest.py (text/x-python, 421 B)
from pysqlite2 import dbapi2 as sqlite3

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("create table foo(a, b)")
cur.execute("explain insert into foo(a, b) values (?, ?)", ("bla", 42))
print ">> With bound parameters"
for row in cur.fetchall():
    print row
print "-" * 50

print ">> Literally"
cur.execute("explain insert into foo(a, b) values ('bla', 42)")
for row in cur.fetchall():
    print row
vdbetest.log (text/x-log, 1.5 KB)
>> With bound parameters
(0, u'Trace', 0, 0, 0, u'explain insert into foo(a, b) values (?, ?)', u'00', None)
(1, u'Goto', 0, 11, 0, u'', u'00', None)
(2, u'SetNumColumns', 0, 2, 0, u'', u'00', None)
(3, u'OpenWrite', 0, 2, 0, u'', u'00', None)
(4, u'NewRowid', 0, 2, 0, u'', u'00', None)
(5, u'Variable', 1, 3, 0, u'', u'00', None)
(6, u'Variable', 2, 4, 0, u'', u'00', None)
(7, u'MakeRecord', 3, 2, 5, u'bb', u'00', None)
(8, u'Insert', 0, 5, 2, u'foo', u'0b', None)
(9, u'Close', 0, 0, 0, u'', u'00', None)
(10, u'Halt', 0, 0, 0, u'', u'00', None)
(11, u'Transaction', 0, 1, 0, u'', u'00', None)
(12, u'VerifyCookie', 0, 1, 0, u'', u'00', None)
(13, u'TableLock', 0, 2, 1, u'foo', u'00', None)
(14, u'Goto', 0, 2, 0, u'', u'00', None)
--------------------------------------------------
>> Literally
(0, u'Trace', 0, 0, 0, u"explain insert into foo(a, b) values ('bla', 42)", u'00', None)
(1, u'Goto', 0, 11, 0, u'', u'00', None)
(2, u'SetNumColumns', 0, 2, 0, u'', u'00', None)
(3, u'OpenWrite', 0, 2, 0, u'', u'00', None)
(4, u'NewRowid', 0, 2, 0, u'', u'00', None)
(5, u'String8', 0, 3, 0, u'bla', u'00', None)
(6, u'Integer', 42, 4, 0, u'', u'00', None)
(7, u'MakeRecord', 3, 2, 5, u'bb', u'00', None)
(8, u'Insert', 0, 5, 2, u'foo', u'0b', None)
(9, u'Close', 0, 0, 0, u'', u'00', None)
(10, u'Halt', 0, 0, 0, u'', u'00', None)
(11, u'Transaction', 0, 1, 0, u'', u'00', None)
(12, u'VerifyCookie', 0, 1, 0, u'', u'00', None)
(13, u'TableLock', 0, 2, 1, u'foo', u'00', None)
(14, u'Goto', 0, 2, 0, u'', u'00', None)