In working on the checksumhelper patch, we came across wanting a background worker to be allowed to bypass datallowconn for a database. Right now we didn't take care of that, and just said "you have to ALTER TABLE" first.
Specifically for this usecase that is OK, but not paticularly user friendly. And I think this is a use that can also be useful for other things. Attached is a patch that adds new Override versions of the functions to connect to a database from a background worker. Another option would be to just add the parameter directly to the regular connection function, and not create separate functions. But that would make it an incompatible change. And since background workers are commonly used in extensions, that would break a lot of extensions out there. I figured it's probably not worth doing that, and thus added the new functions. What do others think about that? Are there any other caveats in doing that this actually makes it dangerous to just allow bypassing it for extensions? -- Magnus Hagander Me: https://www.hagander.net/ <http://www.hagander.net/> Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/>
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 702f8d8188..a52178f7d3 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); @@ -1679,7 +1679,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 f3ddf828bb..1ded418960 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -434,6 +434,9 @@ static void StartAutovacuumWorker(void); static void MaybeStartWalReceiver(void); static void InitPostmasterDeathWatchHandle(void); +static void BackgroundWorkerInitializeConnectionByOidInternal(Oid dboid, Oid useroid, bool override_allow_connections); +static void BackgroundWorkerInitializeConnectionInternal(const char *dbname, const char *username, bool override_allow_connections); + /* * Archiver is allowed to start up at the current postmaster state? * @@ -5587,6 +5590,18 @@ MaxLivePostmasterChildren(void) void BackgroundWorkerInitializeConnection(const char *dbname, const char *username) { + BackgroundWorkerInitializeConnectionInternal(dbname, username, false); +} + +void +BackgroundWorkerInitializeConnectionOverride(const char *dbname, const char *username) +{ + BackgroundWorkerInitializeConnectionInternal(dbname, username, true); +} + +static void +BackgroundWorkerInitializeConnectionInternal(const char *dbname, const char *username, bool override_allow_connections) +{ BackgroundWorker *worker = MyBgworkerEntry; /* XXX is this the right errcode? */ @@ -5595,7 +5610,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, override_allow_connections); /* it had better not gotten out of "init" mode yet */ if (!IsInitProcessingMode()) @@ -5610,6 +5625,18 @@ BackgroundWorkerInitializeConnection(const char *dbname, const char *username) void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid) { + BackgroundWorkerInitializeConnectionByOidInternal(dboid, useroid, false); +} + +void +BackgroundWorkerInitializeConnectionByOidOverride(Oid dboid, Oid useroid) +{ + BackgroundWorkerInitializeConnectionByOidInternal(dboid, useroid, true); +} + +void +BackgroundWorkerInitializeConnectionByOidInternal(Oid dboid, Oid useroid, bool override_allow_connections) +{ BackgroundWorker *worker = MyBgworkerEntry; /* XXX is this the right errcode? */ @@ -5618,7 +5645,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, override_allow_connections); /* it had better not gotten out of "init" mode yet */ if (!IsInitProcessingMode()) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 6dc2095b9a..6b5a32b25b 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3774,7 +3774,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 484628987f..83640e3159 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 a4574cd533..d06f71aceb 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -419,7 +419,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 0c04529f47..83e15c1311 100644 --- a/src/include/postmaster/bgworker.h +++ b/src/include/postmaster/bgworker.h @@ -141,9 +141,11 @@ extern PGDLLIMPORT BackgroundWorker *MyBgworkerEntry; * only shared catalogs can be accessed. */ extern void BackgroundWorkerInitializeConnection(const char *dbname, const char *username); +extern void BackgroundWorkerInitializeConnectionOverride(const char *dbname, const char *username); /* Just like the above, but specifying database and user by OID. */ extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid); +extern void BackgroundWorkerInitializeConnectionByOidOverride(Oid dboid, Oid useroid); /* Block/unblock signals in a background worker process */ extern void BackgroundWorkerBlockSignals(void);