Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 51d04d1

Browse files
committed
Fix sqlite3.Connection.iterdump on tables/fields with reserved names or quotes
Closes #9750
1 parent 54411c1 commit 51d04d1

4 files changed

Lines changed: 41 additions & 22 deletions

File tree

Lib/sqlite3/dump.py

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# Mimic the sqlite3 console shell's .dump command
22
# Author: Paul Kippes <[email protected]>
33

4+
# Every identifier in sql is quoted based on a comment in sqlite
5+
# documentation "SQLite adds new keywords from time to time when it
6+
# takes on new features. So to prevent your code from being broken by
7+
# future enhancements, you should normally quote any identifier that
8+
# is an English language word, even if you do not have to."
9+
410
def _iterdump(connection):
511
"""
612
Returns an iterator to the dump of the database in an SQL text format.
@@ -15,49 +21,49 @@ def _iterdump(connection):
1521

1622
# sqlite_master table contains the SQL CREATE statements for the database.
1723
q = """
18-
SELECT name, type, sql
19-
FROM sqlite_master
20-
WHERE sql NOT NULL AND
21-
type == 'table'
24+
SELECT "name", "type", "sql"
25+
FROM "sqlite_master"
26+
WHERE "sql" NOT NULL AND
27+
"type" == 'table'
2228
"""
2329
schema_res = cu.execute(q)
24-
for table_name, type, sql in schema_res.fetchall():
30+
for table_name, type, sql in sorted(schema_res.fetchall()):
2531
if table_name == 'sqlite_sequence':
26-
yield('DELETE FROM sqlite_sequence;')
32+
yield('DELETE FROM "sqlite_sequence";')
2733
elif table_name == 'sqlite_stat1':
28-
yield('ANALYZE sqlite_master;')
34+
yield('ANALYZE "sqlite_master";')
2935
elif table_name.startswith('sqlite_'):
3036
continue
3137
# NOTE: Virtual table support not implemented
3238
#elif sql.startswith('CREATE VIRTUAL TABLE'):
3339
# qtable = table_name.replace("'", "''")
3440
# yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"\
35-
# "VALUES('table','%s','%s',0,'%s');" %
36-
# qtable,
41+
# "VALUES('table','{0}','{0}',0,'{1}');".format(
3742
# qtable,
38-
# sql.replace("''"))
43+
# sql.replace("''")))
3944
else:
40-
yield('%s;' % sql)
45+
yield('{0};'.format(sql))
4146

4247
# Build the insert statement for each row of the current table
43-
res = cu.execute("PRAGMA table_info('%s')" % table_name)
48+
table_name_ident = table_name.replace('"', '""')
49+
res = cu.execute('PRAGMA table_info("{0}")'.format(table_name_ident))
4450
column_names = [str(table_info[1]) for table_info in res.fetchall()]
45-
q = "SELECT 'INSERT INTO \"%(tbl_name)s\" VALUES("
46-
q += ",".join(["'||quote(" + col + ")||'" for col in column_names])
47-
q += ")' FROM '%(tbl_name)s'"
48-
query_res = cu.execute(q % {'tbl_name': table_name})
51+
q = """SELECT 'INSERT INTO "{0}" VALUES({1})' FROM "{0}";""".format(
52+
table_name_ident,
53+
",".join("""'||quote("{0}")||'""".format(col.replace('"', '""')) for col in column_names))
54+
query_res = cu.execute(q)
4955
for row in query_res:
50-
yield("%s;" % row[0])
56+
yield("{0};".format(row[0]))
5157

5258
# Now when the type is 'index', 'trigger', or 'view'
5359
q = """
54-
SELECT name, type, sql
55-
FROM sqlite_master
56-
WHERE sql NOT NULL AND
57-
type IN ('index', 'trigger', 'view')
60+
SELECT "name", "type", "sql"
61+
FROM "sqlite_master"
62+
WHERE "sql" NOT NULL AND
63+
"type" IN ('index', 'trigger', 'view')
5864
"""
5965
schema_res = cu.execute(q)
6066
for name, type, sql in schema_res.fetchall():
61-
yield('%s;' % sql)
67+
yield('{0};'.format(sql))
6268

6369
yield('COMMIT;')

Lib/sqlite3/test/dump.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ def tearDown(self):
1313

1414
def CheckTableDump(self):
1515
expected_sqls = [
16+
"""CREATE TABLE "index"("index" blob);"""
17+
,
18+
"""INSERT INTO "index" VALUES(X'01');"""
19+
,
20+
"""CREATE TABLE "quoted""table"("quoted""field" text);"""
21+
,
22+
"""INSERT INTO "quoted""table" VALUES('quoted''value');"""
23+
,
1624
"CREATE TABLE t1(id integer primary key, s1 text, " \
1725
"t1_i1 integer not null, i2 integer, unique (s1), " \
1826
"constraint t1_idx1 unique (i2));"

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ Lenny Kneler
503503
Pat Knight
504504
Greg Kochanski
505505
Damon Kohler
506+
Marko Kohtala
506507
Vlad Korolev
507508
Joseph Koshy
508509
Maksim Kozyarchuk

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ Core and Builtins
113113
Library
114114
-------
115115

116+
- Issue #9750: Fix sqlite3.Connection.iterdump on tables and fields
117+
with a name that is a keyword or contains quotes. Patch by Marko
118+
Kohtala.
119+
116120
- Issue #10287: nntplib now queries the server's CAPABILITIES again after
117121
authenticating (since the result may change, according to RFC 4643).
118122
Patch by Hynek Schlawack.

0 commit comments

Comments
 (0)