Re: Quitting an SQL query in 4GL
Posted in 1992
Harry Bochner writes (quoting Dave Snyder):
> |> Check out the example in Tech Notes "Spring 1989". The code is a little
> |> buggy though.
>
> Be aware that this method is obsolescent!
[ 4.1 new-improved method deleted ... ]
Thanks, very interesting. Be even better if they'd buy *me* 4.1 ;-)
> |> Is this something that really isn't needed in
> |> a 4GL program?
>
> Oh, my users would really like it.
It certainly stops the 15-minute pauses that result from queries
like "*smith" really well. If you can fit it in db4glgen, you
should be able to make a bunch of people very happy.
> But from my point of view there's a problem with both the old
> method, and the new functionality of 4.1.
>
> What I would like is to defer interrupts (and set SQL INTERRUPT
> ON) for just short sections of code, in particular while doing
> the first fetch from a cursor. In the rest of the code I'd
> rather have interrupt kill the program, as usual. But once you
> "defer interrupt", you can't turn it back on as least as far as
> I'm aware. So as I understand it, in order to allow my users to
> interrupt queries that are taking much longer than they
> expected, I would have to defer interrupts for the entire
> program, carefully checking at every appropriate point if an
> interrupt has come in. I'm reluctant to go through 20,000 lines
> of code making this change :-(
>
> If any one knows of a good way around this, I'd like to hear about it!
I'm not sure that this is a *good* way, but how 'bout something
like this ? You'll have to change the names to run it against
one of your own DBs, of course, but the general idea is that
exit_on_int() sets up the signal handling to call exit(2) when
you hit the interrupt key. At the same time, it saves the old
signal handler - the informix function which presumably does
"int_flag=1;" - so you can put it back later.
When you call ign_int(), you reinstate the original signal handler and
interrupt has the usual (lack of) effect because of the DEFER INTERRUPT.
DATABASE sis
MAIN
DEFINE tot INTEGER
DEFER INTERRUPT # don't halt prog on interrupt
CALL exit_on_int() # exit from prog on interrupt
SELECT count(*) INTO tot FROM gen_rec # slow-ish
DISPLAY "got tot: ", tot
CALL ign_int() # don't exit from prog on interrupt
SELECT MAX(gen_dtmadd) INTO tot FROM gen_rec # slow
DISPLAY "got tot: ", tot
END MAIN
I've bunged the C-code for these (microscopic) functions at the
bottom, along with the rsqbreak stuff in case anyone's still
looking for it. Don't forget to delete my printf's before you
use it, if you do.
This is on 4.0-something (can't see from here), but the idea should
be ok. on others: we're only swapping between exit(2) and the
informix sig handler, both of which should be pretty thoroughly
tested.
Only hard part seems to be the definitions for the args to signal()
which are in the stuff below as "pointer to function taking int
argument and returning void" but are probably different on your box.
> --
> Harry Bochner
> bochner@das.harvard.edu
Hope this helps, let me know if it doesn't ;-)
Cheers - Tony.
__________________________________________________________________________
Tony Heskett th@bnr.co.uk Voice: (+44) 279 429531 x 2637
BNR, London Road, Harlow, Essex, CM17 9NA Fax: (+44) 279 454187
----8<-------8<-------8<-------8<-------8<-------8<-------8<-------8<---
#include <stdio.h>
#include <signal.h>
extern int int_flag; /* for 4GL and RDS only */
extern int readpend;
void exit();
void (*action)(); /* somewhere to keep the old signal handler */
/*
** Initialize handling of interrupt signals from 4GL.
** Call setup_break() before you need to interrupt the back end.
*/
setup_break(n)
int n; /* dummy parameter for 4GL */
{
int rsqbreak();
/* if interrupts not ignored, call rsqbreak on interrupt */
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, (void(*)()) rsqbreak);
return 0;
}
/* send SIGTERM to backend */
int
rsqbreak(n)
int n;
{
fprintf(stderr, "Caught interrupt\\n");
signal(SIGINT, SIG_IGN); /* block interrupts over sqlbreak() call */
/* if sqlbreak() returns non-zero, engine was not processing: set int_flag
and indicate regular interrupt */
if (sqlbreak() != 0)
int_flag = 1;
signal(SIGINT, (void(*)()) rsqbreak); /* reset interrupt signal handling */
if (readpend) /* for 4GL & RDS */
{
readpend = 0;
sigproc();
}
printf("in rsqbreak, int_flag set to %d\\n", int_flag);
return 0;
}
int
exit_on_int(n)
int n;
{
/* Save the old signal handler, then set up to exit on any interrupt */
/* If you call this twice in succession, you'll lose the informix
signal handler, so it should really look at a flag and only save
the value the first time it's called. I've left that as an
exercise for the reader ... */
action = signal(SIGINT, (void (*)()) exit);
return 0;
}
/* Restore the old signal handler - this should only be called after
** exit_on_int has saved the imix signal handler in "action".
*/
int
ign_int(n)
int n;
{
signal(SIGINT, action);
return 0;
}