Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit44e8a96

Browse files
committed
Invent a new, more thread-safe version of PQrequestCancel, called PQcancel.
Use this new function in psql. Implement query cancellation in psql forWindows. Code by Magnus Hagander, documentation and minor editorializationby Tom Lane.
1 parent80559fa commit44e8a96

File tree

8 files changed

+399
-118
lines changed

8 files changed

+399
-118
lines changed

‎doc/src/sgml/libpq.sgml

Lines changed: 135 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.166 2004/10/18 22:00:41 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.167 2004/10/30 23:09:59 tgl Exp $
33
-->
44

55
<chapter id="libpq">
@@ -2569,49 +2569,11 @@ if <function>PQisBusy</function> returns false (0). It can also call
25692569
A client that uses
25702570
<function>PQsendQuery</function>/<function>PQgetResult</function> can
25712571
also attempt to cancel a command that is still being processed by the
2572-
server.<indexterm><primary>canceling</><secondary>SQL command</></>
2573-
2574-
<variablelist>
2575-
<varlistentry>
2576-
<term><function>PQrequestCancel</function><indexterm><primary>PQrequestCancel</></></term>
2577-
<listitem>
2578-
<para>
2579-
Requests that the server abandon
2580-
processing of the current command.
2581-
<synopsis>
2582-
int PQrequestCancel(PGconn *conn);
2583-
</synopsis>
2584-
</para>
2585-
2586-
<para>
2587-
The return value is 1 if the cancel request was successfully
2588-
dispatched and 0 if not. (If not, <function>PQerrorMessage</function> tells why not.)
2589-
Successful dispatch is no guarantee that the request will have any
2590-
effect, however. Regardless of the return value of <function>PQrequestCancel</function>,
2591-
the application must continue with the normal result-reading
2592-
sequence using <function>PQgetResult</function>. If the cancellation
2593-
is effective, the current command will terminate early and return
2594-
an error result. If the cancellation fails (say, because the
2595-
server was already done processing the command), then there will
2596-
be no visible result at all.
2597-
</para>
2598-
2599-
<para>
2600-
Note that if the current command is part of a transaction block, cancellation
2601-
will abort the whole transaction.
2602-
</para>
2603-
2604-
<para>
2605-
<function>PQrequestCancel</function> can safely be invoked from a signal handler.
2606-
So, it is also possible to use it in conjunction with plain
2607-
<function>PQexec</function>, if the decision to cancel can be made in a signal
2608-
handler. For example, <application>psql</application> invokes
2609-
<function>PQrequestCancel</function> from a <symbol>SIGINT</> signal handler, thus allowing
2610-
interactive cancellation of commands that it issues through <function>PQexec</function>.
2611-
</para>
2612-
</listitem>
2613-
</varlistentry>
2614-
</variablelist>
2572+
server; see <xref linkend="libpq-cancel">. But regardless of the return value
2573+
of <function>PQcancel</function>, the application must continue with the
2574+
normal result-reading sequence using <function>PQgetResult</function>.
2575+
A successful cancellation will simply cause the command to terminate
2576+
sooner than it would have otherwise.
26152577
</para>
26162578

26172579
<para>
@@ -2699,6 +2661,125 @@ and then read the response as described above.
26992661

27002662
</sect1>
27012663

2664+
<sect1 id="libpq-cancel">
2665+
<title>Cancelling Queries in Progress</title>
2666+
2667+
<indexterm zone="libpq-cancel"><primary>canceling</><secondary>SQL command</></>
2668+
2669+
<para>
2670+
A client application can request cancellation of
2671+
a command that is still being processed by the
2672+
server, using the functions described in this section.
2673+
2674+
<variablelist>
2675+
<varlistentry>
2676+
<term><function>PQgetCancel</function><indexterm><primary>PQgetCancel</></></term>
2677+
<listitem>
2678+
<para>
2679+
Creates a data structure containing the information needed to cancel
2680+
a command issued through a particular database connection.
2681+
<synopsis>
2682+
PGcancel *PQgetCancel(PGconn *conn);
2683+
</synopsis>
2684+
</para>
2685+
2686+
<para>
2687+
<function>PQgetCancel</function> creates a
2688+
<structname>PGcancel</><indexterm><primary>PGcancel</></> object given
2689+
a <structname>PGconn</> connection object. It will return NULL if the
2690+
given <parameter>conn</> is NULL or an invalid connection. The
2691+
<structname>PGcancel</> object is an opaque structure that is not meant
2692+
to be accessed directly by the application; it can only be passed to
2693+
<function>PQcancel</function> or <function>PQfreeCancel</function>.
2694+
</para>
2695+
</listitem>
2696+
</varlistentry>
2697+
2698+
<varlistentry>
2699+
<term><function>PQfreeCancel</function><indexterm><primary>PQfreeCancel</></></term>
2700+
<listitem>
2701+
<para>
2702+
Frees a data structure created by <function>PQgetCancel</function>.
2703+
<synopsis>
2704+
void PQfreeCancel(PGcancel *cancel);
2705+
</synopsis>
2706+
</para>
2707+
2708+
<para>
2709+
<function>PQfreeCancel</function> frees a data object previously created
2710+
by <function>PQgetCancel</function>.
2711+
</para>
2712+
</listitem>
2713+
</varlistentry>
2714+
2715+
<varlistentry>
2716+
<term><function>PQcancel</function><indexterm><primary>PQcancel</></></term>
2717+
<listitem>
2718+
<para>
2719+
Requests that the server abandon
2720+
processing of the current command.
2721+
<synopsis>
2722+
int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize);
2723+
</synopsis>
2724+
</para>
2725+
2726+
<para>
2727+
The return value is 1 if the cancel request was successfully
2728+
dispatched and 0 if not. If not, <parameter>errbuf</> is filled with an error
2729+
message explaining why not. <parameter>errbuf</> must be a char array of size
2730+
<parameter>errbufsize</> (the recommended size is 256 bytes).
2731+
</para>
2732+
2733+
<para>
2734+
Successful dispatch is no guarantee that the request will have any effect,
2735+
however. If the cancellation is effective, the current command will terminate
2736+
early and return an error result. If the cancellation fails (say, because the
2737+
server was already done processing the command), then there will be no visible
2738+
result at all.
2739+
</para>
2740+
2741+
<para>
2742+
<function>PQcancel</function> can safely be invoked from a signal handler,
2743+
if the <parameter>errbuf</> is a local variable in the signal handler. The
2744+
<structname>PGcancel</> object is read-only as far as
2745+
<function>PQcancel</function> is concerned, so it can also be invoked from a
2746+
thread that is separate from the one manipulating the <structname>PGconn</>
2747+
object.
2748+
</para>
2749+
</listitem>
2750+
</varlistentry>
2751+
</variablelist>
2752+
2753+
<variablelist>
2754+
<varlistentry>
2755+
<term><function>PQrequestCancel</function><indexterm><primary>PQrequestCancel</></></term>
2756+
<listitem>
2757+
<para>
2758+
Requests that the server abandon
2759+
processing of the current command.
2760+
<synopsis>
2761+
int PQrequestCancel(PGconn *conn);
2762+
</synopsis>
2763+
</para>
2764+
2765+
<para>
2766+
<function>PQrequestCancel</function> is a deprecated variant of
2767+
<function>PQcancel</function>. It operates directly on the
2768+
<structname>PGconn</> object, and in case of failure stores the
2769+
error message in the <structname>PGconn</> object (whence it can be
2770+
retrieved by <function>PQerrorMessage</function>). Although the
2771+
functionality is the same, this approach creates hazards for multiple-thread
2772+
programs and signal handlers, since it is possible that overwriting the
2773+
<structname>PGconn</>'s error message will mess up the operation currently
2774+
in progress on the connection.
2775+
</para>
2776+
</listitem>
2777+
</varlistentry>
2778+
</variablelist>
2779+
</para>
2780+
2781+
</sect1>
2782+
27022783
<sect1 id="libpq-fastpath">
27032784
<title>The Fast-Path Interface</title>
27042785

@@ -3852,11 +3933,16 @@ passed around freely between threads.
38523933
</para>
38533934

38543935
<para>
3855-
The deprecated functions <function>PQoidStatus</function> and
3856-
<function>fe_setauthsvc</function> are not thread-safe and should not be
3857-
used in multithread programs. <function>PQoidStatus</function> can be
3858-
replaced by <function>PQoidValue</function>. There is no good reason to
3859-
call <function>fe_setauthsvc</function> at all.
3936+
The deprecated functions
3937+
<function>PQrequestCancel</function>,
3938+
<function>PQoidStatus</function> and
3939+
<function>fe_setauthsvc</function>
3940+
are not thread-safe and should not be used in multithread programs.
3941+
<function>PQrequestCancel</function> can be replaced by
3942+
<function>PQcancel</function>.
3943+
<function>PQoidStatus</function> can be replaced by
3944+
<function>PQoidValue</function>.
3945+
There is no good reason to call <function>fe_setauthsvc</function> at all.
38603946
</para>
38613947

38623948
<para>

‎src/bin/psql/common.c

Lines changed: 87 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2004, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.92 2004/10/10 23:37:40 neilc Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.93 2004/10/30 23:10:50 tgl Exp $
77
*/
88
#include"postgres_fe.h"
99
#include"common.h"
@@ -223,23 +223,33 @@ NoticeProcessor(void *arg, const char *message)
223223
*
224224
* Before we start a query, we enable a SIGINT signal catcher that sends a
225225
* cancel request to the backend. Note that sending the cancel directly from
226-
* the signal handler is safe becausePQrequestCancel() is written to make it
227-
* so. We use write() to print tostdout because it's better to use simple
226+
* the signal handler is safe becausePQcancel() is written to make it
227+
* so. We use write() to print tostderr because it's better to use simple
228228
* facilities in a signal handler.
229+
*
230+
* On win32, the signal cancelling happens on a separate thread, because
231+
* that's how SetConsoleCtrlHandler works. The PQcancel function is safe
232+
* for this (unlike PQrequestCancel). However, a CRITICAL_SECTION is required
233+
* to protect the PGcancel structure against being changed while the other
234+
* thread is using it.
229235
*/
230-
staticPGconn*volatilecancelConn=NULL;
236+
staticPGcancel*cancelConn=NULL;
237+
#ifdefWIN32
238+
staticCRITICAL_SECTIONcancelConnLock;
239+
#endif
231240

