Michael Wayne Goodman <goodman....@gmail.com> added the comment:

Sorry to resurrect an old bug, but I've also found the docs lacking and I can 
fill in some gaps with some experimental results. Setup:

    >>> import sqlite3
    >>> conn = sqlite3.connect(':memory:')
    >>> conn.execute('CREATE TABLE foo (x INTEGER, y INTEGER, z INTEGER)')
    <sqlite3.Cursor object at 0x7f67257a79d0>

When the parameters is a sequence, the named placeholders can be repeated. 
There should be as many parameters as unique placeholders:

    >>> conn.execute('INSERT INTO foo VALUES (:1, :2, :1)', (4, 5))
    <sqlite3.Cursor object at 0x7f850a990a40>
    >>> conn.execute('SELECT * FROM foo').fetchall()
    [(4, 5, 4)]

Using numeric named placeholders is misleading, because they don't correspond 
to the indices in the parameters sequence. The following inserts (6, 7, 6), not 
(7, 6, 7):

    >>> conn.execute('INSERT INTO foo VALUES (:2, :1, :2)', (6, 7))
    <sqlite3.Cursor object at 0x7f850a990a40>
    >>> conn.execute('SELECT * FROM foo').fetchall()
    [(4, 5, 4), (6, 7, 6)]

So it is probably better to stick to non-numeric names:

    >>> conn.execute('INSERT INTO foo VALUES (:a, :a, :a)', (8,))
    <sqlite3.Cursor object at 0x7f850a990a40>
    >>> conn.execute('SELECT * FROM foo').fetchall()
    [(4, 5, 4), (6, 7, 6), (8, 8, 8)]

When the number of parameters is not the same as the number of unique 
placeholders, an sqlite3.ProgrammingError is raised:

    >>> conn.execute('INSERT INTO foo VALUES (:1, :2, :1)', (4, 5, 6))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    sqlite3.ProgrammingError: Incorrect number of bindings supplied. The 
current statement uses 2, and there are 3 supplied.

Question mark placeholders may be mixed with named placeholders. Each question 
mark uses the next "unclaimed" parameter, which then cannot be reused.

    >>> conn.execute('INSERT INTO foo VALUES (:a, ?, :a)', (1, 2))
    <sqlite3.Cursor object at 0x7f850a990ab0>
    >>> conn.execute('SELECT * FROM foo').fetchall()
    [(4, 5, 4), (6, 7, 6), (8, 8, 8), (1, 2, 1)]

As mentioned by R. David Murray and Terry J. Reedy above, when the parameters 
are given as a dict, extra items are ignored and no error is raised:

    >>> conn.execute('INSERT INTO foo VALUES (:a, :b, :a)', {'a': 3, 'b': 4, 
'c': 5})
    <sqlite3.Cursor object at 0x7f850a990ab0>
    >>> conn.execute('SELECT * FROM foo').fetchall()
    [(4, 5, 4), (6, 7, 6), (8, 8, 8), (1, 2, 1), (3, 4, 3)]

Disclaimer: I tested the above statements on Python 3.8.5. I did verify if the 
behavior is the same with earlier/later versions, and I don't know if this is 
intentional behavior or some undiscovered bug.

----------
nosy: +goodmami

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue20364>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to