]> granicus.if.org Git - postgresql/commitdiff
Add new function BackgroundWorkerInitializeConnectionByOid.
authorRobert Haas <rhaas@postgresql.org>
Mon, 2 Feb 2015 21:23:59 +0000 (16:23 -0500)
committerRobert Haas <rhaas@postgresql.org>
Mon, 2 Feb 2015 21:23:59 +0000 (16:23 -0500)
Sometimes it's useful for a background worker to be able to initialize
its database connection by OID rather than by name, so provide a way
to do that.

doc/src/sgml/bgworker.sgml
src/backend/bootstrap/bootstrap.c
src/backend/postmaster/autovacuum.c
src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/backend/utils/init/miscinit.c
src/backend/utils/init/postinit.c
src/include/miscadmin.h
src/include/postmaster/bgworker.h

index 8e218ac0406a7b8d1ebda3da129e137bf735aafa..ef28f7251141603a9158985cb304c8b206c584e6 100644 (file)
@@ -146,14 +146,17 @@ typedef struct BackgroundWorker
   </para>
 
   <para>Once running, the process can connect to a database by calling
-   <function>BackgroundWorkerInitializeConnection(<parameter>char *dbname</parameter>, <parameter>char *username</parameter>)</function>.
+   <function>BackgroundWorkerInitializeConnection(<parameter>char *dbname</parameter>, <parameter>char *username</parameter>)</function> or
+   <function>BackgroundWorkerInitializeConnectionByOid(<parameter>Oid dboid</parameter>, <parameter>Oid useroid</parameter>)</function>.
    This allows the process to run transactions and queries using the
-   <literal>SPI</literal> interface.  If <varname>dbname</> is NULL,
-   the session is not connected to any particular database, but shared catalogs
-   can be accessed.  If <varname>username</> is NULL, the process will run as
-   the superuser created during <command>initdb</>.
-   BackgroundWorkerInitializeConnection can only be called once per background
-   process, it is not possible to switch databases.
+   <literal>SPI</literal> interface.  If <varname>dbname</> is NULL or
+   <varname>dboid</> is <literal>InvalidOid</>, the session is not connected
+   to any particular database, but shared catalogs can be accessed.
+   If <varname>username</> is NULL or <varname>useroid</> is
+   <literal>InvalidOid</>, the process will run as the superuser created
+   during <command>initdb</>.
+   A background worker can only call one of these two functions, and only
+   once.  It is not possible to switch databases.
   </para>
 
   <para>
index 0819e804becf77d221c9bd35f642723be055efa0..bc66eac9848a30d7dd01e102dc8c97c2cee2bf96 100644 (file)
@@ -467,7 +467,7 @@ BootstrapModeMain(void)
         */
        InitProcess();
 
-       InitPostgres(NULL, InvalidOid, NULL, NULL);
+       InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
 
        /* Initialize stuff for bootstrap-file processing */
        for (i = 0; i < MAXATTR; i++)
index 02f871ce22b24cdf80af81584b07aa42b04cb8ff..6492067d077e5f07b8977f291f8341023cf9b9aa 100644 (file)
@@ -450,7 +450,7 @@ AutoVacLauncherMain(int argc, char *argv[])
        InitProcess();
 #endif
 
-       InitPostgres(NULL, InvalidOid, NULL, NULL);
+       InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
 
        SetProcessingMode(NormalProcessing);
 
@@ -1620,7 +1620,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, dbname);
+               InitPostgres(NULL, dbid, NULL, InvalidOid, dbname);
                SetProcessingMode(NormalProcessing);
                set_ps_display(dbname, false);
                ereport(DEBUG1,
index 36b8267fa50d5c07a33494639e2f6c3af00d7b99..ac431e5dd5a64b7f19067e72cc8acd00040c1464 100644 (file)
@@ -5313,7 +5313,30 @@ BackgroundWorkerInitializeConnection(char *dbname, char *username)
                                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                                 errmsg("database connection requirement not indicated during registration")));
 
-       InitPostgres(dbname, InvalidOid, username, NULL);
+       InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);
+
+       /* it had better not gotten out of "init" mode yet */
+       if (!IsInitProcessingMode())
+               ereport(ERROR,
+                               (errmsg("invalid processing mode in background worker")));
+       SetProcessingMode(NormalProcessing);
+}
+
+/*
+ * Connect background worker to a database using OIDs.
+ */
+void
+BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid)
+{
+       BackgroundWorker *worker = MyBgworkerEntry;
+
+       /* XXX is this the right errcode? */
+       if (!(worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION))
+               ereport(FATAL,
+                               (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                                errmsg("database connection requirement not indicated during registration")));
+
+       InitPostgres(NULL, dboid, NULL, useroid, NULL);
 
        /* it had better not gotten out of "init" mode yet */
        if (!IsInitProcessingMode())
index b82c3b333bd00d6e3b4b5cbbe8fa166f41dd28b4..556e5633284db0381b588248f7acb1007a3ccaa6 100644 (file)
@@ -3714,7 +3714,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, NULL);
+       InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);
 
        /*
         * If the PostmasterContext is still around, recycle the space; we don't
index 4646e0938e94c6c829eaa2f018b36ed3ef5f24b6..1dc31535fd6e6d9cd0e7245bf07f34bdd32fef52 100644 (file)
@@ -453,11 +453,10 @@ has_rolreplication(Oid roleid)
  * Initialize user identity during normal backend startup
  */
 void
-InitializeSessionUserId(const char *rolename)
+InitializeSessionUserId(const char *rolename, Oid roleid)
 {
        HeapTuple       roleTup;
        Form_pg_authid rform;
-       Oid                     roleid;
 
        /*
         * Don't do scans if we're bootstrapping, none of the system catalogs
@@ -468,7 +467,10 @@ InitializeSessionUserId(const char *rolename)
        /* call only once */
        AssertState(!OidIsValid(AuthenticatedUserId));
 
-       roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(rolename));
+       if (rolename != NULL)
+               roleTup = SearchSysCache1(AUTHNAME, PointerGetDatum(rolename));
+       else
+               roleTup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
        if (!HeapTupleIsValid(roleTup))
                ereport(FATAL,
                                (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
index 1f5cf06f234a78849f5ce50162b7f96b922504a7..983b237d7a17b3a157299da414f930bb3482f38f 100644 (file)
@@ -523,6 +523,9 @@ BaseInit(void)
  * name can be returned to the caller in out_dbname.  If out_dbname isn't
  * NULL, it must point to a buffer of size NAMEDATALEN.
  *
+ * Similarly, the username can be passed by name, using the username parameter,
+ * or by OID using the useroid parameter.
+ *
  * In bootstrap mode no parameters are used.  The autovacuum launcher process
  * doesn't use any parameters either, because it only goes far enough to be
  * able to read pg_database; it doesn't connect to any particular database.
@@ -537,7 +540,7 @@ BaseInit(void)
  */
 void
 InitPostgres(const char *in_dbname, Oid dboid, const char *username,
-                        char *out_dbname)
+                        Oid useroid, char *out_dbname)
 {
        bool            bootstrap = IsBootstrapProcessingMode();
        bool            am_superuser;
@@ -692,18 +695,18 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
                                        (errcode(ERRCODE_UNDEFINED_OBJECT),
                                         errmsg("no roles are defined in this database system"),
                                         errhint("You should immediately run CREATE USER \"%s\" SUPERUSER;.",
-                                                        username)));
+                                                        username != NULL ? username : "postgres")));
        }
        else if (IsBackgroundWorker)
        {
-               if (username == NULL)
+               if (username == NULL && !OidIsValid(useroid))
                {
                        InitializeSessionUserIdStandalone();
                        am_superuser = true;
                }
                else
                {
-                       InitializeSessionUserId(username);
+                       InitializeSessionUserId(username, useroid);
                        am_superuser = superuser();
                }
        }
@@ -712,7 +715,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
                /* normal multiuser case */
                Assert(MyProcPort != NULL);
                PerformAuthentication(MyProcPort);
-               InitializeSessionUserId(username);
+               InitializeSessionUserId(username, useroid);
                am_superuser = superuser();
        }
 
index 6c68da5f64fb98a5e2b2205b53f16ca6b94fdf15..c9a46aa4e6a3c958784b387248211e73fae7af81 100644 (file)
@@ -307,7 +307,7 @@ extern bool InLocalUserIdChange(void);
 extern bool InSecurityRestrictedOperation(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);
+extern void InitializeSessionUserId(const char *rolename, Oid useroid);
 extern void InitializeSessionUserIdStandalone(void);
 extern void SetSessionAuthorization(Oid userid, bool is_superuser);
 extern Oid     GetCurrentRoleId(void);
@@ -411,7 +411,7 @@ extern AuxProcType MyAuxProcType;
 extern void pg_split_opts(char **argv, int *argcp, char *optstr);
 extern void InitializeMaxBackends(void);
 extern void InitPostgres(const char *in_dbname, Oid dboid, const char *username,
-                        char *out_dbname);
+                        Oid useroid, char *out_dbname);
 extern void BaseInit(void);
 
 /* in utils/init/miscinit.c */
index 0460653b0511f916faa64c83a0a0f9738bd4ed2f..a81b90badcb77d3486bfd247e5015ec2b422be48 100644 (file)
@@ -130,6 +130,9 @@ extern PGDLLIMPORT BackgroundWorker *MyBgworkerEntry;
  */
 extern void BackgroundWorkerInitializeConnection(char *dbname, char *username);
 
+/* Just like the above, but specifying database and user by OID. */
+extern void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid);
+
 /* Block/unblock signals in a background worker process */
 extern void BackgroundWorkerBlockSignals(void);
 extern void BackgroundWorkerUnblockSignals(void);