232241
volatileboolcancel_pressed= false;
233242

243+
#definewrite_stderr(str)write(fileno(stderr), str, strlen(str))
234244

235-
#ifndefWIN32
236245

237-
#definewrite_stderr(String) write(fileno(stderr), String, strlen(String))
246+
#ifndefWIN32
238247

239248
void
240249
handle_sigint(SIGNAL_ARGS)
241250
{
242251
intsave_errno=errno;
252+
charerrbuf[256];
243253

244254
/* Don't muck around if prompting for a password. */
245255
if (prompt_state)
@@ -250,17 +260,60 @@ handle_sigint(SIGNAL_ARGS)
250260

251261
cancel_pressed= true;
252262

253-
if (PQrequestCancel(cancelConn))
263+
if (PQcancel(cancelConn,errbuf,sizeof(errbuf)))
254264
write_stderr("Cancel request sent\n");
255265
else
256266
{
257267
write_stderr("Could not send cancel request: ");
258-
write_stderr(PQerrorMessage(cancelConn));
268+
write_stderr(errbuf);
259269
}
260270
errno=save_errno;/* just in case the write changed it */
261271
}
262-
#endif/* not WIN32 */
263272

273+
#else/* WIN32 */
274+
275+
staticBOOLWINAPI
276+
consoleHandler(DWORDdwCtrlType)
277+
{
278+
charerrbuf[256];
279+
280+
if (dwCtrlType==CTRL_C_EVENT||
281+
dwCtrlType==CTRL_BREAK_EVENT)
282+
{
283+
if (prompt_state)
284+
return TRUE;
285+
286+
/* Perform query cancel */
287+
EnterCriticalSection(&cancelConnLock);
288+
if (cancelConn!=NULL)
289+
{
290+
cancel_pressed= true;
291+
292+
if (PQcancel(cancelConn,errbuf,sizeof(errbuf)))
293+
write_stderr("Cancel request sent\n");
294+
else
295+
{
296+
write_stderr("Could not send cancel request: ");
297+
write_stderr(errbuf);
298+
}
299+
}
300+
LeaveCriticalSection(&cancelConnLock);
301+
302+
return TRUE;
303+
}
304+
else
305+
/* Return FALSE for any signals not being handled */
306+
return FALSE;
307+
}
308+
309+
void
310+
setup_cancel_handler(void)
311+
{
312+
InitializeCriticalSection(&cancelConnLock);
313+
SetConsoleCtrlHandler(consoleHandler, TRUE);
314+
}
315+
316+
#endif/* WIN32 */
264317

265318

266319
/* ConnectionUp
@@ -327,20 +380,42 @@ CheckConnection(void)
327380
staticvoid
328381
SetCancelConn(void)
329382
{
330-
cancelConn=pset.db;
383+
#ifdefWIN32
384+
EnterCriticalSection(&cancelConnLock);
385+
#endif
386+
387+
/* Free the old one if we have one */
388+
if (cancelConn!=NULL)
389+
PQfreeCancel(cancelConn);
390+
391+
cancelConn=PQgetCancel(pset.db);
392+
393+
#ifdefWIN32
394+
LeaveCriticalSection(&cancelConnLock);
395+
#endif
331396
}
332397

333398

334399
/*
335400
* ResetCancelConn
336401
*
337-
* Set cancelConn to NULL.I don't know what this means exactly, but it saves
338-
* having to export the variable.
402+
* Free the current cancel connection, if any, and set to NULL.
339403
*/
340404
void
341405
ResetCancelConn(void)
342406
{
407+
#ifdefWIN32
408+
EnterCriticalSection(&cancelConnLock);
409+
#endif
410+
411+
if (cancelConn)
412+
PQfreeCancel(cancelConn);
413+
343414
cancelConn=NULL;
415+
416+
#ifdefWIN32
417+
LeaveCriticalSection(&cancelConnLock);
418+
#endif
344419
}
345420

346421

‎src/bin/psql/common.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2000-2004, PostgreSQL Global Development Group
55
*
6-
* $PostgreSQL: pgsql/src/bin/psql/common.h,v 1.39 2004/08/29 04:13:02 momjian Exp $
6+
* $PostgreSQL: pgsql/src/bin/psql/common.h,v 1.40 2004/10/30 23:10:50 tgl Exp $
77
*/
88
#ifndefCOMMON_H
99
#defineCOMMON_H
@@ -48,7 +48,9 @@ extern void ResetCancelConn(void);
4848

4949
#ifndefWIN32
5050
externvoidhandle_sigint(SIGNAL_ARGS);
51-
#endif/* not WIN32 */
51+
#else
52+
externvoidsetup_cancel_handler(void);
53+
#endif
5254

5355
externPGresult*PSQLexec(constchar*query,boolstart_xact);
5456

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp