gh-95271: Extract placeholders howto from sqlite3 tutorial (#95522)

Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
Co-authored-by: Ezio Melotti <ezio.melotti@gmail.com>
This commit is contained in:
Erlend Egeberg Aasland 2022-08-04 22:41:18 +02:00 committed by GitHub
parent c47d09a4ac
commit b24e8b28a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 38 additions and 26 deletions

View File

@ -94,6 +94,12 @@ using :meth:`~Cursor.executemany`::
... ] ... ]
>>> cur.executemany('INSERT INTO stocks VALUES(?, ?, ?, ?, ?)', data) >>> cur.executemany('INSERT INTO stocks VALUES(?, ?, ?, ?, ?)', data)
Notice that we used ``?`` placeholders to bind *data* to the query.
Always use placeholders instead of :ref:`string formatting <tut-formatting>`
to bind Python values to SQL statements,
to avoid `SQL injection attacks`_.
See the :ref:`placeholders how-to <sqlite3-placeholders>` for more details.
Then, retrieve the data by iterating over the result of a ``SELECT`` statement:: Then, retrieve the data by iterating over the result of a ``SELECT`` statement::
>>> for row in cur.execute('SELECT * FROM stocks ORDER BY price'): >>> for row in cur.execute('SELECT * FROM stocks ORDER BY price'):
@ -104,33 +110,9 @@ Then, retrieve the data by iterating over the result of a ``SELECT`` statement::
('2006-04-06', 'SELL', 'IBM', 500, 53.0) ('2006-04-06', 'SELL', 'IBM', 500, 53.0)
('2006-04-05', 'BUY', 'MSFT', 1000, 72.0) ('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)
You've now created an SQLite database using the :mod:`!sqlite3` module.
.. _sqlite3-placeholders: .. _SQL injection attacks: https://en.wikipedia.org/wiki/SQL_injection
SQL operations usually need to use values from Python variables. However,
beware of using Python's string operations to assemble queries, as they
are vulnerable to SQL injection attacks (see the `xkcd webcomic
<https://xkcd.com/327/>`_ for a humorous example of what can go wrong)::
# Never do this -- insecure!
symbol = 'RHAT'
cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
Instead, use the DB-API's parameter substitution. To insert a variable into a
query string, use a placeholder in the string, and substitute the actual values
into the query by providing them as a :class:`tuple` of values to the second
argument of the cursor's :meth:`~Cursor.execute` method. An SQL statement may
use one of two kinds of placeholders: question marks (qmark style) or named
placeholders (named style). For the qmark style, ``parameters`` must be a
:term:`sequence <sequence>`. For the named style, it can be either a
:term:`sequence <sequence>` or :class:`dict` instance. The length of the
:term:`sequence <sequence>` must match the number of placeholders, or a
:exc:`ProgrammingError` is raised. If a :class:`dict` is given, it must contain
keys for all named parameters. Any extra items are ignored. Here's an example of
both styles:
.. literalinclude:: ../includes/sqlite3/execute_1.py
.. seealso:: .. seealso::
@ -1479,6 +1461,36 @@ Type ``.quit`` or CTRL-D to exit the shell.
How-to guides How-to guides
------------- -------------
.. _sqlite3-placeholders:
Using placeholders to bind values in SQL queries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SQL operations usually need to use values from Python variables. However,
beware of using Python's string operations to assemble queries, as they
are vulnerable to `SQL injection attacks`_ (see the `xkcd webcomic
<https://xkcd.com/327/>`_ for a humorous example of what can go wrong)::
# Never do this -- insecure!
symbol = 'RHAT'
cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
Instead, use the DB-API's parameter substitution. To insert a variable into a
query string, use a placeholder in the string, and substitute the actual values
into the query by providing them as a :class:`tuple` of values to the second
argument of the cursor's :meth:`~Cursor.execute` method. An SQL statement may
use one of two kinds of placeholders: question marks (qmark style) or named
placeholders (named style). For the qmark style, ``parameters`` must be a
:term:`sequence <sequence>`. For the named style, it can be either a
:term:`sequence <sequence>` or :class:`dict` instance. The length of the
:term:`sequence <sequence>` must match the number of placeholders, or a
:exc:`ProgrammingError` is raised. If a :class:`dict` is given, it must contain
keys for all named parameters. Any extra items are ignored. Here's an example of
both styles:
.. literalinclude:: ../includes/sqlite3/execute_1.py
.. _sqlite3-adapters: .. _sqlite3-adapters:
Using adapters to store custom Python types in SQLite databases Using adapters to store custom Python types in SQLite databases