summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>2017-01-01 18:04:51 +0100
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>2017-01-01 18:15:01 +0100
commit49461c2c39debdb0c96201f733b0d19da28b70ac (patch)
tree84e9995aca710ff11f2b31d869a23fb4c95a5a2e
parent992694226077b0d5688071ea92cf84e105e05e17 (diff)
downloadpsycopg2-49461c2c39debdb0c96201f733b0d19da28b70ac.tar.gz
More doc love for the sql module
-rw-r--r--doc/src/faq.rst18
-rw-r--r--doc/src/sql.rst4
-rw-r--r--doc/src/usage.rst7
-rw-r--r--lib/sql.py58
4 files changed, 63 insertions, 24 deletions
diff --git a/doc/src/faq.rst b/doc/src/faq.rst
index 89d8a63..fb7b33d 100644
--- a/doc/src/faq.rst
+++ b/doc/src/faq.rst
@@ -151,6 +151,24 @@ Psycopg converts :sql:`json` values into Python objects but :sql:`jsonb` values
See :ref:`adapt-json` for further details.
+.. _faq-identifier:
+.. cssclass:: faq
+
+How can I pass field/table names to a query?
+ The arguments in the `~cursor.execute()` methods can only represent data
+ to pass to the query: they cannot represent a table or field name::
+
+ # This doesn't work
+ cur.execute("insert into %s values (%s)", ["my_table", 42])
+
+ If you want to build a query dynamically you can use the objects exposed
+ by the `psycopg2.sql` module::
+
+ cur.execute(
+ sql.SQL("insert into %s values (%%s)") % [sql.Identifier("my_table")],
+ [42])
+
+
.. _faq-bytea-9.0:
.. cssclass:: faq
diff --git a/doc/src/sql.rst b/doc/src/sql.rst
index 1328a86..f044372 100644
--- a/doc/src/sql.rst
+++ b/doc/src/sql.rst
@@ -9,7 +9,7 @@
The module contains objects and functions useful to generate SQL dynamically,
in a convenient and safe way. SQL identifiers (e.g. names of tables and
-fields) cannot be passed to the `~cursor.execute()` function like query
+fields) cannot be passed to the `~cursor.execute()` method like query
arguments::
# This will not work
@@ -45,7 +45,7 @@ in the presence of a table or field name with containing characters to escape,
or will present a potentially exploitable weakness.
The objects exposed by the `!psycopg2.sql` module allow generating SQL
-statements on the fly, separating clearly the variable parts in the statement
+statements on the fly, separating clearly the variable parts of the statement
from the query parameters::
from psycopg2 import sql
diff --git a/doc/src/usage.rst b/doc/src/usage.rst
index d9fea75..1366485 100644
--- a/doc/src/usage.rst
+++ b/doc/src/usage.rst
@@ -132,9 +132,10 @@ query:
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar",)) # correct
>>> cur.execute("INSERT INTO foo VALUES (%s)", ["bar"]) # correct
-- Only variable values should be bound via this method: it shouldn't be used
- to set table or field names. For these elements, ordinary string formatting
- should be used before running `~cursor.execute()`.
+- Only query values should be bound via this method: it shouldn't be used to
+ merge table or field names to the query. If you need to generate dynamically
+ an SQL query (for instance choosing dynamically a table name) you can use
+ the facilities provided by the `psycopg2.sql` module.
diff --git a/lib/sql.py b/lib/sql.py
index fc946b5..ff7faa1 100644
--- a/lib/sql.py
+++ b/lib/sql.py
@@ -78,9 +78,10 @@ class Composed(Composable):
Example::
- >>> sql.Composed([sql.SQL("insert into "), sql.Identifier("table")]) \\
- ... .as_string(conn)
- 'insert into "table"'
+ >>> comp = sql.Composed(
+ ... [sql.SQL("insert into "), sql.Identifier("table")])
+ >>> print(comp.as_string(conn))
+ insert into "table"
.. automethod:: join
"""
@@ -119,8 +120,8 @@ class Composed(Composable):
Example::
>>> fields = sql.Identifier('foo') + sql.Identifier('bar') # a Composed
- >>> fields.join(', ').as_string(conn)
- '"foo", "bar"'
+ >>> print(fields.join(', ').as_string(conn))
+ "foo", "bar"
"""
if isinstance(joiner, basestring):
@@ -155,9 +156,8 @@ class SQL(Composable):
>>> query = sql.SQL("select %s from %s") % [
... sql.SQL(', ').join([sql.Identifier('foo'), sql.Identifier('bar')]),
... sql.Identifier('table')]
- >>> query.as_string(conn)
- select "foo", "bar" from "table"'
-
+ >>> print(query.as_string(conn))
+ select "foo", "bar" from "table"
.. automethod:: join
"""
@@ -184,8 +184,8 @@ class SQL(Composable):
Example::
>>> snip - sql.SQL(', ').join(map(sql.Identifier, ['foo', 'bar', 'baz']))
- >>> snip.as_string(conn)
- '"foo", "bar", "baz"'
+ >>> print(snip.as_string(conn))
+ "foo", "bar", "baz"
"""
if isinstance(seq, Composed):
seq = seq._seq
@@ -214,6 +214,15 @@ class Identifier(Composable):
.. __: https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html# \
SQL-SYNTAX-IDENTIFIERS
+
+ Example::
+
+ >>> t1 = sql.Identifier("foo")
+ >>> t2 = sql.Identifier("ba'r")
+ >>> t3 = sql.Identifier('ba"z')
+ >>> print(sql.SQL(', ').join([t1, t2, t3]).as_string(conn))
+ "foo", "ba'r", "ba""z"
+
"""
def __init__(self, string):
if not isinstance(string, basestring):
@@ -239,6 +248,14 @@ class Literal(Composable):
The string returned by `!as_string()` follows the normal :ref:`adaptation
rules <python-types-adaptation>` for Python objects.
+ Example::
+
+ >>> s1 = sql.Literal("foo")
+ >>> s2 = sql.Literal("ba'r")
+ >>> s3 = sql.Literal(42)
+ >>> print(sql.SQL(', ').join([s1, s2, s3]).as_string(conn))
+ 'foo', 'ba''r', 42
+
"""
def __init__(self, wrapped):
self._wrapped = wrapped
@@ -277,17 +294,20 @@ class Placeholder(Composable):
Examples::
- >>> (sql.SQL("insert into table (%s) values (%s)") % [
- ... sql.SQL(', ').join(map(sql.Identifier, names)),
- ... sql.SQL(', ').join(sql.Placeholder() * 3)
- ... ]).as_string(conn)
- 'insert into table ("foo", "bar", "baz") values (%s, %s, %s)'
+ >>> names = ['foo', 'bar', 'baz']
- >>> (sql.SQL("insert into table (%s) values (%s)") % [
+ >>> q1 = sql.SQL("insert into table (%s) values (%s)") % [
... sql.SQL(', ').join(map(sql.Identifier, names)),
- ... sql.SQL(', ').join(map(sql.Placeholder, names))
- ... ]).as_string(conn)
- 'insert into table ("foo", "bar", "baz") values (%(foo)s, %(bar)s, %(baz)s)'
+ ... sql.SQL(', ').join(sql.Placeholder() * 3)]
+ >>> print(q1.as_string(conn))
+ insert into table ("foo", "bar", "baz") values (%s, %s, %s)
+
+ >>> q2 = sql.SQL("insert into table (%s) values (%s)") % [
+ ... sql.SQL(', ').join(map(sql.Identifier, names)),
+ ... sql.SQL(', ').join(map(sql.Placeholder, names))]
+ >>> print(q2.as_string(conn))
+ insert into table ("foo", "bar", "baz") values (%(foo)s, %(bar)s, %(baz)s)
+
"""
def __init__(self, name=None):