This sort of works, but it is an accident waiting to happen: the table name
may be an invalid SQL literal and need quoting; even more serious is the
-security problem in case the table name comes from an untrusted source. The
-name should be escaped using `~psycopg.pq.Escaping.escape_identifier()`::
+security problem in case the table name comes from an untrusted source.
- from psycopg.pq import Escaping
+.. note::
- # This works, but it is not optimal
- table_name = 'my_table'
- cur.execute(
- "INSERT INTO %s VALUES (%%s, %%s)" % Escaping.escape_identifier(table_name),
- [10, 20])
-
-This is now safe, but it somewhat ad-hoc. In case, for some reason, it is
-necessary to include a value in the query string (as opposite as in a value)
-the merging rule is still different. It is also still relatively dangerous: if
-`!escape_identifier()` is forgotten somewhere, the program will usually work,
-but will eventually crash in the presence of a table or field name with
-containing characters to escape, or will present a potentially exploitable
-weakness.
+ The low-level `~psycopg.pq.Escaping.escape_identifier()` function can be
+ used to escape a single identifier, but it operates on :sql:`bytes` and
+ is cumbersome to use in practice. The `!psycopg.sql` module, described
+ below, is the recommended approach for building dynamic queries safely.
The objects exposed by the `!psycopg.sql` module allow generating SQL
statements on the fly, separating clearly the variable parts of the statement
elif fmt == FMT_SQL:
# It must have been processed already
raise e.ProgrammingError(
- "sql values must be sql.Composite, sql.SQL, or Template;"
+ "sql values must be sql.Composable, sql.SQL, or Template;"
f" got {type(item.value).__qualname__}"
f" in {{{item.expression}:{fmt}}}"
)