Don't access catalogs to validate GUCs when not connected to a DB.
authorAndres Freund <[email protected]>
Tue, 11 Jun 2019 06:20:48 +0000 (23:20 -0700)
committerAndres Freund <[email protected]>
Tue, 11 Jun 2019 06:36:48 +0000 (23:36 -0700)
Vignesh found this bug in the check function for
default_table_access_method's check hook, but that was just copied
from older GUCs. Investigation by Michael and me then found the bug in
further places.

When not connected to a database (e.g. in a walsender connection), we
cannot perform (most) GUC checks that need database access. Even when
only shared tables are needed, unless they're
nailed (c.f. RelationCacheInitializePhase2()), they cannot be accessed
without pg_class etc. being present.

Fix by extending the existing IsTransactionState() checks to also
check for MyDatabaseOid.

Reported-By: Vignesh C, Michael Paquier, Andres Freund
Author: Vignesh C, Andres Freund
Discussion: https://postgr.es/m/CALDaNm1KXK9gbZfY-p_peRFm_XrBh1OwQO1Kk6Gig0c0fVZ2uw%40mail.gmail.com
Backpatch: 9.4-

src/backend/commands/tablespace.c
src/backend/utils/cache/ts_cache.c

index 8559c3b6b36e69cf7b8977b2f676c9412859cb5f..a688cb7ed484dc0a93aa9a9117ea0219781d2f95 100644 (file)
@@ -1062,10 +1062,11 @@ bool
 check_default_tablespace(char **newval, void **extra, GucSource source)
 {
        /*
-        * If we aren't inside a transaction, we cannot do database access so
-        * cannot verify the name.  Must accept the value on faith.
+        * If we aren't inside a transaction, or connected to a database, we
+        * cannot do the catalog accesses necessary to verify the name.  Must
+        * accept the value on faith.
         */
-       if (IsTransactionState())
+       if (IsTransactionState() && MyDatabaseId != InvalidOid)
        {
                if (**newval != '\0' &&
                        !OidIsValid(get_tablespace_oid(*newval, true)))
@@ -1173,11 +1174,12 @@ check_temp_tablespaces(char **newval, void **extra, GucSource source)
        }
 
        /*
-        * If we aren't inside a transaction, we cannot do database access so
-        * cannot verify the individual names.  Must accept the list on faith.
+        * If we aren't inside a transaction, or connected to a database, we
+        * cannot do the catalog accesses necessary to verify the name.  Must
+        * accept the value on faith.
         * Fortunately, there's then also no need to pass the data to fd.c.
         */
-       if (IsTransactionState())
+       if (IsTransactionState() && MyDatabaseId != InvalidOid)
        {
                temp_tablespaces_extra *myextra;
                Oid                *tblSpcs;
index da5c8ea345b01cb338106c972e2338d702dee990..ac911ad80b6b87cdb25fa1a1d4f1565fda40ce0e 100644 (file)
@@ -38,6 +38,7 @@
 #include "catalog/pg_ts_parser.h"
 #include "catalog/pg_ts_template.h"
 #include "commands/defrem.h"
+#include "miscadmin.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/catcache.h"
@@ -587,10 +588,11 @@ bool
 check_TSCurrentConfig(char **newval, void **extra, GucSource source)
 {
        /*
-        * If we aren't inside a transaction, we cannot do database access so
-        * cannot verify the config name.  Must accept it on faith.
+        * If we aren't inside a transaction, or connected to a database, we
+        * cannot do the catalog accesses necessary to verify the config name.
+        * Must accept it on faith.
         */
-       if (IsTransactionState())
+       if (IsTransactionState() && MyDatabaseId != InvalidOid)
        {
                Oid                     cfgId;
                HeapTuple       tuple;