📄 copy.c
字号:
for (;;) { token = strtokx(NULL, whitespace, ",", "\"", 0, false, pset.encoding); if (!token || strchr(",", token[0])) goto error; if (!result->force_notnull_list) result->force_notnull_list = pg_strdup(token); else xstrcat(&result->force_notnull_list, token); token = strtokx(NULL, whitespace, ",", "\"", 0, false, pset.encoding); if (!token || token[0] != ',') break; xstrcat(&result->force_notnull_list, token); } } else goto error; } else goto error; if (fetch_next) token = strtokx(NULL, whitespace, NULL, NULL, 0, false, pset.encoding); } } free(line); return result;error: if (token) psql_error("\\copy: parse error at \"%s\"\n", token); else psql_error("\\copy: parse error at end of line\n"); free_copy_options(result); free(line); return NULL;}/* * Execute a \copy command (frontend copy). We have to open a file, then * submit a COPY query to the backend and either feed it data from the * file or route its response into the file. */booldo_copy(const char *args){ PQExpBufferData query; FILE *copystream; struct copy_options *options; PGresult *result; bool success; struct stat st; /* parse options */ options = parse_slash_copy(args); if (!options) return false; initPQExpBuffer(&query); printfPQExpBuffer(&query, "COPY "); if (options->binary) appendPQExpBuffer(&query, "BINARY "); appendPQExpBuffer(&query, "%s ", options->table); if (options->column_list) appendPQExpBuffer(&query, "%s ", options->column_list); /* Uses old COPY syntax for backward compatibility 2002-06-19 */ if (options->oids) appendPQExpBuffer(&query, "WITH OIDS "); if (options->from) appendPQExpBuffer(&query, "FROM STDIN"); else appendPQExpBuffer(&query, "TO STDOUT"); /* Uses old COPY syntax for backward compatibility 2002-06-19 */ if (options->delim) { if (options->delim[0] == '\'') appendPQExpBuffer(&query, " USING DELIMITERS %s", options->delim); else appendPQExpBuffer(&query, " USING DELIMITERS '%s'", options->delim); } /* There is no backward-compatible CSV syntax */ if (options->null) { if (options->null[0] == '\'') appendPQExpBuffer(&query, " WITH NULL AS %s", options->null); else appendPQExpBuffer(&query, " WITH NULL AS '%s'", options->null); } if (options->csv_mode) appendPQExpBuffer(&query, " CSV"); if (options->header) appendPQExpBuffer(&query, " HEADER"); if (options->quote) { if (options->quote[0] == '\'') appendPQExpBuffer(&query, " QUOTE AS %s", options->quote); else appendPQExpBuffer(&query, " QUOTE AS '%s'", options->quote); } if (options->escape) { if (options->escape[0] == '\'') appendPQExpBuffer(&query, " ESCAPE AS %s", options->escape); else appendPQExpBuffer(&query, " ESCAPE AS '%s'", options->escape); } if (options->force_quote_list) appendPQExpBuffer(&query, " FORCE QUOTE %s", options->force_quote_list); if (options->force_notnull_list) appendPQExpBuffer(&query, " FORCE NOT NULL %s", options->force_notnull_list); if (options->file) canonicalize_path(options->file); if (options->from) { if (options->file) copystream = fopen(options->file, PG_BINARY_R); else if (!options->psql_inout) copystream = pset.cur_cmd_source; else copystream = stdin; } else { if (options->file) copystream = fopen(options->file, "w"); else if (!options->psql_inout) copystream = pset.queryFout; else copystream = stdout; } if (!copystream) { psql_error("%s: %s\n", options->file, strerror(errno)); free_copy_options(options); return false; } /* make sure the specified file is not a directory */ fstat(fileno(copystream), &st); if (S_ISDIR(st.st_mode)) { fclose(copystream); psql_error("%s: cannot copy from/to a directory\n", options->file); free_copy_options(options); return false; } result = PSQLexec(query.data, true); termPQExpBuffer(&query); switch (PQresultStatus(result)) { case PGRES_COPY_OUT: success = handleCopyOut(pset.db, copystream); break; case PGRES_COPY_IN: success = handleCopyIn(pset.db, copystream); break; case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: case PGRES_BAD_RESPONSE: success = false; psql_error("\\copy: %s", PQerrorMessage(pset.db)); break; default: success = false; psql_error("\\copy: unexpected response (%d)\n", PQresultStatus(result)); } PQclear(result); if (options->file != NULL) { if (fclose(copystream) != 0) { psql_error("%s: %s\n", options->file, strerror(errno)); success = false; } } free_copy_options(options); return success;}#define COPYBUFSIZ 8192 /* size doesn't matter *//* * handleCopyOut * receives data as a result of a COPY ... TO stdout command * * If you want to use COPY TO in your application, this is the code to steal :) * * conn should be a database connection that you just called COPY TO on * (and which gave you PGRES_COPY_OUT back); * copystream is the file stream you want the output to go to */boolhandleCopyOut(PGconn *conn, FILE *copystream){ bool copydone = false; /* haven't started yet */ char copybuf[COPYBUFSIZ]; int ret; while (!copydone) { ret = PQgetline(conn, copybuf, COPYBUFSIZ); if (copybuf[0] == '\\' && copybuf[1] == '.' && copybuf[2] == '\0') { copydone = true; /* we're at the end */ } else { fputs(copybuf, copystream); switch (ret) { case EOF: copydone = true; /* FALLTHROUGH */ case 0: fputc('\n', copystream); break; case 1: break; } } } fflush(copystream); ret = !PQendcopy(conn); ResetCancelConn(); return ret;}/* * handleCopyIn * receives data as a result of a COPY ... FROM stdin command * * Again, if you want to use COPY FROM in your application, copy this. * * conn should be a database connection that you just called COPY FROM on * (and which gave you PGRES_COPY_IN back); * copystream is the file stream you want the input to come from */boolhandleCopyIn(PGconn *conn, FILE *copystream){ const char *prompt; bool copydone = false; bool firstload; bool linedone; bool saw_cr = false; char copybuf[COPYBUFSIZ]; char *s; int bufleft; int c = 0; int ret; unsigned int linecount = 0; /* Prompt if interactive input */ if (isatty(fileno(copystream))) { if (!QUIET()) puts(_("Enter data to be copied followed by a newline.\n" "End with a backslash and a period on a line by itself.")); prompt = get_prompt(PROMPT_COPY); } else prompt = NULL; while (!copydone) { /* for each input line ... */ if (prompt) { fputs(prompt, stdout); fflush(stdout); } firstload = true; linedone = false; while (!linedone) { /* for each bufferload in line ... */ /* Fetch string until \n, EOF, or buffer full */ s = copybuf; for (bufleft = COPYBUFSIZ - 1; bufleft > 0; bufleft--) { c = getc(copystream); if (c == EOF) { linedone = true; break; } *s++ = c; if (c == '\n') { linedone = true; break; } if (c == '\r') saw_cr = true; } *s = '\0'; /* EOF with empty line-so-far? */ if (c == EOF && s == copybuf && firstload) { /* * We are guessing a little bit as to the right line-ending * here... */ if (saw_cr) PQputline(conn, "\\.\r\n"); else PQputline(conn, "\\.\n"); copydone = true; if (pset.cur_cmd_interactive) puts("\\."); break; } /* No, so pass the data to the backend */ PQputline(conn, copybuf); /* Check for line consisting only of \. */ if (firstload) { if (strcmp(copybuf, "\\.\n") == 0 || strcmp(copybuf, "\\.\r\n") == 0) { copydone = true; break; } firstload = false; } } linecount++; } ret = !PQendcopy(conn); pset.lineno += linecount; return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -