diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index a698ab1958dd89ccf53c136d13691c76f915bcb1..c7131fea4c44cdf241d3c4f3bd08ec2097bd8f6f 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.296 2010/01/28 06:28:26 joe Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.297 2010/02/05 03:09:04 joe Exp $ --> <chapter id="libpq"> <title><application>libpq</application> - C Library</title> @@ -98,7 +98,7 @@ Makes a new connection to the database server. <synopsis> - PGconn *PQconnectdbParams(const char **keywords, const char **values); + PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand_dbname); </synopsis> </para> @@ -114,6 +114,12 @@ programming. </para> + <para> + When <literal>expand_dbname</literal> is non-zero, the + <parameter>dbname</parameter> key word value is allowed to be recognized + as a <parameter>conninfo</parameter> string. See below for details. + </para> + <para> The passed arrays can be empty to use all default parameters, or can contain one or more parameter settings. They should be matched in length. @@ -473,6 +479,24 @@ is checked. If the environment variable is not set either, then the indicated built-in defaults are used. </para> + + <para> + If <literal>expand_dbname</literal> is non-zero and + <parameter>dbname</parameter> contains an <symbol>=</symbol> sign, it + is taken as a <parameter>conninfo</parameter> string in exactly the same way as + if it had been passed to <function>PQconnectdb</function>(see below). Previously + processed key words will be overridden by key words in the + <parameter>conninfo</parameter> string. + </para> + + <para> + In general key words are processed from the beginning of these arrays in index + order. The effect of this is that when key words are repeated, the last processed + value is retained. Therefore, through careful placement of the + <parameter>dbname</parameter> key word, it is possible to determine what may + be overridden by a <parameter>conninfo</parameter> string, and what may not. + </para> + </listitem> </varlistentry> @@ -573,7 +597,7 @@ PGconn *PQsetdb(char *pghost, Make a connection to the database server in a nonblocking manner. <synopsis> - PGconn *PQconnectStartParams(const char **keywords, const char **values); + PGconn *PQconnectStartParams(const char **keywords, const char **values, int expand_dbname); </synopsis> <synopsis> @@ -597,8 +621,8 @@ PGconn *PQsetdb(char *pghost, <para> With <function>PQconnectStartParams</function>, the database connection is made using the parameters taken from the <literal>keywords</literal> and - <literal>values</literal> arrays, as described above for - <function>PQconnectdbParams</function>. + <literal>values</literal> arrays, and controlled by <literal>expand_dbname</literal>, + as described above for <function>PQconnectdbParams</function>. </para> <para> diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c index 1d72d6dd7e2470e8aa1f66b66c6f512cc21a08bd..4aa10135bb06ea7e64a08164b9205cb390aa6328 100644 --- a/src/bin/pg_dump/pg_backup_db.c +++ b/src/bin/pg_dump/pg_backup_db.c @@ -5,7 +5,7 @@ * Implements the basic DB functions used by the archiver. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.85 2009/12/14 00:39:11 itagaki Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.86 2010/02/05 03:09:05 joe Exp $ * *------------------------------------------------------------------------- */ @@ -154,10 +154,34 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) do { +#define PARAMS_ARRAY_SIZE 7 + const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); + const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); + + if (!keywords || !values) + die_horribly(AH, modulename, "out of memory\n"); + + keywords[0] = "host"; + values[0] = PQhost(AH->connection); + keywords[1] = "port"; + values[1] = PQport(AH->connection); + keywords[2] = "user"; + values[2] = newuser; + keywords[3] = "password"; + values[3] = password; + keywords[4] = "dbname"; + values[4] = newdb; + keywords[5] = "fallback_application_name"; + values[5] = progname; + keywords[6] = NULL; + values[6] = NULL; + new_pass = false; - newConn = PQsetdbLogin(PQhost(AH->connection), PQport(AH->connection), - NULL, NULL, newdb, - newuser, password); + newConn = PQconnectdbParams(keywords, values, true); + + free(keywords); + free(values); + if (!newConn) die_horribly(AH, modulename, "failed to reconnect to database\n"); @@ -237,9 +261,33 @@ ConnectDatabase(Archive *AHX, */ do { +#define PARAMS_ARRAY_SIZE 7 + const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); + const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); + + if (!keywords || !values) + die_horribly(AH, modulename, "out of memory\n"); + + keywords[0] = "host"; + values[0] = pghost; + keywords[1] = "port"; + values[1] = pgport; + keywords[2] = "user"; + values[2] = username; + keywords[3] = "password"; + values[3] = password; + keywords[4] = "dbname"; + values[4] = dbname; + keywords[5] = "fallback_application_name"; + values[5] = progname; + keywords[6] = NULL; + values[6] = NULL; + new_pass = false; - AH->connection = PQsetdbLogin(pghost, pgport, NULL, NULL, - dbname, username, password); + AH->connection = PQconnectdbParams(keywords, values, true); + + free(keywords); + free(values); if (!AH->connection) die_horribly(AH, modulename, "failed to connect to database\n"); @@ -697,3 +745,4 @@ _isDQChar(unsigned char c, bool atStart) else return false; } + diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 48084db12f880813943981b9975deb901979531a..f1d74574313c94c8a8e2cedbc9a27accf21df8b4 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.131 2010/01/06 03:34:41 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.132 2010/02/05 03:09:05 joe Exp $ * *------------------------------------------------------------------------- */ @@ -1618,8 +1618,36 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport, */ do { +#define PARAMS_ARRAY_SIZE 7 + const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); + const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); + + if (!keywords || !values) + { + fprintf(stderr, _("%s: out of memory\n"), progname); + exit(1); + } + + keywords[0] = "host"; + values[0] = pghost; + keywords[1] = "port"; + values[1] = pgport; + keywords[2] = "user"; + values[2] = pguser; + keywords[3] = "password"; + values[3] = password; + keywords[4] = "dbname"; + values[4] = dbname; + keywords[5] = "fallback_application_name"; + values[5] = progname; + keywords[6] = NULL; + values[6] = NULL; + new_pass = false; - conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password); + conn = PQconnectdbParams(keywords, values, true); + + free(keywords); + free(values); if (!conn) { diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 10f36dc22d451ebc332986eb946451e83947751e..74119fd29f0c927ba132c7502c6c2ba6f8c15abe 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2010, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.213 2010/01/02 16:57:59 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.214 2010/02/05 03:09:05 joe Exp $ */ #include "postgres_fe.h" #include "command.h" @@ -1213,7 +1213,7 @@ param_is_newly_set(const char *old_val, const char *new_val) * Connects to a database with given parameters. If there exists an * established connection, NULL values will be replaced with the ones * in the current connection. Otherwise NULL will be passed for that - * parameter to PQsetdbLogin(), so the libpq defaults will be used. + * parameter to PQconnectdbParams(), so the libpq defaults will be used. * * In interactive mode, if connection fails with the given parameters, * the old connection will be kept. @@ -1255,8 +1255,29 @@ do_connect(char *dbname, char *user, char *host, char *port) while (true) { - n_conn = PQsetdbLogin(host, port, NULL, NULL, - dbname, user, password); +#define PARAMS_ARRAY_SIZE 7 + const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); + const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); + + keywords[0] = "host"; + values[0] = host; + keywords[1] = "port"; + values[1] = port; + keywords[2] = "user"; + values[2] = user; + keywords[3] = "password"; + values[3] = password; + keywords[4] = "dbname"; + values[4] = dbname; + keywords[5] = "fallback_application_name"; + values[5] = pset.progname; + keywords[6] = NULL; + values[6] = NULL; + + n_conn = PQconnectdbParams(keywords, values, true); + + free(keywords); + free(values); /* We can immediately discard the password -- no longer needed */ if (password) diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index b29c84fdaec26f697f38a18f08da280a19c86541..c45a869d92cd0f72f070319ea216b5be3e92224f 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000-2010, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.159 2010/01/28 06:28:26 joe Exp $ + * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.160 2010/02/05 03:09:05 joe Exp $ */ #include "postgres_fe.h" @@ -90,8 +90,6 @@ main(int argc, char *argv[]) char *password = NULL; char *password_prompt = NULL; bool new_pass; - const char *keywords[] = {"host","port","dbname","user", - "password","application_name",NULL}; set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql")); @@ -173,20 +171,31 @@ main(int argc, char *argv[]) /* loop until we have a password if requested by backend */ do { - const char *values[] = { - options.host, - options.port, - (options.action == ACT_LIST_DB && - options.dbname == NULL) ? "postgres" : options.dbname, - options.username, - password, - pset.progname, - NULL - }; - - new_pass = false; - - pset.db = PQconnectdbParams(keywords, values); +#define PARAMS_ARRAY_SIZE 7 + const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); + const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); + + keywords[0] = "host"; + values[0] = options.host; + keywords[1] = "port"; + values[1] = options.port; + keywords[2] = "user"; + values[2] = options.username; + keywords[3] = "password"; + values[3] = password; + keywords[4] = "dbname"; + values[4] = (options.action == ACT_LIST_DB && + options.dbname == NULL) ? + "postgres" : options.dbname; + keywords[5] = "fallback_application_name"; + values[5] = pset.progname; + keywords[6] = NULL; + values[6] = NULL; + + new_pass = false; + pset.db = PQconnectdbParams(keywords, values, true); + free(keywords); + free(values); if (PQstatus(pset.db) == CONNECTION_BAD && PQconnectionNeedsPassword(pset.db) && diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c index 27aafa102c404f92ee54c9c0969d6f840856966a..026eb80a025fd941ca3a7a451d8393af5ad7287b 100644 --- a/src/bin/scripts/common.c +++ b/src/bin/scripts/common.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.38 2010/01/02 16:58:00 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/scripts/common.c,v 1.39 2010/02/05 03:09:05 joe Exp $ * *------------------------------------------------------------------------- */ @@ -108,8 +108,36 @@ connectDatabase(const char *dbname, const char *pghost, const char *pgport, */ do { +#define PARAMS_ARRAY_SIZE 7 + const char **keywords = malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); + const char **values = malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); + + if (!keywords || !values) + { + fprintf(stderr, _("%s: out of memory\n"), progname); + exit(1); + } + + keywords[0] = "host"; + values[0] = pghost; + keywords[1] = "port"; + values[1] = pgport; + keywords[2] = "user"; + values[2] = pguser; + keywords[3] = "password"; + values[3] = password; + keywords[4] = "dbname"; + values[4] = dbname; + keywords[5] = "fallback_application_name"; + values[5] = progname; + keywords[6] = NULL; + values[6] = NULL; + new_pass = false; - conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password); + conn = PQconnectdbParams(keywords, values, true); + + free(keywords); + free(values); if (!conn) { diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 048c438527b81492dd726d2d0affd5ad776f0b9f..994b70b190487888b88af7b8775faf1d962ddc08 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.385 2010/01/28 06:28:26 joe Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.386 2010/02/05 03:09:05 joe Exp $ * *------------------------------------------------------------------------- */ @@ -269,7 +269,7 @@ static PQconninfoOption *conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, bool use_defaults); static PQconninfoOption *conninfo_array_parse(const char **keywords, const char **values, PQExpBuffer errorMessage, - bool use_defaults); + bool use_defaults, int expand_dbname); static char *conninfo_getval(PQconninfoOption *connOptions, const char *keyword); static void defaultNoticeReceiver(void *arg, const PGresult *res); @@ -336,9 +336,11 @@ pgthreadlock_t pg_g_threadlock = default_threadlock; * call succeeded. */ PGconn * -PQconnectdbParams(const char **keywords, const char **values) +PQconnectdbParams(const char **keywords, + const char **values, + int expand_dbname) { - PGconn *conn = PQconnectStartParams(keywords, values); + PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname); if (conn && conn->status != CONNECTION_BAD) (void) connectDBComplete(conn); @@ -400,7 +402,9 @@ PQconnectdb(const char *conninfo) * See PQconnectPoll for more info. */ PGconn * -PQconnectStartParams(const char **keywords, const char **values) +PQconnectStartParams(const char **keywords, + const char **values, + int expand_dbname) { PGconn *conn; PQconninfoOption *connOptions; @@ -416,7 +420,8 @@ PQconnectStartParams(const char **keywords, const char **values) * Parse the conninfo arrays */ connOptions = conninfo_array_parse(keywords, values, - &conn->errorMessage, true); + &conn->errorMessage, + true, expand_dbname); if (connOptions == NULL) { conn->status = CONNECTION_BAD; @@ -3729,16 +3734,53 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage, * left in errorMessage. * Defaults are supplied (from a service file, environment variables, etc) * for unspecified options, but only if use_defaults is TRUE. + * + * If expand_dbname is non-zero, and the value passed for keyword "dbname" + * contains an "=", assume it is a conninfo string and process it, + * overriding any previously processed conflicting keywords. Subsequent + * keywords will take precedence, however. */ static PQconninfoOption * conninfo_array_parse(const char **keywords, const char **values, - PQExpBuffer errorMessage, bool use_defaults) + PQExpBuffer errorMessage, bool use_defaults, + int expand_dbname) { char *tmp; PQconninfoOption *options; + PQconninfoOption *str_options = NULL; PQconninfoOption *option; int i = 0; + /* + * If expand_dbname is non-zero, check keyword "dbname" + * to see if val is actually a conninfo string + */ + while(expand_dbname && keywords[i]) + { + const char *pname = keywords[i]; + const char *pvalue = values[i]; + + /* first find "dbname" if any */ + if (strcmp(pname, "dbname") == 0) + { + /* next look for "=" in the value */ + if (pvalue && strchr(pvalue, '=')) + { + /* + * Must be a conninfo string, so parse it, but do not + * use defaults here -- those get picked up later. + * We only want to override for those parameters actually + * passed. + */ + str_options = conninfo_parse(pvalue, errorMessage, false); + if (str_options == NULL) + return NULL; + } + break; + } + ++i; + } + /* Make a working copy of PQconninfoOptions */ options = malloc(sizeof(PQconninfoOptions)); if (options == NULL) @@ -3749,6 +3791,7 @@ conninfo_array_parse(const char **keywords, const char **values, } memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions)); + i = 0; /* Parse the keywords/values arrays */ while(keywords[i]) { @@ -3774,22 +3817,54 @@ conninfo_array_parse(const char **keywords, const char **values, return NULL; } - /* - * Store the value - */ - if (option->val) - free(option->val); - option->val = strdup(pvalue); - if (!option->val) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("out of memory\n")); - PQconninfoFree(options); - return NULL; - } + /* + * If we are on the dbname parameter, and we have a parsed + * conninfo string, copy those parameters across, overriding + * any existing previous settings + */ + if (strcmp(pname, "dbname") == 0 && str_options) + { + PQconninfoOption *str_option; + + for (str_option = str_options; str_option->keyword != NULL; str_option++) + { + if (str_option->val != NULL) + { + int k; + + for (k = 0; options[k].keyword; k++) + { + if (strcmp(options[k].keyword, str_option->keyword) == 0) + { + if (options[k].val) + free(options[k].val); + options[k].val = strdup(str_option->val); + break; + } + } + } + } + } + else + { + /* + * Store the value, overriding previous settings + */ + if (option->val) + free(option->val); + option->val = strdup(pvalue); + if (!option->val) + { + printfPQExpBuffer(errorMessage, + libpq_gettext("out of memory\n")); + PQconninfoFree(options); + return NULL; + } + } } ++i; } + PQconninfoFree(str_options); /* * Stop here if caller doesn't want defaults filled in. diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 5f59da0f753bc76c0cc8e2b4b0269b159b660976..c2698fe257e1c2667c31cecf44b3cd24a1cf2fe1 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.150 2010/01/28 06:28:26 joe Exp $ + * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-fe.h,v 1.151 2010/02/05 03:09:05 joe Exp $ * *------------------------------------------------------------------------- */ @@ -226,12 +226,14 @@ typedef struct pgresAttDesc /* make a new client connection to the backend */ /* Asynchronous (non-blocking) */ extern PGconn *PQconnectStart(const char *conninfo); -extern PGconn *PQconnectStartParams(const char **keywords, const char **values); +extern PGconn *PQconnectStartParams(const char **keywords, + const char **values, int expand_dbname); extern PostgresPollingStatusType PQconnectPoll(PGconn *conn); /* Synchronous (blocking) */ extern PGconn *PQconnectdb(const char *conninfo); -extern PGconn *PQconnectdbParams(const char **keywords, const char **values); +extern PGconn *PQconnectdbParams(const char **keywords, + const char **values, int expand_dbname); extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions, const char *pgtty, const char *dbName,