As you found out this happens because the cursor is immediately exhausted as there are no rows, and then is cleaned up and so column data names are not available.
Behind the scenes you can use an execution tracer to extract the information. That is what query_info does. although it aborts execution after recording it.
As you found out this happens because the cursor is immediately exhausted as there are no rows, and then is cleaned up and so column data names are not available.
You can use apsw.ext.query_info to get details about a query without running it - see https://rogerbinns.github.io/apsw/ext.html#apsw.ext.query_in... which includes an example.
Behind the scenes you can use an execution tracer to extract the information. That is what query_info does. although it aborts execution after recording it.
(I am the APSW maintainer)