Unfortunately the case you are describing there is indeed one
that can't be solved in the normal callback style. That
assumes you can split up the work in pieces that never block
for a long time. A long running query invalidates that assumption. So for that case you must indeed
use a separate process/thread or use an event driven database
library (which means not directly using DBI. Even though there are plans for it, DBI is currently not event driven).
Though even in the case of a separate process I'd normally set up a socket or pipe style connection between the GUI process
and the DBI process and handle the socket/pipe events with I/O
callbacks at the GUI side. The DBI side would probably be straightfoward code doing blocking calls.