@@ -55,33 +55,6 @@ The data you've saved is persistent and is available in subsequent sessions::
5555   con = sqlite3.connect('example.db') 
5656   cur = con.cursor() 
5757
58- Usually your SQL operations will need to use values from Python variables.  You
59- shouldn't assemble your query using Python's string operations because doing so
60- is insecure; it makes your program vulnerable to an SQL injection attack
61- (see https://xkcd.com/327/ for humorous example of what can go wrong).
62- 
63- Instead, use the DB-API's parameter substitution.  Put ``? `` as a placeholder
64- wherever you want to use a value, and then provide a tuple of values as the
65- second argument to the cursor's :meth: `~Cursor.execute ` method.  (Other database
66- modules may use a different placeholder, such as ``%s `` or ``:1 ``.) For
67- example::
68- 
69-    # Never do this -- insecure! 
70-    symbol = 'RHAT' 
71-    cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol) 
72- 
73-    # Do this instead 
74-    t = ('RHAT',) 
75-    cur.execute('SELECT * FROM stocks WHERE symbol=?', t) 
76-    print(cur.fetchone()) 
77- 
78-    # Larger example that inserts many records at a time 
79-    purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), 
80-                 ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00), 
81-                 ('2006-04-06', 'SELL', 'IBM', 500, 53.00), 
82-                ] 
83-    cur.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases) 
84- 
8558To retrieve data after executing a SELECT statement, you can either treat the
8659cursor as an :term: `iterator `, call the cursor's :meth: `~Cursor.fetchone ` method to
8760retrieve a single matching row, or call :meth: `~Cursor.fetchall ` to get a list of the
@@ -98,6 +71,33 @@ This example uses the iterator form::
9871   ('2006-04-05', 'BUY', 'MSFT', 1000, 72.0) 
9972
10073
74+ .. _sqlite3-placeholders :
75+ 
76+ Usually your SQL operations will need to use values from Python variables.  You
77+ shouldn't assemble your query using Python's string operations because doing so
78+ is insecure; it makes your program vulnerable to an SQL injection attack
79+ (see the `xkcd webcomic  <https://xkcd.com/327/ >`_ for a humorous example of
80+ what can go wrong)::
81+ 
82+    # Never do this -- insecure! 
83+    symbol = 'RHAT' 
84+    cur.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol) 
85+ 
86+ Instead, use the DB-API's parameter substitution. Put a placeholder wherever
87+ you want to use a value, and then provide a tuple of values as the second
88+ argument to the cursor's :meth: `~Cursor.execute ` method. An SQL statement may
89+ use one of two kinds of placeholders: question marks (qmark style) or named
90+ placeholders (named style). For the qmark style, ``parameters `` must be a
91+ :term: `sequence <sequence> `. For the named style, it can be either a
92+ :term: `sequence <sequence> ` or :class: `dict ` instance. The length of the
93+ :term: `sequence <sequence> ` must match the number of placeholders, or a
94+ :exc: `ProgrammingError ` is raised. If a :class: `dict ` is given, it must contain
95+ keys for all named parameters. Any extra items are ignored. Here's an example
96+ of both styles:
97+ 
98+ .. literalinclude :: ../includes/sqlite3/execute_1.py 
99+ 
100+ 
101101.. seealso ::
102102
103103   https://www.sqlite.org
@@ -607,14 +607,8 @@ Cursor Objects
607607
608608   .. method :: execute(sql[, parameters]) 
609609
610-       Executes an SQL statement. The SQL statement may be parameterized (i. e.
611-       placeholders instead of SQL literals). The :mod: `sqlite3 ` module supports two
612-       kinds of placeholders: question marks (qmark style) and named placeholders
613-       (named style).
614- 
615-       Here's an example of both styles:
616- 
617-       .. literalinclude :: ../includes/sqlite3/execute_1.py 
610+       Executes an SQL statement. Values may be bound to the statement using
611+       :ref: `placeholders  <sqlite3-placeholders >`.
618612
619613      :meth: `execute ` will only execute a single SQL statement. If you try to execute
620614      more than one statement with it, it will raise a :exc: `.Warning `. Use
@@ -624,9 +618,10 @@ Cursor Objects
624618
625619   .. method :: executemany(sql, seq_of_parameters) 
626620
627-       Executes an SQL command against all parameter sequences or mappings found in
628-       the sequence *seq_of_parameters *.  The :mod: `sqlite3 ` module also allows
629-       using an :term: `iterator ` yielding parameters instead of a sequence.
621+       Executes a :ref: `parameterized  <sqlite3-placeholders >` SQL command
622+       against all parameter sequences or mappings found in the sequence
623+       *seq_of_parameters *. The :mod: `sqlite3 ` module also allows using an
624+       :term: `iterator ` yielding parameters instead of a sequence.
630625
631626      .. literalinclude :: ../includes/sqlite3/executemany_1.py 
632627
0 commit comments