diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 15bbd7a7f6a..bf29cb98f8e 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -766,23 +766,31 @@ testdb=> - \connect (or \c) [ dbname [ username ] [ host ] [ port ] ] + \connect (or \c) [ dbname [ username ] [ host ] [ port ] ] | conninfo Establishes a new connection to a PostgreSQL - server. If the new connection is successfully made, the - previous connection is closed. If any of dbname, username, host or port are omitted or specified - as -, the value of that parameter from the - previous connection is used. If there is no previous - connection, the libpq default for - the parameter's value is used. + server. The connection parameters to use can be specified either + using a positional syntax, or using conninfo connection + strings as detailed in . + When using positional parameters, if any of + dbname, + username, + host or + port are omitted or + specified as -, the value of that parameter from + the previous connection is used; if there is no previous connection, + the libpq default for the parameter's value + is used. When using conninfo strings, no values from the + previous connection are used for the new connection. + + + + If the new connection is successfully made, the previous + connection is closed. If the connection attempt failed (wrong user name, access denied, etc.), the previous connection will only be kept if psql is in interactive mode. When @@ -792,6 +800,15 @@ testdb=> mechanism that scripts are not accidentally acting on the wrong database on the other hand. + + + Examples: + + +=> \c mydb myuser host.dom 6432 +=> \c service=foo +=> \c "host=localhost port=5432 dbname=mydb connect_timeout=10 sslmode=disable" + diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index d2967edaa0a..cd4309c4655 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1240,9 +1240,10 @@ do_connect(char *dbname, char *user, char *host, char *port) PGconn *o_conn = pset.db, *n_conn; char *password = NULL; + bool keep_password; + bool has_connection_string; - if (!dbname) - dbname = PQdb(o_conn); + /* grab values from the old connection, unless supplied by caller */ if (!user) user = PQuser(o_conn); if (!host) @@ -1250,6 +1251,27 @@ do_connect(char *dbname, char *user, char *host, char *port) if (!port) port = PQport(o_conn); + has_connection_string = + dbname ? recognized_connection_string(dbname) : false; + + /* + * Any change in the parameters read above makes us discard the password. + * We also discard it if we're to use a conninfo rather than the positional + * syntax. + */ + keep_password = + ((strcmp(user, PQuser(o_conn)) == 0) && + (!host || strcmp(host, PQhost(o_conn)) == 0) && + (strcmp(port, PQport(o_conn)) == 0) && + !has_connection_string); + + /* + * Grab dbname from old connection unless supplied by caller. No password + * discard if this changes: passwords aren't (usually) database-specific. + */ + if (!dbname) + dbname = PQdb(o_conn); + /* * If the user asked to be prompted for a password, ask for one now. If * not, use the password from the old connection, provided the username @@ -1264,7 +1286,7 @@ do_connect(char *dbname, char *user, char *host, char *port) { password = prompt_for_password(user); } - else if (o_conn && user && strcmp(PQuser(o_conn), user) == 0) + else if (o_conn && keep_password) { password = strdup(PQpass(o_conn)); } @@ -1274,21 +1296,28 @@ do_connect(char *dbname, char *user, char *host, char *port) #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)); + int paramnum = 0; - 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; + keywords[0] = "dbname"; + values[0] = dbname; + + if (!has_connection_string) + { + keywords[++paramnum] = "host"; + values[paramnum] = host; + keywords[++paramnum] = "port"; + values[paramnum] = port; + keywords[++paramnum] = "user"; + values[paramnum] = user; + } + keywords[++paramnum] = "password"; + values[paramnum] = password; + keywords[++paramnum] = "fallback_application_name"; + values[paramnum] = pset.progname; + + /* add array terminator */ + keywords[++paramnum] = NULL; + values[paramnum] = NULL; n_conn = PQconnectdbParams(keywords, values, true); diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 5013ad36dfd..b0049b59c7f 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -1574,3 +1574,15 @@ expand_tilde(char **filename) return *filename; } + +/* + * Recognized connection string contains a "=" in it. + * + * Must be consistent with conninfo_parse: anything for which this returns true + * should at least look like it's parseable by that routine. + */ +bool +recognized_connection_string(const char *connstr) +{ + return strchr(connstr, '=') != NULL; +} diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h index 838a5526bd1..155771c57cf 100644 --- a/src/bin/psql/common.h +++ b/src/bin/psql/common.h @@ -63,4 +63,6 @@ extern const char *session_username(void); extern char *expand_tilde(char **filename); +extern bool recognized_connection_string(const char *connstr); + #endif /* COMMON_H */ diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index c31d3d6b416..5c7bba11a18 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -249,8 +249,8 @@ slashUsage(unsigned short int pager) fprintf(output, "\n"); fprintf(output, _("Connection\n")); - fprintf(output, _(" \\c[onnect] [DBNAME|- USER|- HOST|- PORT|-]\n" - " connect to new database (currently \"%s\")\n"), + fprintf(output, _(" \\c[onnect] {[DBNAME|- USER|- HOST|- PORT|-] | conninfo}\n" + " connect to new database (currently \"%s\")\n"), currdb); fprintf(output, _(" \\encoding [ENCODING] show or set client encoding\n")); fprintf(output, _(" \\password [USERNAME] securely change the password for a user\n")); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index feeb76f0655..f860e452ddd 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2451,8 +2451,10 @@ psql_completion(char *text, int start, int end) /* Backslash commands */ /* TODO: \dc \dd \dl */ else if (strcmp(prev_wd, "\\connect") == 0 || strcmp(prev_wd, "\\c") == 0) - COMPLETE_WITH_QUERY(Query_for_list_of_databases); - + { + if (!recognized_connection_string(text)) + COMPLETE_WITH_QUERY(Query_for_list_of_databases); + } else if (strncmp(prev_wd, "\\da", strlen("\\da")) == 0) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL); else if (strncmp(prev_wd, "\\db", strlen("\\db")) == 0)