Skip to content

gh-153658: Fix sqlite3 iterdump() for table names containing a single quote#153659

Open
tonghuaroot wants to merge 1 commit into
python:mainfrom
tonghuaroot:iterdump-squote-name
Open

gh-153658: Fix sqlite3 iterdump() for table names containing a single quote#153659
tonghuaroot wants to merge 1 commit into
python:mainfrom
tonghuaroot:iterdump-squote-name

Conversation

@tonghuaroot

@tonghuaroot tonghuaroot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

sqlite3.Connection.iterdump() raised sqlite3.OperationalError for a table
or column name containing a single quote, because the generated INSERT
statement embeds the quoted identifier inside a single-quoted SQL string
literal without doubling the single quotes. The FROM clause uses the
identifier form as-is; only the string-literal copy needs escaping.

Doubling the single quotes in the string-literal copy makes the dump of a
table whose name contains ' well-formed again, and it round-trips through
executescript(). Names containing a double quote or a newline were already
handled and are unaffected.

@erlend-aasland erlend-aasland left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the report and the PR! Mostly looks good, but I have a nitpick regarding the inlined escaping.

Comment thread Lib/sqlite3/dump.py
table_name_ident,
# In the string-literal copy any single quote must be doubled;
# the FROM clause below uses the identifier form as-is.
table_name_literal = table_name_ident.replace("'", "''")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent scattering .replace around in dump.py, consider something like this:

diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py
index d39cebb3e25..b33278567ce 100644
--- a/Lib/sqlite3/dump.py
+++ b/Lib/sqlite3/dump.py
@@ -11,8 +11,12 @@ def _quote_name(name):
     return '"{0}"'.format(name.replace('"', '""'))
 
 
+def _escape_single_quotes(value):
+    return value.replace("'", "''")
+
+
 def _quote_value(value):
-    return "'{0}'".format(value.replace("'", "''"))
+    return "'{0}'".format(_escape_single_quotes)
 
 
 def _iterdump(connection, *, filter=None):
@@ -80,11 +84,8 @@ def _iterdump(connection, *, filter=None):
         table_name_ident = _quote_name(table_name)
         res = cu.execute(f'PRAGMA table_info({table_name_ident})')
         column_names = [str(table_info[1]) for table_info in res.fetchall()]
-        # In the string-literal copy any single quote must be doubled;
-        # the FROM clause below uses the identifier form as-is.
-        table_name_literal = table_name_ident.replace("'", "''")
         q = "SELECT 'INSERT INTO {0} VALUES('{1}')' FROM {2};".format(
-            table_name_literal,
+            _escape_single_quotes(table_name_ident),
             "','".join(
                 "||quote({0})||".format(_quote_name(col)) for col in column_names
             ),

IMO, that would also make the comment redundant.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sqlite3.Connection.iterdump() fails for a table name containing a single quote

2 participants