github
html_url | issue_url | id | node_id | user | created_at | updated_at | author_association | body | reactions | issue | performed_via_github_app |
---|---|---|---|---|---|---|---|---|---|---|---|
https://github.com/simonw/datasette/issues/1293#issuecomment-813480043 | https://api.github.com/repos/simonw/datasette/issues/1293 | 813480043 | MDEyOklzc3VlQ29tbWVudDgxMzQ4MDA0Mw== | 9599 | 2021-04-05T16:16:17Z | 2021-04-05T16:16:17Z | OWNER | https://latest.datasette.io/fixtures?sql=explain+select+*+from+paginated_view will be an interesting test query - because `paginated_view` is defined like this: ```sql CREATE VIEW paginated_view AS SELECT content, '- ' || content || ' -' AS content_extra FROM no_primary_key; ``` So this will help test that the mechanism isn't confused by output columns that are created through a concatenation expression. | { "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 } |
849978964 | |
https://github.com/simonw/datasette/issues/1293#issuecomment-813445512 | https://api.github.com/repos/simonw/datasette/issues/1293 | 813445512 | MDEyOklzc3VlQ29tbWVudDgxMzQ0NTUxMg== | 9599 | 2021-04-05T15:11:40Z | 2021-04-05T15:11:40Z | OWNER | Here's some older example code that works with opcodes from Python, in this case to output indexes used by a query: https://github.com/plasticityai/supersqlite/blob/master/supersqlite/idxchk.py | { "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 } |
849978964 | |
https://github.com/simonw/datasette/issues/1293#issuecomment-813438771 | https://api.github.com/repos/simonw/datasette/issues/1293 | 813438771 | MDEyOklzc3VlQ29tbWVudDgxMzQzODc3MQ== | 9599 | 2021-04-05T14:58:48Z | 2021-04-05T14:58:48Z | OWNER | I may need to do something special for rowid columns - there is a `RowId` opcode that might come into play here. | { "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 } |
849978964 | |
https://github.com/simonw/datasette/issues/1293#issuecomment-813164282 | https://api.github.com/repos/simonw/datasette/issues/1293 | 813164282 | MDEyOklzc3VlQ29tbWVudDgxMzE2NDI4Mg== | 9599 | 2021-04-05T03:42:26Z | 2021-04-05T03:42:36Z | OWNER | Extracting variables with this trick appears to work OK, but you have to pass the correct variables to the `explain select...` query. Using `defaultdict` seems to work there: ```pycon >>> rows = conn.execute('explain select * from repos where id = :id', defaultdict(int)) >>> [dict(r) for r in rows if r['opcode'] == 'Variable'] [{'addr': 2, 'opcode': 'Variable', 'p1': 1, 'p2': 1, 'p3': 0, 'p4': ':id', 'p5': 0, 'comment': None}] ``` | { "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 } |
849978964 | |
https://github.com/simonw/datasette/issues/1293#issuecomment-813162622 | https://api.github.com/repos/simonw/datasette/issues/1293 | 813162622 | MDEyOklzc3VlQ29tbWVudDgxMzE2MjYyMg== | 9599 | 2021-04-05T03:34:24Z | 2021-04-05T03:40:35Z | OWNER | This almost works, but throws errors with some queries (anything with a `rowid` column for example) - it needs a bunch of test coverage. ```python def columns_for_query(conn, sql): rows = conn.execute('explain ' + sql).fetchall() table_rootpage_by_register = {r['p1']: r['p2'] for r in rows if r['opcode'] == 'OpenRead'} names_by_rootpage = dict( conn.execute( 'select rootpage, name from sqlite_master where rootpage in ({})'.format( ', '.join(map(str, table_rootpage_by_register.values())) ) ) ) columns_by_column_register = {} for row in rows: if row['opcode'] == 'Column': addr, opcode, table_id, cid, column_register, p4, p5, comment = row table = names_by_rootpage[table_rootpage_by_register[table_id]] columns_by_column_register[column_register] = (table, cid) result_row = [dict(r) for r in rows if r['opcode'] == 'ResultRow'][0] registers = list(range(result_row["p1"], result_row["p1"] + result_row["p2"] - 1)) all_column_names = {} for table in names_by_rootpage.values(): table_xinfo = conn.execute('pragma table_xinfo({})'.format(table)).fetchall() for row in table_xinfo: all_column_names[(table, row["cid"])] = row["name"] final_output = [] for r in registers: try: table, cid = columns_by_column_register[r] final_output.append((table, all_column_names[table, cid])) except KeyError: final_output.append((None, None)) return final_output ``` | { "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 } |
849978964 | |
https://github.com/simonw/datasette/issues/1293#issuecomment-813134637 | https://api.github.com/repos/simonw/datasette/issues/1293 | 813134637 | MDEyOklzc3VlQ29tbWVudDgxMzEzNDYzNw== | 9599 | 2021-04-05T01:21:59Z | 2021-04-05T01:21:59Z | OWNER | http://www.sqlite.org/draft/lang_explain.html says: > Applications should not use EXPLAIN or EXPLAIN QUERY PLAN since their exact behavior is variable and only partially documented. I'm going to keep exploring this though. | { "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 } |
849978964 | |
https://github.com/simonw/datasette/issues/1293#issuecomment-813134227 | https://api.github.com/repos/simonw/datasette/issues/1293 | 813134227 | MDEyOklzc3VlQ29tbWVudDgxMzEzNDIyNw== | 9599 | 2021-04-05T01:19:31Z | 2021-04-05T01:19:31Z | OWNER | | addr | opcode | p1 | p2 | p3 | p4 | p5 | comment | |--------|---------------|------|------|------|-----------------------|------|-----------| | 0 | Init | 0 | 47 | 0 | | 00 | | | 1 | OpenRead | 0 | 51 | 0 | 15 | 00 | | | 2 | Integer | 15 | 2 | 0 | | 00 | | | 3 | Once | 0 | 15 | 0 | | 00 | | | 4 | OpenEphemeral | 2 | 1 | 0 | k(1,) | 00 | | | 5 | VOpen | 1 | 0 | 0 | vtab:3E692C362158 | 00 | | | 6 | String8 | 0 | 5 | 0 | CPAD_2020a_SuperUnits | 00 | | | 7 | SCopy | 7 | 6 | 0 | | 00 | | | 8 | Integer | 2 | 3 | 0 | | 00 | | | 9 | Integer | 2 | 4 | 0 | | 00 | | | 10 | VFilter | 1 | 15 | 3 | | 00 | | | 11 | Rowid | 1 | 8 | 0 | | 00 | | | 12 | MakeRecord | 8 | 1 | 9 | C | 00 | | | 13 | IdxInsert | 2 | 9 | 8 | 1 | 00 | | | 14 | VNext | 1 | 11 | 0 | | 00 | | | 15 | Return | 2 | 0 | 0 | | 00 | | | 16 | Rewind | 2 | 46 | 0 | | 00 | | | 17 | Column | 2 | 0 | 1 | | 00 | | | 18 | IsNull | 1 | 45 | 0 | | 00 | | | 19 | SeekRowid | 0 | 45 | 1 | | 00 | | | 20 | Column … | { "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 } |
849978964 | |
https://github.com/simonw/datasette/issues/1293#issuecomment-813134072 | https://api.github.com/repos/simonw/datasette/issues/1293 | 813134072 | MDEyOklzc3VlQ29tbWVudDgxMzEzNDA3Mg== | 9599 | 2021-04-05T01:18:37Z | 2021-04-05T01:18:37Z | OWNER | Had a fantastic suggestion on the SQLite forum: it might be possible to get what I want by interpreting the opcodes output by `explain select ...`. Copying the reply I posted to this thread: That's really useful, thanks! It looks like it _might_ be possible for me to reconstruct where each column came from using the `explain select` output. Here's a complex example: <https://calands.datasettes.com/calands?sql=explain+select%0D%0A++AsGeoJSON%28geometry%29%2C+*%0D%0Afrom%0D%0A++CPAD_2020a_SuperUnits%0D%0Awhere%0D%0A++PARK_NAME+like+%27%25mini%25%27+and%0D%0A++Intersects%28GeomFromGeoJSON%28%3Afreedraw%29%2C+geometry%29+%3D+1%0D%0A++and+CPAD_2020a_SuperUnits.rowid+in+%28%0D%0A++++select%0D%0A++++++rowid%0D%0A++++from%0D%0A++++++SpatialIndex%0D%0A++++where%0D%0A++++++f_table_name+%3D+%27CPAD_2020a_SuperUnits%27%0D%0A++++++and+search_frame+%3D+GeomFromGeoJSON%28%3Afreedraw%29%0D%0A++%29&freedraw=%7B%22type%22%3A%22MultiPolygon%22%2C%22coordinates%22%3A%5B%5B%5B%5B-122.42202758789064%2C37.82280243352759%5D%2C%5B-122.39868164062501%2C37.823887203271454%5D%2C%5B-122.38220214843751%2C37.81846319511331%5D%2C%5B-122.35061645507814%2C37.77071473849611%5D%2C%5B-122.34924316406251%2C37.74465712069939%5D%2C%5B-122.37258911132814%2C37.703380457832374%5D%2C%5B-122.39044189453125%2C37.690340943717715%5D%2C%5B-122.41241455078126%2C37.680559803205135%5D%2C%5B-122.44262695312501%2C37.67295135774715%5D%2C%5B-122.47283935546876%2C37.67295135774715%5D%2C%5B-122.52502441406251%2C37.68382032669382%5D%2C%5B-122.53463745117189%2C37.6892542140253%5D%2C%5B-122.54699707031251%2C37.690340943717715%5D%2C%5B-122.55798339843751%2C37.72945260537781%5D%2C%5B-122.54287719726564%2C37.77831314799672%5D%2C%5B-122.49893188476564%2C37.81303878836991%5D%2C%5B-122.46185302734376%2C37.82822612280363%5D%2C%5B-122.42889404296876%2C37.82822612280363%5D%2C%5B-122.42202758789064%2C37.82280243352759%5D%5D%5D%5D%7D> It looks like the opcodes I need to inspect are `OpenRead`, `Column` and `ResultRow`. `OpenRead` tells me which tables are being opened … | { "total_count": 0, "+1": 0, "-1": 0, "laugh": 0, "hooray": 0, "confused": 0, "heart": 0, "rocket": 0, "eyes": 0 } |
849978964 |