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.views import HTTPMethodView
|
||||||
from sanic_jinja2 import SanicJinja2
|
from sanic_jinja2 import SanicJinja2
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
from contextlib import contextmanager
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
@ -18,6 +19,7 @@ app_root = Path(__file__).parent
|
||||||
BUILD_METADATA = 'build-metadata.json'
|
BUILD_METADATA = 'build-metadata.json'
|
||||||
DB_GLOBS = ('*.db', '*.sqlite', '*.sqlite3')
|
DB_GLOBS = ('*.db', '*.sqlite', '*.sqlite3')
|
||||||
HASH_BLOCK_SIZE = 1024 * 1024
|
HASH_BLOCK_SIZE = 1024 * 1024
|
||||||
|
SQL_TIME_LIMIT_MS = 1000
|
||||||
|
|
||||||
conns = {}
|
conns = {}
|
||||||
|
|
||||||
|
|
@ -167,7 +169,8 @@ class DatabaseView(BaseView):
|
||||||
def data(self, request, name, hash):
|
def data(self, request, name, hash):
|
||||||
conn = get_conn(name)
|
conn = get_conn(name)
|
||||||
sql = request.args.get('sql') or 'select * from sqlite_master'
|
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]
|
columns = [r[0] for r in rows.description]
|
||||||
return {
|
return {
|
||||||
'database': name,
|
'database': name,
|
||||||
|
|
@ -192,10 +195,13 @@ class TableView(BaseView):
|
||||||
else:
|
else:
|
||||||
sql = 'select * from "{}" limit 50'.format(table)
|
sql = 'select * from "{}" limit 50'.format(table)
|
||||||
params = []
|
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]
|
columns = [r[0] for r in rows.description]
|
||||||
pks = pks_for_table(conn, table)
|
|
||||||
rows = list(rows)
|
rows = list(rows)
|
||||||
|
pks = pks_for_table(conn, table)
|
||||||
info = ensure_build_metadata()
|
info = ensure_build_metadata()
|
||||||
total_rows = info[name]['tables'].get(table)
|
total_rows = info[name]['tables'].get(table)
|
||||||
return {
|
return {
|
||||||
|
|
@ -355,6 +361,18 @@ class CustomJSONEncoder(json.JSONEncoder):
|
||||||
return json.JSONEncoder.default(self, obj)
|
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 __name__ == '__main__':
|
||||||
if '--build' in sys.argv:
|
if '--build' in sys.argv:
|
||||||
ensure_build_metadata(True)
|
ensure_build_metadata(True)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue