Implementing RESET CONNECTION ... - Mailing list pgsql-patches
| From | Hans-Jürgen Schönig |
|---|---|
| Subject | Implementing RESET CONNECTION ... |
| Date | |
| Msg-id | 41D3F834.9090706@cybertec.at Whole thread Raw |
| Responses |
Re: Implementing RESET CONNECTION ...
Re: Implementing RESET CONNECTION ... Re: Implementing RESET CONNECTION ... |
| List | pgsql-patches |
We have implemented a patch which can be used by connection pools for
instance.
RESECT CONNECTION cleans up a backend so that it can be reused.
Temp tables, LISTEN / NOTIFY stuff, WITH HOLD cursors, open
transactions, prepared statements and GUCs are cleaned up.
I hope we have not missed important per-backend information.
test=# BEGIN;
BEGIN
test=# RESET CONNECTION;
RESET
test=# COMMIT;
WARNING: there is no transaction in progress
COMMIT
test=# PREPARE myplan(int, int) AS SELECT $1 + $2;
PREPARE
test=# RESET CONNECTION;
RESET
test=# EXECUTE myplan(1, 2);
ERROR: prepared statement "myplan" does not exist
test=#
test=# DECLARE mycur CURSOR WITH HOLD FOR SELECT relname FROM pg_class;
DECLARE CURSOR
test=# FETCH NEXT FROM mycur;
relname
---------
views
(1 row)
test=# RESET CONNECTION;
RESET
test=# FETCH NEXT FROM mycur;
ERROR: cursor "mycur" does not exist
test=# CREATE TEMP TABLE mytmp (id int4);
CREATE TABLE
test=# RESET CONNECTION;
RESET
test=# INSERT INTO mytmp VALUES (10);
ERROR: relation "mytmp" does not exist
All regression tests passed.
It would be nice if we had this in 8.1.
Best regards,
Hans
--
Cybertec Geschwinde u Schoenig
Schoengrabern 134, A-2020 Hollabrunn, Austria
Tel: +43/660/816 40 77
www.cybertec.at, www.postgresql.at
*** ./doc/src/sgml/ref/reset.sgml.orig Thu Dec 30 12:29:14 2004
--- ./doc/src/sgml/ref/reset.sgml Thu Dec 30 12:58:41 2004
***************
*** 11,17 ****
<refnamediv>
<refname>RESET</refname>
! <refpurpose>restore the value of a run-time parameter to the default value</refpurpose>
</refnamediv>
<indexterm zone="sql-reset">
--- 11,17 ----
<refnamediv>
<refname>RESET</refname>
! <refpurpose>reset connection or restore the value of a run-time parameter to the default value</refpurpose>
</refnamediv>
<indexterm zone="sql-reset">
***************
*** 20,25 ****
--- 20,26 ----
<refsynopsisdiv>
<synopsis>
+ RESET <replaceable class="PARAMETER">connection</replaceable>
RESET <replaceable class="PARAMETER">name</replaceable>
RESET ALL
</synopsis>
***************
*** 52,57 ****
--- 53,66 ----
See the <command>SET</> reference page for details on the
transaction behavior of <command>RESET</>.
</para>
+
+ <para>
+ <command>RESET CONNECTION</command> can be used to reset the entire
+ backend. This includes temporary tables, open transactions, prepared
+ statements, <literal>WITH HOLD</literal> cursors runtime parameters
+ as well as asynchronous backend settings.
+ </para>
+
</refsect1>
<refsect1>
***************
*** 76,82 ****
--- 85,103 ----
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><literal>CONNECTION</literal></term>
+ <listitem>
+ <para>
+ Reset the entire backend including temporary tables, open transactions,
+ prepared statements, <literal>WITH HOLD</literal> cursors runtime
+ parameters as well as asynchronous backend settings.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
+
</refsect1>
<refsect1>
*** ./src/backend/catalog/namespace.c.orig Tue Dec 28 11:13:08 2004
--- ./src/backend/catalog/namespace.c Tue Dec 28 12:05:37 2004
***************
*** 135,141 ****
/* Local functions */
static void recomputeNamespacePath(void);
static void InitTempTableNamespace(void);
- static void RemoveTempRelations(Oid tempNamespaceId);
static void RemoveTempRelationsCallback(int code, Datum arg);
static void NamespaceCallback(Datum arg, Oid relid);
--- 135,140 ----
***************
*** 1772,1778 ****
* in order to clean out any relations that might have been created by
* a crashed backend.
*/
! static void
RemoveTempRelations(Oid tempNamespaceId)
{
ObjectAddress object;
--- 1771,1777 ----
* in order to clean out any relations that might have been created by
* a crashed backend.
*/
! void
RemoveTempRelations(Oid tempNamespaceId)
{
ObjectAddress object;
*** ./src/backend/commands/async.c.orig Mon Dec 27 21:36:10 2004
--- ./src/backend/commands/async.c Mon Dec 27 21:38:04 2004
***************
*** 128,134 ****
bool Trace_notify = false;
- static void Async_UnlistenAll(void);
static void Async_UnlistenOnExit(int code, Datum arg);
static void ProcessIncomingNotify(void);
static void NotifyMyFrontEnd(char *relname, int32 listenerPID);
--- 128,133 ----
***************
*** 345,351 ****
*
*--------------------------------------------------------------
*/
! static void
Async_UnlistenAll(void)
{
Relation lRel;
--- 344,350 ----
*
*--------------------------------------------------------------
*/
! void
Async_UnlistenAll(void)
{
Relation lRel;
*** ./src/backend/commands/prepare.c.orig Tue Dec 28 12:45:58 2004
--- ./src/backend/commands/prepare.c Tue Dec 28 20:22:06 2004
***************
*** 28,34 ****
#include "utils/hsearch.h"
#include "utils/memutils.h"
-
/*
* The hash table in which prepared queries are stored. This is
* per-backend: query plans are not shared between backends.
--- 28,33 ----
***************
*** 452,457 ****
--- 451,484 ----
}
/*
+ * Remove all prepared plans from the backend.
+ */
+ void
+ DropAllPreparedStatements(void)
+ {
+ PreparedStatement *prep_statement;
+ HASH_SEQ_STATUS status;
+
+ hash_seq_init(&status, prepared_queries);
+
+ /* we have to check for an empty hash here because
+ * otherwise the backend won't be able to loop through
+ * the hash */
+ if (!prepared_queries)
+ return;
+
+ /* we will quit one plan after the other */
+ while ((prep_statement = (PreparedStatement *) hash_seq_search(&status)))
+ {
+ DropDependentPortals(prep_statement->context);
+
+ /* Flush the context holding the subsidiary data */
+ MemoryContextDelete(prep_statement->context);
+ hash_search(prepared_queries, prep_statement->stmt_name, HASH_REMOVE, NULL);
+ }
+ }
+
+ /*
* Internal version of DEALLOCATE
*
* If showError is false, dropping a nonexistent statement is a no-op.
*** ./src/backend/parser/gram.y.orig Mon Dec 27 18:53:10 2004
--- ./src/backend/parser/gram.y Mon Dec 27 18:54:26 2004
***************
*** 341,348 ****
CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
! COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB
! CREATEUSER CROSS CSV CURRENT_DATE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
--- 341,348 ----
CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
! COMMITTED CONNECTION CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY
! CREATE CREATEDB CREATEUSER CROSS CSV CURRENT_DATE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
***************
*** 1075,1080 ****
--- 1075,1086 ----
n->name = $2;
$$ = (Node *) n;
}
+ | RESET CONNECTION
+ {
+ VariableResetStmt *n = makeNode(VariableResetStmt);
+ n->name = "connection";
+ $$ = (Node *) n;
+ }
| RESET TIME ZONE
{
VariableResetStmt *n = makeNode(VariableResetStmt);
*** ./src/backend/utils/misc/guc.c.orig Mon Dec 27 19:13:40 2004
--- ./src/backend/utils/misc/guc.c Thu Dec 30 11:29:08 2004
***************
*** 28,33 ****
--- 28,34 ----
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "commands/async.h"
+ #include "commands/prepare.h"
#include "commands/variable.h"
#include "commands/vacuum.h"
#include "executor/executor.h"
***************
*** 55,65 ****
#include "tcop/tcopprot.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/pg_locale.h"
#include "pgstat.h"
-
#ifndef PG_KRB_SRVTAB
#define PG_KRB_SRVTAB ""
#endif
--- 56,68 ----
#include "tcop/tcopprot.h"
#include "utils/array.h"
#include "utils/builtins.h"
+ #include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/pg_locale.h"
+ #include "utils/portal.h"
+ #include "utils/syscache.h"
#include "pgstat.h"
#ifndef PG_KRB_SRVTAB
#define PG_KRB_SRVTAB ""
#endif
***************
*** 4302,4309 ****
void
ResetPGVariable(const char *name)
{
! if (pg_strcasecmp(name, "all") == 0)
ResetAllOptions();
else
set_config_option(name,
NULL,
--- 4305,4350 ----
void
ResetPGVariable(const char *name)
{
! char namespaceName[NAMEDATALEN];
! Oid namespaceId;
!
! /* resetting all GUC variables */
! if (pg_strcasecmp(name, "all") == 0)
! ResetAllOptions();
!
! /* in case of connection pools it can be desirable to reset the
! * entire connection not just a single GUC variable.
! * what we do is: reset GUCs, remove temp tables, UNLISTEN *,
! * remove prepared plans as well as open cursors */
! else if (pg_strcasecmp(name, "connection") == 0)
! {
! /* resetting those GUC values */
ResetAllOptions();
+
+ /* cleaning temp-tables:
+ * what we do here is to find our namespace. then we can simply
+ * delete those temp tables with the help of onboard
+ * functions */
+ snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
+ namespaceId = GetSysCacheOid(NAMESPACENAME,
+ CStringGetDatum(namespaceName), 0, 0, 0);
+ RemoveTempRelations(namespaceId);
+
+ /* now we will cleanup the prepared queries stored inside our backend */
+ DropAllPreparedStatements();
+
+ /* UNLISTEN * */
+ Async_UnlistenAll();
+
+ /* now we can delete all open cursors. we simply delete all
+ * open cursors because none WITH HOLD cursors would go away at the
+ * end of the transaction anyway */
+ PortalHashTableDeleteAll();
+
+ /* checking for transaction blocks */
+ if (IsTransactionBlock())
+ UserAbortTransactionBlock();
+ }
else
set_config_option(name,
NULL,
*** ./src/backend/utils/mmgr/portalmem.c.orig Wed Dec 29 16:13:21 2004
--- ./src/backend/utils/mmgr/portalmem.c Thu Dec 30 11:33:17 2004
***************
*** 399,404 ****
--- 399,407 ----
HASH_SEQ_STATUS status;
PortalHashEnt *hentry;
+ if (PortalHashTable == NULL)
+ return;
+
hash_seq_init(&status, PortalHashTable);
while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
***************
*** 410,415 ****
--- 413,445 ----
}
}
+ /*
+ * Delete all WITH HOLD cursors
+ *
+ * This function is used to reset the backend in the case of
+ * RESET CONNECTION statements.
+ */
+ void
+ PortalHashTableDeleteAll(void)
+ {
+ HASH_SEQ_STATUS status;
+ PortalHashEnt *hentry;
+
+ hash_seq_init(&status, PortalHashTable);
+
+ if (PortalHashTable == NULL)
+ return;
+
+ while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
+ {
+ Portal portal = hentry->portal;
+
+ if ((portal->cursorOptions & CURSOR_OPT_HOLD) &&
+ portal->status != PORTAL_ACTIVE)
+ PortalDrop(portal, false);
+ }
+ }
+
/*
* Pre-commit processing for portals.
*** ./src/bin/psql/sql_help.h.orig Thu Dec 30 13:07:05 2004
--- ./src/bin/psql/sql_help.h Thu Dec 30 13:08:28 2004
***************
*** 363,369 ****
{ "RESET",
N_("restore the value of a run-time parameter to the default value"),
! N_("RESET name\nRESET ALL") },
{ "REVOKE",
N_("remove access privileges"),
--- 363,369 ----
{ "RESET",
N_("restore the value of a run-time parameter to the default value"),
! N_("RESET name\nRESET ALL\nRESET CONNECTION") },
{ "REVOKE",
N_("remove access privileges"),
*** ./src/include/catalog/namespace.h.orig Tue Dec 28 11:13:38 2004
--- ./src/include/catalog/namespace.h Tue Dec 28 11:15:01 2004
***************
*** 88,93 ****
--- 88,95 ----
extern Oid FindConversionByName(List *conname);
extern Oid FindDefaultConversionProc(int4 for_encoding, int4 to_encoding);
+ extern void RemoveTempRelations(Oid tempNamespaceId);
+
/* initialization & transaction cleanup code */
extern void InitializeSearchPath(void);
extern void AtEOXact_Namespace(bool isCommit);
*** ./src/include/commands/async.h.orig Mon Dec 27 21:36:20 2004
--- ./src/include/commands/async.h Mon Dec 27 21:36:43 2004
***************
*** 19,24 ****
--- 19,25 ----
extern void Async_Notify(char *relname);
extern void Async_Listen(char *relname, int pid);
extern void Async_Unlisten(char *relname, int pid);
+ extern void Async_UnlistenAll(void);
/* perform (or cancel) outbound notify processing at transaction commit */
extern void AtCommit_Notify(void);
*** ./src/include/commands/prepare.h.orig Thu Dec 30 13:20:29 2004
--- ./src/include/commands/prepare.h Thu Dec 30 13:20:05 2004
***************
*** 55,60 ****
--- 55,61 ----
List *argtype_list);
extern PreparedStatement *FetchPreparedStatement(const char *stmt_name,
bool throwError);
+ extern void DropAllPreparedStatements(void);
extern void DropPreparedStatement(const char *stmt_name, bool showError);
extern List *FetchPreparedStatementParams(const char *stmt_name);
extern TupleDesc FetchPreparedStatementResultDesc(PreparedStatement *stmt);
*** ./src/include/utils/portal.h.orig Wed Dec 29 16:14:47 2004
--- ./src/include/utils/portal.h Wed Dec 29 16:16:17 2004
***************
*** 194,199 ****
--- 194,200 ----
extern void AtSubCleanup_Portals(SubTransactionId mySubid);
extern Portal CreatePortal(const char *name, bool allowDup, bool dupSilent);
extern Portal CreateNewPortal(void);
+ extern void PortalHashTableDeleteAll(void);
extern void PortalDrop(Portal portal, bool isTopCommit);
extern void DropDependentPortals(MemoryContext queryContext);
extern Portal GetPortalByName(const char *name);
*** ./src/interfaces/ecpg/preproc/preproc.y.orig Thu Dec 30 11:40:28 2004
--- ./src/interfaces/ecpg/preproc/preproc.y Thu Dec 30 12:01:33 2004
***************
*** 359,365 ****
CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
! COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY
CREATE CREATEDB CREATEUSER CROSS CSV CURRENT_DATE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
--- 359,365 ----
CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
! COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONNECTION CONVERT COPY
CREATE CREATEDB CREATEUSER CROSS CSV CURRENT_DATE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
***************
*** 1157,1162 ****
--- 1157,1164 ----
{ $$ = make_str("reset transaction isolation level"); }
| RESET SESSION AUTHORIZATION
{ $$ = make_str("reset session authorization"); }
+ | RESET CONNECTION
+ { $$ = make_str("reset connection"); }
| RESET ALL
{ $$ = make_str("reset all"); }
;
pgsql-patches by date: