-
-
Notifications
You must be signed in to change notification settings - Fork 813
Description
The three functions execute_write and execute_write_script and execute_write_many all use a transaction automatically - the with conn: bits:
datasette/datasette/database.py
Lines 124 to 160 in e1c80ef
| async def execute_write(self, sql, params=None, block=True): | |
| def _inner(conn): | |
| with conn: | |
| return conn.execute(sql, params or []) | |
| with trace("sql", database=self.name, sql=sql.strip(), params=params): | |
| results = await self.execute_write_fn(_inner, block=block) | |
| return results | |
| async def execute_write_script(self, sql, block=True): | |
| def _inner(conn): | |
| with conn: | |
| return conn.executescript(sql) | |
| with trace("sql", database=self.name, sql=sql.strip(), executescript=True): | |
| results = await self.execute_write_fn(_inner, block=block) | |
| return results | |
| async def execute_write_many(self, sql, params_seq, block=True): | |
| def _inner(conn): | |
| count = 0 | |
| def count_params(params): | |
| nonlocal count | |
| for param in params: | |
| count += 1 | |
| yield param | |
| with conn: | |
| return conn.executemany(sql, count_params(params_seq)), count | |
| with trace( | |
| "sql", database=self.name, sql=sql.strip(), executemany=True | |
| ) as kwargs: | |
| results, count = await self.execute_write_fn(_inner, block=block) | |
| kwargs["count"] = count | |
| return results |
execute_write_fn() does not do that. It leaves the function to implement its own transaction handling:
datasette/datasette/database.py
Lines 182 to 190 in e1c80ef
| async def execute_write_fn(self, fn, block=True): | |
| if self.ds.executor is None: | |
| # non-threaded mode | |
| if self._write_connection is None: | |
| self._write_connection = self.connect(write=True) | |
| self.ds._prepare_connection(self._write_connection, self.name) | |
| return fn(self._write_connection) | |
| else: | |
| return await self._send_to_write_thread(fn, block) |
datasette/datasette/database.py
Lines 246 to 251 in e1c80ef
| try: | |
| result = task.fn(conn) | |
| except Exception as e: | |
| sys.stderr.write("{}\n".format(e)) | |
| sys.stderr.flush() | |
| result = e |
Every time I forget to do my own with conn: in that function I end up with a "database locked" error cropping up! It's an annoying mistake. Here for example:
I'm going to change the execute_write_fn() method to include a transaction=True argument - defaults to True - which causes it to wrap the function in a transaction for you.
You can call transaction=False to opt out of that and handle transactions manually instead.
This would technically be a breaking change which is why I want to get it in before 1.0.