Skip to content

Commit bc74b87

Browse files
LokkookArchmongerpre-commit-ci[bot]
authored
Fix dbrestore on SQLite (jazzband#383)
Co-authored-by: Mark <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Mark Bakhit <[email protected]>
1 parent 163bd9e commit bc74b87

File tree

7 files changed

+63
-18
lines changed

7 files changed

+63
-18
lines changed

dbbackup/db/sqlite.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,23 @@ def restore_dump(self, dump):
7171
if not self.connection.is_usable():
7272
self.connection.connect()
7373
cursor = self.connection.cursor()
74+
sql_command = b""
75+
sql_is_complete = True
7476
for line in dump.readlines():
75-
try:
76-
cursor.execute(line.decode("UTF-8"))
77-
except (OperationalError, IntegrityError) as err:
78-
warnings.warn(f"Error in db restore: {err}")
77+
sql_command = sql_command + line
78+
line_str = line.decode("UTF-8")
79+
if line_str.startswith("INSERT") and not line_str.endswith(");\n"):
80+
sql_is_complete = False
81+
continue
82+
if not sql_is_complete and line_str.endswith(");\n"):
83+
sql_is_complete = True
84+
85+
if sql_is_complete:
86+
try:
87+
cursor.execute(sql_command.decode("UTF-8"))
88+
except (OperationalError, IntegrityError) as err:
89+
warnings.warn(f"Error in db restore: {err}")
90+
sql_command = b""
7991

8092

8193
class SqliteCPConnector(BaseDBConnector):

dbbackup/tests/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"dbbackup",
3030
"dbbackup.tests.testapp",
3131
)
32+
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
3233

3334
DATABASES = {
3435
"default": {

dbbackup/tests/test_connectors/test_sqlite.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from django.test import TestCase
66

77
from dbbackup.db.sqlite import SqliteConnector, SqliteCPConnector
8-
from dbbackup.tests.testapp.models import CharModel
8+
from dbbackup.tests.testapp.models import CharModel, TextModel
99

1010

1111
class SqliteConnectorTest(TestCase):
@@ -28,7 +28,17 @@ def test_create_dump_with_unicode(self):
2828
dump = connector.create_dump()
2929
self.assertTrue(dump.read())
3030

31+
def test_create_dump_with_newline(self):
32+
TextModel.objects.create(
33+
field=f'INSERT ({"foo" * 5000}\nbar\n WHERE \nbaz IS\n "great" );\n'
34+
)
35+
36+
connector = SqliteConnector()
37+
dump = connector.create_dump()
38+
self.assertTrue(dump.read())
39+
3140
def test_restore_dump(self):
41+
TextModel.objects.create(field="T\nf\nw\nnl")
3242
connector = SqliteConnector()
3343
dump = connector.create_dump()
3444
connector.restore_dump(dump)

dbbackup/tests/testapp/migrations/0001_initial.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
class Migration(migrations.Migration):
55

6+
initial = True
67
dependencies = []
78

89
operations = [
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Generated by Django 4.0.1 on 2022-04-27 22:36
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("testapp", "0001_initial"),
10+
]
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name="TextModel",
15+
fields=[
16+
(
17+
"id",
18+
models.AutoField(
19+
auto_created=True,
20+
primary_key=True,
21+
serialize=False,
22+
verbose_name="ID",
23+
),
24+
),
25+
("field", models.TextField()),
26+
],
27+
),
28+
]

dbbackup/tests/testapp/models.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
11
from django.db import models
22

3-
___all__ = (
4-
"CharModel",
5-
"IntegerModel",
6-
"TextModel",
7-
"BooleanModel" "DateModel",
8-
"DateTimeModel",
9-
"ForeignKeyModel",
10-
"ManyToManyModel",
11-
"FileModel",
12-
"TestModel",
13-
)
14-
153

164
class CharModel(models.Model):
175
field = models.CharField(max_length=10)
186

197

8+
class TextModel(models.Model):
9+
field = models.TextField()
10+
11+
2012
class ForeignKeyModel(models.Model):
2113
field = models.ForeignKey(CharModel, on_delete=models.CASCADE)
2214

docs/changelog.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ Changelog
44
Unreleased
55
----------
66

7-
* Add `--no-drop` option to `dbrestore` command to prevent dropping tables before restoring data.
7+
* Add --no-drop option to dbrestore command to prevent dropping tables before restoring data.
8+
* Fix bug where sqlite dbrestore would fail if field data contains the line break character.
89

910
4.2.0 (2024-08-22)
1011
------------------

0 commit comments

Comments
 (0)