diff options
author | Petri Lehtinen <petri@digip.org> | 2012-02-12 19:05:31 (GMT) |
---|---|---|
committer | Petri Lehtinen <petri@digip.org> | 2012-02-12 19:05:31 (GMT) |
commit | 51d04d1ba8643d8a0c89d8307bf43697223f31e2 (patch) | |
tree | c9833d6beddeab16516269de0a916e09a4b8bc0a /Lib/sqlite3/dump.py | |
parent | 54411c1784bc404448f496e7a9bf657eaab14daf (diff) | |
download | cpython-51d04d1ba8643d8a0c89d8307bf43697223f31e2.zip cpython-51d04d1ba8643d8a0c89d8307bf43697223f31e2.tar.gz cpython-51d04d1ba8643d8a0c89d8307bf43697223f31e2.tar.bz2 |
Fix sqlite3.Connection.iterdump on tables/fields with reserved names or quotes
Closes #9750
Diffstat (limited to 'Lib/sqlite3/dump.py')
-rw-r--r-- | Lib/sqlite3/dump.py | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/Lib/sqlite3/dump.py b/Lib/sqlite3/dump.py index 409a405..da6be68 100644 --- a/Lib/sqlite3/dump.py +++ b/Lib/sqlite3/dump.py @@ -1,6 +1,12 @@ # Mimic the sqlite3 console shell's .dump command # Author: Paul Kippes <kippesp@gmail.com> +# Every identifier in sql is quoted based on a comment in sqlite +# documentation "SQLite adds new keywords from time to time when it +# takes on new features. So to prevent your code from being broken by +# future enhancements, you should normally quote any identifier that +# is an English language word, even if you do not have to." + def _iterdump(connection): """ Returns an iterator to the dump of the database in an SQL text format. @@ -15,49 +21,49 @@ def _iterdump(connection): # sqlite_master table contains the SQL CREATE statements for the database. q = """ - SELECT name, type, sql - FROM sqlite_master - WHERE sql NOT NULL AND - type == 'table' + SELECT "name", "type", "sql" + FROM "sqlite_master" + WHERE "sql" NOT NULL AND + "type" == 'table' """ schema_res = cu.execute(q) - for table_name, type, sql in schema_res.fetchall(): + for table_name, type, sql in sorted(schema_res.fetchall()): if table_name == 'sqlite_sequence': - yield('DELETE FROM sqlite_sequence;') + yield('DELETE FROM "sqlite_sequence";') elif table_name == 'sqlite_stat1': - yield('ANALYZE sqlite_master;') + yield('ANALYZE "sqlite_master";') elif table_name.startswith('sqlite_'): continue # NOTE: Virtual table support not implemented #elif sql.startswith('CREATE VIRTUAL TABLE'): # qtable = table_name.replace("'", "''") # yield("INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"\ - # "VALUES('table','%s','%s',0,'%s');" % - # qtable, + # "VALUES('table','{0}','{0}',0,'{1}');".format( # qtable, - # sql.replace("''")) + # sql.replace("''"))) else: - yield('%s;' % sql) + yield('{0};'.format(sql)) # Build the insert statement for each row of the current table - res = cu.execute("PRAGMA table_info('%s')" % table_name) + table_name_ident = table_name.replace('"', '""') + res = cu.execute('PRAGMA table_info("{0}")'.format(table_name_ident)) column_names = [str(table_info[1]) for table_info in res.fetchall()] - q = "SELECT 'INSERT INTO \"%(tbl_name)s\" VALUES(" - q += ",".join(["'||quote(" + col + ")||'" for col in column_names]) - q += ")' FROM '%(tbl_name)s'" - query_res = cu.execute(q % {'tbl_name': table_name}) + q = """SELECT 'INSERT INTO "{0}" VALUES({1})' FROM "{0}";""".format( + table_name_ident, + ",".join("""'||quote("{0}")||'""".format(col.replace('"', '""')) for col in column_names)) + query_res = cu.execute(q) for row in query_res: - yield("%s;" % row[0]) + yield("{0};".format(row[0])) # Now when the type is 'index', 'trigger', or 'view' q = """ - SELECT name, type, sql - FROM sqlite_master - WHERE sql NOT NULL AND - type IN ('index', 'trigger', 'view') + SELECT "name", "type", "sql" + FROM "sqlite_master" + WHERE "sql" NOT NULL AND + "type" IN ('index', 'trigger', 'view') """ schema_res = cu.execute(q) for name, type, sql in schema_res.fetchall(): - yield('%s;' % sql) + yield('{0};'.format(sql)) yield('COMMIT;') |