| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 210a5d7 commit 400a1ce
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,6 +7,10 @@ | |||
| 7 | 7 | # future enhancements, you should normally quote any identifier that | |
| 8 | 8 | # is an English language word, even if you do not have to." | |
| 9 | 9 | ||
| 10 | + | ||
| 11 | + from contextlib import contextmanager | ||
| 12 | + | ||
| 13 | + | ||
| 10 | 14 | def _quote_name(name): | |
| 11 | 15 | return '"{0}"'.format(name.replace('"', '""')) | |
| 12 | 16 | ||
@@ -15,6 +19,24 @@ def _quote_value(value): | |||
| 15 | 19 | return "'{0}'".format(value.replace("'", "''")) | |
| 16 | 20 | ||
| 17 | 21 | ||
| 22 | + def _force_decode(bs, *args, **kwargs): | ||
| 23 | + # gh-108590: Don't fail if the database contains invalid Unicode data. | ||
| 24 | + try: | ||
| 25 | + return bs.decode(*args, **kwargs) | ||
| 26 | + except UnicodeDecodeError: | ||
| 27 | + return "".join([chr(c) for c in bs]) | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + @contextmanager | ||
| 31 | + def _text_factory(con, factory): | ||
| 32 | + saved_factory = con.text_factory | ||
| 33 | + con.text_factory = factory | ||
| 34 | + try: | ||
| 35 | + yield | ||
| 36 | + finally: | ||
| 37 | + con.text_factory = saved_factory | ||
| 38 | + | ||
| 39 | + | ||
| 18 | 40 | def _iterdump(connection): | |
| 19 | 41 | """ | |
| 20 | 42 | Returns an iterator to the dump of the database in an SQL text format. | |
@@ -74,8 +96,9 @@ def _iterdump(connection): | |||
| 74 | 96 | ) | |
| 75 | 97 | ) | |
| 76 | 98 | query_res = cu.execute(q) | |
| 77 | - for row in query_res: | ||
| 78 | - yield("{0};".format(row[0])) | ||
| 99 | + with _text_factory(connection, bytes): | ||
| 100 | + for row in query_res: | ||
| 101 | + yield("{0};".format(_force_decode(row[0]))) | ||
| 79 | 102 | ||
| 80 | 103 | # Now when the type is 'index', 'trigger', or 'view' | |
| 81 | 104 | q = """ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -133,6 +133,21 @@ def test_dump_virtual_tables(self): | |||
| 133 | 133 | actual = list(self.cx.iterdump()) | |
| 134 | 134 | self.assertEqual(expected, actual) | |
| 135 | 135 | ||
| 136 | + def test_dump_unicode_invalid(self): | ||
| 137 | + # gh-108590 | ||
| 138 | + expected = [ | ||
| 139 | + "BEGIN TRANSACTION;", | ||
| 140 | + "CREATE TABLE foo (data TEXT);", | ||
| 141 | + "INSERT INTO \"foo\" VALUES('a\x9f');", | ||
| 142 | + "COMMIT;", | ||
| 143 | + ] | ||
| 144 | + self.cu.executescript(""" | ||
| 145 | + CREATE TABLE foo (data TEXT); | ||
| 146 | + INSERT INTO foo VALUES (CAST(X'619f' AS TEXT)); | ||
| 147 | + """) | ||
| 148 | + actual = list(self.cx.iterdump()) | ||
| 149 | + self.assertEqual(expected, actual) | ||
| 150 | + | ||
| 136 | 151 | ||
| 137 | 152 | if __name__ == "__main__": | |
| 138 | 153 | unittest.main() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1 @@ | |||
| 1 | + Fixed an issue where :meth:`sqlite3.Connection.iterdump` would fail and leave an incomplete SQL dump if a table includes invalid Unicode sequences. Patch by Corvin McPherson | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments