mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
From: Massimo Dal Zotto <dz@cs.unitn.it>
This commit is contained in:
parent
6f3de1bb66
commit
6c4982851a
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.37 1998/08/19 02:01:39 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.38 1998/08/30 21:04:43 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -34,29 +34,7 @@
|
||||
* -- jw, 12/28/93
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* The following is the old model which does not work.
|
||||
*/
|
||||
/*
|
||||
* Model is:
|
||||
* 1. Multiple backends on same machine.
|
||||
*
|
||||
* 2. Query on one backend sends stuff over an asynchronous portal by
|
||||
* appending to a relation, and then doing an async. notification
|
||||
* (which takes place after commit) to all listeners on this relation.
|
||||
*
|
||||
* 3. Async. notification results in all backends listening on relation
|
||||
* to be woken up, by a process signal kill(SIGUSR2), with name of relation
|
||||
* passed in shared memory.
|
||||
*
|
||||
* 4. Each backend notifies its respective frontend over the comm
|
||||
* channel using the out-of-band channel.
|
||||
*
|
||||
* 5. Each frontend receives this notification and processes accordingly.
|
||||
*
|
||||
* #4,#5 are changing soon with pending rewrite of portal/protocol.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
@ -82,17 +60,28 @@
|
||||
#include "tcop/dest.h"
|
||||
#include "utils/mcxt.h"
|
||||
#include "utils/syscache.h"
|
||||
#include <utils/trace.h>
|
||||
#include <utils/ps_status.h>
|
||||
|
||||
#define NotifyUnlock pg_options[OPT_NOTIFYUNLOCK]
|
||||
#define NotifyHack pg_options[OPT_NOTIFYHACK]
|
||||
|
||||
extern TransactionState CurrentTransactionState;
|
||||
extern CommandDest whereToSendOutput;
|
||||
|
||||
GlobalMemory notifyContext = NULL;
|
||||
|
||||
static int notifyFrontEndPending = 0;
|
||||
static int notifyIssued = 0;
|
||||
static Dllist *pendingNotifies = NULL;
|
||||
|
||||
|
||||
static int AsyncExistsPendingNotify(char *);
|
||||
static void ClearPendingNotify(void);
|
||||
static void Async_NotifyFrontEnd(void);
|
||||
static void Async_NotifyFrontEnd_Aux(void);
|
||||
void Async_Unlisten(char *relname, int pid);
|
||||
static void Async_UnlistenOnExit(int code, char *relname);
|
||||
static void Async_UnlistenAll(void);
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------
|
||||
@ -116,33 +105,36 @@ static void Async_UnlistenOnExit(int code, char *relname);
|
||||
void
|
||||
Async_NotifyHandler(SIGNAL_ARGS)
|
||||
{
|
||||
extern TransactionState CurrentTransactionState;
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyHandler");
|
||||
|
||||
if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
|
||||
(CurrentTransactionState->blockState == TRANS_DEFAULT))
|
||||
{
|
||||
|
||||
#ifdef ASYNC_DEBUG
|
||||
elog(DEBUG, "Waking up sleeping backend process");
|
||||
#endif
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyHandler: "
|
||||
"waking up sleeping backend process");
|
||||
PS_SET_STATUS("async_notify");
|
||||
Async_NotifyFrontEnd();
|
||||
|
||||
PS_SET_STATUS("idle");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ASYNC_DEBUG
|
||||
elog(DEBUG, "Process is in the middle of another transaction, state = %d, block state = %d",
|
||||
CurrentTransactionState->state,
|
||||
CurrentTransactionState->blockState);
|
||||
#endif
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyHandler: "
|
||||
"process in middle of transaction, state=%d, blockstate=%d",
|
||||
CurrentTransactionState->state,
|
||||
CurrentTransactionState->blockState);
|
||||
notifyFrontEndPending = 1;
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyHandler: notify frontend pending");
|
||||
}
|
||||
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyHandler: done");
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------
|
||||
* Async_Notify --
|
||||
*
|
||||
* This is executed by the SQL notify command.
|
||||
*
|
||||
* Adds the relation to the list of pending notifies.
|
||||
* All notification happens at end of commit.
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -151,7 +143,6 @@ Async_NotifyHandler(SIGNAL_ARGS)
|
||||
* then each backend notifies its corresponding front end at
|
||||
* the end of commit.
|
||||
*
|
||||
* This correspond to 'notify <relname>' command
|
||||
* -- jw, 12/28/93
|
||||
*
|
||||
* Results:
|
||||
@ -180,9 +171,7 @@ Async_Notify(char *relname)
|
||||
|
||||
char *notifyName;
|
||||
|
||||
#ifdef ASYNC_DEBUG
|
||||
elog(DEBUG, "Async_Notify: %s", relname);
|
||||
#endif
|
||||
TPRINTF(TRACE_NOTIFY, "Async_Notify: %s", relname);
|
||||
|
||||
if (!pendingNotifies)
|
||||
pendingNotifies = DLNewList();
|
||||
@ -217,18 +206,32 @@ Async_Notify(char *relname)
|
||||
{
|
||||
rTuple = heap_modifytuple(lTuple, lRel, value, nulls, repl);
|
||||
heap_replace(lRel, &lTuple->t_ctid, rTuple);
|
||||
/* notify is really issued only if a tuple has been changed */
|
||||
notifyIssued = 1;
|
||||
}
|
||||
}
|
||||
heap_endscan(sRel);
|
||||
RelationUnsetLockForWrite(lRel);
|
||||
|
||||
/*
|
||||
* Note: if the write lock is unset we can get multiple tuples
|
||||
* with same oid if other backends notify the same relation.
|
||||
* Use this option at your own risk.
|
||||
*/
|
||||
if (NotifyUnlock) {
|
||||
RelationUnsetLockForWrite(lRel);
|
||||
}
|
||||
|
||||
heap_close(lRel);
|
||||
notifyIssued = 1;
|
||||
|
||||
TPRINTF(TRACE_NOTIFY, "Async_Notify: done %s", relname);
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------
|
||||
* Async_NotifyAtCommit --
|
||||
*
|
||||
* This is called at transaction commit.
|
||||
*
|
||||
* Signal our corresponding frontend process on relations that
|
||||
* were notified. Signal all other backend process that
|
||||
* are listening also.
|
||||
@ -265,14 +268,12 @@ Async_NotifyAtCommit()
|
||||
if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
|
||||
(CurrentTransactionState->blockState == TRANS_DEFAULT))
|
||||
{
|
||||
|
||||
if (notifyIssued)
|
||||
{ /* 'notify <relname>' issued by us */
|
||||
{
|
||||
/* 'notify <relname>' issued by us */
|
||||
notifyIssued = 0;
|
||||
StartTransactionCommand();
|
||||
#ifdef ASYNC_DEBUG
|
||||
elog(DEBUG, "Async_NotifyAtCommit.");
|
||||
#endif
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyAtCommit");
|
||||
ScanKeyEntryInitialize(&key, 0,
|
||||
Anum_pg_listener_notify,
|
||||
F_INT4EQ,
|
||||
@ -294,16 +295,15 @@ Async_NotifyAtCommit()
|
||||
|
||||
if (MyProcPid == DatumGetInt32(d))
|
||||
{
|
||||
#ifdef ASYNC_DEBUG
|
||||
elog(DEBUG, "Notifying self, setting notifyFronEndPending to 1");
|
||||
#endif
|
||||
notifyFrontEndPending = 1;
|
||||
TPRINTF(TRACE_NOTIFY,
|
||||
"Async_NotifyAtCommit: notifying self");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef ASYNC_DEBUG
|
||||
elog(DEBUG, "Notifying others");
|
||||
#endif
|
||||
TPRINTF(TRACE_NOTIFY,
|
||||
"Async_NotifyAtCommit: notifying pid %d",
|
||||
DatumGetInt32(d));
|
||||
#ifdef HAVE_KILL
|
||||
if (kill(DatumGetInt32(d), SIGUSR2) < 0)
|
||||
{
|
||||
@ -315,19 +315,35 @@ Async_NotifyAtCommit()
|
||||
}
|
||||
}
|
||||
heap_endscan(sRel);
|
||||
RelationUnsetLockForWrite(lRel);
|
||||
heap_close(lRel);
|
||||
|
||||
/*
|
||||
* Notify the frontend inside the current transaction while
|
||||
* we still have a valid write lock on pg_listeners. This
|
||||
* avoid waiting until all other backends have finished
|
||||
* with pg_listener.
|
||||
*/
|
||||
if (notifyFrontEndPending) {
|
||||
/* The aux version is called inside transaction */
|
||||
Async_NotifyFrontEnd_Aux();
|
||||
}
|
||||
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyAtCommit: done");
|
||||
CommitTransactionCommand();
|
||||
ClearPendingNotify();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* No notifies issued by us. If notifyFrontEndPending has been set
|
||||
* by Async_NotifyHandler notify the frontend of pending notifies
|
||||
* from other backends.
|
||||
*/
|
||||
if (notifyFrontEndPending) {
|
||||
Async_NotifyFrontEnd();
|
||||
}
|
||||
}
|
||||
|
||||
if (notifyFrontEndPending)
|
||||
{ /* we need to notify the frontend of all
|
||||
* pending notifies. */
|
||||
notifyFrontEndPending = 1;
|
||||
Async_NotifyFrontEnd();
|
||||
}
|
||||
ClearPendingNotify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,6 +351,8 @@ Async_NotifyAtCommit()
|
||||
*--------------------------------------------------------------
|
||||
* Async_NotifyAtAbort --
|
||||
*
|
||||
* This is called at transaction commit.
|
||||
*
|
||||
* Gets rid of pending notifies. List elements are automatically
|
||||
* freed through memory context.
|
||||
*
|
||||
@ -350,20 +368,19 @@ Async_NotifyAtCommit()
|
||||
void
|
||||
Async_NotifyAtAbort()
|
||||
{
|
||||
extern TransactionState CurrentTransactionState;
|
||||
|
||||
if (notifyIssued)
|
||||
if (pendingNotifies) {
|
||||
ClearPendingNotify();
|
||||
notifyIssued = 0;
|
||||
if (pendingNotifies)
|
||||
DLFreeList(pendingNotifies);
|
||||
}
|
||||
pendingNotifies = DLNewList();
|
||||
notifyIssued = 0;
|
||||
|
||||
if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
|
||||
(CurrentTransactionState->blockState == TRANS_DEFAULT))
|
||||
{
|
||||
/* don't forget to notify front end */
|
||||
if (notifyFrontEndPending)
|
||||
{ /* don't forget to notify front end */
|
||||
{
|
||||
Async_NotifyFrontEnd();
|
||||
}
|
||||
}
|
||||
@ -373,11 +390,11 @@ Async_NotifyAtAbort()
|
||||
*--------------------------------------------------------------
|
||||
* Async_Listen --
|
||||
*
|
||||
* This is executed by the SQL listen command.
|
||||
*
|
||||
* Register a backend (identified by its Unix PID) as listening
|
||||
* on the specified relation.
|
||||
*
|
||||
* This corresponds to the 'listen <relation>' command in SQL
|
||||
*
|
||||
* One listener per relation, pg_listener relation is keyed
|
||||
* on (relname,pid) to provide multiple listeners in future.
|
||||
*
|
||||
@ -406,9 +423,13 @@ Async_Listen(char *relname, int pid)
|
||||
char *relnamei;
|
||||
TupleDesc tupDesc;
|
||||
|
||||
#ifdef ASYNC_DEBUG
|
||||
elog(DEBUG, "Async_Listen: %s", relname);
|
||||
#endif
|
||||
if (whereToSendOutput != Remote) {
|
||||
elog(NOTICE, "Async_Listen: "
|
||||
"listen not available on interactive sessions");
|
||||
return;
|
||||
}
|
||||
|
||||
TPRINTF(TRACE_NOTIFY, "Async_Listen: %s", relname);
|
||||
for (i = 0; i < Natts_pg_listener; i++)
|
||||
{
|
||||
nulls[i] = ' ';
|
||||
@ -438,6 +459,10 @@ Async_Listen(char *relname, int pid)
|
||||
if (pid == MyProcPid)
|
||||
alreadyListener = 1;
|
||||
}
|
||||
if (alreadyListener) {
|
||||
/* No need to scan the rest of the table */
|
||||
break;
|
||||
}
|
||||
}
|
||||
heap_endscan(scan);
|
||||
|
||||
@ -445,15 +470,14 @@ Async_Listen(char *relname, int pid)
|
||||
{
|
||||
elog(NOTICE, "Async_Listen: We are already listening on %s",
|
||||
relname);
|
||||
RelationUnsetLockForWrite(lDesc);
|
||||
heap_close(lDesc);
|
||||
return;
|
||||
}
|
||||
|
||||
tupDesc = lDesc->rd_att;
|
||||
newtup = heap_formtuple(tupDesc,
|
||||
values,
|
||||
nulls);
|
||||
newtup = heap_formtuple(tupDesc, values, nulls);
|
||||
heap_insert(lDesc, newtup);
|
||||
|
||||
pfree(newtup);
|
||||
|
||||
/*
|
||||
@ -477,12 +501,11 @@ Async_Listen(char *relname, int pid)
|
||||
*--------------------------------------------------------------
|
||||
* Async_Unlisten --
|
||||
*
|
||||
* This is executed by the SQL unlisten command.
|
||||
*
|
||||
* Remove the backend from the list of listening backends
|
||||
* for the specified relation.
|
||||
*
|
||||
* This would correspond to the 'unlisten <relation>'
|
||||
* command, but there isn't one yet.
|
||||
*
|
||||
* Results:
|
||||
* pg_listeners is updated.
|
||||
*
|
||||
@ -497,20 +520,81 @@ Async_Unlisten(char *relname, int pid)
|
||||
Relation lDesc;
|
||||
HeapTuple lTuple;
|
||||
|
||||
lTuple = SearchSysCacheTuple(LISTENREL,
|
||||
PointerGetDatum(relname),
|
||||
/* Handle specially the `unlisten "*"' command */
|
||||
if ((!relname) || (*relname == '\0') || (strcmp(relname,"*")==0)) {
|
||||
Async_UnlistenAll();
|
||||
return;
|
||||
}
|
||||
|
||||
TPRINTF(TRACE_NOTIFY, "Async_Unlisten %s", relname);
|
||||
|
||||
lTuple = SearchSysCacheTuple(LISTENREL, PointerGetDatum(relname),
|
||||
Int32GetDatum(pid),
|
||||
0, 0);
|
||||
lDesc = heap_openr(ListenerRelationName);
|
||||
RelationSetLockForWrite(lDesc);
|
||||
|
||||
if (lTuple != NULL)
|
||||
{
|
||||
lDesc = heap_openr(ListenerRelationName);
|
||||
RelationSetLockForWrite(lDesc);
|
||||
heap_delete(lDesc, &lTuple->t_ctid);
|
||||
|
||||
RelationUnsetLockForWrite(lDesc);
|
||||
heap_close(lDesc);
|
||||
RelationUnsetLockForWrite(lDesc);
|
||||
heap_close(lDesc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------
|
||||
* Async_UnlistenAll --
|
||||
*
|
||||
* Unlisten all relations for this backend.
|
||||
*
|
||||
* Results:
|
||||
* pg_listeners is updated.
|
||||
*
|
||||
* Side effects:
|
||||
* XXX
|
||||
*
|
||||
*--------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
Async_UnlistenAll()
|
||||
{
|
||||
HeapTuple lTuple;
|
||||
Relation lRel;
|
||||
HeapScanDesc sRel;
|
||||
TupleDesc tdesc;
|
||||
ScanKeyData key[1];
|
||||
|
||||
TPRINTF(TRACE_NOTIFY, "Async_UnlistenAll");
|
||||
ScanKeyEntryInitialize(&key[0], 0,
|
||||
Anum_pg_listener_pid,
|
||||
F_INT4EQ,
|
||||
Int32GetDatum(MyProcPid));
|
||||
lRel = heap_openr(ListenerRelationName);
|
||||
RelationSetLockForWrite(lRel);
|
||||
tdesc = RelationGetTupleDescriptor(lRel);
|
||||
sRel = heap_beginscan(lRel, 0, SnapshotNow, 1, key);
|
||||
|
||||
while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0)))
|
||||
{
|
||||
heap_delete(lRel, &lTuple->t_ctid);
|
||||
}
|
||||
heap_endscan(sRel);
|
||||
RelationUnsetLockForWrite(lRel);
|
||||
heap_close(lRel);
|
||||
TPRINTF(TRACE_NOTIFY, "Async_UnlistenAll: done");
|
||||
}
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------
|
||||
* Async_UnlistenOnExit --
|
||||
*
|
||||
* This is called at backend exit for each registered listen.
|
||||
*
|
||||
* Results:
|
||||
* XXX
|
||||
*
|
||||
* --------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
Async_UnlistenOnExit(int code, /* from exitpg */
|
||||
char *relname)
|
||||
@ -522,6 +606,25 @@ Async_UnlistenOnExit(int code, /* from exitpg */
|
||||
* --------------------------------------------------------------
|
||||
* Async_NotifyFrontEnd --
|
||||
*
|
||||
* This is called outside transactions. The real work is done
|
||||
* by Async_NotifyFrontEnd_Aux().
|
||||
*
|
||||
* --------------------------------------------------------------
|
||||
*/
|
||||
static void
|
||||
Async_NotifyFrontEnd()
|
||||
{
|
||||
StartTransactionCommand();
|
||||
Async_NotifyFrontEnd_Aux();
|
||||
CommitTransactionCommand();
|
||||
}
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------
|
||||
* Async_NotifyFrontEnd_Aux --
|
||||
*
|
||||
* This must be called inside a transaction block.
|
||||
*
|
||||
* Perform an asynchronous notification to front end over
|
||||
* portal comm channel. The name of the relation which contains the
|
||||
* data is sent to the front end.
|
||||
@ -534,12 +637,9 @@ Async_UnlistenOnExit(int code, /* from exitpg */
|
||||
*
|
||||
* --------------------------------------------------------------
|
||||
*/
|
||||
GlobalMemory notifyContext = NULL;
|
||||
|
||||
static void
|
||||
Async_NotifyFrontEnd()
|
||||
Async_NotifyFrontEnd_Aux()
|
||||
{
|
||||
extern CommandDest whereToSendOutput;
|
||||
HeapTuple lTuple,
|
||||
rTuple;
|
||||
Relation lRel;
|
||||
@ -552,12 +652,15 @@ Async_NotifyFrontEnd()
|
||||
nulls[3];
|
||||
bool isnull;
|
||||
|
||||
#define MAX_DONE 64
|
||||
|
||||
char *done[MAX_DONE];
|
||||
int ndone = 0;
|
||||
int i;
|
||||
|
||||
notifyFrontEndPending = 0;
|
||||
|
||||
#ifdef ASYNC_DEBUG
|
||||
elog(DEBUG, "Async_NotifyFrontEnd: notifying front end.");
|
||||
#endif
|
||||
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyFrontEnd");
|
||||
StartTransactionCommand();
|
||||
ScanKeyEntryInitialize(&key[0], 0,
|
||||
Anum_pg_listener_notify,
|
||||
@ -580,11 +683,35 @@ Async_NotifyFrontEnd()
|
||||
|
||||
while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0)))
|
||||
{
|
||||
d = heap_getattr(lTuple, Anum_pg_listener_relname, tdesc, &isnull);
|
||||
d = heap_getattr(lTuple, Anum_pg_listener_relname, tdesc,
|
||||
&isnull);
|
||||
|
||||
/*
|
||||
* This hack deletes duplicate tuples which can be left
|
||||
* in the table if the NotifyUnlock option is set.
|
||||
* I'm further investigating this. -- dz
|
||||
*/
|
||||
if (NotifyHack) {
|
||||
for (i=0; i<ndone; i++) {
|
||||
if (strcmp(DatumGetName(d)->data, done[i]) == 0) {
|
||||
TPRINTF(TRACE_NOTIFY,
|
||||
"Async_NotifyFrontEnd: duplicate %s",
|
||||
DatumGetName(d)->data);
|
||||
heap_delete(lRel, &lTuple->t_ctid);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ndone < MAX_DONE) {
|
||||
done[ndone++] = pstrdup(DatumGetName(d)->data);
|
||||
}
|
||||
}
|
||||
|
||||
rTuple = heap_modifytuple(lTuple, lRel, value, nulls, repl);
|
||||
heap_replace(lRel, &lTuple->t_ctid, rTuple);
|
||||
|
||||
/* notifying the front end */
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyFrontEnd: notifying %s",
|
||||
DatumGetName(d)->data);
|
||||
|
||||
if (whereToSendOutput == Remote)
|
||||
{
|
||||
@ -593,12 +720,12 @@ Async_NotifyFrontEnd()
|
||||
pq_putstr(DatumGetName(d)->data);
|
||||
pq_flush();
|
||||
}
|
||||
else
|
||||
elog(NOTICE, "Async_NotifyFrontEnd: no asynchronous notification to frontend on interactive sessions");
|
||||
}
|
||||
heap_endscan(sRel);
|
||||
RelationUnsetLockForWrite(lRel);
|
||||
heap_close(lRel);
|
||||
CommitTransactionCommand();
|
||||
|
||||
TPRINTF(TRACE_NOTIFY, "Async_NotifyFrontEnd: done");
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.86 1998/08/25 21:34:04 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.87 1998/08/30 21:05:27 scrappy Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
@ -443,11 +443,41 @@ pg_parse_and_plan(char *query_string, /* string to execute */
|
||||
|
||||
querytree = querytree_list->qtrees[i];
|
||||
|
||||
if (DebugPrintQuery == true)
|
||||
if (DebugPrintQuery)
|
||||
{
|
||||
printf("\n---- \tquery is:\n%s\n", query_string);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
if (DebugPrintQuery > 3) {
|
||||
/* Print the query string as is if query debug level > 3 */
|
||||
TPRINTF(TRACE_QUERY, "query: %s",query_string);
|
||||
} else {
|
||||
/* Print condensed query string to fit in one log line */
|
||||
char buff[8192+1];
|
||||
char c,
|
||||
*s,
|
||||
*d;
|
||||
int n,
|
||||
is_space=1;
|
||||
|
||||
for (s=query_string,d=buff,n=0; (c=*s) && (n<8192); s++) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '\t':
|
||||
c = ' ';
|
||||
/* fall through */
|
||||
case ' ':
|
||||
if (is_space) continue;
|
||||
is_space = 1;
|
||||
break;
|
||||
default:
|
||||
is_space = 0;
|
||||
break;
|
||||
}
|
||||
*d++ = c;
|
||||
n++;
|
||||
}
|
||||
*d = '\0';
|
||||
TPRINTF(TRACE_QUERY, "query: %s",buff);
|
||||
}
|
||||
}
|
||||
|
||||
/* don't rewrite utilites */
|
||||
@ -457,11 +487,10 @@ pg_parse_and_plan(char *query_string, /* string to execute */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DebugPrintParse == true)
|
||||
if (DebugPrintParse)
|
||||
{
|
||||
printf("\n---- \tparser outputs :\n");
|
||||
TPRINTF(TRACE_PARSE, "parser outputs:");
|
||||
nodeDisplay(querytree);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* rewrite queries (retrieve, append, delete, replace) */
|
||||
@ -906,9 +935,11 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||
char firstchar;
|
||||
char parser_input[MAX_PARSE_BUFFER];
|
||||
char *userName;
|
||||
char *remote_info;
|
||||
char *remote_host;
|
||||
unsigned short remote_port = 0;
|
||||
|
||||
/* Used if verbose is set, must be initialized */
|
||||
char *remote_info = "interactive";
|
||||
char *remote_host = "";
|
||||
unsigned short remote_port = 0;
|
||||
|
||||
char *DBDate = NULL;
|
||||
extern int optind;
|
||||
@ -1490,7 +1521,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
puts("\nPOSTGRES backend interactive interface");
|
||||
puts("$Revision: 1.86 $ $Date: 1998/08/25 21:34:04 $");
|
||||
puts("$Revision: 1.87 $ $Date: 1998/08/30 21:05:27 $");
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/create_sequence.l,v 1.5 1998/07/14 01:45:25 momjian Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/create_sequence.l,v 1.6 1998/08/30 21:03:19 scrappy Exp $
|
||||
.TH "CREATE SEQUENCE" SQL 07/13/98 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
create sequence - create a new sequence number generator
|
||||
@ -82,6 +82,14 @@ given sequence in the current backend session. Also beware that it
|
||||
does not give the last number ever allocated, only the last one allocated
|
||||
by this backend.
|
||||
.PP
|
||||
The function
|
||||
.BR setval
|
||||
('sequence_name', value)
|
||||
may be used to set the current value of the specified sequence.
|
||||
The next call to
|
||||
.BR nextval
|
||||
will return the given value + the sequence increment.
|
||||
.PP
|
||||
Use a query like
|
||||
.nf
|
||||
SELECT * FROM <sequence_name>;
|
||||
@ -134,6 +142,15 @@ select nextval ('seq');
|
||||
-- Use sequence in insert
|
||||
--
|
||||
insert into table _table_ values (nextval ('seq'),...);
|
||||
.nf
|
||||
--
|
||||
-- Set the sequence value after a copy in
|
||||
--
|
||||
create function table_id_max() returns int4
|
||||
as 'select max(id) from _table_'
|
||||
language 'sql';
|
||||
copy _table_ from 'input_file';
|
||||
select setval('seq', table_id_max());
|
||||
.fi
|
||||
.SH "SEE ALSO"
|
||||
drop_sequence(l).
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" This is -*-nroff-*-
|
||||
.\" XXX standard disclaimer belongs here....
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/listen.l,v 1.7 1998/07/09 03:29:09 scrappy Exp $
|
||||
.\" $Header: /cvsroot/pgsql/src/man/Attic/listen.l,v 1.8 1998/08/30 21:03:20 scrappy Exp $
|
||||
.TH "LISTEN" SQL 03/12/94 PostgreSQL PostgreSQL
|
||||
.SH NAME
|
||||
listen - listen for notification on a relation
|
||||
@ -27,16 +27,19 @@ in order to find out the name of the class to which a given
|
||||
notification corresponds. If this code is not included in
|
||||
the application, the event notification will be queued and
|
||||
never be processed.
|
||||
.PP
|
||||
Note that
|
||||
.IR class_name
|
||||
needs not to be a valid class name but can be any ascii string up to 32
|
||||
characters long. It must however be eclosed in double-quotes if it is
|
||||
not valid as class name.
|
||||
.SH "SEE ALSO"
|
||||
create_rule(l),
|
||||
notify(l),
|
||||
select(l),
|
||||
unlisten(l),
|
||||
libpq.
|
||||
.SH BUGS
|
||||
There is no way to un-\c
|
||||
.BR listen
|
||||
except to drop the connection (i.e., restart the backend server).
|
||||
.PP
|
||||
The
|
||||
.IR psql(1)
|
||||
command does not poll for asynchronous events.
|
||||
|
Loading…
x
Reference in New Issue
Block a user