Index: src/bin/psql/command.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/bin/psql/command.c,v retrieving revision 1.164 diff -c -r1.164 command.c *** src/bin/psql/command.c 5 Mar 2006 15:58:51 -0000 1.164 --- src/bin/psql/command.c 12 Mar 2006 17:42:10 -0000 *************** *** 188,215 **** free(opt); } ! /*---------- ! * \c or \connect -- connect to new database or as different user, ! * and/or new host and/or port * ! * \c foo bar [-] [-] connect to db "foo" as user "bar" on current host and port ! * \c foo [-] [-] [-] connect to db "foo" as current user on current host and port ! * \c - bar [-] [-] connect to current db as user "bar" on current host and port ! * \c - - host.domain.tld [-] connect to default db as default user on host.domain.tld on default port ! * \c - - - 5555 connect to default db as default user on default host at port 5555 ! * \c connect to default db as default user ! *---------- */ else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0) { ! char *opt1, ! *opt2, ! *opt3, ! *opt4; ! char opt1q, ! opt2q, ! opt3q, ! opt4q; /* * Ideally we should treat the arguments as SQL identifiers. But for --- 188,221 ---- free(opt); } ! /* ! * \c or \connect -- connect to database with using specified parameters. ! * ! * \c dbname user host port ! * ! * Place a `-' instead of the related parameter to make it use its current ! * value. (If there doesn't exist any current value for the specified ! * parameter, it won't get included in the connection string.) * ! * Here are some examples: ! * ! * \c - - hst Connect to current database on current port of ! * host "hst" as current user. ! * \c - usr - prt Connect to current database on "prt" port of current ! * host as user "usr". ! * \c dbs Connect to "dbs" database on current port of current ! * host as current user. */ else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0) { ! char *opt1, ! *opt2, ! *opt3, ! *opt4; ! char opt1q, ! opt2q, ! opt3q, ! opt4q; /* * Ideally we should treat the arguments as SQL identifiers. But for *************** *** 220,272 **** * double-quote all mixed-case \connect arguments, and then we can get * rid of OT_SQLIDHACK. */ ! opt1 = psql_scan_slash_option(scan_state, ! OT_SQLIDHACK, &opt1q, true); ! opt2 = psql_scan_slash_option(scan_state, ! OT_SQLIDHACK, &opt2q, true); ! opt3 = psql_scan_slash_option(scan_state, ! OT_SQLIDHACK, &opt3q, true); ! opt4 = psql_scan_slash_option(scan_state, ! OT_SQLIDHACK, &opt4q, true); ! ! if (opt4) ! /* gave port */ ! success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || ! strcmp(opt1, "") == 0) ? "" : opt1, ! !opt2q && (strcmp(opt2, "-") == 0 || ! strcmp(opt2, "") == 0) ? "" : opt2, ! !opt3q && (strcmp(opt3, "-") == 0 || ! strcmp(opt3, "") == 0) ? "" : opt3, ! !opt3q && (strcmp(opt3, "-") == 0 || ! strcmp(opt3, "") == 0) ? "" : opt3); ! if (opt3) ! /* gave host */ ! success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || ! strcmp(opt1, "") == 0) ? "" : opt1, ! !opt2q && (strcmp(opt2, "-") == 0 || ! strcmp(opt2, "") == 0) ? "" : opt2, ! !opt3q && (strcmp(opt3, "-") == 0 || ! strcmp(opt3, "") == 0) ? "" : opt3, ! NULL); ! if (opt2) ! /* gave username */ ! success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || ! strcmp(opt1, "") == 0) ? "" : opt1, ! !opt2q && (strcmp(opt2, "-") == 0 || ! strcmp(opt2, "") == 0) ? "" : opt2, ! NULL, ! NULL); ! else if (opt1) ! /* gave database name */ ! success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || ! strcmp(opt1, "") == 0) ? "" : opt1, ! "", ! NULL, ! NULL); ! else ! /* connect to default db as default user */ ! success = do_connect(NULL, NULL, NULL, NULL); free(opt1); free(opt2); free(opt3); --- 226,250 ---- * double-quote all mixed-case \connect arguments, and then we can get * rid of OT_SQLIDHACK. */ ! #define PARSE_OPT(optq_addr) \ ! psql_scan_slash_option(scan_state, OT_SQLIDHACK, optq_addr, true); + opt1 = PARSE_OPT(&opt1q); + opt2 = PARSE_OPT(&opt2q); + opt3 = PARSE_OPT(&opt3q); + opt4 = PARSE_OPT(&opt4q); + + #define VALIDATE_OPT(oq, o) \ + ((!oq && (*o == '\0' || strcmp(o, "-") == 0)) ? NULL : o) + + #define CHECK_OPT(o, oq) \ + (o ? VALIDATE_OPT(oq, o) : NULL) + + success = do_connect(CHECK_OPT(opt1, opt1q), + CHECK_OPT(opt2, opt2q), + CHECK_OPT(opt3, opt3q), + CHECK_OPT(opt4, opt4q)); + free(opt1); free(opt2); free(opt3); *************** *** 987,1151 **** ! /* do_connect ! * -- handler for \connect * ! * Connects to a database (new_dbname) as a certain user (new_user). ! * The new user can be NULL. A db name of "-" is the same as the old one. ! * (That is, the one currently in pset. But pset.db can also be NULL. A NULL ! * dbname is handled by libpq.) ! * Returns true if all ok, false if the new connection couldn't be established. ! * The old connection will be kept if the session is interactive. */ static bool ! do_connect(const char *new_dbname, const char *new_user, const char *new_host, const char *new_port) { ! PGconn *oldconn = pset.db; ! const char *dbparam = NULL; ! const char *userparam = NULL; ! const char *hostparam = NULL; ! const char *portparam = NULL; ! const char *pwparam = NULL; ! char *password_prompt = NULL; ! char *prompted_password = NULL; ! bool need_pass; ! bool success = false; ! ! /* Delete variables (in case we fail before setting them anew) */ ! UnsyncVariables(); ! ! /* If dbname is "" then use old name, else new one (even if NULL) */ ! if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "") == 0) ! dbparam = PQdb(oldconn); ! else ! dbparam = new_dbname; ! ! /* If user is "" then use the old one */ ! if (new_user && PQuser(oldconn) && strcmp(new_user, "") == 0) ! userparam = PQuser(oldconn); ! else ! userparam = new_user; ! ! /* If host is "" then use the old one */ ! if (new_host && PQhost(oldconn) && strcmp(new_host, "") == 0) ! hostparam = PQhost(oldconn); ! else ! hostparam = new_host; ! ! /* If port is "" then use the old one */ ! if (new_port && PQport(oldconn) && strcmp(new_port, "") == 0) ! portparam = PQport(oldconn); ! else ! portparam = new_port; ! ! if (userparam == NULL) ! password_prompt = strdup("Password: "); ! else ! { ! password_prompt = malloc(strlen(_("Password for user %s: ")) - 2 + ! strlen(userparam) + 1); ! sprintf(password_prompt, _("Password for user %s: "), userparam); ! } ! ! /* need to prompt for password? */ ! if (pset.getPassword) ! pwparam = prompted_password = simple_prompt(password_prompt, 100, false); ! ! /* ! * Use old password (if any) if no new one given and we are reconnecting ! * as same user ! */ ! if (!pwparam && oldconn && PQuser(oldconn) && userparam && ! strcmp(PQuser(oldconn), userparam) == 0) ! pwparam = PQpass(oldconn); ! ! do ! { ! need_pass = false; ! pset.db = PQsetdbLogin(hostparam, portparam, ! NULL, NULL, dbparam, userparam, pwparam); ! ! if (PQstatus(pset.db) == CONNECTION_BAD && ! strcmp(PQerrorMessage(pset.db), PQnoPasswordSupplied) == 0 && ! !feof(stdin)) ! { ! PQfinish(pset.db); ! need_pass = true; ! free(prompted_password); ! prompted_password = NULL; ! pwparam = prompted_password = simple_prompt(password_prompt, 100, false); } ! } while (need_pass); ! ! free(prompted_password); ! free(password_prompt); ! /* ! * If connection failed, try at least keep the old one. That's probably ! * more convenient than just kicking you out of the program. ! */ ! if (!pset.db || PQstatus(pset.db) == CONNECTION_BAD) { if (pset.cur_cmd_interactive) { ! psql_error("%s", PQerrorMessage(pset.db)); ! PQfinish(pset.db); ! if (oldconn) ! { fputs(_("Previous connection kept\n"), stderr); - pset.db = oldconn; - } - else - pset.db = NULL; } else ! { ! /* ! * we don't want unpredictable things to happen in scripting mode ! */ ! psql_error("\\connect: %s", PQerrorMessage(pset.db)); ! PQfinish(pset.db); ! if (oldconn) ! PQfinish(oldconn); ! pset.db = NULL; ! } } ! else { ! if (!QUIET()) { ! if ((hostparam == new_host) && (portparam == new_port)) /* no new host or port */ ! { ! if (userparam != new_user) /* no new user */ ! printf(_("You are now connected to database \"%s\".\n"), dbparam); ! else if (dbparam != new_dbname) /* no new db */ ! printf(_("You are now connected as new user \"%s\".\n"), new_user); ! else ! /* both new */ ! printf(_("You are now connected to database \"%s\" as user \"%s\".\n"), ! PQdb(pset.db), PQuser(pset.db)); ! } ! else /* At least one of host and port are new */ ! { ! printf( ! _("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port %s.\n"), ! PQdb(pset.db), PQuser(pset.db), PQhost(pset.db), ! PQport(pset.db)); ! } ! } ! if (oldconn) ! PQfinish(oldconn); ! ! success = true; } ! PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); ! /* Update variables */ ! SyncVariables(); ! return success; } --- 965,1178 ---- ! /* ! * do_connect -- handler for \connect * ! * 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, related parameter won't get added to ! * connection string. ! * ! * If connection fails with the given parameters, old connection will be kept. */ static bool ! do_connect(const char *n_dbname, const char *n_user, const char *n_host, const char *n_port) { ! PGconn *o_conn = pset.db, ! *n_conn = NULL; ! const char *dbname, ! *user, ! *host, ! *port; ! int sz; ! char *conn_param, *c, ! *pw_prompt = NULL; ! bool done = false; ! ! dbname = (n_dbname ? n_dbname : ((o_conn && PQdb(o_conn)) ? PQdb(o_conn) : NULL)); ! user = (n_user ? n_user : ((o_conn && PQuser(o_conn)) ? PQuser(o_conn) : NULL)); ! host = (n_host ? n_host : ((o_conn && PQhost(o_conn)) ? PQhost(o_conn) : NULL)); ! port = (n_port ? n_port : ((o_conn && PQport(o_conn)) ? PQport(o_conn) : NULL)); ! ! sz = (dbname ? (strlen(dbname) + 8) : 0) /* strlen("dbname= ") = 8 */ ! + (user ? (strlen(user) + 6) : 0) ! + (host ? (strlen(host) + 6) : 0) ! + (port ? (strlen(port) + 6) : 0) ! + 1; ! c = conn_param = malloc(sz); ! if (!c) ! goto OutOfMemory; ! ! /* Form connection parameter string */ ! if (dbname) ! { ! sprintf(c, "dbname=%s ", dbname); ! c += strlen(c); ! } ! if (user) ! { ! sprintf(c, "user=%s ", user); ! c += strlen(c); ! } ! if (host) ! { ! sprintf(c, "host=%s ", host); ! c += strlen(c); ! } ! if (port) ! sprintf(c, "port=%s ", port); ! ! /* First try with these settings without a password */ ! n_conn = PQconnectdb(conn_param); ! if (PQstatus(n_conn) == CONNECTION_OK) ! done = true; ! ! /* Do we need a password? */ ! else if (strcmp(PQerrorMessage(n_conn), PQnoPasswordSupplied) == 0 || ! pset.getPassword) ! { ! bool first = true; ! int n_sz; ! char *password; ! ! /* Free previous failed one */ ! PQfinish(n_conn); ! ! /* First, use password of current connection - if any. */ ! password = ((o_conn && PQpass(o_conn)) ? strdup(PQpass(o_conn)) : NULL); ! ! for (;;) ! { ! /* In the second turn try with prompted password. */ ! if (!first) ! { ! if (!user) ! pw_prompt = strdup("Password: "); ! if (!pw_prompt) ! goto OutOfMemory; ! else ! { ! pw_prompt = malloc(strlen(_("Password for user %s: ")) - 2 ! + strlen(user) + 1); ! if (!pw_prompt) ! goto OutOfMemory; ! sprintf(pw_prompt, _("Password for user %s: "), user); ! } ! ! password = simple_prompt(pw_prompt, 100, false); ! free(pw_prompt); ! if (!password) ! goto OutOfMemory; ! } ! ! /* This is our first turn and we're lacking of old password! */ ! else if (!password) ! continue; ! ! n_sz = sz + 9 + strlen(password); /* strlen("Password=") = 9 */ ! c = realloc(conn_param, n_sz); ! if (!c) ! goto OutOfMemory; ! conn_param = c; ! c = conn_param + sz - 1; ! sprintf(c, "password=%s", password); ! ! /* Password is allocated, not returned from PQpass(). */ ! if (!first) ! free(password); ! ! /* Try again with supplied connection parameter. */ ! n_conn = PQconnectdb(conn_param); ! if (PQstatus(n_conn) == CONNECTION_OK) ! { ! done = true; ! break; ! } ! ! if (first) ! first = false; ! else ! break; } ! } ! /* None of above methods worked, giving up. */ ! if (!done) { if (pset.cur_cmd_interactive) { ! psql_error("%s", PQerrorMessage(n_conn)); ! ! /* Not touching to pset.db */ ! if (o_conn) fputs(_("Previous connection kept\n"), stderr); } else ! psql_error("\\connect: %s", PQerrorMessage(n_conn)); ! ! PQfinish(n_conn); ! free(conn_param); ! ! return false; } ! ! /* Shout new connection. */ ! if (!QUIET()) { ! /* At least one of host and port are new */ ! if ((host && strcmp(host, PQhost(o_conn))) || ! (port && strcmp(port, PQport(o_conn)))) ! printf(_("You are now connected to database \"%s\" as user " ! "\"%s\" on host \"%s\" at port %s.\n"), ! PQdb(n_conn), PQuser(n_conn), PQhost(n_conn), ! PQport(n_conn)); ! ! /* Now new host or port. */ ! else { ! /* Both are new. */ ! if (dbname && strcmp(dbname, PQdb(o_conn)) && ! user && strcmp(user, PQuser(o_conn))) ! printf(_("You are now connected to database \"%s\" as" ! "user \"%s\".\n"), ! PQdb(n_conn), PQuser(n_conn)); ! ! /* Database is new. */ ! else if (dbname && strcmp(dbname, PQdb(o_conn))) ! printf(_("You are now connected to database \"%s\".\n"), ! PQdb(n_conn)); ! ! /* User is new. */ ! else if (user && strcmp(user, PQuser(o_conn))) ! printf(_("You are now connected as new user \"%s\".\n"), ! PQuser(n_conn)); ! /* No parameter changings. Seems like a connection reset. */ ! else ! printf(_("Connection is reseted.\n")); ! } } ! ! /* Replacing old connection structure with the new one. */ ! UnsyncVariables(); ! if (pset.db) ! PQfinish(pset.db); ! pset.db = n_conn; ! SyncVariables(); ! PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); ! return true; ! OutOfMemory: ! psql_error("out of memory\n"); ! ! if (conn_param) ! free(conn_param); ! if (n_conn) ! PQfinish(n_conn); ! ! return false; }