From eed1ce72e1593d3e8b7461d7744808d4d6bf402b Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Thu, 5 Apr 2018 18:59:32 +0200 Subject: [PATCH] Allow background workers to bypass datallowconn THis adds a "flags" field to the BackgroundWorkerInitializeConnection() and BackgroundWorkerInitializeConnectionByOid(). For now only one flag, BGWORKER_BYPASS_ALLOWCONN, is defined, which allows the worker to ignore datallowconn. --- contrib/pg_prewarm/autoprewarm.c | 2 +- src/backend/access/transam/parallel.c | 3 ++- src/backend/bootstrap/bootstrap.c | 2 +- src/backend/postmaster/autovacuum.c | 4 ++-- src/backend/postmaster/postmaster.c | 8 ++++---- src/backend/replication/logical/launcher.c | 2 +- src/backend/replication/logical/worker.c | 3 ++- src/backend/tcop/postgres.c | 2 +- src/backend/utils/init/postinit.c | 10 +++++----- src/include/miscadmin.h | 2 +- src/include/postmaster/bgworker.h | 7 +++++-- 11 files changed, 25 insertions(+), 20 deletions(-) diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index f99f9c07af..bb28e237d1 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -445,7 +445,7 @@ autoprewarm_database_main(Datum main_arg) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("could not map dynamic shared memory segment"))); - BackgroundWorkerInitializeConnectionByOid(apw_state->database, InvalidOid); + BackgroundWorkerInitializeConnectionByOid(apw_state->database, InvalidOid, 0); block_info = (BlockInfoRecord *) dsm_segment_address(seg); pos = apw_state->prewarm_start_idx; diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index 9d4efc0f8f..1d631b7275 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -1324,7 +1324,8 @@ ParallelWorkerMain(Datum main_arg) /* Restore database connection. */ BackgroundWorkerInitializeConnectionByOid(fps->database_id, - fps->authenticated_user_id); + fps->authenticated_user_id, + 0); /* * Set the client encoding to the database encoding, since that is what diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 28ff2f0979..1430894ad2 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -498,7 +498,7 @@ BootstrapModeMain(void) */ InitProcess(); - InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL); + InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL, false); /* Initialize stuff for bootstrap-file processing */ for (i = 0; i < MAXATTR; i++) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index c4bc09ea81..3b90b16dae 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -477,7 +477,7 @@ AutoVacLauncherMain(int argc, char *argv[]) InitProcess(); #endif - InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL); + InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL, false); SetProcessingMode(NormalProcessing); @@ -1693,7 +1693,7 @@ AutoVacWorkerMain(int argc, char *argv[]) * Note: if we have selected a just-deleted database (due to using * stale stats info), we'll fail and exit here. */ - InitPostgres(NULL, dbid, NULL, InvalidOid, dbname); + InitPostgres(NULL, dbid, NULL, InvalidOid, dbname, false); SetProcessingMode(NormalProcessing); set_ps_display(dbname, false); ereport(DEBUG1, diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 660f3185e6..3dfb87d701 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -5582,7 +5582,7 @@ MaxLivePostmasterChildren(void) * Connect background worker to a database. */ void -BackgroundWorkerInitializeConnection(const char *dbname, const char *username) +BackgroundWorkerInitializeConnection(const char *dbname, const char *username, uint32 flags) { BackgroundWorker *worker = MyBgworkerEntry; @@ -5592,7 +5592,7 @@ BackgroundWorkerInitializeConnection(const char *dbname, const char *username) (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("database connection requirement not indicated during registration"))); - InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL); + InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL, (flags & BGWORKER_BYPASS_ALLOWCONN) != 0); /* it had better not gotten out of "init" mode yet */ if (!IsInitProcessingMode()) @@ -5605,7 +5605,7 @@ BackgroundWorkerInitializeConnection(const char *dbname, const char *username) * Connect background worker to a database using OIDs. */ void -BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid) +BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags) { BackgroundWorker *worker = MyBgworkerEntry; @@ -5615,7 +5615,7 @@ BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid) (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("database connection requirement not indicated during registration"))); - InitPostgres(NULL, dboid, NULL, useroid, NULL); + InitPostgres(NULL, dboid, NULL, useroid, NULL, (flags & BGWORKER_BYPASS_ALLOWCONN) != 0); /* it had better not gotten out of "init" mode yet */ if (!IsInitProcessingMode()) diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c index 2da9129562..6ef333b725 100644 --- a/src/backend/replication/logical/launcher.c +++ b/src/backend/replication/logical/launcher.c @@ -901,7 +901,7 @@ ApplyLauncherMain(Datum main_arg) * Establish connection to nailed catalogs (we only ever access * pg_subscription). */ - BackgroundWorkerInitializeConnection(NULL, NULL); + BackgroundWorkerInitializeConnection(NULL, NULL, 0); /* Enter main loop */ for (;;) diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index fdace7eea2..93a42d9322 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -1544,7 +1544,8 @@ ApplyWorkerMain(Datum main_arg) /* Connect to our database. */ BackgroundWorkerInitializeConnectionByOid(MyLogicalRepWorker->dbid, - MyLogicalRepWorker->userid); + MyLogicalRepWorker->userid, + 0); /* Load the subscription into persistent memory context. */ ApplyContext = AllocSetContextCreate(TopMemoryContext, diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6fc1cc272b..7bdecc32ec 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3775,7 +3775,7 @@ PostgresMain(int argc, char *argv[], * it inside InitPostgres() instead. In particular, anything that * involves database access should be there, not here. */ - InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL); + InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL, false); /* * If the PostmasterContext is still around, recycle the space; we don't diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index d8f45b3c43..09e0df290d 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -66,7 +66,7 @@ static HeapTuple GetDatabaseTuple(const char *dbname); static HeapTuple GetDatabaseTupleByOid(Oid dboid); static void PerformAuthentication(Port *port); -static void CheckMyDatabase(const char *name, bool am_superuser); +static void CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connections); static void InitCommunication(void); static void ShutdownPostgres(int code, Datum arg); static void StatementTimeoutHandler(void); @@ -290,7 +290,7 @@ PerformAuthentication(Port *port) * CheckMyDatabase -- fetch information from the pg_database entry for our DB */ static void -CheckMyDatabase(const char *name, bool am_superuser) +CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connections) { HeapTuple tup; Form_pg_database dbform; @@ -326,7 +326,7 @@ CheckMyDatabase(const char *name, bool am_superuser) /* * Check that the database is currently allowing connections. */ - if (!dbform->datallowconn) + if (!dbform->datallowconn && !override_allow_connections) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("database \"%s\" is not currently accepting connections", @@ -563,7 +563,7 @@ BaseInit(void) */ void InitPostgres(const char *in_dbname, Oid dboid, const char *username, - Oid useroid, char *out_dbname) + Oid useroid, char *out_dbname, bool override_allow_connections) { bool bootstrap = IsBootstrapProcessingMode(); bool am_superuser; @@ -1006,7 +1006,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, * user is a superuser, so the above stuff has to happen first.) */ if (!bootstrap) - CheckMyDatabase(dbname, am_superuser); + CheckMyDatabase(dbname, am_superuser, override_allow_connections); /* * Now process any command-line switches and any additional GUC variable diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index a429a19964..b5ad841968 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -421,7 +421,7 @@ extern AuxProcType MyAuxProcType; extern void pg_split_opts(char **argv, int *argcp, const char *optstr); extern void InitializeMaxBackends(void); extern void InitPostgres(const char *in_dbname, Oid dboid, const char *username, - Oid useroid, char *out_dbname); + Oid useroid, char *out_dbname, bool override_allow_connections); extern void BaseInit(void); /* in utils/init/miscinit.c */ diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h index a8753df8d1..9c49bb7f4b 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -140,10 +140,13 @@ extern PGDLLIMPORT BackgroundWorker *MyBgworkerEntry; * If dbname is NULL, connection is made to no specific database; * only shared catalogs can be accessed. */ -extern void BackgroundWorkerInitializeConnection(const char *dbname, const char *username); +extern void BackgroundWorkerInitializeConnection(const char *dbname, const char *username, uint32 flags); /* Just like the above, but specifying database and user by OID. */ -extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid); +extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags); + +/* Flags to BackgroundWorkerInitializeConnection et al */ +#define BGWORKER_BYPASS_ALLOWCONN 1 /* Block/unblock signals in a background worker process */ extern void BackgroundWorkerBlockSignals(void);