*** a/doc/src/sgml/ref/pg_basebackup.sgml --- b/doc/src/sgml/ref/pg_basebackup.sgml *************** *** 357,362 **** PostgreSQL documentation --- 357,375 ---- The following command-line options control the database connection parameters. + + + + + + + Specifies connection string options, used for connecting to server. + These options can be used along with other user supplied options. + In case of conflicting option, user supplied option is choosen. + + + + *** a/doc/src/sgml/ref/pg_dump.sgml --- b/doc/src/sgml/ref/pg_dump.sgml *************** *** 815,820 **** PostgreSQL documentation --- 815,833 ---- The following command-line options control the database connection parameters. + + + + + + + + Specifies connection string options, used for connecting to server. + These options can be used along with other user supplied options. + In case of conflicting option, user supplied option is choosen. + + + *** a/doc/src/sgml/ref/pg_dumpall.sgml --- b/doc/src/sgml/ref/pg_dumpall.sgml *************** *** 403,408 **** PostgreSQL documentation --- 403,421 ---- The following command-line options control the database connection parameters. + + + + + + + + Specifies connection string options, used for connecting to server. + These options can be used along with other user supplied options. + In case of conflicting option, user supplied option is choosen. + + + *** a/doc/src/sgml/ref/pg_receivexlog.sgml --- b/doc/src/sgml/ref/pg_receivexlog.sgml *************** *** 121,126 **** PostgreSQL documentation --- 121,139 ---- The following command-line options control the database connection parameters. + + + + + + + Specifies connection string options, used for connecting to server. + These options can be used along with other user supplied options. + In case of conflicting option, user supplied option is choosen. + + + + *** a/src/bin/pg_basebackup/pg_basebackup.c --- b/src/bin/pg_basebackup/pg_basebackup.c *************** *** 126,131 **** usage(void) --- 126,132 ---- printf(_(" -V, --version output version information, then exit\n")); printf(_(" -?, --help show this help, then exit\n")); printf(_("\nConnection options:\n")); + printf(_(" -C, --connection-string=\"OPTIONS\" connect to server using OPTIONS\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); printf(_(" -p, --port=PORT database server port number\n")); printf(_(" -s, --status-interval=INTERVAL\n" *************** *** 1534,1539 **** main(int argc, char **argv) --- 1535,1541 ---- {"pgdata", required_argument, NULL, 'D'}, {"format", required_argument, NULL, 'F'}, {"checkpoint", required_argument, NULL, 'c'}, + {"connection-string", required_argument, NULL, 'C'}, {"write-recovery-conf", no_argument, NULL, 'R'}, {"xlog", no_argument, NULL, 'x'}, {"xlog-method", required_argument, NULL, 'X'}, *************** *** 1572,1578 **** main(int argc, char **argv) } } ! while ((c = getopt_long(argc, argv, "D:F:RxX:l:zZ:c:h:p:U:s:wWvP", long_options, &option_index)) != -1) { switch (c) --- 1574,1580 ---- } } ! while ((c = getopt_long(argc, argv, "D:F:RxX:l:zZ:C:c:h:p:U:s:wWvP", long_options, &option_index)) != -1) { switch (c) *************** *** 1663,1668 **** main(int argc, char **argv) --- 1665,1673 ---- exit(1); } break; + case 'C': + connection_string = pg_strdup(optarg); + break; case 'h': dbhost = pg_strdup(optarg); break; *** a/src/bin/pg_basebackup/pg_receivexlog.c --- b/src/bin/pg_basebackup/pg_receivexlog.c *************** *** 58,63 **** usage(void) --- 58,64 ---- printf(_(" -V, --version output version information, then exit\n")); printf(_(" -?, --help show this help, then exit\n")); printf(_("\nConnection options:\n")); + printf(_(" -C, --connection-string=\"OPTIONS\" connect to server using OPTIONS\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); printf(_(" -p, --port=PORT database server port number\n")); printf(_(" -s, --status-interval=INTERVAL\n" *************** *** 305,310 **** main(int argc, char **argv) --- 306,312 ---- static struct option long_options[] = { {"help", no_argument, NULL, '?'}, {"version", no_argument, NULL, 'V'}, + {"connection-string", required_argument, NULL, 'C'}, {"directory", required_argument, NULL, 'D'}, {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, *************** *** 338,348 **** main(int argc, char **argv) } } ! while ((c = getopt_long(argc, argv, "D:h:p:U:s:nwWv", long_options, &option_index)) != -1) { switch (c) { case 'D': basedir = pg_strdup(optarg); break; --- 340,353 ---- } } ! while ((c = getopt_long(argc, argv, "C:D:h:p:U:s:nwWv", long_options, &option_index)) != -1) { switch (c) { + case 'C': + connection_string = pg_strdup(optarg); + break; case 'D': basedir = pg_strdup(optarg); break; *** a/src/bin/pg_basebackup/streamutil.c --- b/src/bin/pg_basebackup/streamutil.c *************** *** 24,29 **** char *dbport = NULL; --- 24,31 ---- int dbgetpassword = 0; /* 0=auto, -1=never, 1=always */ static char *dbpassword = NULL; PGconn *conn = NULL; + char *connection_string = NULL; + /* * Connect to the server. Returns a valid PGconn pointer if connected, *************** *** 34,64 **** PGconn * GetConnection(void) { PGconn *tmpconn; ! int argcount = 4; /* dbname, replication, fallback_app_name, ! * password */ ! int i; const char **keywords; const char **values; char *password = NULL; const char *tmpparam; - if (dbhost) - argcount++; - if (dbuser) - argcount++; - if (dbport) - argcount++; - - keywords = pg_malloc0((argcount + 1) * sizeof(*keywords)); - values = pg_malloc0((argcount + 1) * sizeof(*values)); - - keywords[0] = "dbname"; - values[0] = "replication"; - keywords[1] = "replication"; - values[1] = "true"; - keywords[2] = "fallback_application_name"; - values[2] = progname; - i = 3; if (dbhost) { keywords[i] = "host"; --- 36,97 ---- GetConnection(void) { PGconn *tmpconn; ! int i = 0; const char **keywords; const char **values; char *password = NULL; const char *tmpparam; + PQconninfoOption *conn_opts = NULL, + *conn_opts_merged = NULL; + PQconninfoOption *conn_opt; + char *err_msg = NULL; + + + keywords = pg_malloc0(MAX_CONNINFO_OPTIONS * sizeof(*keywords)); + values = pg_malloc0(MAX_CONNINFO_OPTIONS * sizeof(*values)); + + /* + * Merge the connection info inputs given in form of connection string, + * options and default values (dbname=replication, replication=true, + * etc.). We could have written new function to connect using + * PQconninfoOption, but it's not a lot of code to iterate through the + * PGconnInfoOption array and turn it back into keywords and values + * arrays, so just do that straight in the client code. + */ + + if (connection_string) + { + conn_opts = PQconninfoParse(connection_string, &err_msg); + if (conn_opts != NULL) + { + for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) + { + if (conn_opt->val != NULL && conn_opt->val[0] != '\0') + { + keywords[i] = conn_opt->keyword; + values[i] = conn_opt->val; + i++; + } + } + } + else + { + fprintf(stderr, "%s: %s\n", progname, err_msg); + return NULL; + } + + } + + keywords[i] = "dbname"; + values[i] = "replication"; + i++; + keywords[i] = "replication"; + values[i] = "true"; + i++; + keywords[i] = "fallback_application_name"; + values[i] = progname; + i++; if (dbhost) { keywords[i] = "host"; *************** *** 78,83 **** GetConnection(void) --- 111,143 ---- i++; } + if (connection_string) + { + conn_opts_merged = PQconninfoParseParams(keywords, values, + true, &err_msg); + if (conn_opts_merged != NULL) + { + i = 0; + MemSet(keywords, 0, MAX_CONNINFO_OPTIONS * sizeof(*keywords)); + MemSet(values, 0, MAX_CONNINFO_OPTIONS * sizeof(*values)); + for (conn_opt = conn_opts_merged; conn_opt->keyword != NULL; conn_opt++) + { + if (conn_opt->val != NULL && conn_opt->val[0] != '\0') + { + keywords[i] = conn_opt->keyword; + values[i] = conn_opt->val; + i++; + } + } + } + else + { + fprintf(stderr, "%s: %s\n", progname, err_msg); + PQconninfoFree(conn_opts); + return NULL; + } + } + while (true) { if (password) *************** *** 90,104 **** GetConnection(void) * meaning this is the call for a second session to the same * database, so just forcibly reuse that password. */ ! keywords[argcount - 1] = "password"; ! values[argcount - 1] = dbpassword; dbgetpassword = -1; /* Don't try again if this fails */ } else if (dbgetpassword == 1) { password = simple_prompt(_("Password: "), 100, false); ! keywords[argcount - 1] = "password"; ! values[argcount - 1] = password; } tmpconn = PQconnectdbParams(keywords, values, true); --- 150,164 ---- * meaning this is the call for a second session to the same * database, so just forcibly reuse that password. */ ! keywords[i] = "password"; ! values[i] = dbpassword; dbgetpassword = -1; /* Don't try again if this fails */ } else if (dbgetpassword == 1) { password = simple_prompt(_("Password: "), 100, false); ! keywords[i] = "password"; ! values[i] = password; } tmpconn = PQconnectdbParams(keywords, values, true); *************** *** 130,141 **** GetConnection(void) --- 190,205 ---- PQfinish(tmpconn); free(values); free(keywords); + PQconninfoFree(conn_opts); + PQconninfoFree(conn_opts_merged); return NULL; } /* Connection ok! */ free(values); free(keywords); + PQconninfoFree(conn_opts); + PQconninfoFree(conn_opts_merged); /* * Ensure we have the same value of integer timestamps as the server *** a/src/bin/pg_basebackup/streamutil.h --- b/src/bin/pg_basebackup/streamutil.h *************** *** 5,10 **** extern char *dbhost; --- 5,11 ---- extern char *dbuser; extern char *dbport; extern int dbgetpassword; + extern char *connection_string; /* Connection kept global so we can disconnect easily */ extern PGconn *conn; *** a/src/bin/pg_dump/dumputils.c --- b/src/bin/pg_dump/dumputils.c *************** *** 28,33 **** extern const int NumFEScanKeywords; --- 28,34 ---- /* Globals exported by this file */ int quote_all_identifiers = 0; const char *progname = NULL; + char *connection_string = NULL; #define MAX_ON_EXIT_NICELY 20 *** a/src/bin/pg_dump/dumputils.h --- b/src/bin/pg_dump/dumputils.h *************** *** 44,49 **** typedef void (*on_exit_nicely_callback) (int code, void *arg); --- 44,50 ---- extern int quote_all_identifiers; extern const char *progname; + extern char *connection_string; extern void init_parallel_dump_utils(void); extern const char *fmtId(const char *identifier); *** a/src/bin/pg_dump/pg_backup_db.c --- b/src/bin/pg_dump/pg_backup_db.c *************** *** 254,283 **** ConnectDatabase(Archive *AHX, */ do { ! #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] = 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 = PQconnectdbParams(keywords, values, true); free(keywords); free(values); if (!AH->connection) exit_horribly(modulename, "failed to connect to database\n"); --- 254,349 ---- */ do { ! const char **keywords = pg_malloc(MAX_CONNINFO_OPTIONS * sizeof(*keywords)); ! const char **values = pg_malloc(MAX_CONNINFO_OPTIONS * sizeof(*values)); ! PQconninfoOption *conn_opts = NULL, ! *conn_opts_merged = NULL; ! PQconninfoOption *conn_opt; ! char *err_msg = NULL; ! int i = 0; ! ! /* ! * Merge the connection info inputs given in form of connection string ! * and options. We could have written new function to connect using ! * PQconninfoOption, but it's not a lot of code to iterate through the ! * PGconnInfoOption array and turn it back into keywords and values ! * arrays, so just do that straight in the client code. ! */ ! if (connection_string) ! { ! conn_opts = PQconninfoParse(connection_string, &err_msg); ! if (conn_opts != NULL) ! { ! for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) ! { ! if (conn_opt->val != NULL && conn_opt->val[0] != '\0') ! { ! keywords[i] = conn_opt->keyword; ! values[i] = conn_opt->val; ! i++; ! } ! } ! } ! else ! exit_horribly(modulename, "%s\n", err_msg); ! } ! ! keywords[i] = "host"; ! values[i] = pghost; ! i++; ! keywords[i] = "port"; ! values[i] = pgport; ! i++; ! keywords[i] = "user"; ! values[i] = username; ! i++; ! keywords[i] = "password"; ! values[i] = password; ! i++; ! keywords[i] = "dbname"; ! values[i] = dbname; ! i++; ! keywords[i] = "fallback_application_name"; ! values[i] = progname; ! i++; ! keywords[i] = NULL; ! values[i] = NULL; ! ! if (connection_string) ! { ! conn_opts_merged = PQconninfoParseParams(keywords, values, ! true, &err_msg); ! if (conn_opts_merged != NULL) ! { ! i = 0; ! MemSet(keywords, 0, MAX_CONNINFO_OPTIONS * sizeof(*keywords)); ! MemSet(values, 0, MAX_CONNINFO_OPTIONS * sizeof(*values)); ! for (conn_opt = conn_opts_merged; conn_opt->keyword != NULL; conn_opt++) ! { ! if (conn_opt->val != NULL && conn_opt->val[0] != '\0') ! { ! keywords[i] = conn_opt->keyword; ! values[i] = conn_opt->val; ! i++; ! } ! } ! } ! else ! { ! PQconninfoFree(conn_opts); ! exit_horribly(modulename, "%s\n", err_msg); ! ! } ! } new_pass = false; AH->connection = PQconnectdbParams(keywords, values, true); free(keywords); free(values); + PQconninfoFree(conn_opts); + PQconninfoFree(conn_opts_merged); if (!AH->connection) exit_horribly(modulename, "failed to connect to database\n"); *** a/src/bin/pg_dump/pg_dump.c --- b/src/bin/pg_dump/pg_dump.c *************** *** 311,316 **** main(int argc, char **argv) --- 311,317 ---- {"format", required_argument, NULL, 'F'}, {"host", required_argument, NULL, 'h'}, {"ignore-version", no_argument, NULL, 'i'}, + {"connection-string", required_argument, NULL, 'K'}, {"no-reconnect", no_argument, NULL, 'R'}, {"oids", no_argument, NULL, 'o'}, {"no-owner", no_argument, NULL, 'O'}, *************** *** 387,393 **** main(int argc, char **argv) } } ! while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxZ:", long_options, &optindex)) != -1) { switch (c) --- 388,394 ---- } } ! while ((c = getopt_long(argc, argv, "abcCE:f:F:h:iK:n:N:oOp:RsS:t:T:U:vwWxZ:", long_options, &optindex)) != -1) { switch (c) *************** *** 428,433 **** main(int argc, char **argv) --- 429,438 ---- /* ignored, deprecated option */ break; + case 'K': + connection_string = pg_strdup(optarg); + break; + case 'n': /* include schema(s) */ simple_string_list_append(&schema_include_patterns, optarg); include_everything = false; *************** *** 872,877 **** help(const char *progname) --- 877,883 ---- " ALTER OWNER commands to set ownership\n")); printf(_("\nConnection options:\n")); + printf(_(" -K, --connection-string=\"OPTIONS\" connect to server using OPTIONS\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); printf(_(" -p, --port=PORT database server port number\n")); printf(_(" -U, --username=NAME connect as specified database user\n")); *** a/src/bin/pg_dump/pg_dumpall.c --- b/src/bin/pg_dump/pg_dumpall.c *************** *** 79,85 **** static int server_version; static FILE *OPF; static char *filename = NULL; - int main(int argc, char *argv[]) { --- 79,84 ---- *************** *** 90,95 **** main(int argc, char *argv[]) --- 89,95 ---- {"globals-only", no_argument, NULL, 'g'}, {"host", required_argument, NULL, 'h'}, {"ignore-version", no_argument, NULL, 'i'}, + {"connection-string", required_argument, NULL, 'K'}, {"database", required_argument, NULL, 'l'}, {"oids", no_argument, NULL, 'o'}, {"no-owner", no_argument, NULL, 'O'}, *************** *** 187,193 **** main(int argc, char *argv[]) pgdumpopts = createPQExpBuffer(); ! while ((c = getopt_long(argc, argv, "acf:gh:il:oOp:rsS:tU:vwWx", long_options, &optindex)) != -1) { switch (c) { --- 187,193 ---- pgdumpopts = createPQExpBuffer(); ! while ((c = getopt_long(argc, argv, "acf:gh:iK:l:oOp:rsS:tU:vwWx", long_options, &optindex)) != -1) { switch (c) { *************** *** 220,225 **** main(int argc, char *argv[]) --- 220,231 ---- /* ignored, deprecated option */ break; + case 'K': + connection_string = pg_strdup(optarg); + appendPQExpBuffer(pgdumpopts, " -K "); + doShellQuoting(pgdumpopts, connection_string); + break; + case 'l': pgdb = pg_strdup(optarg); break; *************** *** 567,572 **** help(void) --- 573,579 ---- " ALTER OWNER commands to set ownership\n")); printf(_("\nConnection options:\n")); + printf(_(" -K, --connection-string=\"OPTIONS\" connect to server using OPTIONS\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); printf(_(" -l, --database=DBNAME alternative default database\n")); printf(_(" -p, --port=PORT database server port number\n")); *************** *** 1710,1739 **** connectDatabase(const char *dbname, const char *pghost, const char *pgport, */ do { ! #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] = 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 = PQconnectdbParams(keywords, values, true); free(keywords); free(values); if (!conn) { --- 1717,1814 ---- */ do { ! const char **keywords = pg_malloc(MAX_CONNINFO_OPTIONS * sizeof(*keywords)); ! const char **values = pg_malloc(MAX_CONNINFO_OPTIONS * sizeof(*values)); ! PQconninfoOption *conn_opts = NULL, ! *conn_opts_merged = NULL; ! PQconninfoOption *conn_opt; ! char *err_msg = NULL; ! int i = 0; ! ! /* ! * Merge the connection info inputs given in form of connection string ! * and options. We could have written new function to connect using ! * PQconninfoOption, but it's not a lot of code to iterate through the ! * PGconnInfoOption array and turn it back into keywords and values ! * arrays, so just do that straight in the client code. ! */ ! if (connection_string) ! { ! conn_opts = PQconninfoParse(connection_string, &err_msg); ! if (conn_opts != NULL) ! { ! for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) ! { ! if (conn_opt->val != NULL && conn_opt->val[0] != '\0') ! { ! keywords[i] = conn_opt->keyword; ! values[i] = conn_opt->val; ! i++; ! } ! } ! } ! else ! { ! fprintf(stderr, "%s: %s\n", progname, err_msg); ! return NULL; ! } ! } ! ! keywords[i] = "host"; ! values[i] = pghost; ! i++; ! keywords[i] = "port"; ! values[i] = pgport; ! i++; ! keywords[i] = "user"; ! values[i] = pguser; ! i++; ! keywords[i] = "password"; ! values[i] = password; ! i++; ! keywords[i] = "dbname"; ! values[i] = dbname; ! i++; ! keywords[i] = "fallback_application_name"; ! values[i] = progname; ! i++; ! keywords[i] = NULL; ! values[i] = NULL; ! ! if (connection_string) ! { ! conn_opts_merged = PQconninfoParseParams(keywords, values, ! true, &err_msg); ! if (conn_opts_merged != NULL) ! { ! i = 0; ! MemSet(keywords, 0, MAX_CONNINFO_OPTIONS * sizeof(*keywords)); ! MemSet(values, 0, MAX_CONNINFO_OPTIONS * sizeof(*values)); ! for (conn_opt = conn_opts_merged; conn_opt->keyword != NULL; conn_opt++) ! { ! if (conn_opt->val != NULL && conn_opt->val[0] != '\0') ! { ! keywords[i] = conn_opt->keyword; ! values[i] = conn_opt->val; ! i++; ! } ! } ! } ! else ! { ! fprintf(stderr, "%s: %s\n", progname, err_msg); ! PQconninfoFree(conn_opts); ! return NULL; ! } ! } new_pass = false; conn = PQconnectdbParams(keywords, values, true); free(keywords); free(values); + PQconninfoFree(conn_opts); + PQconninfoFree(conn_opts_merged); if (!conn) { *** a/src/include/pg_config_manual.h --- b/src/include/pg_config_manual.h *************** *** 200,205 **** --- 200,213 ---- #endif /* + * MAX_CONNINFO_OPTIONS: maximum number of options for connection. + * It refers to PQconninfoOptions, currently it is less than 50, kept + * this considering future additions, however it can be kept same. + */ + #define MAX_CONNINFO_OPTIONS 50 + + + /* *------------------------------------------------------------------------ * The following symbols are for enabling debugging code, not for * controlling user-visible features or resource limits. *** a/src/interfaces/libpq/exports.txt --- b/src/interfaces/libpq/exports.txt *************** *** 165,167 **** lo_lseek64 162 --- 165,169 ---- lo_tell64 163 lo_truncate64 164 PQconninfo 165 + PQconninfoParseParams 166 + PQconninfodefaultsMerge 167 *** a/src/interfaces/libpq/fe-connect.c --- b/src/interfaces/libpq/fe-connect.c *************** *** 4002,4007 **** PQconninfoParse(const char *conninfo, char **errmsg) --- 4002,4086 ---- } /* + * PQconninfoParseParams + * + * Parse a string like PQconnectdbParams() would do and return the + * resulting connection options array. NULL is returned on failure. + * The result contains only options specified directly in the array, + * not any possible default values. + * + * If errmsg isn't NULL, *errmsg is set to NULL on success, or a malloc'd + * string on failure (use PQfreemem to free it). In out-of-memory conditions + * both *errmsg and the result could be NULL. + * + * NOTE: the returned array is dynamically allocated and should + * be freed when no longer needed via PQconninfoFree(). + */ + PQconninfoOption * + PQconninfoParseParams(const char *const * keywords, + const char *const * values, int expand_dbname, + char **errmsg) + { + PQExpBufferData errorBuf; + PQconninfoOption *connOptions; + + if (errmsg) + *errmsg = NULL; /* default */ + initPQExpBuffer(&errorBuf); + if (PQExpBufferDataBroken(errorBuf)) + return NULL; /* out of memory already :-( */ + connOptions = conninfo_array_parse(keywords, values, + &errorBuf, + false, expand_dbname); + + if (connOptions == NULL && errmsg) + *errmsg = errorBuf.data; + else + termPQExpBuffer(&errorBuf); + return connOptions; + } + + /* + * PQconninfodefaultsMerge + * + * Add the default values for any unspecified options to the connection + * options array. + * + * Defaults are obtained from a service file, environment variables, etc. + * + * Returns 1 if successful, otherwise 0; connOptions is freed and errmsg is + * filled in upon failure. Note that failure to locate a default value is + * not an error condition here --- we just leave the option's value as NULL. + * + * If errmsg isn't NULL, *errmsg is set to NULL on success, or a malloc'd + * string on failure (use PQfreemem to free it). In out-of-memory conditions + * both *errmsg and the result could be NULL. + */ + int + PQconninfodefaultsMerge(PQconninfoOption *connOptions, char **errmsg) + { + PQExpBufferData errorBuf; + + if (errmsg) + *errmsg = NULL; + initPQExpBuffer(&errorBuf); + if (PQExpBufferDataBroken(errorBuf)) + { + PQconninfoFree(connOptions); + return 0; + } + if (!conninfo_add_defaults(connOptions, &errorBuf)) + { + if (errmsg) + *errmsg = errorBuf.data; + PQconninfoFree(connOptions); + return 0; + } + termPQExpBuffer(&errorBuf); + return 1; + } + + /* * Build a working copy of the constant PQconninfoOptions array. */ static PQconninfoOption * *** a/src/interfaces/libpq/libpq-fe.h --- b/src/interfaces/libpq/libpq-fe.h *************** *** 267,276 **** extern PQconninfoOption *PQconndefaults(void); /* parse connection options in same way as PQconnectdb */ extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); /* return the connection options used by a live connection */ extern PQconninfoOption *PQconninfo(PGconn *conn); ! /* free the data structure returned by PQconndefaults() or PQconninfoParse() */ extern void PQconninfoFree(PQconninfoOption *connOptions); /* --- 267,284 ---- /* parse connection options in same way as PQconnectdb */ extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg); + /* parse connection options in same way as PQconnectdbParams */ + extern PQconninfoOption *PQconninfoParseParams(const char *const * keywords, + const char *const * values, int expand_dbname, + char **errmsg); + + /* Merge default connection options into an existing PQconninfoOption struct */ + extern int PQconninfodefaultsMerge(PQconninfoOption *connOptions, char **errmsg); + /* return the connection options used by a live connection */ extern PQconninfoOption *PQconninfo(PGconn *conn); ! /* free the data structure returned by PQconndefaults(), PQconninfoParse(), or PQconninfoParseParams() */ extern void PQconninfoFree(PQconninfoOption *connOptions); /*