bool pgConn::EndPutCopy(const wxString errormsg) { int result; // Execute the query and get the status if (errormsg.Length() == 0) result = PQputCopyEnd(conn, NULL); else result = PQputCopyEnd(conn, errormsg.mb_str(*conv)); return result == 1; }
static awk_value_t * do_pg_putcopyend(int nargs, awk_value_t *result) { PGconn *conn; awk_value_t emsg; int res; if (do_lint && (nargs > 2)) lintwarn(ext_id, _("pg_putcopyend: called with too many arguments")); if (!(conn = find_handle(conns, 0))) { set_ERRNO(_("pg_putcopyend called with unknown connection handle")); RET_NUM(-1); } if (nargs > 1) { if (!get_argument(1, AWK_STRING, &emsg)) { set_ERRNO(_("pg_putcopyend optional 2nd argument should be a string")); RET_NUM(-1); } } else emsg.str_value.str = NULL; res = PQputCopyEnd(conn, emsg.str_value.str); if (res < 0) /* connection is probably bad */ set_ERRNO(PQerrorMessage(conn)); RET_NUM(res); }
s_object * RS_PostgreSQL_CopyIn(Con_Handle * conHandle, s_object * filename) { S_EVALUATOR RS_DBI_connection * con; PGconn *my_connection; char *dyn_filename; char copybuf[COPY_IN_BUFSIZE]; FILE* filehandle; size_t len; int pqretcode; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; dyn_filename = RS_DBI_copyString(CHR_EL(filename, 0)); filehandle=fopen(dyn_filename, "r"); if(filehandle == NULL){ char errmsg[1024]; snprintf(errmsg, 1024, "could not open file: %s", dyn_filename); RS_DBI_errorMessage(dyn_filename, RS_DBI_ERROR); return S_NULL_ENTRY; } while((len = fread(copybuf,1,COPY_IN_BUFSIZE, filehandle))){ pqretcode = PQputCopyData(my_connection, copybuf, len); chkpqcopydataerr(my_connection, pqretcode); } PQputCopyEnd(my_connection, NULL); fclose(filehandle); free(dyn_filename); return S_NULL_ENTRY; }
void output_gazetteer_t::stop_copy(void) { /* Do we have a copy active? */ if (!copy_active) return; if (buffer.length() > 0) { pgsql_CopyData("place", Connection, buffer); buffer.clear(); } /* Terminate the copy */ if (PQputCopyEnd(Connection, nullptr) != 1) { std::cerr << "COPY_END for place failed: " << PQerrorMessage(Connection) << "\n"; util::exit_nicely(); } /* Check the result */ PGresult *res = PQgetResult(Connection); if (PQresultStatus(res) != PGRES_COMMAND_OK) { std::cerr << "COPY_END for place failed: " << PQerrorMessage(Connection) << "\n"; PQclear(res); util::exit_nicely(); } /* Discard the result */ PQclear(res); /* We no longer have an active copy */ copy_active = false; }
void output_gazetteer_t::stop_copy(void) { PGresult *res; /* Do we have a copy active? */ if (!CopyActive) return; /* Terminate the copy */ if (PQputCopyEnd(Connection, NULL) != 1) { fprintf(stderr, "COPY_END for place failed: %s\n", PQerrorMessage(Connection)); util::exit_nicely(); } /* Check the result */ res = PQgetResult(Connection); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "COPY_END for place failed: %s\n", PQerrorMessage(Connection)); PQclear(res); util::exit_nicely(); } /* Discard the result */ PQclear(res); /* We no longer have an active copy */ CopyActive = 0; return; }
static void stop_error_copy(void) { PGresult *res; /* Do we have a copy active? */ if (!CopyErrorActive) return; /* Terminate the copy */ if (PQputCopyEnd(ConnectionError, NULL) != 1) { fprintf(stderr, "COPY_END for import_polygon_error failed: %s\n", PQerrorMessage(ConnectionError)); exit_nicely(); } /* Check the result */ res = PQgetResult(ConnectionError); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "COPY_END for import_polygon_error failed: %s\n", PQerrorMessage(ConnectionError)); PQclear(res); exit_nicely(); } /* Discard the result */ PQclear(res); /* We no longer have an active copy */ CopyErrorActive = 0; return; }
void finishHim(PGconn *conn) { PGresult *res; if(PQputCopyEnd(conn, NULL)) { //std::cerr << std::endl << "Copy End..." << std::endl; } while((res = PQgetResult(conn)) != NULL) { //std::cerr << "\r" << "Waiting for Copy to finish"; } //std::cerr << "\r" << "Copy finished " << std:: endl; PQendcopy(conn); while((res = PQgetResult(conn)) != NULL) { //std::cerr << "\r" << "Waiting for Server to Sync"; } //std::cerr << "Sync Done" << std:: endl; res = PQexec(conn, "END;"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { std::cerr << "COMMAND END failded: "; std::cerr << PQerrorMessage(conn) << std::endl; PQclear(res); PQfinish(conn); return; } PQfinish(conn); }
VALUE put_end( VALUE self) { struct pgconn_data *c; int r; PGresult *res; Data_Get_Struct( self, struct pgconn_data, c); /* * I would like to hand over something like * RSTRING_PTR( rb_obj_as_string( RB_ERRINFO)) * here but when execution is inside a rescue block * the error info will be non-null even though the * exception just has been caught. */ while ((r = PQputCopyEnd( c->conn, NULL)) == 0) ; if (r < 0) rb_raise( rb_ePgConnCopy, "Copy from stdin failed to finish."); while ((res = PQgetResult( c->conn)) != NULL) pgresult_new( res, c, Qnil, Qnil); return Qnil; }
/* * Terminate a COPY operation during direct-to-DB restore */ void EndDBCopyMode(Archive *AHX, const char *tocEntryTag) { ArchiveHandle *AH = (ArchiveHandle *) AHX; if (AH->pgCopyIn) { PGresult *res; if (PQputCopyEnd(AH->connection, NULL) <= 0) exit_horribly(modulename, "error returned by PQputCopyEnd: %s", PQerrorMessage(AH->connection)); /* Check command status and return to normal libpq state */ res = PQgetResult(AH->connection); if (PQresultStatus(res) != PGRES_COMMAND_OK) warn_or_exit_horribly(AH, modulename, "COPY failed for table \"%s\": %s", tocEntryTag, PQerrorMessage(AH->connection)); PQclear(res); AH->pgCopyIn = false; } }
static PGresult * RemoteLoad(PGconn *conn, FILE *copystream, bool isbinary) { bool OK; char buf[COPYBUFSIZ]; OK = true; if (isbinary) { while (!interrupted) { int buflen; buflen = fread(buf, 1, COPYBUFSIZ, copystream); if (buflen <= 0) break; if (PQputCopyData(conn, buf, buflen) <= 0) { OK = false; break; } } } else { bool copydone = false; while (!interrupted && !copydone) { /* for each input line ... */ bool firstload; bool linedone; firstload = true; linedone = false; while (!linedone) { /* for each bufferload in line ... */ int linelen; char *fgresult; fgresult = fgets(buf, sizeof(buf), copystream); if (!fgresult) { copydone = true; break; } linelen = strlen(buf); /* current line is done? */ if (linelen > 0 && buf[linelen - 1] == '\n') linedone = true; /* check for EOF marker, but not on a partial line */ if (firstload) { if (strcmp(buf, "\\.\n") == 0 || strcmp(buf, "\\.\r\n") == 0) { copydone = true; break; } firstload = false; } if (PQputCopyData(conn, buf, linelen) <= 0) { OK = false; copydone = true; break; } } } } if (interrupted) { PQputCopyEnd(conn, "canceled by user"); return PQgetResult(conn); } /* Check for read error */ if (ferror(copystream)) OK = false; /* Terminate data transfer */ if (PQputCopyEnd(conn, OK ? NULL : "aborted because of read failure") <= 0) OK = false; /* Check command status and return to normal libpq state */ if (!OK) return NULL; return PQgetResult(conn); }
/* * Fetch all changed blocks from remote source data directory. */ void libpq_executeFileMap(filemap_t *map) { file_entry_t *entry; const char *sql; PGresult *res; int i; /* * First create a temporary table, and load it with the blocks that we * need to fetch. */ sql = "CREATE TEMPORARY TABLE fetchchunks(path text, begin int8, len int4);"; res = PQexec(conn, sql); if (PQresultStatus(res) != PGRES_COMMAND_OK) pg_fatal("could not create temporary table: %s", PQresultErrorMessage(res)); PQclear(res); sql = "COPY fetchchunks FROM STDIN"; res = PQexec(conn, sql); if (PQresultStatus(res) != PGRES_COPY_IN) pg_fatal("could not send file list: %s", PQresultErrorMessage(res)); PQclear(res); for (i = 0; i < map->narray; i++) { entry = map->array[i]; /* If this is a relation file, copy the modified blocks */ execute_pagemap(&entry->pagemap, entry->path); switch (entry->action) { case FILE_ACTION_NONE: /* nothing else to do */ break; case FILE_ACTION_COPY: /* Truncate the old file out of the way, if any */ open_target_file(entry->path, true); fetch_file_range(entry->path, 0, entry->newsize); break; case FILE_ACTION_TRUNCATE: truncate_target_file(entry->path, entry->newsize); break; case FILE_ACTION_COPY_TAIL: fetch_file_range(entry->path, entry->oldsize, entry->newsize); break; case FILE_ACTION_REMOVE: remove_target(entry); break; case FILE_ACTION_CREATE: create_target(entry); break; } } if (PQputCopyEnd(conn, NULL) != 1) pg_fatal("could not send end-of-COPY: %s", PQerrorMessage(conn)); while ((res = PQgetResult(conn)) != NULL) { if (PQresultStatus(res) != PGRES_COMMAND_OK) pg_fatal("unexpected result while sending file list: %s", PQresultErrorMessage(res)); PQclear(res); } /* * We've now copied the list of file ranges that we need to fetch to the * temporary table. Now, actually fetch all of those ranges. */ sql = "SELECT path, begin, \n" " pg_read_binary_file(path, begin, len, true) AS chunk\n" "FROM fetchchunks\n"; receiveFileChunks(sql); }
bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary) { bool OK; const char* prompt; char buf[COPYBUFSIZ]; PGresult* res; /* * Establish longjmp destination for exiting from wait-for-input. (This is * only effective while sigint_interrupt_enabled is TRUE.) */ if (sigsetjmp(sigint_interrupt_jmp, 1) != 0) { /* got here with longjmp */ /* Terminate data transfer */ PQputCopyEnd(conn, _("canceled by user")); /* Check command status and return to normal libpq state */ res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_COMMAND_OK) psql_error("%s", PQerrorMessage(conn)); PQclear(res); return false; } /* Prompt if interactive input */ if (isatty(fileno(copystream))) { if (!pset.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; } OK = true; if (isbinary) { /* interactive input probably silly, but give one prompt anyway */ if (prompt) { fputs(prompt, stdout); fflush(stdout); } for (;;) { int buflen; /* enable longjmp while waiting for input */ sigint_interrupt_enabled = true; buflen = fread(buf, 1, COPYBUFSIZ, copystream); sigint_interrupt_enabled = false; if (buflen <= 0) break; if (PQputCopyData(conn, buf, buflen) <= 0) { OK = false; break; } } } else { bool copydone = false; while (!copydone) { /* for each input line ... */ bool firstload; bool linedone; if (prompt) { fputs(prompt, stdout); fflush(stdout); } firstload = true; linedone = false; while (!linedone) { /* for each bufferload in line ... */ int linelen; char* fgresult; /* enable longjmp while waiting for input */ sigint_interrupt_enabled = true; fgresult = fgets(buf, sizeof(buf), copystream); sigint_interrupt_enabled = false; if (!fgresult) { copydone = true; break; } linelen = strlen(buf); /* current line is done? */ if (linelen > 0 && buf[linelen - 1] == '\n') linedone = true; /* check for EOF marker, but not on a partial line */ if (firstload) { if (strcmp(buf, "\\.\n") == 0 || strcmp(buf, "\\.\r\n") == 0) { copydone = true; break; } firstload = false; } if (PQputCopyData(conn, buf, linelen) <= 0) { OK = false; copydone = true; break; } } if (copystream == pset.cur_cmd_source) pset.lineno++; } } /* Check for read error */ if (ferror(copystream)) OK = false; /* Terminate data transfer */ if (PQputCopyEnd(conn, OK ? NULL : _("aborted because of read failure")) <= 0) OK = false; /* Check command status and return to normal libpq state */ res = PQgetResult(conn); if (PQresultStatus(res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } PQclear(res); return OK; }
/* * 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. */ bool do_copy(const char *args) { struct pqbuf 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; /* prepare to read or write the target file */ 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, PG_BINARY_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; } /* build the command we will send to the backend */ init_pqbuf(&query); print_pqbuf(&query, "COPY "); append_pqbuf_str(&query, options->before_tofrom); if (options->from) append_pqbuf(&query, " FROM STDIN "); else append_pqbuf(&query, " TO STDOUT "); if (options->after_tofrom) append_pqbuf_str(&query, options->after_tofrom); result = PSQLexec(query.data, true); term_pqbuf(&query); switch (PQresultStatus(result)) { case PGRES_COPY_OUT: SetCancelConn(); success = handleCopyOut(pset.db, copystream); ResetCancelConn(); break; case PGRES_COPY_IN: SetCancelConn(); success = handleCopyIn(pset.db, copystream, PQbinaryTuples(result)); ResetCancelConn(); 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)); break; } PQclear(result); /* * Make sure we have pumped libpq dry of results; else it may still be in * ASYNC_BUSY state, leading to false readings in, eg, get_prompt(). */ while ((result = PQgetResult(pset.db)) != NULL) { success = false; psql_error("\\copy: unexpected response (%d)\n", PQresultStatus(result)); /* if still in COPY IN state, try to get out of it */ if (PQresultStatus(result) == PGRES_COPY_IN) PQputCopyEnd(pset.db, _("trying to exit copy mode")); 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; }
void PG_cache_purge(struct db_cache *queue[], int index, struct insert_data *idata) { PGresult *ret; struct logfile lf; struct db_cache **reprocess_queries_queue, **bulk_reprocess_queries_queue; char orig_insert_clause[LONGSRVBUFLEN], orig_update_clause[LONGSRVBUFLEN], orig_lock_clause[LONGSRVBUFLEN]; char orig_copy_clause[LONGSRVBUFLEN], tmpbuf[LONGLONGSRVBUFLEN], tmptable[SRVBUFLEN]; time_t start; int j, r, reprocess = 0, stop, go_to_pending, reprocess_idx, bulk_reprocess_idx, saved_index = index; struct primitives_ptrs prim_ptrs; struct pkt_data dummy_data; pid_t writer_pid = getpid(); if (!index) { Log(LOG_INFO, "INFO ( %s/%s ): *** Purging cache - START (PID: %u) ***\n", config.name, config.type, writer_pid); Log(LOG_INFO, "INFO ( %s/%s ): *** Purging cache - END (PID: %u, QN: 0/0, ET: 0) ***\n", config.name, config.type, writer_pid); return; } bed.lf = &lf; memset(&lf, 0, sizeof(struct logfile)); memset(&prim_ptrs, 0, sizeof(prim_ptrs)); memset(&dummy_data, 0, sizeof(dummy_data)); reprocess_queries_queue = (struct db_cache **) malloc(qq_size*sizeof(struct db_cache *)); bulk_reprocess_queries_queue = (struct db_cache **) malloc(qq_size*sizeof(struct db_cache *)); if (!reprocess_queries_queue || !bulk_reprocess_queries_queue) { Log(LOG_ERR, "ERROR ( %s/%s ): malloc() failed (reprocess_queries_queue). Exiting ..\n", config.name, config.type); exit_plugin(1); } for (j = 0, stop = 0; (!stop) && sql_preprocess_funcs[j]; j++) stop = sql_preprocess_funcs[j](queue, &index, j); if (config.what_to_count & COUNT_CLASS) sql_invalidate_shadow_entries(queue, &index); idata->ten = index; Log(LOG_INFO, "INFO ( %s/%s ): *** Purging cache - START (PID: %u) ***\n", config.name, config.type, writer_pid); start = time(NULL); /* re-using pending queries queue stuff from parent and saving clauses */ memcpy(pending_queries_queue, queue, index*sizeof(struct db_cache *)); pqq_ptr = index; strlcpy(orig_copy_clause, copy_clause, LONGSRVBUFLEN); strlcpy(orig_insert_clause, insert_clause, LONGSRVBUFLEN); strlcpy(orig_update_clause, update_clause, LONGSRVBUFLEN); strlcpy(orig_lock_clause, lock_clause, LONGSRVBUFLEN); start: memcpy(queue, pending_queries_queue, pqq_ptr*sizeof(struct db_cache *)); memset(pending_queries_queue, 0, pqq_ptr*sizeof(struct db_cache *)); index = pqq_ptr; pqq_ptr = 0; /* We check for variable substitution in SQL table */ if (idata->dyn_table) { time_t stamp = 0; memset(tmpbuf, 0, LONGLONGSRVBUFLEN); stamp = queue[0]->basetime; prim_ptrs.data = &dummy_data; primptrs_set_all_from_db_cache(&prim_ptrs, queue[0]); strlcpy(idata->dyn_table_name, config.sql_table, SRVBUFLEN); strlcpy(insert_clause, orig_insert_clause, LONGSRVBUFLEN); strlcpy(update_clause, orig_update_clause, LONGSRVBUFLEN); strlcpy(lock_clause, orig_lock_clause, LONGSRVBUFLEN); handle_dynname_internal_strings_same(tmpbuf, LONGSRVBUFLEN, copy_clause, &prim_ptrs); handle_dynname_internal_strings_same(tmpbuf, LONGSRVBUFLEN, insert_clause, &prim_ptrs); handle_dynname_internal_strings_same(tmpbuf, LONGSRVBUFLEN, update_clause, &prim_ptrs); handle_dynname_internal_strings_same(tmpbuf, LONGSRVBUFLEN, lock_clause, &prim_ptrs); handle_dynname_internal_strings_same(tmpbuf, LONGSRVBUFLEN, idata->dyn_table_name, &prim_ptrs); strftime_same(copy_clause, LONGSRVBUFLEN, tmpbuf, &stamp); strftime_same(insert_clause, LONGSRVBUFLEN, tmpbuf, &stamp); strftime_same(update_clause, LONGSRVBUFLEN, tmpbuf, &stamp); strftime_same(lock_clause, LONGSRVBUFLEN, tmpbuf, &stamp); strftime_same(idata->dyn_table_name, LONGSRVBUFLEN, tmpbuf, &stamp); if (config.sql_table_schema) sql_create_table(bed.p, &stamp, &prim_ptrs); } /* beginning DB transaction */ (*sqlfunc_cbr.lock)(bed.p); /* for each element of the queue to be processed we execute sql_query(); the function returns a non-zero value if DB has failed; then we use reprocess_queries_queue and bulk_reprocess_queries_queue to handle reprocessing of specific elements or bulk queue (of elements not being held in a pending_queries_queue) due to final COMMIT failure */ memset(reprocess_queries_queue, 0, qq_size*sizeof(struct db_cache *)); memset(bulk_reprocess_queries_queue, 0, qq_size*sizeof(struct db_cache *)); reprocess_idx = 0; bulk_reprocess_idx = 0; for (j = 0; j < index; j++) { go_to_pending = FALSE; if (idata->dyn_table) { time_t stamp = 0; memset(tmpbuf, 0, LONGLONGSRVBUFLEN); // XXX: pedantic? stamp = queue[idata->current_queue_elem]->basetime; strlcpy(tmptable, config.sql_table, SRVBUFLEN); prim_ptrs.data = &dummy_data; primptrs_set_all_from_db_cache(&prim_ptrs, queue[idata->current_queue_elem]); handle_dynname_internal_strings_same(tmpbuf, LONGSRVBUFLEN, tmptable, &prim_ptrs); strftime_same(tmptable, LONGSRVBUFLEN, tmpbuf, &stamp); if (strncmp(idata->dyn_table_name, tmptable, SRVBUFLEN)) { pending_queries_queue[pqq_ptr] = queue[idata->current_queue_elem]; pqq_ptr++; go_to_pending = TRUE; } } if (!go_to_pending) { if (queue[j]->valid) { r = sql_query(&bed, queue[j], idata); /* note down all elements in case of a reprocess due to COMMIT failure */ bulk_reprocess_queries_queue[bulk_reprocess_idx] = queue[j]; bulk_reprocess_idx++; } else r = FALSE; /* not valid elements are marked as not to be reprocessed */ if (r) { reprocess_queries_queue[reprocess_idx] = queue[j]; reprocess_idx++; if (!reprocess) sql_db_fail(&p); reprocess = REPROCESS_SPECIFIC; } } } /* Finalizing DB transaction */ if (!p.fail) { if (config.sql_use_copy) { if (PQputCopyEnd(p.desc, NULL) < 0) Log(LOG_ERR, "ERROR ( %s/%s ): COPY failed!\n\n", config.name, config.type); } ret = PQexec(p.desc, "COMMIT"); if (PQresultStatus(ret) != PGRES_COMMAND_OK) { if (!reprocess) sql_db_fail(&p); reprocess = REPROCESS_BULK; } PQclear(ret); } /* don't reprocess free (SQL_CACHE_FREE) and already recovered (SQL_CACHE_ERROR) elements */ if (p.fail) { if (reprocess == REPROCESS_SPECIFIC) { for (j = 0; j < reprocess_idx; j++) { if (reprocess_queries_queue[j]->valid == SQL_CACHE_COMMITTED) sql_query(&bed, reprocess_queries_queue[j], idata); } } else if (reprocess == REPROCESS_BULK) { for (j = 0; j < bulk_reprocess_idx; j++) { if (bulk_reprocess_queries_queue[j]->valid == SQL_CACHE_COMMITTED) sql_query(&bed, bulk_reprocess_queries_queue[j], idata); } } } if (b.connected) { if (config.sql_use_copy) { if (PQputCopyEnd(b.desc, NULL) < 0) Log(LOG_ERR, "ERROR ( %s/%s ): COPY failed!\n\n", config.name, config.type); } ret = PQexec(b.desc, "COMMIT"); if (PQresultStatus(ret) != PGRES_COMMAND_OK) sql_db_fail(&b); PQclear(ret); } /* rewinding stuff */ if (lf.file) PG_file_close(&lf); if (lf.fail || b.fail) Log(LOG_ALERT, "ALERT ( %s/%s ): recovery for PgSQL operation failed.\n", config.name, config.type); /* If we have pending queries then start again */ if (pqq_ptr) goto start; idata->elap_time = time(NULL)-start; Log(LOG_INFO, "INFO ( %s/%s ): *** Purging cache - END (PID: %u, QN: %u/%u, ET: %u) ***\n", config.name, config.type, writer_pid, idata->qn, saved_index, idata->elap_time); if (config.sql_trigger_exec) { if (!config.debug) idata->elap_time = time(NULL)-start; SQL_SetENV_child(idata); } }
bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary) { bool OK; const char *prompt; char buf[COPYBUFSIZ]; PGresult *res; /* * Establish longjmp destination for exiting from wait-for-input. (This is * only effective while sigint_interrupt_enabled is TRUE.) */ if (sigsetjmp(sigint_interrupt_jmp, 1) != 0) { /* got here with longjmp */ /* Terminate data transfer */ PQputCopyEnd(conn, _("canceled by user")); OK = false; goto copyin_cleanup; } /* Prompt if interactive input */ if (isatty(fileno(copystream))) { if (!pset.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; OK = true; if (isbinary) { /* interactive input probably silly, but give one prompt anyway */ if (prompt) { fputs(prompt, stdout); fflush(stdout); } for (;;) { int buflen; /* enable longjmp while waiting for input */ sigint_interrupt_enabled = true; buflen = fread(buf, 1, COPYBUFSIZ, copystream); sigint_interrupt_enabled = false; if (buflen <= 0) break; if (PQputCopyData(conn, buf, buflen) <= 0) { OK = false; break; } } } else { bool copydone = false; while (!copydone) { /* for each input line ... */ bool firstload; bool linedone; if (prompt) { fputs(prompt, stdout); fflush(stdout); } firstload = true; linedone = false; while (!linedone) { /* for each bufferload in line ... */ int linelen; char *fgresult; /* enable longjmp while waiting for input */ sigint_interrupt_enabled = true; fgresult = fgets(buf, sizeof(buf), copystream); sigint_interrupt_enabled = false; if (!fgresult) { copydone = true; break; } linelen = strlen(buf); /* current line is done? */ if (linelen > 0 && buf[linelen - 1] == '\n') linedone = true; /* check for EOF marker, but not on a partial line */ if (firstload) { /* * This code erroneously assumes '\.' on a line alone * inside a quoted CSV string terminates the \copy. * http://www.postgresql.org/message-id/[email protected] */ if (strcmp(buf, "\\.\n") == 0 || strcmp(buf, "\\.\r\n") == 0) { copydone = true; break; } firstload = false; } if (PQputCopyData(conn, buf, linelen) <= 0) { OK = false; copydone = true; break; } } if (copystream == pset.cur_cmd_source) pset.lineno++; } } /* Check for read error */ if (ferror(copystream)) OK = false; /* Terminate data transfer */ if (PQputCopyEnd(conn, OK ? NULL : _("aborted because of read failure")) <= 0) OK = false; copyin_cleanup: /* * Check command status and return to normal libpq state * * We must not ever return with the status still PGRES_COPY_IN. Our * caller is unable to distinguish that situation from reaching the next * COPY in a command string that happened to contain two consecutive COPY * FROM STDIN commands. XXX if something makes PQputCopyEnd() fail * indefinitely while retaining status PGRES_COPY_IN, we get an infinite * loop. This is more realistic than handleCopyOut()'s counterpart risk. */ while (res = PQgetResult(conn), PQresultStatus(res) == PGRES_COPY_IN) { OK = false; PQclear(res); PQputCopyEnd(pset.db, _("trying to exit copy mode")); } if (PQresultStatus(res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } PQclear(res); return OK; }
bool handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res) { bool OK; const char *prompt; char buf[COPYBUFSIZ]; /* * Establish longjmp destination for exiting from wait-for-input. (This is * only effective while sigint_interrupt_enabled is TRUE.) */ if (sigsetjmp(sigint_interrupt_jmp, 1) != 0) { /* got here with longjmp */ /* Terminate data transfer */ PQputCopyEnd(conn, (PQprotocolVersion(conn) < 3) ? NULL : _("canceled by user")); OK = false; goto copyin_cleanup; } /* Prompt if interactive input */ if (isatty(fileno(copystream))) { if (!pset.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; OK = true; if (isbinary) { /* interactive input probably silly, but give one prompt anyway */ if (prompt) { fputs(prompt, stdout); fflush(stdout); } for (;;) { int buflen; /* enable longjmp while waiting for input */ sigint_interrupt_enabled = true; buflen = fread(buf, 1, COPYBUFSIZ, copystream); sigint_interrupt_enabled = false; if (buflen <= 0) break; if (PQputCopyData(conn, buf, buflen) <= 0) { OK = false; break; } } } else { bool copydone = false; while (!copydone) { /* for each input line ... */ bool firstload; bool linedone; if (prompt) { fputs(prompt, stdout); fflush(stdout); } firstload = true; linedone = false; while (!linedone) { /* for each bufferload in line ... */ int linelen; char *fgresult; /* enable longjmp while waiting for input */ sigint_interrupt_enabled = true; fgresult = fgets(buf, sizeof(buf), copystream); sigint_interrupt_enabled = false; if (!fgresult) { copydone = true; break; } linelen = strlen(buf); /* current line is done? */ if (linelen > 0 && buf[linelen - 1] == '\n') linedone = true; /* check for EOF marker, but not on a partial line */ if (firstload) { /* * This code erroneously assumes '\.' on a line alone * inside a quoted CSV string terminates the \copy. * http://www.postgresql.org/message-id/E1TdNVQ-0001ju-GO@w * rigleys.postgresql.org */ if (strcmp(buf, "\\.\n") == 0 || strcmp(buf, "\\.\r\n") == 0) { copydone = true; break; } firstload = false; } if (PQputCopyData(conn, buf, linelen) <= 0) { OK = false; copydone = true; break; } } if (copystream == pset.cur_cmd_source) pset.lineno++; } } /* Check for read error */ if (ferror(copystream)) OK = false; /* * Terminate data transfer. We can't send an error message if we're using * protocol version 2. */ if (PQputCopyEnd(conn, (OK || PQprotocolVersion(conn) < 3) ? NULL : _("aborted because of read failure")) <= 0) OK = false; copyin_cleanup: /* * Check command status and return to normal libpq state. * * We do not want to return with the status still PGRES_COPY_IN: our * caller would be unable to distinguish that situation from reaching the * next COPY in a command string that happened to contain two consecutive * COPY FROM STDIN commands. We keep trying PQputCopyEnd() in the hope * it'll work eventually. (What's actually likely to happen is that in * attempting to flush the data, libpq will eventually realize that the * connection is lost. But that's fine; it will get us out of COPY_IN * state, which is what we need.) */ while (*res = PQgetResult(conn), PQresultStatus(*res) == PGRES_COPY_IN) { OK = false; PQclear(*res); /* We can't send an error message if we're using protocol version 2 */ PQputCopyEnd(conn, (PQprotocolVersion(conn) < 3) ? NULL : _("trying to exit copy mode")); } if (PQresultStatus(*res) != PGRES_COMMAND_OK) { psql_error("%s", PQerrorMessage(conn)); OK = false; } return OK; }
SEXP RS_PostgreSQL_CopyInDataframe(Con_Handle * conHandle, SEXP x, SEXP nrow, SEXP ncol) { S_EVALUATOR RS_DBI_connection * con; int nr, nc, i, j; const char *cna ="\\N", *tmp=NULL /* -Wall */; char cdec = '.'; PGconn *my_connection; int pqretcode; nr = asInteger(nrow); nc = asInteger(ncol); const int buff_threshold = 8000; con = RS_DBI_getConnection(conHandle); my_connection = (PGconn *) con->drvConnection; if(isVectorList(x)) { /* A data frame */ R_StringBuffer rstrbuf = {NULL, 0, 10000}; char *strBuf = Calloc(buff_threshold * 2 + 2, char); /* + 2 for '\t' or '\n' plus '\0'*/ char *strendp = strBuf; SEXP *levels; *strendp = '\0'; R_AllocStringBuffer(10000, &rstrbuf); /* handle factors internally, check integrity */ levels = (SEXP *) R_alloc(nc, sizeof(SEXP)); for(j = 0; j < nc; j++) { SEXP xj; xj = VECTOR_ELT(x, j); if(LENGTH(xj) != nr) error(("corrupt data frame -- length of column %d does not not match nrows"), j+1); if(inherits(xj, "factor")) { levels[j] = getAttrib(xj, R_LevelsSymbol); } else levels[j] = R_NilValue; } for(i = 0; i < nr; i++) { for(j = 0; j < nc; j++) { SEXP xj; xj = VECTOR_ELT(x, j); if(j > 0){ *strendp++ = '\t';/*need no size count check here*/ } if(isna(xj, i)) tmp = cna; else { if(!isNull(levels[j])) { /* We cannot assume factors have integer levels */ if(TYPEOF(xj) == INTSXP){ tmp = EncodeElementS(levels[j], INTEGER(xj)[i] - 1, &rstrbuf, cdec); }else if(TYPEOF(xj) == REALSXP){ tmp = EncodeElementS(levels[j], REAL(xj)[i] - 1, &rstrbuf, cdec); }else error("column %s claims to be a factor but does not have numeric codes", j+1); } else { tmp = EncodeElementS(xj, i, &rstrbuf, cdec); } } { size_t n; size_t len = strendp - strBuf; n = strlen(tmp); if (len + n < buff_threshold){ memcpy(strendp, tmp, n);/* we already know the length */ strendp += n; }else if(n < buff_threshold){ /*copy and flush*/ memcpy(strendp, tmp, n);/* we already know the length */ pqretcode = PQputCopyData(my_connection, strBuf, len + n); chkpqcopydataerr(my_connection, pqretcode); strendp = strBuf; }else{ /*flush and copy current*/ if(len > 0){ pqretcode = PQputCopyData(my_connection, strBuf, len); chkpqcopydataerr(my_connection, pqretcode); strendp = strBuf; } pqretcode = PQputCopyData(my_connection, tmp, n); chkpqcopydataerr(my_connection, pqretcode); } } } *strendp = '\n'; strendp +=1; *strendp='\0'; } pqretcode = PQputCopyData(my_connection, strBuf, strendp - strBuf); chkpqcopydataerr(my_connection, pqretcode); Free(strBuf); R_FreeStringBuffer(&rstrbuf); } PQputCopyEnd(my_connection, NULL); return R_NilValue; }
/* * Fetch all changed blocks from remote source data directory. */ void libpq_executeFileMap(filemap_t *map) { file_entry_t *entry; const char *sql; PGresult *res; /* * First create a temporary table, and load it with the blocks that * we need to fetch. */ sql = "create temporary table fetchchunks(path text, begin int4, len int4);"; res = PQexec(conn, sql); if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "error creating temporary table: %s\n", PQresultErrorMessage(res)); exit(1); } sql = "copy fetchchunks from stdin"; res = PQexec(conn, sql); if (PQresultStatus(res) != PGRES_COPY_IN) { fprintf(stderr, "unexpected result while sending file list: %s\n", PQresultErrorMessage(res)); exit(1); } for (entry = map->first; entry != NULL; entry = entry->next) { execute_pagemap(&entry->pagemap, entry->path); switch (entry->action) { case FILE_ACTION_NONE: /* ok, do nothing.. */ break; case FILE_ACTION_COPY: /* Truncate the old file out of the way, if any */ open_target_file(entry->path, true); copy_file_range(entry->path, 0, entry->newsize); break; case FILE_ACTION_REMOVE: remove_target_file(entry->path); break; case FILE_ACTION_TRUNCATE: truncate_target_file(entry->path, entry->newsize); break; case FILE_ACTION_COPY_TAIL: copy_file_range(entry->path, entry->oldsize, entry->newsize); break; case FILE_ACTION_CREATEDIR: create_target_dir(entry->path); break; case FILE_ACTION_REMOVEDIR: remove_target_dir(entry->path); break; } } if (PQputCopyEnd(conn, NULL) != 1) { fprintf(stderr, "error sending end-of-COPY: %s\n", PQerrorMessage(conn)); exit(1); } while ((res = PQgetResult(conn)) != NULL) { if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "unexpected result while sending file list: %s\n", PQresultErrorMessage(res)); exit(1); } } /* Ok, we've sent the file list. Now receive the files */ sql = "-- fetch all the blocks listed in the temp table.\n" "select path, begin, \n" " pg_read_binary_file(path, begin, len) as chunk\n" "from fetchchunks\n"; receiveFileChunks(sql); }
int pgQueryThread::Execute() { wxMutexLocker lock(m_queriesLock); PGresult *result = NULL; wxMBConv &conv = *(m_conn->conv); wxString &query = m_queries[m_currIndex]->m_query; int &resultToRetrieve = m_queries[m_currIndex]->m_resToRetrieve; long &rowsInserted = m_queries[m_currIndex]->m_rowsInserted; Oid &insertedOid = m_queries[m_currIndex]->m_insertedOid; // using the alias for the pointer here, in order to save the result back // in the pgBatchQuery object pgSet *&dataSet = m_queries[m_currIndex]->m_resultSet; int &rc = m_queries[m_currIndex]->m_returnCode; pgParamsArray *params = m_queries[m_currIndex]->m_params; bool useCallable = m_queries[m_currIndex]->m_useCallable; pgError &err = m_queries[m_currIndex]->m_err; wxCharBuffer queryBuf = query.mb_str(conv); if (PQstatus(m_conn->conn) != CONNECTION_OK) { rc = pgQueryResultEvent::PGQ_CONN_LOST; err.msg_primary = _("Connection to the database server lost"); return(RaiseEvent(rc)); } if (!queryBuf && !query.IsEmpty()) { rc = pgQueryResultEvent::PGQ_STRING_INVALID; m_conn->SetLastResultError(NULL, _("the query could not be converted to the required encoding.")); err.msg_primary = _("Query string is empty"); return(RaiseEvent(rc)); } // Honour the parameters (if any) if (params && params->GetCount() > 0) { int pCount = params->GetCount(); int ret = 0, idx = 0; Oid *pOids = (Oid *)malloc(pCount * sizeof(Oid)); const char **pParams = (const char **)malloc(pCount * sizeof(const char *)); int *pLens = (int *)malloc(pCount * sizeof(int)); int *pFormats = (int *)malloc(pCount * sizeof(int)); // modes are used only by enterprisedb callable statement #if defined (__WXMSW__) || (EDB_LIBPQ) int *pModes = (int *)malloc(pCount * sizeof(int)); #endif for (; idx < pCount; idx++) { pgParam *param = (*params)[idx]; pOids[idx] = param->m_type; pParams[idx] = (const char *)param->m_val; pLens[idx] = param->m_len; pFormats[idx] = param->GetFormat(); #if defined (__WXMSW__) || (EDB_LIBPQ) pModes[idx] = param->m_mode; #endif } if (useCallable) { #if defined (__WXMSW__) || (EDB_LIBPQ) wxLogInfo(wxString::Format( _("using an enterprisedb callable statement (queryid:%ld, threadid:%ld)"), (long)m_currIndex, (long)GetId())); wxString stmt = wxString::Format(wxT("pgQueryThread-%ld-%ld"), this->GetId(), m_currIndex); PGresult *res = PQiPrepareOut(m_conn->conn, stmt.mb_str(wxConvUTF8), queryBuf, pCount, pOids, pModes); if( PQresultStatus(res) != PGRES_COMMAND_OK) { rc = pgQueryResultEvent::PGQ_ERROR_PREPARE_CALLABLE; err.SetError(res, &conv); PQclear(res); goto return_with_error; } ret = PQiSendQueryPreparedOut(m_conn->conn, stmt.mb_str(wxConvUTF8), pCount, pParams, pLens, pFormats, 1); if (ret != 1) { rc = pgQueryResultEvent::PGQ_ERROR_EXECUTE_CALLABLE; m_conn->SetLastResultError(NULL, _("Failed to run PQsendQuery in pgQueryThread")); err.msg_primary = wxString(PQerrorMessage(m_conn->conn), conv); PQclear(res); res = NULL; goto return_with_error; } PQclear(res); res = NULL; #else rc = -1; wxASSERT_MSG(false, _("the program execution flow must not reach to this point in pgQueryThread")); goto return_with_error; #endif } else { // assumptions: we will need the results in text format only ret = PQsendQueryParams(m_conn->conn, queryBuf, pCount, pOids, pParams, pLens, pFormats, 0); if (ret != 1) { rc = pgQueryResultEvent::PGQ_ERROR_SEND_QUERY; m_conn->SetLastResultError(NULL, _("Failed to run PQsendQueryParams in pgQueryThread")); err.msg_primary = _("Failed to run PQsendQueryParams in pgQueryThread.\n") + wxString(PQerrorMessage(m_conn->conn), conv); goto return_with_error; } } goto continue_without_error; return_with_error: { free(pOids); free(pParams); free(pLens); free(pFormats); #if defined (__WXMSW__) || (EDB_LIBPQ) free(pModes); #endif return (RaiseEvent(rc)); } } else { // use the PQsendQuery api in case, we don't have any parameters to // pass to the server if (!PQsendQuery(m_conn->conn, queryBuf)) { rc = pgQueryResultEvent::PGQ_ERROR_SEND_QUERY; err.msg_primary = _("Failed to run PQsendQueryParams in pgQueryThread.\n") + wxString(PQerrorMessage(m_conn->conn), conv); return(RaiseEvent(rc)); } } continue_without_error: int resultsRetrieved = 0; PGresult *lastResult = 0; while (true) { // This is a 'joinable' thread, it is not advisable to call 'delete' // function on this. // Hence - it does not make sense to use the function 'testdestroy' here. // We introduced the 'CancelExecution' function for the same purpose. // // Also, do not raise event when the query execution is cancelled to // avoid the bugs introduced to handle events by the event handler, // which is missing or being deleted. // // It will be responsibility of the compononent, using the object of // pgQueryThread, to take the required actions to take care of the // issue. if (m_cancelled) { m_conn->CancelExecution(); rc = pgQueryResultEvent::PGQ_EXECUTION_CANCELLED; err.msg_primary = _("Execution Cancelled"); if (lastResult) { PQclear(lastResult); lastResult = NULL; } AppendMessage(_("Query-thread execution cancelled...\nthe query is:")); AppendMessage(query); return rc; } if ((rc = PQconsumeInput(m_conn->conn)) != 1) { if (rc == 0) { err.msg_primary = wxString(PQerrorMessage(m_conn->conn), conv); } if (PQstatus(m_conn->conn) == CONNECTION_BAD) { err.msg_primary = _("Connection to the database server lost"); rc = pgQueryResultEvent::PGQ_CONN_LOST; } else { rc = pgQueryResultEvent::PGQ_ERROR_CONSUME_INPUT; } return(RaiseEvent(rc)); } if (PQisBusy(m_conn->conn)) { Yield(); this->Sleep(10); continue; } // if resultToRetrieve is given, the nth result will be returned, // otherwise the last result set will be returned. // all others are discarded PGresult *res = PQgetResult(m_conn->conn); if (!res) break; if((PQresultStatus(res) == PGRES_NONFATAL_ERROR) || (PQresultStatus(res) == PGRES_FATAL_ERROR) || (PQresultStatus(res) == PGRES_BAD_RESPONSE)) { result = res; err.SetError(res, &conv); // Wait for the execution to be finished // We need to fetch all the results, before sending the error // message do { if (PQconsumeInput(m_conn->conn) != 1) { if (m_cancelled) { rc = pgQueryResultEvent::PGQ_EXECUTION_CANCELLED; // Release the result as the query execution has been cancelled by the // user if (result) PQclear(result); return rc; } goto out_of_consume_input_loop; } if ((res = PQgetResult(m_conn->conn)) == NULL) { goto out_of_consume_input_loop; } // Release the temporary results PQclear(res); res = NULL; if (PQisBusy(m_conn->conn)) { Yield(); this->Sleep(10); } } while (true); break; } #if defined (__WXMSW__) || (EDB_LIBPQ) // there should be 2 results in the callable statement - the first is the // dummy, the second contains our out params. if (useCallable) { PQclear(res); result = PQiGetOutResult(m_conn->conn); } #endif if (PQresultStatus(res) == PGRES_COPY_IN) { rc = PGRES_COPY_IN; PQputCopyEnd(m_conn->conn, "not supported by pgadmin"); } if (PQresultStatus(res) == PGRES_COPY_OUT) { int copyRc; char *buf; int copyRows = 0; int lastCopyRc = 0; rc = PGRES_COPY_OUT; AppendMessage(_("query returned copy data:\n")); while((copyRc = PQgetCopyData(m_conn->conn, &buf, 1)) >= 0) { if (buf != NULL) { if (copyRows < 100) { wxString str(buf, conv); wxCriticalSectionLocker cs(m_criticalSection); m_queries[m_currIndex]->m_message.Append(str); } else if (copyRows == 100) AppendMessage(_("Query returned more than 100 copy rows, discarding the rest...\n")); PQfreemem(buf); } if (copyRc > 0) copyRows++; if (m_cancelled) { m_conn->CancelExecution(); rc = pgQueryResultEvent::PGQ_EXECUTION_CANCELLED; return -1; } if (lastCopyRc == 0 && copyRc == 0) { Yield(); this->Sleep(10); } if (copyRc == 0) { if (!PQconsumeInput(m_conn->conn)) { if (PQstatus(m_conn->conn) == CONNECTION_BAD) { err.msg_primary = _("Connection to the database server lost"); rc = pgQueryResultEvent::PGQ_CONN_LOST; } else { rc = pgQueryResultEvent::PGQ_ERROR_CONSUME_INPUT; err.msg_primary = wxString(PQerrorMessage(m_conn->conn), conv); } return(RaiseEvent(rc)); } } lastCopyRc = copyRc; } res = PQgetResult(m_conn->conn); if (!res) break; } resultsRetrieved++; if (resultsRetrieved == resultToRetrieve) { result = res; insertedOid = PQoidValue(res); if (insertedOid && insertedOid != (Oid) - 1) AppendMessage(wxString::Format(_("query inserted one row with oid %d.\n"), insertedOid)); else AppendMessage(wxString::Format(wxPLURAL("query result with %d row will be returned.\n", "query result with %d rows will be returned.\n", PQntuples(result)), PQntuples(result))); continue; } if (lastResult) { if (PQntuples(lastResult)) AppendMessage(wxString::Format(wxPLURAL("query result with %d row discarded.\n", "query result with %d rows discarded.\n", PQntuples(lastResult)), PQntuples(lastResult))); PQclear(lastResult); } lastResult = res; } out_of_consume_input_loop: if (!result) result = lastResult; err.SetError(result, &conv); AppendMessage(wxT("\n")); rc = PQresultStatus(result); if (rc == PGRES_TUPLES_OK) { dataSet = new pgSet(result, m_conn, conv, m_conn->needColQuoting); dataSet->MoveFirst(); } else if (rc == PGRES_COMMAND_OK) { char *s = PQcmdTuples(result); if (*s) rowsInserted = atol(s); } else if (rc == PGRES_FATAL_ERROR || rc == PGRES_NONFATAL_ERROR || rc == PGRES_BAD_RESPONSE) { if (result) { AppendMessage(wxString(PQresultErrorMessage(result), conv)); PQclear(result); result = NULL; } else { AppendMessage(wxString(PQerrorMessage(m_conn->conn), conv)); } return(RaiseEvent(rc)); } insertedOid = PQoidValue(result); if (insertedOid == (Oid) - 1) insertedOid = 0; return(RaiseEvent(1)); }
/* * 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. */ bool do_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 "); appendPQExpBuffer(&query, "%s ", options->table); if (options->column_list) appendPQExpBuffer(&query, "%s ", options->column_list); if (options->from) appendPQExpBuffer(&query, "FROM STDIN"); else appendPQExpBuffer(&query, "TO STDOUT"); if (options->binary) appendPQExpBuffer(&query, " BINARY "); if (options->oids) appendPQExpBuffer(&query, " OIDS "); if (options->delim) emit_copy_option(&query, " DELIMITER ", options->delim); if (options->null) emit_copy_option(&query, " NULL AS ", options->null); if (options->csv_mode) appendPQExpBuffer(&query, " CSV"); if (options->header) appendPQExpBuffer(&query, " HEADER"); if (options->quote) emit_copy_option(&query, " QUOTE AS ", options->quote); if (options->escape) emit_copy_option(&query, " ESCAPE AS ", 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, options->binary ? PG_BINARY_W : "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: SetCancelConn(); success = handleCopyOut(pset.db, copystream); ResetCancelConn(); break; case PGRES_COPY_IN: SetCancelConn(); success = handleCopyIn(pset.db, copystream, PQbinaryTuples(result)); ResetCancelConn(); 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)); break; } PQclear(result); /* * Make sure we have pumped libpq dry of results; else it may still be * in ASYNC_BUSY state, leading to false readings in, eg, get_prompt(). */ while ((result = PQgetResult(pset.db)) != NULL) { success = false; psql_error("\\copy: unexpected response (%d)\n", PQresultStatus(result)); /* if still in COPY IN state, try to get out of it */ if (PQresultStatus(result) == PGRES_COPY_IN) PQputCopyEnd(pset.db, _("trying to exit copy mode")); 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; }