Add new function BackgroundWorkerInitializeConnectionByOid.

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.
This commit is contained in:
Robert Haas 2015-02-02 16:23:59 -05:00
parent 2488eff889
commit 5d2f957f3f
9 changed files with 56 additions and 22 deletions

View File

@ -146,14 +146,17 @@ typedef struct BackgroundWorker
</para> </para>
<para>Once running, the process can connect to a database by calling <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 This allows the process to run transactions and queries using the
<literal>SPI</literal> interface. If <varname>dbname</> is NULL, <literal>SPI</literal> interface. If <varname>dbname</> is NULL or
the session is not connected to any particular database, but shared catalogs <varname>dboid</> is <literal>InvalidOid</>, the session is not connected
can be accessed. If <varname>username</> is NULL, the process will run as to any particular database, but shared catalogs can be accessed.
the superuser created during <command>initdb</>. If <varname>username</> is NULL or <varname>useroid</> is
BackgroundWorkerInitializeConnection can only be called once per background <literal>InvalidOid</>, the process will run as the superuser created
process, it is not possible to switch databases. 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>
<para> <para>

View File

@ -467,7 +467,7 @@ BootstrapModeMain(void)
*/ */
InitProcess(); InitProcess();
InitPostgres(NULL, InvalidOid, NULL, NULL); InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
/* Initialize stuff for bootstrap-file processing */ /* Initialize stuff for bootstrap-file processing */
for (i = 0; i < MAXATTR; i++) for (i = 0; i < MAXATTR; i++)

View File

@ -450,7 +450,7 @@ AutoVacLauncherMain(int argc, char *argv[])
InitProcess(); InitProcess();
#endif #endif
InitPostgres(NULL, InvalidOid, NULL, NULL); InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
SetProcessingMode(NormalProcessing); SetProcessingMode(NormalProcessing);
@ -1620,7 +1620,7 @@ AutoVacWorkerMain(int argc, char *argv[])
* Note: if we have selected a just-deleted database (due to using * Note: if we have selected a just-deleted database (due to using
* stale stats info), we'll fail and exit here. * stale stats info), we'll fail and exit here.
*/ */
InitPostgres(NULL, dbid, NULL, dbname); InitPostgres(NULL, dbid, NULL, InvalidOid, dbname);
SetProcessingMode(NormalProcessing); SetProcessingMode(NormalProcessing);
set_ps_display(dbname, false); set_ps_display(dbname, false);
ereport(DEBUG1, ereport(DEBUG1,

View File

@ -5313,7 +5313,30 @@ BackgroundWorkerInitializeConnection(char *dbname, char *username)
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("database connection requirement not indicated during registration"))); 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 */ /* it had better not gotten out of "init" mode yet */
if (!IsInitProcessingMode()) if (!IsInitProcessingMode())

View File

@ -3714,7 +3714,7 @@ PostgresMain(int argc, char *argv[],
* it inside InitPostgres() instead. In particular, anything that * it inside InitPostgres() instead. In particular, anything that
* involves database access should be there, not here. * 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 * If the PostmasterContext is still around, recycle the space; we don't

View File

@ -453,11 +453,10 @@ has_rolreplication(Oid roleid)
* Initialize user identity during normal backend startup * Initialize user identity during normal backend startup
*/ */
void void
InitializeSessionUserId(const char *rolename) InitializeSessionUserId(const char *rolename, Oid roleid)
{ {
HeapTuple roleTup; HeapTuple roleTup;
Form_pg_authid rform; Form_pg_authid rform;
Oid roleid;
/* /*
* Don't do scans if we're bootstrapping, none of the system catalogs * Don't do scans if we're bootstrapping, none of the system catalogs
@ -468,7 +467,10 @@ InitializeSessionUserId(const char *rolename)
/* call only once */ /* call only once */
AssertState(!OidIsValid(AuthenticatedUserId)); 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)) if (!HeapTupleIsValid(roleTup))
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),

View File

@ -523,6 +523,9 @@ BaseInit(void)
* name can be returned to the caller in out_dbname. If out_dbname isn't * 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. * 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 * 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 * 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. * able to read pg_database; it doesn't connect to any particular database.
@ -537,7 +540,7 @@ BaseInit(void)
*/ */
void void
InitPostgres(const char *in_dbname, Oid dboid, const char *username, InitPostgres(const char *in_dbname, Oid dboid, const char *username,
char *out_dbname) Oid useroid, char *out_dbname)
{ {
bool bootstrap = IsBootstrapProcessingMode(); bool bootstrap = IsBootstrapProcessingMode();
bool am_superuser; bool am_superuser;
@ -692,18 +695,18 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("no roles are defined in this database system"), errmsg("no roles are defined in this database system"),
errhint("You should immediately run CREATE USER \"%s\" SUPERUSER;.", errhint("You should immediately run CREATE USER \"%s\" SUPERUSER;.",
username))); username != NULL ? username : "postgres")));
} }
else if (IsBackgroundWorker) else if (IsBackgroundWorker)
{ {
if (username == NULL) if (username == NULL && !OidIsValid(useroid))
{ {
InitializeSessionUserIdStandalone(); InitializeSessionUserIdStandalone();
am_superuser = true; am_superuser = true;
} }
else else
{ {
InitializeSessionUserId(username); InitializeSessionUserId(username, useroid);
am_superuser = superuser(); am_superuser = superuser();
} }
} }
@ -712,7 +715,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
/* normal multiuser case */ /* normal multiuser case */
Assert(MyProcPort != NULL); Assert(MyProcPort != NULL);
PerformAuthentication(MyProcPort); PerformAuthentication(MyProcPort);
InitializeSessionUserId(username); InitializeSessionUserId(username, useroid);
am_superuser = superuser(); am_superuser = superuser();
} }

View File

@ -307,7 +307,7 @@ extern bool InLocalUserIdChange(void);
extern bool InSecurityRestrictedOperation(void); extern bool InSecurityRestrictedOperation(void);
extern void GetUserIdAndContext(Oid *userid, bool *sec_def_context); extern void GetUserIdAndContext(Oid *userid, bool *sec_def_context);
extern void SetUserIdAndContext(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 InitializeSessionUserIdStandalone(void);
extern void SetSessionAuthorization(Oid userid, bool is_superuser); extern void SetSessionAuthorization(Oid userid, bool is_superuser);
extern Oid GetCurrentRoleId(void); extern Oid GetCurrentRoleId(void);
@ -411,7 +411,7 @@ extern AuxProcType MyAuxProcType;
extern void pg_split_opts(char **argv, int *argcp, char *optstr); extern void pg_split_opts(char **argv, int *argcp, char *optstr);
extern void InitializeMaxBackends(void); extern void InitializeMaxBackends(void);
extern void InitPostgres(const char *in_dbname, Oid dboid, const char *username, extern void InitPostgres(const char *in_dbname, Oid dboid, const char *username,
char *out_dbname); Oid useroid, char *out_dbname);
extern void BaseInit(void); extern void BaseInit(void);
/* in utils/init/miscinit.c */ /* in utils/init/miscinit.c */

View File

@ -130,6 +130,9 @@ extern PGDLLIMPORT BackgroundWorker *MyBgworkerEntry;
*/ */
extern void BackgroundWorkerInitializeConnection(char *dbname, char *username); 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 */ /* Block/unblock signals in a background worker process */
extern void BackgroundWorkerBlockSignals(void); extern void BackgroundWorkerBlockSignals(void);
extern void BackgroundWorkerUnblockSignals(void); extern void BackgroundWorkerUnblockSignals(void);