Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

sqlite3 seems to consider ?1 a named placeholder #117995

Copy link
Copy link
Closed
@kalekundert

Description

@kalekundert
Issue body actions

Bug report

Bug description:

Starting in python 3.12, the following snippet generates a deprecation warning:

import sqlite3

db = sqlite3.connect(':memory:')

db.execute('CREATE TABLE a (b, c)')
db.execute('INSERT INTO a (b, c) VALUES (?2, ?1)', [3, 4])

# This line isn't necessary to reproduce the warning, it's just to show that 
# the insert did in fact put "4" in column "b" and "3" in column "c".
print(db.execute('SELECT * FROM a').fetchall())

Here's the warning for the first placeholder (there's another identical one for the second):

DeprecationWarning: Binding 1 ('?1') is a named parameter, but you supplied a sequence which requires nameless (qmark) placeholders. Starting with Python 3.14 an sqlite3.ProgrammingError will be raised.

I'll admit to not having a great understanding of how databases are supposed to work in python, but I don't think this warning should be issued. The sqlite docs specify that the ?<number> syntax is used to specify a parameter index, not a parameter name. So this kind of placeholder is meant to be used with sequence-style parameters like [3, 4]. I think the above warning should be issued only when the user tries to use :<word> placeholders with sequence-style parameters.

The above example is very simplified, so I think it might also be helpful to show the real-life query that triggered this warning for me. The goal is to insert key/value pairs from a dictionary, updating any keys that are already in the table. The query requires referring to the value in two places. ?<number> placeholders seem like the right syntax to use here, because they allow the metadata.items() to be used directly:

def upsert_metadata(db: sqlite3.Connection, metadata: dict[str, Any]):
    db.executemany(
            '''\
            INSERT INTO metadata (key, value)
            VALUES (?1, ?2)
            ON CONFLICT (key)
            DO UPDATE SET value=?2
            ''',
            metadata.items(),
    )

CPython versions tested on:

3.11, 3.12

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Labels

3.12only security fixesonly security fixes3.13bugs and security fixesbugs and security fixestopic-sqlite3type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.