Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
6c498285
Commit
6c498285
authored
Aug 30, 1998
by
Marc G. Fournier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
parent
6f3de1bb
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
295 additions
and
117 deletions
+295
-117
src/backend/commands/async.c
src/backend/commands/async.c
+226
-99
src/backend/tcop/postgres.c
src/backend/tcop/postgres.c
+43
-12
src/man/create_sequence.l
src/man/create_sequence.l
+18
-1
src/man/listen.l
src/man/listen.l
+8
-5
No files found.
src/backend/commands/async.c
View file @
6c498285
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.3
7 1998/08/19 02:01:39 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.3
8 1998/08/30 21:04:43 scrappy
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -34,29 +34,7 @@
...
@@ -34,29 +34,7 @@
* -- jw, 12/28/93
* -- 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 <unistd.h>
#include <signal.h>
#include <signal.h>
#include <string.h>
#include <string.h>
...
@@ -82,17 +60,28 @@
...
@@ -82,17 +60,28 @@
#include "tcop/dest.h"
#include "tcop/dest.h"
#include "utils/mcxt.h"
#include "utils/mcxt.h"
#include "utils/syscache.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
notifyFrontEndPending
=
0
;
static
int
notifyIssued
=
0
;
static
int
notifyIssued
=
0
;
static
Dllist
*
pendingNotifies
=
NULL
;
static
Dllist
*
pendingNotifies
=
NULL
;
static
int
AsyncExistsPendingNotify
(
char
*
);
static
int
AsyncExistsPendingNotify
(
char
*
);
static
void
ClearPendingNotify
(
void
);
static
void
ClearPendingNotify
(
void
);
static
void
Async_NotifyFrontEnd
(
void
);
static
void
Async_NotifyFrontEnd
(
void
);
static
void
Async_NotifyFrontEnd_Aux
(
void
);
void
Async_Unlisten
(
char
*
relname
,
int
pid
);
void
Async_Unlisten
(
char
*
relname
,
int
pid
);
static
void
Async_UnlistenOnExit
(
int
code
,
char
*
relname
);
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);
...
@@ -116,33 +105,36 @@ static void Async_UnlistenOnExit(int code, char *relname);
void
void
Async_NotifyHandler
(
SIGNAL_ARGS
)
Async_NotifyHandler
(
SIGNAL_ARGS
)
{
{
extern
TransactionState
CurrentTransactionState
;
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyHandler"
)
;
if
((
CurrentTransactionState
->
state
==
TRANS_DEFAULT
)
&&
if
((
CurrentTransactionState
->
state
==
TRANS_DEFAULT
)
&&
(
CurrentTransactionState
->
blockState
==
TRANS_DEFAULT
))
(
CurrentTransactionState
->
blockState
==
TRANS_DEFAULT
))
{
{
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyHandler: "
#ifdef ASYNC_DEBUG
"waking up sleeping backend process"
);
elog
(
DEBUG
,
"Waking up sleeping backend process"
);
PS_SET_STATUS
(
"async_notify"
);
#endif
Async_NotifyFrontEnd
();
Async_NotifyFrontEnd
();
PS_SET_STATUS
(
"idle"
);
}
}
else
else
{
{
#ifdef ASYNC_DEBUG
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyHandler: "
elog
(
DEBUG
,
"Process is in the middle of another transaction, state = %d, block state =
%d"
,
"process in middle of transaction, state=%d, blockstate=
%d"
,
CurrentTransactionState
->
state
,
CurrentTransactionState
->
state
,
CurrentTransactionState
->
blockState
);
CurrentTransactionState
->
blockState
);
#endif
notifyFrontEndPending
=
1
;
notifyFrontEndPending
=
1
;
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyHandler: notify frontend pending"
);
}
}
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyHandler: done"
);
}
}
/*
/*
*--------------------------------------------------------------
*--------------------------------------------------------------
* Async_Notify --
* Async_Notify --
*
*
* This is executed by the SQL notify command.
*
* Adds the relation to the list of pending notifies.
* Adds the relation to the list of pending notifies.
* All notification happens at end of commit.
* All notification happens at end of commit.
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
@@ -151,7 +143,6 @@ Async_NotifyHandler(SIGNAL_ARGS)
...
@@ -151,7 +143,6 @@ Async_NotifyHandler(SIGNAL_ARGS)
* then each backend notifies its corresponding front end at
* then each backend notifies its corresponding front end at
* the end of commit.
* the end of commit.
*
*
* This correspond to 'notify <relname>' command
* -- jw, 12/28/93
* -- jw, 12/28/93
*
*
* Results:
* Results:
...
@@ -180,9 +171,7 @@ Async_Notify(char *relname)
...
@@ -180,9 +171,7 @@ Async_Notify(char *relname)
char
*
notifyName
;
char
*
notifyName
;
#ifdef ASYNC_DEBUG
TPRINTF
(
TRACE_NOTIFY
,
"Async_Notify: %s"
,
relname
);
elog
(
DEBUG
,
"Async_Notify: %s"
,
relname
);
#endif
if
(
!
pendingNotifies
)
if
(
!
pendingNotifies
)
pendingNotifies
=
DLNewList
();
pendingNotifies
=
DLNewList
();
...
@@ -217,18 +206,32 @@ Async_Notify(char *relname)
...
@@ -217,18 +206,32 @@ Async_Notify(char *relname)
{
{
rTuple
=
heap_modifytuple
(
lTuple
,
lRel
,
value
,
nulls
,
repl
);
rTuple
=
heap_modifytuple
(
lTuple
,
lRel
,
value
,
nulls
,
repl
);
heap_replace
(
lRel
,
&
lTuple
->
t_ctid
,
rTuple
);
heap_replace
(
lRel
,
&
lTuple
->
t_ctid
,
rTuple
);
/* notify is really issued only if a tuple has been changed */
notifyIssued
=
1
;
}
}
}
}
heap_endscan
(
sRel
);
heap_endscan
(
sRel
);
/*
* 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
);
RelationUnsetLockForWrite
(
lRel
);
}
heap_close
(
lRel
);
heap_close
(
lRel
);
notifyIssued
=
1
;
TPRINTF
(
TRACE_NOTIFY
,
"Async_Notify: done %s"
,
relname
);
}
}
/*
/*
*--------------------------------------------------------------
*--------------------------------------------------------------
* Async_NotifyAtCommit --
* Async_NotifyAtCommit --
*
*
* This is called at transaction commit.
*
* Signal our corresponding frontend process on relations that
* Signal our corresponding frontend process on relations that
* were notified. Signal all other backend process that
* were notified. Signal all other backend process that
* are listening also.
* are listening also.
...
@@ -265,14 +268,12 @@ Async_NotifyAtCommit()
...
@@ -265,14 +268,12 @@ Async_NotifyAtCommit()
if
((
CurrentTransactionState
->
state
==
TRANS_DEFAULT
)
&&
if
((
CurrentTransactionState
->
state
==
TRANS_DEFAULT
)
&&
(
CurrentTransactionState
->
blockState
==
TRANS_DEFAULT
))
(
CurrentTransactionState
->
blockState
==
TRANS_DEFAULT
))
{
{
if
(
notifyIssued
)
if
(
notifyIssued
)
{
/* 'notify <relname>' issued by us */
{
/* 'notify <relname>' issued by us */
notifyIssued
=
0
;
notifyIssued
=
0
;
StartTransactionCommand
();
StartTransactionCommand
();
#ifdef ASYNC_DEBUG
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyAtCommit"
);
elog
(
DEBUG
,
"Async_NotifyAtCommit."
);
#endif
ScanKeyEntryInitialize
(
&
key
,
0
,
ScanKeyEntryInitialize
(
&
key
,
0
,
Anum_pg_listener_notify
,
Anum_pg_listener_notify
,
F_INT4EQ
,
F_INT4EQ
,
...
@@ -294,16 +295,15 @@ Async_NotifyAtCommit()
...
@@ -294,16 +295,15 @@ Async_NotifyAtCommit()
if
(
MyProcPid
==
DatumGetInt32
(
d
))
if
(
MyProcPid
==
DatumGetInt32
(
d
))
{
{
#ifdef ASYNC_DEBUG
elog
(
DEBUG
,
"Notifying self, setting notifyFronEndPending to 1"
);
#endif
notifyFrontEndPending
=
1
;
notifyFrontEndPending
=
1
;
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyAtCommit: notifying self"
);
}
}
else
else
{
{
#ifdef ASYNC_DEBUG
TPRINTF
(
TRACE_NOTIFY
,
elog
(
DEBUG
,
"Notifying others"
);
"Async_NotifyAtCommit: notifying pid %d"
,
#endif
DatumGetInt32
(
d
));
#ifdef HAVE_KILL
#ifdef HAVE_KILL
if
(
kill
(
DatumGetInt32
(
d
),
SIGUSR2
)
<
0
)
if
(
kill
(
DatumGetInt32
(
d
),
SIGUSR2
)
<
0
)
{
{
...
@@ -315,26 +315,44 @@ Async_NotifyAtCommit()
...
@@ -315,26 +315,44 @@ Async_NotifyAtCommit()
}
}
}
}
heap_endscan
(
sRel
);
heap_endscan
(
sRel
);
RelationUnsetLockForWrite
(
lRel
);
heap_close
(
lRel
);
heap_close
(
lRel
);
CommitTransactionCommand
();
/*
ClearPendingNotify
();
* 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
();
}
}
if
(
notifyFrontEndPending
)
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyAtCommit: done"
);
{
/* we need to notify the frontend of all
CommitTransactionCommand
();
* pending notifies. */
}
notifyFrontEndPending
=
1
;
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
();
Async_NotifyFrontEnd
();
}
}
}
}
ClearPendingNotify
();
}
}
}
/*
/*
*--------------------------------------------------------------
*--------------------------------------------------------------
* Async_NotifyAtAbort --
* Async_NotifyAtAbort --
*
*
* This is called at transaction commit.
*
* Gets rid of pending notifies. List elements are automatically
* Gets rid of pending notifies. List elements are automatically
* freed through memory context.
* freed through memory context.
*
*
...
@@ -350,20 +368,19 @@ Async_NotifyAtCommit()
...
@@ -350,20 +368,19 @@ Async_NotifyAtCommit()
void
void
Async_NotifyAtAbort
()
Async_NotifyAtAbort
()
{
{
extern
TransactionState
CurrentTransactionState
;
if
(
pendingNotifies
)
{
if
(
notifyIssued
)
ClearPendingNotify
();
ClearPendingNotify
();
notifyIssued
=
0
;
if
(
pendingNotifies
)
DLFreeList
(
pendingNotifies
);
DLFreeList
(
pendingNotifies
);
}
pendingNotifies
=
DLNewList
();
pendingNotifies
=
DLNewList
();
notifyIssued
=
0
;
if
((
CurrentTransactionState
->
state
==
TRANS_DEFAULT
)
&&
if
((
CurrentTransactionState
->
state
==
TRANS_DEFAULT
)
&&
(
CurrentTransactionState
->
blockState
==
TRANS_DEFAULT
))
(
CurrentTransactionState
->
blockState
==
TRANS_DEFAULT
))
{
{
/* don't forget to notify front end */
if
(
notifyFrontEndPending
)
if
(
notifyFrontEndPending
)
{
/* don't forget to notify front end */
{
Async_NotifyFrontEnd
();
Async_NotifyFrontEnd
();
}
}
}
}
...
@@ -373,11 +390,11 @@ Async_NotifyAtAbort()
...
@@ -373,11 +390,11 @@ Async_NotifyAtAbort()
*--------------------------------------------------------------
*--------------------------------------------------------------
* Async_Listen --
* Async_Listen --
*
*
* This is executed by the SQL listen command.
*
* Register a backend (identified by its Unix PID) as listening
* Register a backend (identified by its Unix PID) as listening
* on the specified relation.
* on the specified relation.
*
*
* This corresponds to the 'listen <relation>' command in SQL
*
* One listener per relation, pg_listener relation is keyed
* One listener per relation, pg_listener relation is keyed
* on (relname,pid) to provide multiple listeners in future.
* on (relname,pid) to provide multiple listeners in future.
*
*
...
@@ -406,9 +423,13 @@ Async_Listen(char *relname, int pid)
...
@@ -406,9 +423,13 @@ Async_Listen(char *relname, int pid)
char
*
relnamei
;
char
*
relnamei
;
TupleDesc
tupDesc
;
TupleDesc
tupDesc
;
#ifdef ASYNC_DEBUG
if
(
whereToSendOutput
!=
Remote
)
{
elog
(
DEBUG
,
"Async_Listen: %s"
,
relname
);
elog
(
NOTICE
,
"Async_Listen: "
#endif
"listen not available on interactive sessions"
);
return
;
}
TPRINTF
(
TRACE_NOTIFY
,
"Async_Listen: %s"
,
relname
);
for
(
i
=
0
;
i
<
Natts_pg_listener
;
i
++
)
for
(
i
=
0
;
i
<
Natts_pg_listener
;
i
++
)
{
{
nulls
[
i
]
=
' '
;
nulls
[
i
]
=
' '
;
...
@@ -438,6 +459,10 @@ Async_Listen(char *relname, int pid)
...
@@ -438,6 +459,10 @@ Async_Listen(char *relname, int pid)
if
(
pid
==
MyProcPid
)
if
(
pid
==
MyProcPid
)
alreadyListener
=
1
;
alreadyListener
=
1
;
}
}
if
(
alreadyListener
)
{
/* No need to scan the rest of the table */
break
;
}
}
}
heap_endscan
(
scan
);
heap_endscan
(
scan
);
...
@@ -445,15 +470,14 @@ Async_Listen(char *relname, int pid)
...
@@ -445,15 +470,14 @@ Async_Listen(char *relname, int pid)
{
{
elog
(
NOTICE
,
"Async_Listen: We are already listening on %s"
,
elog
(
NOTICE
,
"Async_Listen: We are already listening on %s"
,
relname
);
relname
);
RelationUnsetLockForWrite
(
lDesc
);
heap_close
(
lDesc
);
return
;
return
;
}
}
tupDesc
=
lDesc
->
rd_att
;
tupDesc
=
lDesc
->
rd_att
;
newtup
=
heap_formtuple
(
tupDesc
,
newtup
=
heap_formtuple
(
tupDesc
,
values
,
nulls
);
values
,
nulls
);
heap_insert
(
lDesc
,
newtup
);
heap_insert
(
lDesc
,
newtup
);
pfree
(
newtup
);
pfree
(
newtup
);
/*
/*
...
@@ -477,12 +501,11 @@ Async_Listen(char *relname, int pid)
...
@@ -477,12 +501,11 @@ Async_Listen(char *relname, int pid)
*--------------------------------------------------------------
*--------------------------------------------------------------
* Async_Unlisten --
* Async_Unlisten --
*
*
* This is executed by the SQL unlisten command.
*
* Remove the backend from the list of listening backends
* Remove the backend from the list of listening backends
* for the specified relation.
* for the specified relation.
*
*
* This would correspond to the 'unlisten <relation>'
* command, but there isn't one yet.
*
* Results:
* Results:
* pg_listeners is updated.
* pg_listeners is updated.
*
*
...
@@ -497,20 +520,81 @@ Async_Unlisten(char *relname, int pid)
...
@@ -497,20 +520,81 @@ Async_Unlisten(char *relname, int pid)
Relation
lDesc
;
Relation
lDesc
;
HeapTuple
lTuple
;
HeapTuple
lTuple
;
lTuple
=
SearchSysCacheTuple
(
LISTENREL
,
/* Handle specially the `unlisten "*"' command */
PointerGetDatum
(
relname
),
if
((
!
relname
)
||
(
*
relname
==
'\0'
)
||
(
strcmp
(
relname
,
"*"
)
==
0
))
{
Async_UnlistenAll
();
return
;
}
TPRINTF
(
TRACE_NOTIFY
,
"Async_Unlisten %s"
,
relname
);
lTuple
=
SearchSysCacheTuple
(
LISTENREL
,
PointerGetDatum
(
relname
),
Int32GetDatum
(
pid
),
Int32GetDatum
(
pid
),
0
,
0
);
0
,
0
);
if
(
lTuple
!=
NULL
)
{
lDesc
=
heap_openr
(
ListenerRelationName
);
lDesc
=
heap_openr
(
ListenerRelationName
);
RelationSetLockForWrite
(
lDesc
);
RelationSetLockForWrite
(
lDesc
);
if
(
lTuple
!=
NULL
)
heap_delete
(
lDesc
,
&
lTuple
->
t_ctid
);
heap_delete
(
lDesc
,
&
lTuple
->
t_ctid
);
RelationUnsetLockForWrite
(
lDesc
);
RelationUnsetLockForWrite
(
lDesc
);
heap_close
(
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
static
void
Async_UnlistenOnExit
(
int
code
,
/* from exitpg */
Async_UnlistenOnExit
(
int
code
,
/* from exitpg */
char
*
relname
)
char
*
relname
)
...
@@ -522,6 +606,25 @@ Async_UnlistenOnExit(int code, /* from exitpg */
...
@@ -522,6 +606,25 @@ Async_UnlistenOnExit(int code, /* from exitpg */
* --------------------------------------------------------------
* --------------------------------------------------------------
* Async_NotifyFrontEnd --
* 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
* Perform an asynchronous notification to front end over
* portal comm channel. The name of the relation which contains the
* portal comm channel. The name of the relation which contains the
* data is sent to the front end.
* data is sent to the front end.
...
@@ -534,12 +637,9 @@ Async_UnlistenOnExit(int code, /* from exitpg */
...
@@ -534,12 +637,9 @@ Async_UnlistenOnExit(int code, /* from exitpg */
*
*
* --------------------------------------------------------------
* --------------------------------------------------------------
*/
*/
GlobalMemory
notifyContext
=
NULL
;
static
void
static
void
Async_NotifyFrontEnd
()
Async_NotifyFrontEnd
_Aux
()
{
{
extern
CommandDest
whereToSendOutput
;
HeapTuple
lTuple
,
HeapTuple
lTuple
,
rTuple
;
rTuple
;
Relation
lRel
;
Relation
lRel
;
...
@@ -552,12 +652,15 @@ Async_NotifyFrontEnd()
...
@@ -552,12 +652,15 @@ Async_NotifyFrontEnd()
nulls
[
3
];
nulls
[
3
];
bool
isnull
;
bool
isnull
;
notifyFrontEndPending
=
0
;
#define MAX_DONE 64
#ifdef ASYNC_DEBUG
char
*
done
[
MAX_DONE
];
elog
(
DEBUG
,
"Async_NotifyFrontEnd: notifying front end."
);
int
ndone
=
0
;
#endif
int
i
;
notifyFrontEndPending
=
0
;
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyFrontEnd"
);
StartTransactionCommand
();
StartTransactionCommand
();
ScanKeyEntryInitialize
(
&
key
[
0
],
0
,
ScanKeyEntryInitialize
(
&
key
[
0
],
0
,
Anum_pg_listener_notify
,
Anum_pg_listener_notify
,
...
@@ -580,11 +683,35 @@ Async_NotifyFrontEnd()
...
@@ -580,11 +683,35 @@ Async_NotifyFrontEnd()
while
(
HeapTupleIsValid
(
lTuple
=
heap_getnext
(
sRel
,
0
)))
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
);
rTuple
=
heap_modifytuple
(
lTuple
,
lRel
,
value
,
nulls
,
repl
);
heap_replace
(
lRel
,
&
lTuple
->
t_ctid
,
rTuple
);
heap_replace
(
lRel
,
&
lTuple
->
t_ctid
,
rTuple
);
/* notifying the front end */
/* notifying the front end */
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyFrontEnd: notifying %s"
,
DatumGetName
(
d
)
->
data
);
if
(
whereToSendOutput
==
Remote
)
if
(
whereToSendOutput
==
Remote
)
{
{
...
@@ -593,12 +720,12 @@ Async_NotifyFrontEnd()
...
@@ -593,12 +720,12 @@ Async_NotifyFrontEnd()
pq_putstr
(
DatumGetName
(
d
)
->
data
);
pq_putstr
(
DatumGetName
(
d
)
->
data
);
pq_flush
();
pq_flush
();
}
}
else
elog
(
NOTICE
,
"Async_NotifyFrontEnd: no asynchronous notification to frontend on interactive sessions"
);
}
}
heap_endscan
(
sRel
);
heap_endscan
(
sRel
);
RelationUnsetLockForWrite
(
lRel
);
heap_close
(
lRel
);
heap_close
(
lRel
);
CommitTransactionCommand
();
TPRINTF
(
TRACE_NOTIFY
,
"Async_NotifyFrontEnd: done"
);
}
}
static
int
static
int
...
...
src/backend/tcop/postgres.c
View file @
6c498285
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.8
6 1998/08/25 21:34:04
scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.8
7 1998/08/30 21:05:27
scrappy Exp $
*
*
* NOTES
* NOTES
* this is the "main" module of the postgres backend and
* this is the "main" module of the postgres backend and
...
@@ -443,11 +443,41 @@ pg_parse_and_plan(char *query_string, /* string to execute */
...
@@ -443,11 +443,41 @@ pg_parse_and_plan(char *query_string, /* string to execute */
querytree
=
querytree_list
->
qtrees
[
i
];
querytree
=
querytree_list
->
qtrees
[
i
];
if
(
DebugPrintQuery
==
true
)
if
(
DebugPrintQuery
)
{
{
printf
(
"
\n
----
\t
query is:
\n
%s
\n
"
,
query_string
);
if
(
DebugPrintQuery
>
3
)
{
printf
(
"
\n
"
);
/* Print the query string as is if query debug level > 3 */
fflush
(
stdout
);
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 */
/* don't rewrite utilites */
...
@@ -457,11 +487,10 @@ pg_parse_and_plan(char *query_string, /* string to execute */
...
@@ -457,11 +487,10 @@ pg_parse_and_plan(char *query_string, /* string to execute */
continue
;
continue
;
}
}
if
(
DebugPrintParse
==
true
)
if
(
DebugPrintParse
)
{
{
printf
(
"
\n
----
\t
parser outputs :
\n
"
);
TPRINTF
(
TRACE_PARSE
,
"parser outputs:
"
);
nodeDisplay
(
querytree
);
nodeDisplay
(
querytree
);
printf
(
"
\n
"
);
}
}
/* rewrite queries (retrieve, append, delete, replace) */
/* rewrite queries (retrieve, append, delete, replace) */
...
@@ -906,8 +935,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
...
@@ -906,8 +935,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
char
firstchar
;
char
firstchar
;
char
parser_input
[
MAX_PARSE_BUFFER
];
char
parser_input
[
MAX_PARSE_BUFFER
];
char
*
userName
;
char
*
userName
;
char
*
remote_info
;
char
*
remote_host
;
/* Used if verbose is set, must be initialized */
char
*
remote_info
=
"interactive"
;
char
*
remote_host
=
""
;
unsigned
short
remote_port
=
0
;
unsigned
short
remote_port
=
0
;
char
*
DBDate
=
NULL
;
char
*
DBDate
=
NULL
;
...
@@ -1490,7 +1521,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
...
@@ -1490,7 +1521,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if
(
!
IsUnderPostmaster
)
if
(
!
IsUnderPostmaster
)
{
{
puts
(
"
\n
POSTGRES backend interactive interface"
);
puts
(
"
\n
POSTGRES backend interactive interface"
);
puts
(
"$Revision: 1.8
6 $ $Date: 1998/08/25 21:34:04
$"
);
puts
(
"$Revision: 1.8
7 $ $Date: 1998/08/30 21:05:27
$"
);
}
}
/* ----------------
/* ----------------
...
...
src/man/create_sequence.l
View file @
6c498285
.\" This is -*-nroff-*-
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" 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
.TH "CREATE SEQUENCE" SQL 07/13/98 PostgreSQL PostgreSQL
.SH NAME
.SH NAME
create sequence - create a new sequence number generator
create sequence - create a new sequence number generator
...
@@ -82,6 +82,14 @@ given sequence in the current backend session. Also beware that it
...
@@ -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
does not give the last number ever allocated, only the last one allocated
by this backend.
by this backend.
.PP
.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
Use a query like
.nf
.nf
SELECT * FROM <sequence_name>;
SELECT * FROM <sequence_name>;
...
@@ -134,6 +142,15 @@ select nextval ('seq');
...
@@ -134,6 +142,15 @@ select nextval ('seq');
-- Use sequence in insert
-- Use sequence in insert
--
--
insert into table _table_ values (nextval ('seq'),...);
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
.fi
.SH "SEE ALSO"
.SH "SEE ALSO"
drop_sequence(l).
drop_sequence(l).
src/man/listen.l
View file @
6c498285
.\" This is -*-nroff-*-
.\" This is -*-nroff-*-
.\" XXX standard disclaimer belongs here....
.\" 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
.TH "LISTEN" SQL 03/12/94 PostgreSQL PostgreSQL
.SH NAME
.SH NAME
listen - listen for notification on a relation
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
...
@@ -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
notification corresponds. If this code is not included in
the application, the event notification will be queued and
the application, the event notification will be queued and
never be processed.
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"
.SH "SEE ALSO"
create_rule(l),
create_rule(l),
notify(l),
notify(l),
select(l),
select(l),
unlisten(l),
libpq.
libpq.
.SH BUGS
.SH BUGS
There is no way to un-\c
.BR listen
except to drop the connection (i.e., restart the backend server).
.PP
The
The
.IR psql(1)
.IR psql(1)
command does not poll for asynchronous events.
command does not poll for asynchronous events.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment