📄 psql.c
字号:
else printf("Copy failed.\n"); } } }}static voiddo_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset){ if (!new_dbname) fprintf(stderr, "\\connect must be followed by a database name\n"); else if (new_user != NULL && pset->getPassword) fprintf(stderr, "You can't specify a username when using passwords.\n"); else { PGconn *olddb = pset->db; const char *dbparam; const char *userparam; const char *pwparam; if (strcmp(new_dbname, "-") != 0) dbparam = new_dbname; else dbparam = PQdb(olddb); if (new_user != NULL && strcmp(new_user, "-") != 0) userparam = new_user; else userparam = PQuser(olddb); /* FIXME: if changing user, ought to prompt for a new password? */ pwparam = PQpass(olddb);#ifdef MULTIBYTE /* * PGCLIENTENCODING may be set by the previous connection. if a * user does not explicitly set PGCLIENTENCODING, we should * discard PGCLIENTENCODING so that libpq could get the backend * encoding as the default PGCLIENTENCODING value. -- 1998/12/12 * Tatsuo Ishii */ if (!has_client_encoding) { static const char ev[] = "PGCLIENTENCODING="; putenv(ev); }#endif pset->db = PQsetdbLogin(PQhost(olddb), PQport(olddb), NULL, NULL, dbparam, userparam, pwparam); if (!pset->quiet) { if (!new_user) printf("connecting to new database: %s\n", dbparam); else if (dbparam != new_dbname) printf("connecting as new user: %s\n", new_user); else printf("connecting to new database: %s as user: %s\n", dbparam, new_user); } if (PQstatus(pset->db) == CONNECTION_BAD) { fprintf(stderr, "%s\n", PQerrorMessage(pset->db)); fprintf(stderr, "Could not connect to new database. exiting\n"); exit(2); } else { cancelConn = pset->db; /* redirect sigint's loving * attentions */ PQfinish(olddb); free(pset->prompt); pset->prompt = malloc(strlen(PQdb(pset->db)) + 10); sprintf(pset->prompt, "%s%s", PQdb(pset->db), PROMPT); } }}static voiddo_edit(const char *filename_arg, char *query, int *status_p){ int fd; char tmp[64]; char *fname; int cc; const int ql = strlen(query); bool error; if (filename_arg) { fname = (char *) filename_arg; error = false; } else {#ifndef WIN32 sprintf(tmp, "/tmp/psql.%ld.%ld", (long) geteuid(), (long) getpid());#else GetTempFileName(".", "psql", 0, tmp);#endif fname = tmp; unlink(tmp); if (ql > 0) { if ((fd = open(tmp, O_EXCL | O_CREAT | O_WRONLY, 0600)) == -1) { perror(tmp); error = true; } else { if (query[ql - 1] != '\n') strcat(query, "\n"); if (write(fd, query, ql) != ql) { perror(tmp); close(fd); unlink(tmp); error = true; } else error = false; close(fd); } } else error = false; } if (error) *status_p = CMD_SKIP_LINE; else { editFile(fname); if ((fd = open(fname, O_RDONLY, 0)) == -1) { perror(fname); if (!filename_arg) unlink(fname); *status_p = CMD_SKIP_LINE; } else { if ((cc = read(fd, query, MAX_QUERY_BUFFER)) == -1) { perror(fname); close(fd); if (!filename_arg) unlink(fname); *status_p = CMD_SKIP_LINE; } else { query[cc] = '\0'; close(fd); if (!filename_arg) unlink(fname); rightTrim(query); *status_p = CMD_NEWEDIT; } } }}static voiddo_help(PsqlSettings *pset, const char *topic){ if (!topic) { char left_center_right; /* Which column we're displaying */ int i; /* Index into QL_HELP[] */ printf("type \\h <cmd> where <cmd> is one of the following:\n"); left_center_right = 'L';/* Start with left column */ i = 0; while (QL_HELP[i].cmd != NULL) { switch (left_center_right) { case 'L': printf(" %-25s", QL_HELP[i].cmd); left_center_right = 'C'; break; case 'C': printf("%-25s", QL_HELP[i].cmd); left_center_right = 'R'; break; case 'R': printf("%-25s\n", QL_HELP[i].cmd); left_center_right = 'L'; break; } i++; } if (left_center_right != 'L') puts("\n"); printf("type \\h * for a complete description of all commands\n"); } else { int i; /* Index into QL_HELP[] */ bool help_found; /* We found the help he asked for */ int usePipe = 0; char *pagerenv; FILE *fout; if (strcmp(topic, "*") == 0 && (pset->notty == 0) && (pagerenv = getenv("PAGER")) && (pagerenv[0] != '\0') && (fout = popen(pagerenv, "w"))) { usePipe = 1; pqsignal(SIGPIPE, SIG_IGN); } else fout = stdout; help_found = false; /* Haven't found it yet */ for (i = 0; QL_HELP[i].cmd; i++) { if (strcasecmp(QL_HELP[i].cmd, topic) == 0 || strcmp(topic, "*") == 0) { help_found = true; fprintf(fout, "Command: %s\n", QL_HELP[i].cmd); fprintf(fout, "Description: %s\n", QL_HELP[i].help); fprintf(fout, "Syntax:\n"); fprintf(fout, "%s\n", QL_HELP[i].syntax); fprintf(fout, "\n"); } } if (usePipe) { pclose(fout); pqsignal(SIGPIPE, SIG_DFL); } if (!help_found) fprintf(stderr, "command not found, " "try \\h with no arguments to see available help\n"); }}static voiddo_shell(const char *command){ if (!command) { char *sys; char *shellName; shellName = getenv("SHELL"); if (shellName == NULL) shellName = DEFAULT_SHELL; sys = malloc(strlen(shellName) + 16); if (!sys) { perror("malloc"); exit(1); } sprintf(sys, "exec %s", shellName); system(sys); free(sys); } else system(command);}/* * HandleSlashCmds: * * Handles all the different commands that start with \ * db_ptr is a pointer to the TgDb* structure line is the current input * line prompt_ptr is a pointer to the prompt string, a pointer is used * because the prompt can be used with a connection to a new database. * Returns a status: * 0 - send currently constructed query to backend (i.e. we got a \g) * 1 - skip processing of this line, continue building up query * 2 - terminate processing of this query entirely * 3 - new query supplied by edit */static intHandleSlashCmds(PsqlSettings *pset, char *line, char *query){ int status = CMD_SKIP_LINE; char *optarg; bool success; /* * Pointer inside the <cmd> string to the argument of the slash * command, assuming it is a one-character slash command. If it's not * a one-character command, this is meaningless. */ char *optarg2; /* * Pointer inside the <cmd> string to the argument of the slash * command assuming it's not a one-character command. If it's a * one-character command, this is meaningless. */ char *cmd; /* * String: value of the slash command, less the slash and with escape * sequences decoded. */ int blank_loc; /* Offset within <cmd> of first blank */ cmd = malloc(strlen(line)); /* unescaping better not make string grow. */ unescape(cmd, line + 1); /* sets cmd string */ if (strlen(cmd) >= 1 && cmd[strlen(cmd) - 1] == ';') /* strip trailing ; */ cmd[strlen(cmd) - 1] = '\0'; /* * Originally, there were just single character commands. Now, we * define some longer, friendly commands, but we have to keep the old * single character commands too. \c used to be what \connect is now. * Complicating matters is the fact that with the single-character * commands, you can start the argument right after the single * character, so "\copy" would mean "connect to database named 'opy'". */ if (strlen(cmd) > 1) optarg = cmd + 1 + strspn(cmd + 1, " \t"); else optarg = NULL; blank_loc = strcspn(cmd, " \t"); if (blank_loc == 0 || !cmd[blank_loc]) optarg2 = NULL; else optarg2 = cmd + blank_loc + strspn(cmd + blank_loc, " \t"); switch (cmd[0]) { case 'a': /* toggles to align fields on output */ toggle(pset, &pset->opt.align, "field alignment"); break; case 'C': /* define new caption */ if (pset->opt.caption) { free(pset->opt.caption); pset->opt.caption = NULL; } if (optarg && !(pset->opt.caption = strdup(optarg))) { perror("malloc"); exit(CMD_TERMINATE); } break; case 'c': { if (strncmp(cmd, "copy ", strlen("copy ")) == 0 || strncmp(cmd, "copy ", strlen("copy ")) == 0) do_copy(optarg2, pset); else if (strcmp(cmd, "copy") == 0) { fprintf(stderr, "See \\? for help\n"); break; } else if (strncmp(cmd, "connect ", strlen("connect ")) == 0 || strcmp(cmd, "connect") == 0 /* issue error message */ ) { char *optarg3 = NULL; int blank_loc2; if (optarg2) { blank_loc2 = strcspn(optarg2, " \t"); if (blank_loc2 == 0 || *(optarg2 + blank_loc2) == '\0') optarg3 = NULL; else { optarg3 = optarg2 + blank_loc2 + strspn(optarg2 + blank_loc2, " \t"); *(optarg2 + blank_loc2) = '\0'; } } do_connect(optarg2, optarg3, pset); } else { char *optarg3 = NULL; int blank_loc2; if (optarg) { blank_loc2 = strcspn(optarg, " \t"); if (blank_loc2 == 0 || *(optarg + blank_loc2) == '\0') optarg3 = NULL; else { optarg3 = optarg + blank_loc2 + strspn(optarg + blank_loc2, " \t"); *(optarg + blank_loc2) = '\0'; } } do_connect(optarg, optarg3, pset); } } break; case 'd': /* \d describe database information */ /* * if the optarg2 name is surrounded by double-quotes, then * don't convert case */ if (optarg2) { if (*optarg2 == '"') { optarg2++; if (*(optarg2 + strlen(optarg2) - 1) == '"') *(optarg2 + strlen(optarg2) - 1) = '\0'; } else { int i;#ifdef MULTIBYTE for (i = 0; optarg2[i]; i += PQmblen(optarg2 + i))#else for (i = 0; optarg2[i]; i++)#endif if (isupper(optarg2[i])) optarg2[i] = tolower(optarg2[i]); } }#ifdef TIOCGWINSZ if (pset->notty == 0 && (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || screen_size.ws_col == 0 || screen_size.ws_row == 0)) {#endif screen_size.ws_row = 24; screen_size.ws_col = 80;#ifdef TIOCGWINSZ }#endif if (strncmp(cmd, "da", 2) == 0) { char descbuf[4096]; /* aggregates */ descbuf[0] = '\0'; strcat(descbuf, "SELECT a.aggname AS aggname, "); strcat(descbuf, " t.typname AS type, "); strcat(descbuf, " obj_description(a.oid) as description "); strcat(descbuf, "FROM pg_aggregate a, pg_type t "); strcat(descbuf, "WHERE a.aggbasetype = t.oid "); if (optarg2) { strcat(descbuf, "AND a.aggname ~ '^"); strcat(descbuf, optarg2); strcat(descbuf, "' "); } strcat(descbuf, "UNION "); strcat(descbuf, "SELECT a.aggname AS aggname, "); strcat(descbuf, " 'all types' as type, "); strcat(descbuf, " obj_description(a.oid) as description "); strcat(descbuf, "FROM pg_aggregate a "); strcat(descbuf, "WHERE a.aggbasetype = 0 "); if (optarg2) { strcat(descbuf, "AND a.aggname ~ '^"); strcat(descbuf, optarg2); strcat(descbuf, "' "); } strcat(descbuf, "ORDER BY aggname, type;"); success = SendQuery(pset, descbuf, NULL, NULL); } else if (strncmp(cmd, "dd", 2) == 0) /* descriptions */ objectDescription(pset, optarg + 1); else if (strncmp(cmd, "df", 2) == 0) { char descbuf[4096]; /* functions/procedures */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -