r-dbi / odbc

Connect to ODBC databases (using the DBI interface)
https://odbc.r-dbi.org/
Other
390 stars 107 forks source link

Feature/interruptible execution clean2 #796

Closed detule closed 4 months ago

detule commented 5 months ago

Hi All:

Please consider adding this feature - the ability to "Ctrl-C" past a long running query. For example in SQL Server

> dbGetQuery(conn, "WAITFOR DELAY '00:10'", immediate = TRUE);
^C
Caught user interrupt, attempting a clean exit...
Error: nanodbc/nanodbc.cpp:1711: 00000
<SQL> 'WAITFOR DELAY '00:10''
>

Some notes - i feel like I am being wordy below but I am sure I still left quite a bit out:

Appreciate any feedback - and thanks for taking a look!

detule commented 5 months ago
gaborcsardi commented 5 months ago

@detule @simonpcouch Some quick comments wrt the new argument and having a (not so) secret option instead. I think an option or an env var is much friendlier for the users than the new argument.

gaborcsardi commented 5 months ago

@detule A quick question about concurrency and resources. If there is an interrupt, then cleanup_fn() runs concurrently with the async thread, right?

And after an interrupt, the main thread invalidates the DB handle that the async thread is using? If that's the case, are the ODBC drivers prepared for this?

simonpcouch commented 5 months ago

Not doing this myself in case @detule has local changes, but this PR should pass CI with changes merged from main!

detule commented 5 months ago

HI @gaborcsardi

Appreciate you taking a look.

detule commented 5 months ago

Not doing this myself in case @detule has local changes, but this PR should pass CI with changes merged from main!

Thanks @simonpcouch - rebased on top of main. Hopefully it's all green.

gaborcsardi commented 4 months ago

Per the ODBC spec this should be fine, since before invalidating the statement as part of the clean up, we first call SQLCancel

I don't see where that happens, probably in close()?

In any case, this looks pretty good then. The only concern I have is that you need to install the dev MariaDB drivers to make ODBC run reliably. I would think that many ODBC users are stuck on older Linux systems, so we could potentially break their projects.

So maybe you could make this feature opt-in for now? And make it the default in the next release?

detule commented 4 months ago

Per the ODBC spec this should be fine, since before invalidating the statement as part of the clean up, we first call SQLCancel

I don't see where that happens, probably in close()?

Yes, both set_current_result, and close in the cleanup function will cancel the current result, as needed.

In any case, this looks pretty good then. The only concern I have is that you need to install the dev MariaDB drivers to make ODBC run reliably. I would think that many ODBC users are stuck on older Linux systems, so we could potentially break their projects.

So maybe you could make this feature opt-in for now? And make it the default in the next release?

Thanks @gaborcsardi . Appreciate you taking a look. On mariadb - do you still feel the same way knowing that the only test that the driver seems to be misfiring on is the relatively contrived dbGetQuery(conn, NA_character_) ? All other tests, more than three thousand of them, seem to be passing on both Linux and Windows ( admittedly MySQL, not MariaDB ) without issues. At any rate, I don't have a problem making it opt-in and happy to do it, just a bit concerned that it won't get enough mileage.

gaborcsardi commented 4 months ago

At any rate, I don't have a problem making it opt-in and happy to do it, just a bit concerned that it won't get enough mileage.

You can make a much more informed decision than me. In general I tend to be conservative in these kind of issues, especially with packages that may be used on older systems, like odbc.

You can also make the default depend on whether the session is interactive or not. I would think that interruption is much less important in non-interactive sessions, where an interruption just kills the process, because there are already ways to kill the process. So you could turn it on in interactive sessions only.

detule commented 4 months ago

You can also make the default depend on whether the session is interactive or not. I would think that interruption is much less important in non-interactive sessions, where an interruption just kills the process, because there are already ways to kill the process. So you could turn it on in interactive sessions only.

Done - thanks, that's a great suggestion.

r2evans commented 2 months ago

(I cannot express sufficiently how much I've wanted this and never knew to ask for it.)