mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Set time limit of 1000ms on SQL queries
Using the (undocumented in the Python docs) fact that if you return 1 from a set_progress_handler callback, SQLite will cancel the current query. Closes #35
This commit is contained in:
parent
2fe94641b0
commit
6823b09406
1 changed files with 21 additions and 3 deletions
24
app.py
24
app.py
|
|
@ -4,6 +4,7 @@ from sanic.exceptions import NotFound
|
|||
from sanic.views import HTTPMethodView
|
||||
from sanic_jinja2 import SanicJinja2
|
||||
import sqlite3
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from functools import wraps
|
||||
import urllib.parse
|
||||
|
|
@ -18,6 +19,7 @@ app_root = Path(__file__).parent
|
|||
BUILD_METADATA = 'build-metadata.json'
|
||||
DB_GLOBS = ('*.db', '*.sqlite', '*.sqlite3')
|
||||
HASH_BLOCK_SIZE = 1024 * 1024
|
||||
SQL_TIME_LIMIT_MS = 1000
|
||||
|
||||
conns = {}
|
||||
|
||||
|
|
@ -167,7 +169,8 @@ class DatabaseView(BaseView):
|
|||
def data(self, request, name, hash):
|
||||
conn = get_conn(name)
|
||||
sql = request.args.get('sql') or 'select * from sqlite_master'
|
||||
rows = conn.execute(sql)
|
||||
with sqlite_timelimit(conn, SQL_TIME_LIMIT_MS):
|
||||
rows = conn.execute(sql)
|
||||
columns = [r[0] for r in rows.description]
|
||||
return {
|
||||
'database': name,
|
||||
|
|
@ -192,10 +195,13 @@ class TableView(BaseView):
|
|||
else:
|
||||
sql = 'select * from "{}" limit 50'.format(table)
|
||||
params = []
|
||||
rows = conn.execute(sql, params)
|
||||
|
||||
with sqlite_timelimit(conn, SQL_TIME_LIMIT_MS):
|
||||
rows = conn.execute(sql, params)
|
||||
|
||||
columns = [r[0] for r in rows.description]
|
||||
pks = pks_for_table(conn, table)
|
||||
rows = list(rows)
|
||||
pks = pks_for_table(conn, table)
|
||||
info = ensure_build_metadata()
|
||||
total_rows = info[name]['tables'].get(table)
|
||||
return {
|
||||
|
|
@ -355,6 +361,18 @@ class CustomJSONEncoder(json.JSONEncoder):
|
|||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def sqlite_timelimit(conn, ms):
|
||||
deadline = time.time() + (ms / 1000)
|
||||
|
||||
def handler():
|
||||
if time.time() >= deadline:
|
||||
return 1
|
||||
conn.set_progress_handler(handler, 10000)
|
||||
yield
|
||||
conn.set_progress_handler(None, 10000)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if '--build' in sys.argv:
|
||||
ensure_build_metadata(True)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue