Hi,

On 10/4/23 8:20 AM, Michael Paquier wrote:
On Mon, Oct 02, 2023 at 10:53:22AM +0200, Drouvot, Bertrand wrote:
On 10/2/23 10:17 AM, Michael Paquier wrote:
On Mon, Oct 02, 2023 at 10:01:04AM +0200, Drouvot, Bertrand wrote:
I think that would make sense to have more flexibility in the worker_spi
module. I think that could be done in a dedicated patch though. I
think it makes more sense to have the current patch "focusing" on
this new flag (while adding a test about it without too much
refactoring). What about doing the worker_spi module  re-factoring
as a follow up of this one?

I would do that first, as that's what I usually do,

The reason I was thinking not doing that first is that there is no real use
case in the current worker_spi module test.

As a template, improving and extending it seems worth it to me as long
as it can also improve tests.

but I see also
your point that this is not mandatory.  If you want, I could give it a
shot tomorrow to see where it leads.

Oh yeah that would be great (and maybe you already see a use case in the
current test). Thanks!

Yes, while it shows a bit more what one can achieve with bgw_extra, it
also helps in improving the test coverage with starting dynamic
workers across defined databases and roles through a SQL function.


Yeah right.

It took me a bit longer than I expected,

Thanks for having looked at it!

but here is what I finish
with:
- 0001 extends worker_spi to be able to pass down database and role
IDs for the workers to start, through MyBgworkerEntry->bgw_extra.
Perhaps the two new arguments of worker_spi_launch() should use
InvalidOid as default, actually, to fall back to the database and
roles defined by the GUCs in these cases.

I'm fine with the way it's currently done in 0001 and that sounds
more logical to me. I mean we don't "really" want InvalidOid but to fall
back to the GUCs.

Just a remark here:

+       if (!OidIsValid(roleoid))
+       {
+               /*
+                * worker_spi_role is NULL by default, so just pass down an 
invalid
+                * OID to let the main() routine do its connection work.
+                */
+               if (worker_spi_role)
+                       roleoid = get_role_oid(worker_spi_role, false);
+               else
+                       roleoid = InvalidOid;

the

+               else
+                       roleoid = InvalidOid;

I think it is not needed as we're already in "!OidIsValid(roleoid)".

- 0002 is your patch, on top of which I have added handling for the
flags in the launch() function with a text[].  The tests get much
simpler, and don't need restarts.


Yeah, agree that's better.

By the way, I am pretty sure that we are going to need a wait phase
after the startup of the worker in the case where "nologrole" is not
allowed to log in even with the original patch: the worker may not
have started at the point where we check the logs.

I agree and it's now failing on my side.
I added this "wait" in v4-0002 attach and it's now working fine.

Please note there is more changes than adding this wait in 001_worker_spi.pl 
(as compare
to v3-0002) as I ran pgperltidy on it.
FWIW, the new "wait" is just the part related to "nb_errors".

What do you think?

Except the Nit that I mentioned in 0001, that looks all good to me (with the
new wait in 001_worker_spi.pl).

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
From 64465c2b2d54ba1c316efe347f346687415d01e0 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Wed, 4 Oct 2023 15:06:25 +0900
Subject: [PATCH v4 2/2] Allow background workers to bypass login check

This adds a new flag value (BGWORKER_BYPASS_ROLELOGINCHECK) to the flags
being used in BackgroundWorkerInitializeConnection() and
BackgroundWorkerInitializeConnectionByOid().  This flag allows the
background workers to bypass the login check done in
InitializeSessionUserId().
---
 doc/src/sgml/bgworker.sgml                    |  3 +-
 src/backend/bootstrap/bootstrap.c             |  2 +-
 src/backend/postmaster/autovacuum.c           |  5 +-
 src/backend/postmaster/postmaster.c           |  6 +-
 src/backend/tcop/postgres.c                   |  1 +
 src/backend/utils/init/miscinit.c             |  4 +-
 src/backend/utils/init/postinit.c             |  5 +-
 src/include/miscadmin.h                       |  4 +-
 src/include/postmaster/bgworker.h             | 10 +--
 .../modules/worker_spi/t/001_worker_spi.pl    | 68 +++++++++++++++++--
 .../modules/worker_spi/worker_spi--1.0.sql    |  3 +-
 src/test/modules/worker_spi/worker_spi.c      | 49 +++++++++++--
 12 files changed, 134 insertions(+), 26 deletions(-)
   4.6% doc/src/sgml/
   6.8% src/backend/postmaster/
   7.6% src/backend/utils/init/
   7.1% src/include/postmaster/
  41.4% src/test/modules/worker_spi/t/
  29.8% src/test/modules/worker_spi/

diff --git a/doc/src/sgml/bgworker.sgml b/doc/src/sgml/bgworker.sgml
index 9ad1146ba0..7335c02ed8 100644
--- a/doc/src/sgml/bgworker.sgml
+++ b/doc/src/sgml/bgworker.sgml
@@ -200,7 +200,8 @@ typedef struct BackgroundWorker
    <literal>InvalidOid</literal>, the process will run as the superuser created
    during <command>initdb</command>. If 
<literal>BGWORKER_BYPASS_ALLOWCONN</literal>
    is specified as <varname>flags</varname> it is possible to bypass the 
restriction
-   to connect to databases not allowing user connections.
+   to connect to databases not allowing user connections. If 
<literal>BGWORKER_BYPASS_ROLELOGINCHECK</literal>
+   is specified as <varname>flags</varname> it is possible to bypass the login 
check to connect to databases.
    A background worker can only call one of these two functions, and only
    once.  It is not possible to switch databases.
   </para>
diff --git a/src/backend/bootstrap/bootstrap.c 
b/src/backend/bootstrap/bootstrap.c
index 5810f8825e..bdd005b66a 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -345,7 +345,7 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
        if (pg_link_canary_is_frontend())
                elog(ERROR, "backend is incorrectly linked to frontend 
functions");
 
-       InitPostgres(NULL, InvalidOid, NULL, InvalidOid, false, false, NULL);
+       InitPostgres(NULL, InvalidOid, NULL, InvalidOid, false, false, false, 
NULL);
 
        /* 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 ae9be9b911..4686b81f68 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -488,7 +488,7 @@ AutoVacLauncherMain(int argc, char *argv[])
        /* Early initialization */
        BaseInit();
 
-       InitPostgres(NULL, InvalidOid, NULL, InvalidOid, false, false, NULL);
+       InitPostgres(NULL, InvalidOid, NULL, InvalidOid, false, false, false, 
NULL);
 
        SetProcessingMode(NormalProcessing);
 
@@ -1706,8 +1706,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, false, false,
-                                        dbname);
+               InitPostgres(NULL, dbid, NULL, InvalidOid, false, false, false, 
dbname);
                SetProcessingMode(NormalProcessing);
                set_ps_display(dbname);
                ereport(DEBUG1,
diff --git a/src/backend/postmaster/postmaster.c 
b/src/backend/postmaster/postmaster.c
index 54e9bfb8c4..37f5b94469 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -5575,7 +5575,7 @@ MaxLivePostmasterChildren(void)
  * Connect background worker to a database.
  */
 void
-BackgroundWorkerInitializeConnection(const char *dbname, const char *username, 
uint32 flags)
+BackgroundWorkerInitializeConnection(const char *dbname, const char *username, 
bits32 flags)
 {
        BackgroundWorker *worker = MyBgworkerEntry;
 
@@ -5589,6 +5589,7 @@ BackgroundWorkerInitializeConnection(const char *dbname, 
const char *username, u
                                 username, InvalidOid,  /* role to connect as */
                                 false,                 /* never honor 
session_preload_libraries */
                                 (flags & BGWORKER_BYPASS_ALLOWCONN) != 0,      
/* ignore datallowconn? */
+                                (flags & BGWORKER_BYPASS_ROLELOGINCHECK) != 0, 
/* bypass login check? */
                                 NULL);                 /* no out_dbname */
 
        /* it had better not gotten out of "init" mode yet */
@@ -5602,7 +5603,7 @@ BackgroundWorkerInitializeConnection(const char *dbname, 
const char *username, u
  * Connect background worker to a database using OIDs.
  */
 void
-BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags)
+BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, bits32 flags)
 {
        BackgroundWorker *worker = MyBgworkerEntry;
 
@@ -5616,6 +5617,7 @@ BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid 
useroid, uint32 flags)
                                 NULL, useroid, /* role to connect as */
                                 false,                 /* never honor 
session_preload_libraries */
                                 (flags & BGWORKER_BYPASS_ALLOWCONN) != 0,      
/* ignore datallowconn? */
+                                (flags & BGWORKER_BYPASS_ROLELOGINCHECK) != 0, 
/* bypass login check? */
                                 NULL);                 /* no out_dbname */
 
        /* it had better not gotten out of "init" mode yet */
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 21b9763183..5c1e21b99d 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4211,6 +4211,7 @@ PostgresMain(const char *dbname, const char *username)
                                 username, InvalidOid,  /* role to connect as */
                                 !am_walsender, /* honor 
session_preload_libraries? */
                                 false,                 /* don't ignore 
datallowconn */
+                                false,                 /* don't bypass login 
check */
                                 NULL);                 /* no out_dbname */
 
        /*
diff --git a/src/backend/utils/init/miscinit.c 
b/src/backend/utils/init/miscinit.c
index 1e671c560c..182d666852 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -725,7 +725,7 @@ has_rolreplication(Oid roleid)
  * Initialize user identity during normal backend startup
  */
 void
-InitializeSessionUserId(const char *rolename, Oid roleid)
+InitializeSessionUserId(const char *rolename, Oid roleid, bool 
bypass_login_check)
 {
        HeapTuple       roleTup;
        Form_pg_authid rform;
@@ -789,7 +789,7 @@ InitializeSessionUserId(const char *rolename, Oid roleid)
                /*
                 * Is role allowed to login at all?
                 */
-               if (!rform->rolcanlogin)
+               if (!bypass_login_check && !rform->rolcanlogin)
                        ereport(FATAL,
                                        
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
                                         errmsg("role \"%s\" is not permitted 
to log in",
diff --git a/src/backend/utils/init/postinit.c 
b/src/backend/utils/init/postinit.c
index df4d15a50f..dcfeb30832 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -719,6 +719,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
                         const char *username, Oid useroid,
                         bool load_session_libraries,
                         bool override_allow_connections,
+                        bool bypass_login_check,
                         char *out_dbname)
 {
        bool            bootstrap = IsBootstrapProcessingMode();
@@ -901,7 +902,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
                }
                else
                {
-                       InitializeSessionUserId(username, useroid);
+                       InitializeSessionUserId(username, useroid, 
bypass_login_check);
                        am_superuser = superuser();
                }
        }
@@ -910,7 +911,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
                /* normal multiuser case */
                Assert(MyProcPort != NULL);
                PerformAuthentication(MyProcPort);
-               InitializeSessionUserId(username, useroid);
+               InitializeSessionUserId(username, useroid, false);
                /* ensure that auth_method is actually valid, aka authn_id is 
not NULL */
                if (MyClientConnectionInfo.authn_id)
                        InitializeSystemUser(MyClientConnectionInfo.authn_id,
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 14bd574fc2..f1d03f2df8 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -364,7 +364,8 @@ extern bool InSecurityRestrictedOperation(void);
 extern bool InNoForceRLSOperation(void);
 extern void GetUserIdAndContext(Oid *userid, bool *sec_def_context);
 extern void SetUserIdAndContext(Oid userid, bool sec_def_context);
-extern void InitializeSessionUserId(const char *rolename, Oid roleid);
+extern void InitializeSessionUserId(const char *rolename, Oid roleid,
+                                                                       bool 
bypass_login_check);
 extern void InitializeSessionUserIdStandalone(void);
 extern void SetSessionAuthorization(Oid userid, bool is_superuser);
 extern Oid     GetCurrentRoleId(void);
@@ -469,6 +470,7 @@ extern void InitPostgres(const char *in_dbname, Oid dboid,
                                                 const char *username, Oid 
useroid,
                                                 bool load_session_libraries,
                                                 bool 
override_allow_connections,
+                                                bool bypass_login_check,
                                                 char *out_dbname);
 extern void BaseInit(void);
 
diff --git a/src/include/postmaster/bgworker.h 
b/src/include/postmaster/bgworker.h
index 7815507e3d..0fdbfaf431 100644
--- a/src/include/postmaster/bgworker.h
+++ b/src/include/postmaster/bgworker.h
@@ -141,18 +141,20 @@ 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, uint32 flags);
+extern void BackgroundWorkerInitializeConnection(const char *dbname, const 
char *username, bits32 flags);
 
 /* Just like the above, but specifying database and user by OID. */
-extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, 
uint32 flags);
+extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, 
bits32 flags);
 
 /*
  * Flags to BackgroundWorkerInitializeConnection et al
  *
  *
- * Allow bypassing datallowconn restrictions when connecting to database
+ * Allow bypassing datallowconn restrictions and login check when connecting
+ * to database
  */
-#define BGWORKER_BYPASS_ALLOWCONN 1
+#define BGWORKER_BYPASS_ALLOWCONN 0x0001
+#define BGWORKER_BYPASS_ROLELOGINCHECK 0x0002
 
 
 /* Block/unblock signals in a background worker process */
diff --git a/src/test/modules/worker_spi/t/001_worker_spi.pl 
b/src/test/modules/worker_spi/t/001_worker_spi.pl
index a026042c65..64f1197a32 100644
--- a/src/test/modules/worker_spi/t/001_worker_spi.pl
+++ b/src/test/modules/worker_spi/t/001_worker_spi.pl
@@ -7,6 +7,7 @@ use warnings;
 use PostgreSQL::Test::Cluster;
 use PostgreSQL::Test::Utils;
 use Test::More;
+use Time::HiRes qw(usleep);
 
 my $node = PostgreSQL::Test::Cluster->new('mynode');
 $node->init;
@@ -24,7 +25,8 @@ $node->safe_psql('postgres', 'CREATE EXTENSION worker_spi;');
 # an undefined role, falling back to the GUC defaults (InvalidOid for
 # worker_spi_launch).
 my $result =
-  $node->safe_psql('postgres', 'SELECT worker_spi_launch(4, 0, 0) IS NOT 
NULL;');
+  $node->safe_psql('postgres',
+       'SELECT worker_spi_launch(4, 0, 0) IS NOT NULL;');
 is($result, 't', "dynamic bgworker launched");
 $node->poll_query_until(
        'postgres',
@@ -84,10 +86,14 @@ ok( $node->poll_query_until(
 # Ask worker_spi to launch dynamic bgworkers with the library loaded, then
 # check their existence.  Use IDs that do not overlap with the schemas created
 # by the previous workers.  These use a specific role.
-my $myrole_id = $node->safe_psql('mydb', "SELECT oid FROM pg_roles where 
rolname = 'myrole';");
-my $mydb_id = $node->safe_psql('mydb', "SELECT oid FROM pg_database where 
datname = 'mydb';");
-my $worker1_pid = $node->safe_psql('mydb', "SELECT worker_spi_launch(10, 
$mydb_id, $myrole_id);");
-my $worker2_pid = $node->safe_psql('mydb', "SELECT worker_spi_launch(11, 
$mydb_id, $myrole_id);");
+my $myrole_id = $node->safe_psql('mydb',
+       "SELECT oid FROM pg_roles where rolname = 'myrole';");
+my $mydb_id = $node->safe_psql('mydb',
+       "SELECT oid FROM pg_database where datname = 'mydb';");
+my $worker1_pid = $node->safe_psql('mydb',
+       "SELECT worker_spi_launch(10, $mydb_id, $myrole_id);");
+my $worker2_pid = $node->safe_psql('mydb',
+       "SELECT worker_spi_launch(11, $mydb_id, $myrole_id);");
 
 ok( $node->poll_query_until(
                'mydb',
@@ -98,4 +104,56 @@ ok( $node->poll_query_until(
        'dynamic bgworkers all launched'
 ) or die "Timed out while waiting for dynamic bgworkers to be launched";
 
+# Check BGWORKER_BYPASS_ROLELOGINCHECK.
+# First create a role without login access.
+$node->safe_psql(
+       'postgres', qq[
+  CREATE ROLE nologrole with nologin;
+  ALTER ROLE nologrole with superuser;
+]);
+my $nologrole_id = $node->safe_psql('mydb',
+       "SELECT oid FROM pg_roles where rolname = 'nologrole';");
+
+my $log_start = -s $node->logfile;
+
+# Ask the background workers to connect with this role, failing.
+$node->safe_psql('mydb',
+       "SELECT worker_spi_launch(12, $mydb_id, $nologrole_id);");
+
+# An error message should be issued.
+my $nb_errors = 0;
+for (my $i = 0; $i < 10 * $PostgreSQL::Test::Utils::timeout_default; $i++)
+{
+       if ($node->log_contains(
+                       "role \"nologrole\" is not permitted to log in", 
$log_start))
+       {
+               $nb_errors = 1;
+               last;
+       }
+       usleep(100_000);
+}
+
+ok($nb_errors,
+       'nologrole not allowed to connect if ROLELOGINCHECK is not set');
+
+$log_start = -s $node->logfile;
+
+my $worker3_pid = $node->safe_psql('mydb',
+       qq(SELECT worker_spi_launch(13, $mydb_id, $nologrole_id, 
'{"ROLELOGINCHECK"}');)
+);
+
+ok( $node->poll_query_until(
+               'mydb',
+               qq[SELECT datname, usename, wait_event FROM pg_stat_activity
+            WHERE backend_type = 'worker_spi dynamic' AND
+            pid = $worker3_pid;],
+               'mydb|nologrole|worker_spi_main'),
+       'dynamic bgworkers '
+) or die "Timed out while waiting for dynamic bgworkers to be launched";
+
+# An error message should not be issued.
+ok( !$node->log_contains(
+               "role \"nologrole\" is not permitted to log in", $log_start),
+       "nologrole allowed to connect if ROLELOGINCHECK is set");
+
 done_testing();
diff --git a/src/test/modules/worker_spi/worker_spi--1.0.sql 
b/src/test/modules/worker_spi/worker_spi--1.0.sql
index f5b91128ff..59c0c686f3 100644
--- a/src/test/modules/worker_spi/worker_spi--1.0.sql
+++ b/src/test/modules/worker_spi/worker_spi--1.0.sql
@@ -3,7 +3,8 @@
 -- complain if script is sourced in psql, rather than via CREATE EXTENSION
 \echo Use "CREATE EXTENSION worker_spi" to load this file. \quit
 
-CREATE FUNCTION worker_spi_launch(pg_catalog.int4, pg_catalog.oid, 
pg_catalog.oid)
+CREATE FUNCTION worker_spi_launch(pg_catalog.int4, pg_catalog.oid,
+                                 pg_catalog.oid, pg_catalog.text[] DEFAULT 
'{}')
 RETURNS pg_catalog.int4 STRICT
 AS 'MODULE_PATHNAME'
 LANGUAGE C;
diff --git a/src/test/modules/worker_spi/worker_spi.c 
b/src/test/modules/worker_spi/worker_spi.c
index f35897ddac..07d8bab721 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -144,6 +144,7 @@ worker_spi_main(Datum main_arg)
        Oid                     dboid;
        Oid                     roleoid;
        char       *p;
+       bits32          flags = 0;
 
        table = palloc(sizeof(worktable));
        sprintf(name, "schema%d", index);
@@ -155,6 +156,8 @@ worker_spi_main(Datum main_arg)
        memcpy(&dboid, p, sizeof(Oid));
        p += sizeof(Oid);
        memcpy(&roleoid, p, sizeof(Oid));
+       p += sizeof(bits32);
+       memcpy(&flags, p, sizeof(bits32));
 
        /* Establish signal handlers before unblocking signals. */
        pqsignal(SIGHUP, SignalHandlerForConfigReload);
@@ -165,9 +168,10 @@ worker_spi_main(Datum main_arg)
 
        /* Connect to our database */
        if (OidIsValid(dboid))
-               BackgroundWorkerInitializeConnectionByOid(dboid, roleoid, 0);
+               BackgroundWorkerInitializeConnectionByOid(dboid, roleoid, 
flags);
        else
-               BackgroundWorkerInitializeConnection(worker_spi_database, 
worker_spi_role, 0);
+               BackgroundWorkerInitializeConnection(worker_spi_database,
+                                                                               
         worker_spi_role, flags);
 
        elog(LOG, "%s initialized with %s.%s",
                 MyBgworkerEntry->bgw_name, table->schema, table->name);
@@ -371,8 +375,9 @@ _PG_init(void)
        /*
         * Now fill in worker-specific data, and do the actual registrations.
         *
-        * bgw_extra can optionally include a dabatase OID and a role OID.  This
-        * is left empty here to fallback to the related GUCs at startup.
+        * bgw_extra can optionally include a dabatase OID, a role OID and a set
+        * of flags.  This is left empty here to fallback to the related GUCs at
+        * startup (or 0 for the flags).
         */
        for (int i = 1; i <= worker_spi_total_workers; i++)
        {
@@ -398,6 +403,11 @@ worker_spi_launch(PG_FUNCTION_ARGS)
        BgwHandleStatus status;
        pid_t           pid;
        char       *p;
+       bits32          flags = 0;
+       ArrayType  *arr = PG_GETARG_ARRAYTYPE_P(3);
+       Size            ndim;
+       int                     nelems;
+       Datum      *datum_flags;
 
        memset(&worker, 0, sizeof(worker));
        worker.bgw_flags = BGWORKER_SHMEM_ACCESS |
@@ -412,6 +422,35 @@ worker_spi_launch(PG_FUNCTION_ARGS)
        /* set bgw_notify_pid so that we can use WaitForBackgroundWorkerStartup 
*/
        worker.bgw_notify_pid = MyProcPid;
 
+       /* extract flags, if any */
+       ndim = ARR_NDIM(arr);
+       if (ndim > 1)
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("flags array must be 
one-dimensional")));
+
+       if (array_contains_nulls(arr))
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("flags array must not contain nulls")));
+
+       Assert(ARR_ELEMTYPE(arr) == TEXTOID);
+       deconstruct_array_builtin(arr, TEXTOID, &datum_flags, NULL, &nelems);
+
+       for (i = 0; i < nelems; i++)
+       {
+               char       *optname = TextDatumGetCString(datum_flags[i]);
+
+               if (strcmp(optname, "ROLELOGINCHECK") == 0)
+                       flags |= BGWORKER_BYPASS_ROLELOGINCHECK;
+               else if (strcmp(optname, "ALLOWCONN") == 0)
+                       flags |= BGWORKER_BYPASS_ALLOWCONN;
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("incorrect flag value found in 
array")));
+       }
+
        /*
         * Register database and role to use for the worker started in 
bgw_extra.
         * If none have been provided, fallback to the GUCs.
@@ -433,6 +472,8 @@ worker_spi_launch(PG_FUNCTION_ARGS)
        memcpy(p, &dboid, sizeof(Oid));
        p += sizeof(Oid);
        memcpy(p, &roleoid, sizeof(Oid));
+       p += sizeof(bits32);
+       memcpy(p, &flags, sizeof(bits32));
 
        if (!RegisterDynamicBackgroundWorker(&worker, &handle))
                PG_RETURN_NULL();
-- 
2.34.1

Reply via email to