From af15b22d737ec89326d14d6d16a7e85136949bf5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 29 Oct 2021 23:58:38 +0200 Subject: [PATCH 01/14] bpo-45677: Avoid addressing the reader as 'you' in sqlite3 docs --- Doc/library/sqlite3.rst | 48 ++++++++++++++++++++--------------------- Lib/sqlite3/__init__.py | 10 ++++----- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 19a4155542382f..e60280762a5572 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -21,17 +21,17 @@ The sqlite3 module was written by Gerhard Häring. It provides a SQL interface compliant with the DB-API 2.0 specification described by :pep:`249`, and requires SQLite 3.7.15 or newer. -To use the module, you must first create a :class:`Connection` object that +To use the module, start by creating a :class:`Connection` object that represents the database. Here the data will be stored in the :file:`example.db` file:: import sqlite3 con = sqlite3.connect('example.db') -You can also supply the special name ``:memory:`` to create a database in RAM. +Use the special path name ``:memory:`` to create a temporary database in RAM. -Once you have a :class:`Connection`, you can create a :class:`Cursor` object -and call its :meth:`~Cursor.execute` method to perform SQL commands:: +Now, create a :class:`Cursor` object and call its :meth:`~Cursor.execute` +method to perform SQL commands:: cur = con.cursor() @@ -49,16 +49,16 @@ and call its :meth:`~Cursor.execute` method to perform SQL commands:: # Just be sure any changes have been committed or they will be lost. con.close() -The data you've saved is persistent and is available in subsequent sessions:: +The saved data is persistent and is available in subsequent sessions:: import sqlite3 con = sqlite3.connect('example.db') cur = con.cursor() -To retrieve data after executing a SELECT statement, you can either treat the -cursor as an :term:`iterator`, call the cursor's :meth:`~Cursor.fetchone` method to -retrieve a single matching row, or call :meth:`~Cursor.fetchall` to get a list of the -matching rows. +To retrieve data after executing a SELECT statement, either treat the cursor as +an :term:`iterator`, call the cursor's :meth:`~Cursor.fetchone` method to +retrieve a single matching row, or call :meth:`~Cursor.fetchall` to get a list +of the matching rows. This example uses the iterator form:: @@ -73,27 +73,25 @@ This example uses the iterator form:: .. _sqlite3-placeholders: -Usually your SQL operations will need to use values from Python variables. You -shouldn't assemble your query using Python's string operations because doing so -is insecure; it makes your program vulnerable to an SQL injection attack -(see the `xkcd webcomic `_ for a humorous example of -what can go wrong):: +SQL operations will usually need to use values from Python variables. It is not +adviced to assemble queries using Python's string operations because it is +vulnerable to an SQL injection attacks (see the `xkcd webcomic +`_ 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. Put a placeholder wherever -you want to use a value, and then provide a tuple of values as the second -argument to 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 `. For the named style, it can be either a -:term:`sequence ` or :class:`dict` instance. The length of the -:term:`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: +Instead, use the DB-API's parameter substitution by putting placeholders in the +query string. Provide the values as a :class:`tuple` via 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 +`. For the named style, it can be either a :term:`sequence ` +or :class:`dict` instance. The length of the :term:`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 diff --git a/Lib/sqlite3/__init__.py b/Lib/sqlite3/__init__.py index edc58f15b25cee..1a00cfb192c759 100644 --- a/Lib/sqlite3/__init__.py +++ b/Lib/sqlite3/__init__.py @@ -24,18 +24,18 @@ The sqlite3 extension module provides a DB-API 2.0 (PEP 249) compilant interface to the SQLite library, and requires SQLite 3.7.15 or newer. -To use the module, you must first create a database Connection object: +To use the module, start by creating a database Connection object: import sqlite3 cx = sqlite3.connect("test.db") # test.db will be created or opened -You can also use the special database name ":memory:" to connect to a transient -in-memory database: +Use the special path name ":memory:" to connect to a transient in-memory +database: cx = sqlite3.connect(":memory:") # connect to a database in RAM -Once you have a Connection object, you can create a Cursor object and call its -execute() method to perform SQL queries: +Now, create a Cursor object and call its execute() method to perform SQL +queries: cu = cx.cursor() From c1e758d58533bde8c0947fd7638500cd693944b6 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 30 Oct 2021 00:04:02 +0200 Subject: [PATCH 02/14] Adjust wording --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index e60280762a5572..47a4562b603fcb 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -74,7 +74,7 @@ This example uses the iterator form:: .. _sqlite3-placeholders: SQL operations will usually need to use values from Python variables. It is not -adviced to assemble queries using Python's string operations because it is +adviced to assemble queries using Python's string operations, because they are vulnerable to an SQL injection attacks (see the `xkcd webcomic `_ for a humorous example of what can go wrong):: From 204052c630ae896abf5a4dd2417007a42e83125b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 30 Oct 2021 00:05:29 +0200 Subject: [PATCH 03/14] Adjust wording again --- Doc/library/sqlite3.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 47a4562b603fcb..bc219e0d59b7bb 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -83,15 +83,16 @@ vulnerable to an SQL injection attacks (see the `xkcd webcomic cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol) Instead, use the DB-API's parameter substitution by putting placeholders in the -query string. Provide the values as a :class:`tuple` via 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 -`. For the named style, it can be either a :term:`sequence ` -or :class:`dict` instance. The length of the :term:`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: +query string. Provide the actual values as a :class:`tuple` as the second +argument oo 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 `. For the named style, it can be either a +:term:`sequence ` or :class:`dict` instance. The length of the +:term:`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 From 02d2a53b901d1f9b2894e7c1daf27f469ea112cc Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 30 Oct 2021 00:07:46 +0200 Subject: [PATCH 04/14] Typo --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index bc219e0d59b7bb..a659ec6e6ec891 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -84,7 +84,7 @@ vulnerable to an SQL injection attacks (see the `xkcd webcomic Instead, use the DB-API's parameter substitution by putting placeholders in the query string. Provide the actual values as a :class:`tuple` as the second -argument oo the cursor's :meth:`~Cursor.execute` method. An SQL statement may +argument to 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 `. For the named style, it can be either a From 15008ee8e33079fb4e2f9171de917bcfee788b7a Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Sun, 31 Oct 2021 09:40:36 +0100 Subject: [PATCH 05/14] Update Doc/library/sqlite3.rst Co-authored-by: Jacob Walls --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index a659ec6e6ec891..5147f82ee16339 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -75,7 +75,7 @@ This example uses the iterator form:: SQL operations will usually need to use values from Python variables. It is not adviced to assemble queries using Python's string operations, because they are -vulnerable to an SQL injection attacks (see the `xkcd webcomic +vulnerable to SQL injection attacks (see the `xkcd webcomic `_ for a humorous example of what can go wrong):: # Never do this -- insecure! From 4d53130d02e35c6309b2e1eab645a621b7e2750e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 31 Oct 2021 09:45:01 +0100 Subject: [PATCH 06/14] Address review: adjust wording --- Doc/library/sqlite3.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 5147f82ee16339..c23c92cb195678 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -73,8 +73,8 @@ This example uses the iterator form:: .. _sqlite3-placeholders: -SQL operations will usually need to use values from Python variables. It is not -adviced to assemble queries using Python's string operations, because they are +SQL operations will usually need to use values from Python variables. It is poor +practice to assemble queries using Python's string operations, because they are vulnerable to SQL injection attacks (see the `xkcd webcomic `_ for a humorous example of what can go wrong):: From f5ce4af05cafdf0ce4d797aed628cb826424522d Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Sun, 31 Oct 2021 14:36:07 +0100 Subject: [PATCH 07/14] Update Doc/library/sqlite3.rst Co-authored-by: Alex Waygood --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index c23c92cb195678..3f041f6909d8b1 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -30,7 +30,7 @@ represents the database. Here the data will be stored in the Use the special path name ``:memory:`` to create a temporary database in RAM. -Now, create a :class:`Cursor` object and call its :meth:`~Cursor.execute` +Once a :class:`Connection` has been established, create a :class:`Cursor` object and call its :meth:`~Cursor.execute` method to perform SQL commands:: cur = con.cursor() From e9c3e97f0b53daa09100be7076215de4bb443357 Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Sun, 31 Oct 2021 14:40:37 +0100 Subject: [PATCH 08/14] Update Lib/sqlite3/__init__.py Co-authored-by: Alex Waygood --- Lib/sqlite3/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/sqlite3/__init__.py b/Lib/sqlite3/__init__.py index 1a00cfb192c759..ed6917371efb7b 100644 --- a/Lib/sqlite3/__init__.py +++ b/Lib/sqlite3/__init__.py @@ -29,8 +29,8 @@ import sqlite3 cx = sqlite3.connect("test.db") # test.db will be created or opened -Use the special path name ":memory:" to connect to a transient in-memory -database: +The special path name ":memory:" can be provided to connect to a transient +in-memory database: cx = sqlite3.connect(":memory:") # connect to a database in RAM From 86efc853442c8a74332ebc4809af169ed1705daa Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Sun, 31 Oct 2021 14:46:37 +0100 Subject: [PATCH 09/14] Update Doc/library/sqlite3.rst Co-authored-by: Alex Waygood --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 3f041f6909d8b1..37791c00647f9e 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -28,7 +28,7 @@ represents the database. Here the data will be stored in the import sqlite3 con = sqlite3.connect('example.db') -Use the special path name ``:memory:`` to create a temporary database in RAM. +The special path name ``:memory:`` can be provided to create a temporary database in RAM. Once a :class:`Connection` has been established, create a :class:`Cursor` object and call its :meth:`~Cursor.execute` method to perform SQL commands:: From 6923fee62c629dc270c557bc8e8c1e9e2e9910f8 Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Sun, 31 Oct 2021 14:48:47 +0100 Subject: [PATCH 10/14] Update Doc/library/sqlite3.rst Co-authored-by: Alex Waygood --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 37791c00647f9e..e943d52384e7e0 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -49,7 +49,7 @@ method to perform SQL commands:: # Just be sure any changes have been committed or they will be lost. con.close() -The saved data is persistent and is available in subsequent sessions:: +The saved data is persistent: it can be reloaded in a subsequent session even after restarting the Python interpreter:: import sqlite3 con = sqlite3.connect('example.db') From c794d16713c10af8bda861812b7ec7f5eb8dd539 Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Sun, 31 Oct 2021 14:59:43 +0100 Subject: [PATCH 11/14] Update Lib/sqlite3/__init__.py Co-authored-by: Alex Waygood --- Lib/sqlite3/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/sqlite3/__init__.py b/Lib/sqlite3/__init__.py index ed6917371efb7b..db6a9046a23bc1 100644 --- a/Lib/sqlite3/__init__.py +++ b/Lib/sqlite3/__init__.py @@ -34,8 +34,8 @@ cx = sqlite3.connect(":memory:") # connect to a database in RAM -Now, create a Cursor object and call its execute() method to perform SQL -queries: +Once a Connection has been established, create a Cursor object and call +its execute() method to perform SQL queries: cu = cx.cursor() From f4059152b40a2c3da2b2011d23bcf0a045e80aa2 Mon Sep 17 00:00:00 2001 From: Erlend Egeberg Aasland Date: Sun, 31 Oct 2021 15:00:05 +0100 Subject: [PATCH 12/14] Update Doc/library/sqlite3.rst Co-authored-by: Alex Waygood --- Doc/library/sqlite3.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index e943d52384e7e0..b915a1583e748d 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -73,9 +73,9 @@ This example uses the iterator form:: .. _sqlite3-placeholders: -SQL operations will usually need to use values from Python variables. It is poor -practice to assemble queries using Python's string operations, because they are -vulnerable to SQL injection attacks (see the `xkcd webcomic +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 `_ for a humorous example of what can go wrong):: # Never do this -- insecure! From d451f9db2c1417d225bb46e286140716902f6871 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 31 Oct 2021 18:53:36 +0100 Subject: [PATCH 13/14] Apply Alex' suggestion, and apply 80 char limit to PR --- Doc/library/sqlite3.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index b915a1583e748d..347e750a04cf81 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -28,10 +28,11 @@ represents the database. Here the data will be stored in the import sqlite3 con = sqlite3.connect('example.db') -The special path name ``:memory:`` can be provided to create a temporary database in RAM. +The special path name ``:memory:`` can be provided to create a temporary +database in RAM. -Once a :class:`Connection` has been established, create a :class:`Cursor` object and call its :meth:`~Cursor.execute` -method to perform SQL commands:: +Once a :class:`Connection` has been established, create a :class:`Cursor` object +and call its :meth:`~Cursor.execute` method to perform SQL commands:: cur = con.cursor() @@ -49,7 +50,8 @@ method to perform SQL commands:: # Just be sure any changes have been committed or they will be lost. con.close() -The saved data is persistent: it can be reloaded in a subsequent session even after restarting the Python interpreter:: +The saved data is persistent: it can be reloaded in a subsequent session even +after restarting the Python interpreter:: import sqlite3 con = sqlite3.connect('example.db') @@ -82,9 +84,10 @@ are vulnerable to SQL injection attacks (see the `xkcd webcomic symbol = 'RHAT' cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol) -Instead, use the DB-API's parameter substitution by putting placeholders in the -query string. Provide the actual values as a :class:`tuple` as the second -argument to the cursor's :meth:`~Cursor.execute` method. An SQL statement may +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 `. For the named style, it can be either a From 9bd8121b37d8165b11bba0e29537d26206d1a115 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 31 Oct 2021 18:58:30 +0100 Subject: [PATCH 14/14] Minor adjustment --- Lib/sqlite3/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/sqlite3/__init__.py b/Lib/sqlite3/__init__.py index db6a9046a23bc1..0dedf186b1a1eb 100644 --- a/Lib/sqlite3/__init__.py +++ b/Lib/sqlite3/__init__.py @@ -34,7 +34,7 @@ cx = sqlite3.connect(":memory:") # connect to a database in RAM -Once a Connection has been established, create a Cursor object and call +Once a connection has been established, create a Cursor object and call its execute() method to perform SQL queries: cu = cx.cursor()