mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-09-28 04:44:26 +02:00
Split out _iter_complete_sql_statements
To make it clearer why we are avoiding executescript()
This commit is contained in:
parent
83311dc738
commit
a65df4cc69
2 changed files with 57 additions and 12 deletions
|
|
@ -196,6 +196,19 @@ DEFAULT = Default()
|
||||||
Tracer = Callable[[str, Optional[Union[Sequence[Any], Dict[str, Any]]]], None]
|
Tracer = Callable[[str, Optional[Union[Sequence[Any], Dict[str, Any]]]], None]
|
||||||
|
|
||||||
|
|
||||||
|
def _iter_complete_sql_statements(sql: str) -> Generator[str, None, None]:
|
||||||
|
statement = []
|
||||||
|
for char in sql:
|
||||||
|
statement.append(char)
|
||||||
|
statement_sql = "".join(statement).strip()
|
||||||
|
if statement_sql and sqlite3.complete_statement(statement_sql):
|
||||||
|
yield statement_sql
|
||||||
|
statement = []
|
||||||
|
statement_sql = "".join(statement).strip()
|
||||||
|
if statement_sql:
|
||||||
|
yield statement_sql
|
||||||
|
|
||||||
|
|
||||||
COLUMN_TYPE_MAPPING: Dict[Any, str] = {
|
COLUMN_TYPE_MAPPING: Dict[Any, str] = {
|
||||||
float: "REAL",
|
float: "REAL",
|
||||||
int: "INTEGER",
|
int: "INTEGER",
|
||||||
|
|
@ -618,16 +631,9 @@ class Database:
|
||||||
def _executescript(self, sql: str) -> sqlite3.Cursor:
|
def _executescript(self, sql: str) -> sqlite3.Cursor:
|
||||||
if self.conn.in_transaction:
|
if self.conn.in_transaction:
|
||||||
cursor = self.conn.cursor()
|
cursor = self.conn.cursor()
|
||||||
statement = []
|
# avoid sqlite3.executescript()'s implicit commit:
|
||||||
for char in sql:
|
for statement in _iter_complete_sql_statements(sql):
|
||||||
statement.append(char)
|
cursor.execute(statement)
|
||||||
statement_sql = "".join(statement).strip()
|
|
||||||
if statement_sql and sqlite3.complete_statement(statement_sql):
|
|
||||||
cursor.execute(statement_sql)
|
|
||||||
statement = []
|
|
||||||
statement_sql = "".join(statement).strip()
|
|
||||||
if statement_sql:
|
|
||||||
cursor.execute(statement_sql)
|
|
||||||
return cursor
|
return cursor
|
||||||
return self.conn.executescript(sql)
|
return self.conn.executescript(sql)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,46 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from sqlite_utils.db import _iter_complete_sql_statements
|
||||||
from sqlite_utils.utils import sqlite3
|
from sqlite_utils.utils import sqlite3
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"sql,expected",
|
||||||
|
(
|
||||||
|
(
|
||||||
|
"CREATE TABLE t(id); INSERT INTO t VALUES (1)",
|
||||||
|
["CREATE TABLE t(id);", "INSERT INTO t VALUES (1)"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"INSERT INTO t VALUES ('a;b');",
|
||||||
|
["INSERT INTO t VALUES ('a;b');"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"-- comment;\nCREATE TABLE t(id);",
|
||||||
|
["-- comment;\nCREATE TABLE t(id);"],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""
|
||||||
|
CREATE TRIGGER t_ai AFTER INSERT ON t
|
||||||
|
BEGIN
|
||||||
|
UPDATE t SET value = 'a;b' WHERE id = new.id;
|
||||||
|
INSERT INTO log VALUES ('x;y');
|
||||||
|
END;
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
"CREATE TRIGGER t_ai AFTER INSERT ON t\n"
|
||||||
|
" BEGIN\n"
|
||||||
|
" UPDATE t SET value = 'a;b' WHERE id = new.id;\n"
|
||||||
|
" INSERT INTO log VALUES ('x;y');\n"
|
||||||
|
" END;"
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_iter_complete_sql_statements(sql, expected):
|
||||||
|
assert list(_iter_complete_sql_statements(sql)) == expected
|
||||||
|
|
||||||
|
|
||||||
def test_atomic_commits(fresh_db):
|
def test_atomic_commits(fresh_db):
|
||||||
with fresh_db.atomic():
|
with fresh_db.atomic():
|
||||||
fresh_db["dogs"].insert({"id": 1, "name": "Cleo"}, pk="id")
|
fresh_db["dogs"].insert({"id": 1, "name": "Cleo"}, pk="id")
|
||||||
|
|
@ -54,9 +92,10 @@ def test_executescript_does_not_commit_open_atomic_block(fresh_db):
|
||||||
CREATE TABLE dogs(id INTEGER PRIMARY KEY, name TEXT);
|
CREATE TABLE dogs(id INTEGER PRIMARY KEY, name TEXT);
|
||||||
CREATE TRIGGER dogs_ai AFTER INSERT ON dogs
|
CREATE TRIGGER dogs_ai AFTER INSERT ON dogs
|
||||||
BEGIN
|
BEGIN
|
||||||
UPDATE dogs SET name = upper(new.name) WHERE id = new.id;
|
UPDATE dogs SET name = upper(new.name) || '; updated' WHERE id = new.id;
|
||||||
END;
|
END;
|
||||||
INSERT INTO dogs VALUES (1, 'Cleo');
|
-- This comment has a semicolon;
|
||||||
|
INSERT INTO dogs VALUES (1, 'Cleo; the first');
|
||||||
""")
|
""")
|
||||||
raise RuntimeError("boom")
|
raise RuntimeError("boom")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue