vacuumdb: Skip temporary tables in query to build list of relations
authorMichael Paquier <michael@paquier.xyz>
Wed, 25 Sep 2024 05:43:16 +0000 (14:43 +0900)
committerMichael Paquier <michael@paquier.xyz>
Wed, 25 Sep 2024 05:43:16 +0000 (14:43 +0900)
Running vacuumdb with a non-superuser while another user has created a
temporary table would lead to a mid-flight permission failure,
interrupting the operation.  vacuum_rel() skips temporary relations of
other backends, and it makes no sense for vacuumdb to know about these
relations, so let's switch it to ignore temporary relations entirely.

Adding a qual in the query based on relpersistence simplifies the
generation of its WHERE clause in vacuum_one_database(), per se the
removal of "has_where".

Author: VaibhaveS, Michael Paquier
Reviewed-by: Fujii Masao
Discussion: https://postgr.es/m/CAM_eQjwfAR=y3G1fGyS1U9FTmc+FyJm9amNfY2QCZBnDDbNPZg@mail.gmail.com
Backpatch-through: 12

src/bin/scripts/vacuumdb.c

index 7c33e13e1ac3fdbe6c2dc92fc23f8068ba4cc81b..249622068a088ed85ddc71530b51c1b6739c8102 100644 (file)
@@ -491,7 +491,6 @@ vacuum_one_database(ConnParams *cparams,
    int         ntups;
    bool        failed = false;
    bool        objects_listed = false;
-   bool        has_where = false;
    const char *initcmd;
    const char *stage_commands[] = {
        "SET default_statistics_target=1; SET vacuum_cost_delay=0;",
@@ -665,7 +664,10 @@ vacuum_one_database(ConnParams *cparams,
                         " LEFT JOIN pg_catalog.pg_class t"
                         " ON c.reltoastrelid OPERATOR(pg_catalog.=) t.oid\n");
 
-   /* Used to match the tables or schemas listed by the user */
+   /*
+    * Used to match the tables or schemas listed by the user, completing the
+    * JOIN clause.
+    */
    if (objects_listed)
    {
        appendPQExpBufferStr(&catalog_query, " LEFT JOIN listed_objects"
@@ -676,14 +678,26 @@ vacuum_one_database(ConnParams *cparams,
            appendPQExpBufferStr(&catalog_query, "c.oid\n");
        else
            appendPQExpBufferStr(&catalog_query, "ns.oid\n");
+   }
 
+   /*
+    * Exclude temporary tables, beginning the WHERE clause.
+    */
+   appendPQExpBufferStr(&catalog_query,
+                        " WHERE c.relpersistence != " CppAsString2(RELPERSISTENCE_TEMP));
+
+   /*
+    * Used to match the tables or schemas listed by the user, for the WHERE
+    * clause.
+    */
+   if (objects_listed)
+   {
        if (objfilter & OBJFILTER_SCHEMA_EXCLUDE)
            appendPQExpBuffer(&catalog_query,
-                             " WHERE listed_objects.object_oid IS NULL\n");
+                             " AND listed_objects.object_oid IS NULL\n");
        else
            appendPQExpBuffer(&catalog_query,
-                             " WHERE listed_objects.object_oid IS NOT NULL\n");
-       has_where = true;
+                             " AND listed_objects.object_oid IS NOT NULL\n");
    }
 
    /*
@@ -695,11 +709,9 @@ vacuum_one_database(ConnParams *cparams,
    if ((objfilter & OBJFILTER_TABLE) == 0)
    {
        appendPQExpBuffer(&catalog_query,
-                         " %s c.relkind OPERATOR(pg_catalog.=) ANY (array["
+                         " AND c.relkind OPERATOR(pg_catalog.=) ANY (array["
                          CppAsString2(RELKIND_RELATION) ", "
-                         CppAsString2(RELKIND_MATVIEW) "])\n",
-                         has_where ? "AND" : "WHERE");
-       has_where = true;
+                         CppAsString2(RELKIND_MATVIEW) "])\n");
    }
 
    /*
@@ -712,25 +724,23 @@ vacuum_one_database(ConnParams *cparams,
    if (vacopts->min_xid_age != 0)
    {
        appendPQExpBuffer(&catalog_query,
-                         " %s GREATEST(pg_catalog.age(c.relfrozenxid),"
+                         " AND GREATEST(pg_catalog.age(c.relfrozenxid),"
                          " pg_catalog.age(t.relfrozenxid)) "
                          " OPERATOR(pg_catalog.>=) '%d'::pg_catalog.int4\n"
                          " AND c.relfrozenxid OPERATOR(pg_catalog.!=)"
                          " '0'::pg_catalog.xid\n",
-                         has_where ? "AND" : "WHERE", vacopts->min_xid_age);
-       has_where = true;
+                         vacopts->min_xid_age);
    }
 
    if (vacopts->min_mxid_age != 0)
    {
        appendPQExpBuffer(&catalog_query,
-                         " %s GREATEST(pg_catalog.mxid_age(c.relminmxid),"
+                         " AND GREATEST(pg_catalog.mxid_age(c.relminmxid),"
                          " pg_catalog.mxid_age(t.relminmxid)) OPERATOR(pg_catalog.>=)"
                          " '%d'::pg_catalog.int4\n"
                          " AND c.relminmxid OPERATOR(pg_catalog.!=)"
                          " '0'::pg_catalog.xid\n",
-                         has_where ? "AND" : "WHERE", vacopts->min_mxid_age);
-       has_where = true;
+                         vacopts->min_mxid_age);
    }
 
    /*