This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author goodmami
Recipients Rosuav, docs@python, ghaering, goodmami, r.david.murray, terry.reedy
Date 2021-02-16.05:14:34
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1613452474.62.0.51225636444.issue20364@roundup.psfhosted.org>
In-reply-to
Content
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.
History
Date User Action Args
2021-02-16 05:14:34goodmamisetrecipients: + goodmami, terry.reedy, ghaering, r.david.murray, docs@python, Rosuav
2021-02-16 05:14:34goodmamisetmessageid: <1613452474.62.0.51225636444.issue20364@roundup.psfhosted.org>
2021-02-16 05:14:34goodmamilinkissue20364 messages
2021-02-16 05:14:34goodmamicreate