Move processing of startup-packet switches and GUC settings into InitPostgres,

to fix the problem that SetClientEncoding needs to be done before
InitializeClientEncoding, as reported by Zdenek Kotala.  We get at least
the small consolation of being able to remove the bizarre API detail that
had InitPostgres returning whether user is a superuser.
This commit is contained in:
Tom Lane 2009-09-01 00:09:42 +00:00
parent 00e6a16d01
commit 0905e8aeeb
4 changed files with 91 additions and 95 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.571 2009/08/29 19:26:51 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.572 2009/09/01 00:09:42 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -2862,7 +2862,7 @@ get_stats_option_name(const char *arg)
* from the client's startup packet. The latter have the same syntax but
* may be restricted in what they can do.
*
* argv[0] is the program name either way.
* argv[0] is ignored in either case (it's assumed to be the program name).
*
* ctx is PGC_POSTMASTER for secure options, PGC_BACKEND for insecure options
* coming from the client, or PGC_SUSET for insecure options coming from
@ -2871,11 +2871,10 @@ get_stats_option_name(const char *arg)
* Returns the database name extracted from the command line, if any.
* ----------------------------------------------------------------
*/
static const char *
const char *
process_postgres_switches(int argc, char *argv[], GucContext ctx)
{
const char *dbname;
const char *argv0 = argv[0];
bool secure = (ctx == PGC_POSTMASTER);
int errs = 0;
GucSource gucsource;
@ -3073,13 +3072,13 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx)
ereport(FATAL,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid command-line arguments for server process"),
errhint("Try \"%s --help\" for more information.", argv0)));
errhint("Try \"%s --help\" for more information.", progname)));
else
ereport(FATAL,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s: invalid command-line arguments",
argv0),
errhint("Try \"%s --help\" for more information.", argv0)));
progname),
errhint("Try \"%s --help\" for more information.", progname)));
}
if (argc - optind == 1)
@ -3114,8 +3113,6 @@ int
PostgresMain(int argc, char *argv[], const char *username)
{
const char *dbname;
bool am_superuser;
GucContext ctx;
int firstchar;
char stack_base;
StringInfoData input_message;
@ -3176,13 +3173,13 @@ PostgresMain(int argc, char *argv[], const char *username)
ereport(FATAL,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("%s: no database nor user name specified",
argv[0])));
progname)));
}
/* Acquire configuration parameters, unless inherited from postmaster */
if (!IsUnderPostmaster)
{
if (!SelectConfigFiles(userDoption, argv[0]))
if (!SelectConfigFiles(userDoption, progname))
proc_exit(1);
/* If timezone is not set, determine what the OS uses */
pg_timezone_initialize();
@ -3314,7 +3311,7 @@ PostgresMain(int argc, char *argv[], const char *username)
* it inside InitPostgres() instead. In particular, anything that
* involves database access should be there, not here.
*/
am_superuser = InitPostgres(dbname, InvalidOid, username, NULL);
InitPostgres(dbname, InvalidOid, username, NULL);
/*
* If the PostmasterContext is still around, recycle the space; we don't
@ -3331,70 +3328,6 @@ PostgresMain(int argc, char *argv[], const char *username)
SetProcessingMode(NormalProcessing);
set_ps_display("startup", false);
/*
* Now that we know if client is a superuser, we can try to apply any
* command-line options passed in the startup packet.
*/
ctx = am_superuser ? PGC_SUSET : PGC_BACKEND;
if (MyProcPort != NULL &&
MyProcPort->cmdline_options != NULL)
{
/*
* The maximum possible number of commandline arguments that could
* come from MyProcPort->cmdline_options is (strlen + 1) / 2; see
* pg_split_opts().
*/
char **av;
int maxac;
int ac;
maxac = 2 + (strlen(MyProcPort->cmdline_options) + 1) / 2;
av = (char **) palloc(maxac * sizeof(char *));
ac = 0;
av[ac++] = argv[0];
/* Note this mangles MyProcPort->cmdline_options */
pg_split_opts(av, &ac, MyProcPort->cmdline_options);
av[ac] = NULL;
Assert(ac < maxac);
(void) process_postgres_switches(ac, av, ctx);
}
/*
* Process any additional GUC variable settings passed in startup packet.
* These are handled exactly like command-line variables.
*/
if (MyProcPort != NULL)
{
ListCell *gucopts = list_head(MyProcPort->guc_options);
while (gucopts)
{
char *name;
char *value;
name = lfirst(gucopts);
gucopts = lnext(gucopts);
value = lfirst(gucopts);
gucopts = lnext(gucopts);
SetConfigOption(name, value, ctx, PGC_S_CLIENT);
}
}
/* Apply PostAuthDelay as soon as we've read all options */
if (PostAuthDelay > 0)
pg_usleep(PostAuthDelay * 1000000L);
/*
* Now all GUC states are fully set up. Report them to client if
* appropriate.

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.196 2009/08/31 19:41:00 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.197 2009/09/01 00:09:42 tgl Exp $
*
*
*-------------------------------------------------------------------------
@ -44,11 +44,13 @@
#include "storage/procsignal.h"
#include "storage/sinvaladt.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/pg_locale.h"
#include "utils/portal.h"
#include "utils/ps_status.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
@ -217,6 +219,8 @@ PerformAuthentication(Port *port)
(errmsg("connection authorized: user=%s database=%s",
port->user_name, port->database_name)));
set_ps_display("startup", false);
ClientAuthInProgress = false; /* client_min_messages is active now */
}
@ -256,7 +260,7 @@ CheckMyDatabase(const char *name, bool am_superuser)
* a way to recover from disabling all access to all databases, for
* example "UPDATE pg_database SET datallowconn = false;".
*
* We do not enforce them for the autovacuum worker processes either.
* We do not enforce them for autovacuum worker processes either.
*/
if (IsUnderPostmaster && !IsAutoVacuumWorkerProcess())
{
@ -464,10 +468,6 @@ BaseInit(void)
* 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.
*
* The return value indicates whether the userID is a superuser. (That
* can only be tested inside a transaction, so we want to do it during
* the startup transaction rather than doing a separate one in postgres.c.)
*
* As of PostgreSQL 8.2, we expect InitProcess() was already called, so we
* already have a PGPROC struct ... but it's not completely filled in yet.
*
@ -475,13 +475,13 @@ BaseInit(void)
* Be very careful with the order of calls in the InitPostgres function.
* --------------------------------
*/
bool
void
InitPostgres(const char *in_dbname, Oid dboid, const char *username,
char *out_dbname)
{
bool bootstrap = IsBootstrapProcessingMode();
bool autovacuum = IsAutoVacuumWorkerProcess();
bool am_superuser;
GucContext gucctx;
char *fullpath;
char dbname[NAMEDATALEN];
@ -558,7 +558,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
/* The autovacuum launcher is done here */
if (IsAutoVacuumLauncherProcess())
return true; /* result doesn't matter */
return;
/*
* Start a new transaction here before first access to db, and get a
@ -706,12 +706,12 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
/*
* Perform client authentication if necessary, then figure out our
* postgres user id, and see if we are a superuser.
* postgres user ID, and see if we are a superuser.
*
* In standalone mode and in the autovacuum process, we use a fixed id,
* otherwise we figure it out from the authenticated user name.
* In standalone mode and in autovacuum worker processes, we use a fixed
* ID, otherwise we figure it out from the authenticated user name.
*/
if (bootstrap || autovacuum)
if (bootstrap || IsAutoVacuumWorkerProcess())
{
InitializeSessionUserIdStandalone();
am_superuser = true;
@ -724,7 +724,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
ereport(WARNING,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("no roles are defined in this database system"),
errhint("You should immediately run CREATE USER \"%s\" CREATEUSER;.",
errhint("You should immediately run CREATE USER \"%s\" SUPERUSER;.",
username)));
}
else
@ -768,6 +768,69 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("connection limit exceeded for non-superusers")));
/*
* Now process any command-line switches that were included in the startup
* packet, if we are in a regular backend. We couldn't do this before
* because we didn't know if client is a superuser.
*/
gucctx = am_superuser ? PGC_SUSET : PGC_BACKEND;
if (MyProcPort != NULL &&
MyProcPort->cmdline_options != NULL)
{
/*
* The maximum possible number of commandline arguments that could
* come from MyProcPort->cmdline_options is (strlen + 1) / 2; see
* pg_split_opts().
*/
char **av;
int maxac;
int ac;
maxac = 2 + (strlen(MyProcPort->cmdline_options) + 1) / 2;
av = (char **) palloc(maxac * sizeof(char *));
ac = 0;
av[ac++] = "postgres";
/* Note this mangles MyProcPort->cmdline_options */
pg_split_opts(av, &ac, MyProcPort->cmdline_options);
av[ac] = NULL;
Assert(ac < maxac);
(void) process_postgres_switches(ac, av, gucctx);
}
/*
* Process any additional GUC variable settings passed in startup packet.
* These are handled exactly like command-line variables.
*/
if (MyProcPort != NULL)
{
ListCell *gucopts = list_head(MyProcPort->guc_options);
while (gucopts)
{
char *name;
char *value;
name = lfirst(gucopts);
gucopts = lnext(gucopts);
value = lfirst(gucopts);
gucopts = lnext(gucopts);
SetConfigOption(name, value, gucctx, PGC_S_CLIENT);
}
}
/* Apply PostAuthDelay as soon as we've read all options */
if (PostAuthDelay > 0)
pg_usleep(PostAuthDelay * 1000000L);
/*
* Initialize various default states that can't be set up until we've
* selected the active user and gotten the right GUC settings.
@ -786,8 +849,6 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
/* close the transaction we started above */
if (!bootstrap)
CommitTransactionCommand();
return am_superuser;
}

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.213 2009/08/29 19:26:51 tgl Exp $
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.214 2009/09/01 00:09:42 tgl Exp $
*
* NOTES
* some of the information in this file should be moved to other files.
@ -324,7 +324,7 @@ extern ProcessingMode Mode;
/* in utils/init/postinit.c */
extern void pg_split_opts(char **argv, int *argcp, char *optstr);
extern bool 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);
extern void BaseInit(void);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.99 2009/08/29 19:26:52 tgl Exp $
* $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.100 2009/09/01 00:09:42 tgl Exp $
*
* OLD COMMENTS
* This file was created so that other c files could get the two
@ -62,6 +62,8 @@ extern void StatementCancelHandler(SIGNAL_ARGS);
extern void FloatExceptionHandler(SIGNAL_ARGS);
extern void prepare_for_client_read(void);
extern void client_read_ended(void);
extern const char *process_postgres_switches(int argc, char *argv[],
GucContext ctx);
extern int PostgresMain(int argc, char *argv[], const char *username);
extern long get_stack_depth_rlimit(void);
extern void ResetUsage(void);