[DB-SIG] Test suite update for format conversion accuracy.

Vernon D. Cole vernondcole at gmail.com
Mon May 20 18:46:36 CEST 2013


On Mon, May 20, 2013 at 8:12 AM, Daniele Varrazzo <
daniele.varrazzo at gmail.com> wrote:

> On Mon, May 20, 2013 at 12:51 PM, Vernon D. Cole <vernondcole at gmail.com>
> wrote:
> > Stuart:
> >
> > I have just uploaded a branch for your consideration for
> > https://code.launchpad.net/dbapi-compliance.  This version adds a second
> > field to the second test table (barflies) and loads that field with the
> > literal 'thi%s :may cau%(e)s? troub:1e'.  The value of this literal is a
> > trap for unwary format conversion routines which fail to notice that they
> > are re-formatting a literal value.
>
> You are requiring the sql string to be parsed, literal string
> identified and placeholders inside them not treated. This is not a
> DBAPI2 requirement.
>

Indeed, the DB API2 does not address parameter reformatting at all.  We are
just starting to play with that.  I am merely making sure that a reformat
operation does not step on the contents of an ANSI standard literal. And,
yes, when I am reformatting a string I do have to parse it.  How else would
I find my format markers?


>
> Without this requirement a driver can be implemented just passing the
> string to the client library, an extremely reasonable way to implement
> a client library wrapper. If you add it every driver will need to know
> the parsing rule of the server (and of its version). This is not a
> task as trivial as counting the quotes


As a matter of fact, counting quotes handles this problem quite nicely.
Actually, in my code I don't really count them.  I do a .split("'") [that
is using a single quote] and then only parse the odd-numbered tokens.  Then
do a "'".join().


> or applying a regexp: take a
> look at the Postgres literals grammar:
> <http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html>.
>
v v v v v v v v
 4.1.2.1. String Constants

A string constant in SQL is an arbitrary sequence of characters bounded by
single quotes ('), for example 'This is a string'. To include a
single-quote character within a string constant, write two adjacent single
quotes, e.g., 'Dianne''s horse'. Note that this is not the same as a
double-quote character (").
^ ^ ^ ^ ^ ^

That's what I am using for this test: an arbitrary sequence of characters
bounded by single quotes.


> Of course PG developers are free to complicate that as much as they
> want: a client driver is expected to be agnostic and just forward the
> query.
>

Yes, that is the point: forward the query, not mess it up.


>
> I don't think any currently implemented driver behaves as you wish.
>

I happen to _know_ that at least _one_ does.  ( My code is GPL, feel free
to copy. I copied from yours yesterday morning.)


> Here is stdlib's sqlite3:
>
> In [1]: import sqlite3
>
> In [2]: cnn = sqlite3.connect(':memory:')
>
> In [3]: cur = cnn.cursor()
>
> In [4]: cur.execute("create table test (a text, b text)")
> Out[4]: <sqlite3.Cursor at 0x2a4d500>
>
> In [5]: cur.execute("insert into test values (?, ?)", ('hi', 'mum'))
> Out[5]: <sqlite3.Cursor at 0x2a4d500>
>
> In [6]: cur.execute("insert into test values (?, 'wat?')", ('hi'))
> ---------------------------------------------------------------------------
> ProgrammingError                          Traceback (most recent call last)
> /home/piro/src/qmarkpg/<ipython-input-6-b8a3105dc710> in <module>()
> ----> 1 cur.execute("insert into test values (?, 'wat?')", ('hi'))
>
> ProgrammingError: Incorrect number of bindings supplied. The current
> statement uses 1, and there are 2 supplied.
>
> That is, indeed, a programming error. "h" and "i" are two values. The line
should have another comma:
In [6]: cur.execute("insert into test values (?, 'wat?')", ('hi',))
I usually pass a single parameter in a list simply to avoid that pattern:
In [6]: cur.execute("insert into test values (?, 'wat?')", ['hi'])

(for extra fun, I don't think sqlite3 even contemplates the
> possibility to use ? into a literal and neither ?? nor \? appear to
> work, see <http://www.sqlite.org/lang_expr.html#varparam>)
>
> Here is what the document you linked says:
v v v v
4.1.2.1. String Constants

A string constant in SQL is an arbitrary sequence of characters bounded by
single quotes ('), for example 'This is a string'. To include a
single-quote character within a string constant, write two adjacent single
quotes, e.g., 'Dianne''s horse'. Note that this is not the same as a
double-quote character (").

^ ^ ^ ^ ^

Nothing in there about avoiding question marks.

Now let's try it....

C:\Users\vernon\Projects\qmarkpg\tests>python
Python 2.7.4 (default, Apr  6 2013, 19:55:15) [MSC v.1500 64 bit (AMD64)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import adodbapi
>>> cnn = adodbapi.connect(
...
'%(prov_drv)s;Server=%(host)s;Database=%(database)s;uid=%(user)s;pwd=%(password)s;',
... 'adotestuser', '12345678', "25.223.161.222", 'adotest',
...   prov_drv='Provider=MSDASQL;Driver={PostgreSQL Unicode(x64)}')
>>> cnn.dbms_name
u'PostgreSQL'
>>> cnn.dbms_version
u'9.1.9'
>>> cur = cnn.cursor()
>>> cur.execute("create table test (a text, b text)")
>>> cur.paramstyle
'qmark'
>>> cur.execute("insert into test values (?, ?)", ('hi', 'mum'))
>>> cur.execute("insert into test values (?, 'wat?')", ('hi',))
>>> cur.paramstyle = 'format'
>>> cur.execute("insert into test values (%s, '%sure')", ('hello',))
>>> cnn.commit()
>>> cur.execute('select * from test')
>>> for row in cur:
...   print row
...
('hi', 'mum')
('hi', 'wat?')
('hello', '%sure')
>>>

Seems to me that counting quotes works.

--

Vernon
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/db-sig/attachments/20130520/09a344e8/attachment-0001.html>


More information about the DB-SIG mailing list