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: