Skip to Content.
Sympa Menu

freetds - Re: [freetds] SQLCancel() and error diagnostic: Expecting HY008 SQLSTATE

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: "James K. Lowden" <jklowden AT freetds.org>
  • To: FreeTDS Development Group <freetds AT lists.ibiblio.org>
  • Subject: Re: [freetds] SQLCancel() and error diagnostic: Expecting HY008 SQLSTATE
  • Date: Mon, 14 Jan 2008 18:45:54 -0500

Sebastien FLAESCH wrote:
> James K. Lowden wrote:
> > I think all the signal handler can do is record the fact that a signal
> > was caught in a more-or-less global variable. When the called
> > function returns an error -- e.g. a timeout on reads -- the app can
> > then decide whether or not to call SQLCancel.
>
> How would you implement
> SQL interruption in a text-based SQL command interpreter?

Before I answer that, let me remind you:

> James K. Lowden wrote:
> > I don't know the proper treatment of signals in an ODBC application,

:-)

But this for sure:

> > The
> > handler doesn't have enough information to know whether that's the
> > right thing to do.

The application can't know the state of the TDS connection. The handler
can't even know (without a lot of help) the state of the application.
Together they definitely don't know whether the server is ready to receive
a cancel packet.

More: Is the driver ready? How will the driver handle a nested
signal-driven call?

SQLFetch
waiting ... waiting ...
[sigint]
SQLCancel ... OK (or not)
(handler returns control to SQLFetch)
waiting ... waiting ...
waiting ... waiting ...

But you asked what to do, not what not to do.

Signal handling is tricky. The trick is to make a note and adjust course
when time permits. The application and the driver have to cooperate in a
12-step program back to sanity:

1. Application installs handler.
2. Driver *also* installs handler, stores app's handler.
3. Connect, Exec, Fetch ....
4. SIGINT!
5. Driver catches. Prepares to send SYBETIME (HY008).
6. Driver calls app's handler.
7. App catches, prepares to send Cancel.
8. App handler returns, Driver handler returns.
9. Driver "times out".
10. SQLFetch fails with HY008.
11. App sees timeout and SIGINT evidence.
12. App: 4 = 2 + 2. Calls SQLCancel.

> For sure GUI applications typically handle user interruption by catching
> a special GUI event (click on cancel button), and can then call
> SQLCancel() outside a signal handler flow... be this is about a non-GUI
> application.

GUI or not makes no difference. Win32 makes a difference. Details vary
by OS even within the Unixish world.

An interactive program might want to query the user by writing to the tty
or putting up a message box asking what to do. Depending on the
environment, that might be OK to do inside the handler.

> This is to me unexpected: The application should handle signals such as
> SIGINT, and do the DB client API calls (if available) to cancel a query.
>
> This works for us with:
>
> - Postgresql using PQcancel()
> - DB2 CLI using SQLCancel()
> - ANTS DS using SQLCancel()
> - Informix using sqlbreak() on Unix, and callback method on MS Windows.
> - Oracle using OCIBreak() (but need to register SIGINT handle after
> connection)

To be robust, the FreeTDS could be made to tolerate having SQLCancel
called inside a signal handler.

1. SIGINT!
2. Driver catches, calls app's handler.
3. App catches, calls SQLCancel
4. Driver calls special low-level function to tidy up the connection.
5. Driver completes SQLCancel, returns.
6. App handler returns, Driver handler returns.
7. Driver sees the maid was here, "times out".
8. SQLFetch fails with HY008.

With some housekeeping -- keeping track of nesting level and which API
function is being executed -- step #2 wouldn't be needed. SQLCancel could
tell that it was on a separate, nested thread of control and be mindful of
the TDS state.

You may know I rewrote the socket logic last year, to make it handle
timeouts. I focussed on db-lib semantics, which include callbacks and
*prohibit* calling any API function inside any handler. The "special
low-level function to tidy up the connection" has to live in that world.

It's easy to fake, and it will work most of the time:

3. App catches, calls SQLCancel
4. SQLCancels set flag for odbc_errmsg_handler, returns OK.
5. App handler returns.
6. Driver handler returns.
7. Driver calls odbc_errmsg_handler (per normal)
8 Driver sends Cancel -- might or might not work, but OK
9. SQLFetch fails with HY008.

It would be easy to implement and hard to tell the difference. Let's see
what Frediano says.

Regards,

--jkl






Archive powered by MHonArc 2.6.24.

Top of Page