Have DISCARD ALL/TEMP remove leftover temp tables
authorAlvaro Herrera
Thu, 27 Dec 2018 19:17:40 +0000 (16:17 -0300)
committerAlvaro Herrera
Thu, 27 Dec 2018 19:17:40 +0000 (16:17 -0300)
Previously, it would only remove temp tables created in the same
session; but if the session uses the BackendId of a previously crashed
backend that left temp tables around, those would not get removed.
Since autovacuum would not drop them either (because it sees that the
BackendId is in use by the current session) these can cause annoying
xid-wraparound warnings.

Apply to branches 9.4 to 10.  This is not a problem since version 11,
because commit 943576bddcb5 added state tracking that makes autovacuum
realize that those temp tables are not ours, so it removes them.

This is useful to handle in DISCARD, because even though it does not
handle all situations, it does handle the common one where a connection
pooler keeps the same session open for an indefinitely long time.

Discussion: https://postgr.es/m/20181226190834[email protected]
Reviewed-by: Takayuki Tsunakawa, Michaël Paquier
src/backend/catalog/namespace.c

index 5d71302ded2dcbbd14cb2b6ade3d1545cbc17267..63859b5e76aaf5263e6d2cc8417abb9591c64431 100644 (file)
@@ -4042,12 +4042,31 @@ RemoveTempRelationsCallback(int code, Datum arg)
 
 /*
  * Remove all temp tables from the temporary namespace.
+ *
+ * If we haven't set up one yet, but one exists from a previous crashed
+ * backend, clean that one; but only do this once in a session's life.
  */
 void
 ResetTempTableNamespace(void)
 {
+   static bool TempNamespaceCleaned = false;
+
    if (OidIsValid(myTempNamespace))
        RemoveTempRelations(myTempNamespace);
+   else if (MyBackendId != InvalidBackendId && !RecoveryInProgress() &&
+            !TempNamespaceCleaned)
+   {
+       char        namespaceName[NAMEDATALEN];
+       Oid         namespaceId;
+
+       snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d",
+                MyBackendId);
+       namespaceId = get_namespace_oid(namespaceName, true);
+       if (OidIsValid(namespaceId))
+           RemoveTempRelations(namespaceId);
+   }
+
+   TempNamespaceCleaned = true;
 }