bool CancelQuery(PGconn *conn, int timeout) { char errbuf[ERRBUFF_SIZE]; PGcancel *pgcancel; if (wait_connection_availability(conn, timeout) != 1) return false; pgcancel = PQgetCancel(conn); if (pgcancel != NULL) { /* * PQcancel can only return 0 if socket()/connect()/send() * fails, in any of those cases we can assume something * bad happened to the connection */ if (PQcancel(pgcancel, errbuf, ERRBUFF_SIZE) == 0) { log_warning(_("Can't stop current query: %s\n"), errbuf); PQfreeCancel(pgcancel); return false; } PQfreeCancel(pgcancel); } return true; }
GSQLCursorState pgsql_cursor_stop (GSQLCursor *cursor) { GSQL_TRACE_FUNC; GSQLSession *session; GSQLEPGSQLSession *spec_session; GSQLEPGSQLCursor *spec_cursor; PGcancel *cancel = NULL; gchar buff[256]; g_return_val_if_fail (GSQL_IS_CURSOR (cursor), GSQL_CURSOR_STATE_ERROR); session = cursor->session; g_return_val_if_fail (GSQL_IS_SESSION (session), GSQL_CURSOR_STATE_ERROR); spec_session = session->spec; spec_cursor = cursor->spec; cancel = PQgetCancel (spec_session->pgconn); if ( ! PQcancel (cancel, buff, 256) ) { pgsql_session_workspace_info (session, buff); PQfreeCancel (cancel); return GSQL_CURSOR_STATE_ERROR; } PQfreeCancel (cancel); return GSQL_CURSOR_STATE_STOP; }
/* * on_before_exec * * Set cancel_conn to point to the current database connection. */ static void on_before_exec(PGconn *conn) { PGcancel *old; if (in_cleanup) return; /* forbid cancel during cleanup */ #ifdef WIN32 EnterCriticalSection(&cancelConnLock); #endif /* Free the old one if we have one */ old = cancel_conn; /* be sure handle_sigint doesn't use pointer while freeing */ cancel_conn = NULL; if (old != NULL) PQfreeCancel(old); cancel_conn = PQgetCancel(conn); #ifdef WIN32 LeaveCriticalSection(&cancelConnLock); #endif }
/* MultiClientCancel cancels the running query on the given connection. */ bool MultiClientCancel(int32 connectionId) { PGconn *connection = NULL; PGcancel *cancelObject = NULL; int cancelSent = 0; bool canceled = true; char errorBuffer[STRING_BUFFER_SIZE]; Assert(connectionId != INVALID_CONNECTION_ID); connection = ClientConnectionArray[connectionId]; Assert(connection != NULL); cancelObject = PQgetCancel(connection); cancelSent = PQcancel(cancelObject, errorBuffer, sizeof(errorBuffer)); if (cancelSent == 0) { ereport(WARNING, (errmsg("could not issue cancel request"), errdetail("Client error: %s", errorBuffer))); canceled = false; } PQfreeCancel(cancelObject); return canceled; }
static void connection_dealloc(PyObject* obj) { connectionObject *self = (connectionObject *)obj; /* Make sure to untrack the connection before calling conn_close, which may * allow a different thread to try and dealloc the connection again, * resulting in a double-free segfault (ticket #166). */ PyObject_GC_UnTrack(self); conn_close(self); if (self->weakreflist) { PyObject_ClearWeakRefs(obj); } conn_notice_clean(self); PyMem_Free(self->dsn); PyMem_Free(self->encoding); if (self->critical) free(self->critical); if (self->cancel) PQfreeCancel(self->cancel); connection_clear(self); pthread_mutex_destroy(&(self->lock)); Dprintf("connection_dealloc: deleted connection object at %p, refcnt = " FORMAT_CODE_PY_SSIZE_T, obj, Py_REFCNT(obj) ); Py_TYPE(obj)->tp_free(obj); }
void pgConn::ResetConnCancel(void) { wxMutexLocker lock(m_cancelConnMutex); PGcancel *oldCancelConn = m_cancelConn; m_cancelConn = NULL; if (oldCancelConn != NULL) PQfreeCancel(oldCancelConn); }
void dbgPgConn::Cancel() { // Attempt to cancel any ongoing query if (m_pgConn) { PGcancel *cancel = PQgetCancel(m_pgConn); char errbuf[256]; PQcancel(cancel, errbuf, sizeof(errbuf)); PQfreeCancel(cancel); } }
void CancelQuery(PGconn *conn) { char errbuf[ERRBUFF_SIZE]; PGcancel *pgcancel; pgcancel = PQgetCancel(conn); if (!pgcancel || PQcancel(pgcancel, errbuf, ERRBUFF_SIZE) == 0) log_warning(_("Can't stop current query: %s\n"), errbuf); PQfreeCancel(pgcancel); }
static void CancelQuery(void) { char errbuf[256]; PGcancel *pgcancel; pgcancel = PQgetCancel(primaryConn); if (!pgcancel || PQcancel(pgcancel, errbuf, 256) == 0) fprintf(stderr, "Can't stop current query: %s", errbuf); PQfreeCancel(pgcancel); }
static void CancelQuery(void) { char errbuf[ERRBUFF_SIZE]; PGcancel *pgcancel; pgcancel = PQgetCancel(primaryConn); if (!pgcancel || PQcancel(pgcancel, errbuf, ERRBUFF_SIZE) == 0) log_warning("Can't stop current query: %s\n", errbuf); PQfreeCancel(pgcancel); }
/* set up the cancel key of the connection. * On success return 0, else set an exception and return -1 */ RAISES_NEG static int conn_setup_cancel(connectionObject *self, PGconn *pgconn) { if (self->cancel) { PQfreeCancel(self->cancel); } if (!(self->cancel = PQgetCancel(self->pgconn))) { PyErr_SetString(OperationalError, "can't get cancellation key"); return -1; } return 0; }
static HB_GARBAGE_FUNC( PGcancel_release ) { void ** ph = ( void ** ) Cargo; /* Check if pointer is not NULL to avoid multiple freeing */ if( ph && *ph ) { /* Destroy the object */ PQfreeCancel( ( PGcancel * ) *ph ); /* set pointer to NULL to avoid multiple freeing */ *ph = NULL; } }
static inline void free_conn(value v_conn) { PGconn *conn = get_conn(v_conn); if (conn) { PGcancel *cancel = get_cancel_obj(v_conn); set_cancel_obj(v_conn, NULL); np_decr_refcount(get_conn_cb(v_conn)); set_conn_cb(v_conn, NULL); set_conn(v_conn, NULL); caml_enter_blocking_section(); PQfreeCancel(cancel); PQfinish(conn); caml_leave_blocking_section(); } }
void pgConn::SetConnCancel(void) { wxMutexLocker lock(m_cancelConnMutex); PGcancel *oldCancelConn = m_cancelConn; m_cancelConn = NULL; if (oldCancelConn != NULL) PQfreeCancel(oldCancelConn); if (!conn) return; m_cancelConn = PQgetCancel(conn); }
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_cancel_real(const char *file, const char *func, int line, switch_pgsql_handle_t *handle) { switch_pgsql_status_t ret = SWITCH_PGSQL_SUCCESS; #ifdef SWITCH_HAVE_PGSQL char err_buf[256]; PGcancel *cancel = NULL; memset(err_buf, 0, 256); cancel = PQgetCancel(handle->con); if(!PQcancel(cancel, err_buf, 256)) { switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_CRIT, "Failed to cancel long-running query (%s): %s\n", handle->sql, err_buf); ret = SWITCH_PGSQL_FAIL; } PQfreeCancel(cancel); #endif return ret; }
static void connection_dealloc(PyObject* obj) { connectionObject *self = (connectionObject *)obj; /* Make sure to untrack the connection before calling conn_close, which may * allow a different thread to try and dealloc the connection again, * resulting in a double-free segfault (ticket #166). */ PyObject_GC_UnTrack(self); /* close the connection only if this is the same process it was created * into, otherwise using multiprocessing we may close the connection * belonging to another process. */ #ifdef CONN_CHECK_PID if (self->procpid == getpid()) #endif { conn_close(self); } if (self->weakreflist) { PyObject_ClearWeakRefs(obj); } conn_notice_clean(self); PyMem_Free(self->dsn); PyMem_Free(self->encoding); if (self->error) free(self->error); if (self->cancel) PQfreeCancel(self->cancel); PQclear(self->pgres); connection_clear(self); pthread_mutex_destroy(&(self->lock)); Dprintf("connection_dealloc: deleted connection object at %p, refcnt = " FORMAT_CODE_PY_SSIZE_T, obj, Py_REFCNT(obj) ); Py_TYPE(obj)->tp_free(obj); }
/* * ResetCancelConn * * Free the current cancel connection, if any, and set to NULL. */ void ResetCancelConn(void) { PGcancel *oldCancelConn; #ifdef WIN32 EnterCriticalSection(&cancelConnLock); #endif oldCancelConn = cancelConn; /* be sure handle_sigint doesn't use pointer while freeing */ cancelConn = NULL; if (oldCancelConn != NULL) PQfreeCancel(oldCancelConn); #ifdef WIN32 LeaveCriticalSection(&cancelConnLock); #endif }
void toQPSqlConnectionSub::nativeCancel() { QVariant v = Connection.driver()->handle(); if (v.isValid() && v.typeName() == QString("PGconn*")) { #ifdef LIBPQ_DECL_CANCEL PGconn *handle = *static_cast<PGconn **>(v.data()); if (!handle) return; PGcancel *cancel = PQgetCancel(handle); if (!cancel) return; char *errbuf = new char[1024]; PQcancel(cancel, errbuf, 1024); PQfreeCancel(cancel); delete[] errbuf; #endif } }
void pgConn::CancelExecution(void) { char errbuf[256]; wxMutexLocker lock(m_cancelConnMutex); if (m_cancelConn) { PGcancel *cancelConn = m_cancelConn; m_cancelConn = NULL; if (PQcancel(cancelConn, errbuf, sizeof(errbuf))) { SetLastResultError(NULL, wxT("Cancel request sent")); } else { SetLastResultError(NULL, wxString::Format(wxT("Could not send cancel request:\n%s"), errbuf)); } PQfreeCancel(cancelConn); } }
/* * Close the connection to the database and also cancel off the query if we * have one running. */ void DisconnectDatabase(Archive *AHX) { ArchiveHandle *AH = (ArchiveHandle *) AHX; PGcancel *cancel; char errbuf[1]; if (!AH->connection) return; if (PQtransactionStatus(AH->connection) == PQTRANS_ACTIVE) { if ((cancel = PQgetCancel(AH->connection))) { PQcancel(cancel, errbuf, sizeof(errbuf)); PQfreeCancel(cancel); } } PQfinish(AH->connection); AH->connection = NULL; }
/* * DisconnectDatabase * Disconnect the connection associated with the given slot */ static void DisconnectDatabase(ParallelSlot *slot) { char errbuf[256]; if (!slot->connection) return; if (PQtransactionStatus(slot->connection) == PQTRANS_ACTIVE) { PGcancel *cancel; if ((cancel = PQgetCancel(slot->connection))) { PQcancel(cancel, errbuf, sizeof(errbuf)); PQfreeCancel(cancel); } } PQfinish(slot->connection); slot->connection = NULL; }
/* * Send cancel/finish signal to still-running QE through libpq. * waitMode is either CANCEL or FINISH. Returns true if we successfully * sent a signal (not necessarily received by the target process). */ static DispatchWaitMode cdbdisp_signalQE(SegmentDatabaseDescriptor * segdbDesc, DispatchWaitMode waitMode) { char errbuf[256]; PGcancel *cn = PQgetCancel(segdbDesc->conn); int ret = 0; if (cn == NULL) return DISPATCH_WAIT_NONE; /* * PQcancel uses some strcpy/strcat functions; let's * clear this for safety. */ MemSet(errbuf, 0, sizeof(errbuf)); if (Debug_cancel_print || DEBUG4 >= log_min_messages) write_log("Calling PQcancel for %s", segdbDesc->whoami); /* * Send query-finish, unless the client really wants to cancel the * query. This could happen if cancel comes after we sent finish. */ if (waitMode == DISPATCH_WAIT_CANCEL) ret = PQcancel(cn, errbuf, 256); else if (waitMode == DISPATCH_WAIT_FINISH) ret = PQrequestFinish(cn, errbuf, 256); else write_log("unknown waitMode: %d", waitMode); if (ret == 0 && (Debug_cancel_print || LOG >= log_min_messages)) write_log("Unable to cancel: %s", errbuf); PQfreeCancel(cn); return (ret != 0 ? waitMode : DISPATCH_WAIT_NONE); }
/* * SetCancelConn * * Set cancelConn to point to the current database connection. */ void SetCancelConn(void) { PGcancel *oldCancelConn; #ifdef WIN32 EnterCriticalSection(&cancelConnLock); #endif /* Free the old one if we have one */ oldCancelConn = cancelConn; /* be sure handle_sigint doesn't use pointer while freeing */ cancelConn = NULL; if (oldCancelConn != NULL) PQfreeCancel(oldCancelConn); cancelConn = PQgetCancel(pset.db); #ifdef WIN32 LeaveCriticalSection(&cancelConnLock); #endif }
/* * on_after_exec * * Free the current cancel connection, if any, and set to NULL. */ static void on_after_exec(void) { PGcancel *old; if (in_cleanup) return; /* forbid cancel during cleanup */ #ifdef WIN32 EnterCriticalSection(&cancelConnLock); #endif old = cancel_conn; /* be sure handle_sigint doesn't use pointer while freeing */ cancel_conn = NULL; if (old != NULL) PQfreeCancel(old); #ifdef WIN32 LeaveCriticalSection(&cancelConnLock); #endif }
void conn_close(connectionObject *self) { if (self->closed) { return; } /* sets this connection as closed even for other threads; also note that we need to check the value of pgconn, because we get called even when the connection fails! */ Py_BEGIN_ALLOW_THREADS; pthread_mutex_lock(&self->lock); /* We used to call pq_abort_locked here, but the idea of issuing a * rollback on close/GC has been considered inappropriate. * * Dropping the connection on the server has the same effect as the * transaction is automatically rolled back. Some middleware, such as * PgBouncer, have problem with connections closed in the middle of the * transaction though: to avoid these problems the transaction should be * closed only in status CONN_STATUS_READY. */ self->closed = 1; if (self->pgconn) { PQfinish(self->pgconn); self->pgconn = NULL; Dprintf("conn_close: PQfinish called"); PQfreeCancel(self->cancel); self->cancel = NULL; } pthread_mutex_unlock(&self->lock); Py_END_ALLOW_THREADS; }
/* * Run one permutation */ static void run_permutation(TestSpec * testspec, int nsteps, Step ** steps) { PGresult *res; int i; Step *waiting = NULL; /* * In dry run mode, just display the permutation in the same format used * by spec files, and return. */ if (dry_run) { printf("permutation"); for (i = 0; i < nsteps; i++) printf(" \"%s\"", steps[i]->name); printf("\n"); return; } printf("\nstarting permutation:"); for (i = 0; i < nsteps; i++) printf(" %s", steps[i]->name); printf("\n"); /* Perform setup */ for (i = 0; i < testspec->nsetupsqls; i++) { res = PQexec(conns[0], testspec->setupsqls[i]); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup failed: %s", PQerrorMessage(conns[0])); exit_nicely(); } PQclear(res); } /* Perform per-session setup */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->setupsql) { res = PQexec(conns[i + 1], testspec->sessions[i]->setupsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "setup of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i + 1])); exit_nicely(); } PQclear(res); } } /* Perform steps */ for (i = 0; i < nsteps; i++) { Step *step = steps[i]; PGconn *conn = conns[1 + step->session]; if (waiting != NULL && step->session == waiting->session) { PGcancel *cancel; PGresult *res; int j; /* * This permutation is invalid: it can never happen in real life. * * A session is blocked on an earlier step (waiting) and no * further steps from this session can run until it is unblocked, * but it can only be unblocked by running steps from other * sessions. */ fflush(stdout); fprintf(stderr, "invalid permutation detected\n"); fflush(stderr); /* Cancel the waiting statement from this session. */ cancel = PQgetCancel(conn); if (cancel != NULL) { char buf[256]; if (!PQcancel(cancel, buf, sizeof(buf))) fprintf(stderr, "PQcancel failed: %s\n", buf); /* Be sure to consume the error message. */ while ((res = PQgetResult(conn)) != NULL) PQclear(res); PQfreeCancel(cancel); } /* * Now we really have to complete all the running transactions to * make sure teardown doesn't block. */ for (j = 1; j < nconns; j++) { res = PQexec(conns[j], "ROLLBACK"); if (res != NULL) PQclear(res); } goto teardown; } if (!PQsendQuery(conn, step->sql)) { fprintf(stdout, "failed to send query for step %s: %s\n", step->name, PQerrorMessage(conns[1 + step->session])); exit_nicely(); } if (waiting != NULL) { /* Some other step is already waiting: just block. */ try_complete_step(step, 0); /* * See if this step unblocked the waiting step; report both error * messages together if so. */ if (!try_complete_step(waiting, STEP_NONBLOCK | STEP_RETRY)) { report_two_error_messages(step, waiting); waiting = NULL; } else report_error_message(step); } else { if (try_complete_step(step, STEP_NONBLOCK)) waiting = step; report_error_message(step); } } /* Finish any waiting query. */ if (waiting != NULL) { try_complete_step(waiting, STEP_RETRY); report_error_message(waiting); } teardown: /* Perform per-session teardown */ for (i = 0; i < testspec->nsessions; i++) { if (testspec->sessions[i]->teardownsql) { res = PQexec(conns[i + 1], testspec->sessions[i]->teardownsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown of session %s failed: %s", testspec->sessions[i]->name, PQerrorMessage(conns[i + 1])); /* don't exit on teardown failure */ fflush(stderr); } PQclear(res); } } /* Perform teardown */ if (testspec->teardownsql) { res = PQexec(conns[0], testspec->teardownsql); if (PQresultStatus(res) == PGRES_TUPLES_OK) { printResultSet(res); } else if (PQresultStatus(res) != PGRES_COMMAND_OK) { fprintf(stderr, "teardown failed: %s", PQerrorMessage(conns[0])); /* don't exit on teardown failure */ fflush(stderr); } PQclear(res); } }
int main (int argc, char *argv[]) { volatile int errcode = 0; int c; char *procname = argv[0]; int forceprompt = false; int needpass = false; char *filename = NULL; char *username = NULL; char *database = NULL; char *hostname = NULL; char *port = NULL; mapred_olist_t *documents; mapred_olist_t *doc_item; FILE *file; /* The long_options structure */ static struct option long_options[] = { {"help", no_argument, 0, '?'}, {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, {"password", no_argument, 0, 'W'}, {"explain", no_argument, 0, 'x'}, {"explain-analyze", no_argument, 0, 'X'}, {"username", required_argument, 0, 'U'}, {"host", required_argument, 0, 'h'}, {"port", required_argument, 0, 'p'}, {"file", required_argument, 0, 'f'}, {"key", required_argument, 0, 'k'}, #ifdef INTERNAL_BUILD {"print", no_argument, 0, 'P'}, {"debug", no_argument, 0, 'D'}, #endif {0, 0, 0, 0} }; #ifdef INTERNAL_BUILD static char* short_options = "VvWxXU:h:p:f:k:?PD"; #else static char* short_options = "VvWxXU:h:p:f:k:?"; #endif while (1) { int option_index = 0; c = getopt_long(argc, argv, short_options, long_options, &option_index); if (c == -1) break; /* done processing options */ switch (c) { case '?': /* --help */ /* Actual help option given */ if (strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0) { usage(procname, true); exit(0); } /* unknown option reported by getopt */ fprintf(stderr, "Try \"%s --help\" for usage information.\n", procname); exit(1); case 'V': /* --version */ showVersion(procname); exit(0); case 'v': /* --verbose */ global_verbose_flag = true; break; case 'x': /* --explain */ global_explain_flag |= global_explain; break; case 'X': /* --explain-analyze */ global_explain_flag |= global_explain | global_analyze; break; #ifdef INTERNAL_BUILD case 'P': /* --print (INTERNAL_BUILD only) */ global_print_flag = 1; break; case 'D': /* --debug (INTERNAL_BUILD only) */ global_debug_flag = 1; break; #endif case 'W': /* --password */ forceprompt = true; break; case 'U': /* --username */ username = optarg; break; case 'h': /* --host */ hostname = optarg; break; case 'p': /* --port */ port = optarg; break; case 'f': /* --file */ filename = optarg; break; case 'k': /* --key */ { mapred_plist_t *newitem; char *name = optarg; char *value = NULL; char *eq = strchr(name, '='); /* * either --key value : sets parameter named "key" * or --key name=value : sets parameter named "name" */ if (eq) { eq[0] = '\0'; value = eq+1; /* make sure parameter is a valid name */ if (strspn(name, wordchars) != strlen(name)) { fprintf(stderr, "bad parameter --key %s\n", name); exit(1); } } else { value = name; name = "key"; } /* Add the parameter to the global parameter list */ newitem = malloc(sizeof(mapred_plist_t)); newitem->name = name; newitem->type = value; newitem->next = global_plist; global_plist = newitem; } break; default: /* not feasible */ fprintf(stderr, "Error processing options\n"); exit(1); } } /* open the file */ if (!filename) { usage(procname, false); exit(1); } file = fopen(filename, "rb"); if (!file) { fprintf(stderr, "Error: Could not open file '%s'\n", filename); exit(1); } /* * Handle additional arguments as would psql: * - First argument is database * - Second argument is username, if not specified via -U * - All other arguments generate warnings */ if (optind < argc && !database) database = argv[optind++]; if (optind < argc && !username) username = argv[optind++]; while (optind < argc) { fprintf(stderr, "%s: warning: extra command-line argument \"%s\" ignored\n", procname, argv[optind++]); } if (global_verbose_flag) { mapred_plist_t *param = global_plist; while (param) { fprintf(stderr, "- Parameter: %s=%s\n", param->name, param->type); param = param->next; } fprintf(stderr, "- Parsing '%s':\n", filename); } documents = NULL; XTRY { documents = mapred_parse_file(file); } XCATCH(ASSERTION_FAILURE) { fprintf(stderr, "Assertion failure at %s:%d\n", xframe.file, xframe.lineno); exit(1); } XCATCH_ANY { if (global_verbose_flag) fprintf(stderr, " - "); if (xframe.exception) fprintf(stderr, "Error: %s\n", (char *) xframe.exception); else fprintf(stderr, "Unknown Error (%d) at %s:%d\n", xframe.errcode, xframe.file, xframe.lineno); exit(1); } XTRY_END; /* Do something interesting with documents */ for (doc_item = documents; doc_item; doc_item = doc_item->next) { PGconn *conn = NULL; char pwdbuf[100]; char portbuf[11]; /* max int size should be 10 digits */ char *user, *db, *host, *pwd, *pqport, *options, *tty; XTRY { mapred_document_t *doc = &doc_item->object->u.document; if (global_verbose_flag) { fprintf(stderr, "- Executing Document %d:\n", doc->id); } if (port) { pqport = port; } else if (doc->port > 0) { snprintf(portbuf, sizeof(portbuf), "%d", doc->port); pqport = portbuf; } else { pqport = NULL; } if (database) db = database; else db = doc->database; if (username) user = username; else user = doc->user; if (hostname) host = hostname; else host = doc->host; options = NULL; tty = NULL; pwd = NULL; if (forceprompt) { read_password(pwdbuf, sizeof(pwdbuf)); pwd = pwdbuf; } do { conn = PQsetdbLogin(host, pqport, options, tty, db, user, pwd); needpass = false; if (PQstatus(conn) == CONNECTION_BAD && !strcmp(PQerrorMessage(conn), PQnoPasswordSupplied)) { PQfinish(conn); read_password(pwdbuf, sizeof(pwdbuf)); pwd = pwdbuf; needpass = true; } } while (needpass); if (PQstatus(conn) == CONNECTION_BAD) { XRAISE(CONNECTION_ERROR, PQerrorMessage(conn)); } else { if (global_verbose_flag) { fprintf(stderr, " - Connected Established:\n"); fprintf(stderr, " HOST: %s\n", PQhost(conn) ? PQhost(conn) : "localhost"); fprintf(stderr, " PORT: %s\n", PQport(conn)); fprintf(stderr, " USER: %s/%s\n", PQuser(conn), PQdb(conn)); } check_version(conn); /* Prepare to receive interupts */ cancelConn = PQgetCancel(conn); if (signal(SIGINT, sigint_handler) == SIG_IGN) signal(SIGINT, SIG_IGN); if (signal(SIGHUP, sigint_handler) == SIG_IGN) signal(SIGHUP, SIG_IGN); if (signal(SIGTERM, sigint_handler) == SIG_IGN) signal(SIGTERM, SIG_IGN); mapred_run_document(conn, doc); } } XCATCH(ASSERTION_FAILURE) { fprintf(stderr, "Assertion failure at %s:%d\n", xframe.file, xframe.lineno); errcode = 1; } XCATCH(USER_INTERUPT) { if (global_verbose_flag) fprintf(stderr, " - "); fprintf(stderr, "Job Cancelled: User Interrupt"); exit(2); /* exit immediately */ } XCATCH_ANY { if (global_verbose_flag) fprintf(stderr, " - "); if (xframe.exception) fprintf(stderr, "Error: %s\n", (char *) xframe.exception); else fprintf(stderr, "Unknown Error (%d) at %s:%d\n", xframe.errcode, xframe.file, xframe.lineno); errcode = 1; } XFINALLY { /* Ignore signals until we exit */ signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGTERM, SIG_IGN); PQfreeCancel(cancelConn); cancelConn = NULL; PQfinish(conn); } XTRY_END; } /* Cleanup */ mapred_destroy_olist(&documents); fclose(file); return errcode; }
/* * pgfdw_subxact_callback --- cleanup at subtransaction end. */ static void pgfdw_subxact_callback(SubXactEvent event, SubTransactionId mySubid, SubTransactionId parentSubid, void *arg) { HASH_SEQ_STATUS scan; ConnCacheEntry *entry; int curlevel; /* Nothing to do at subxact start, nor after commit. */ if (!(event == SUBXACT_EVENT_PRE_COMMIT_SUB || event == SUBXACT_EVENT_ABORT_SUB)) return; /* Quick exit if no connections were touched in this transaction. */ if (!xact_got_connection) return; /* * Scan all connection cache entries to find open remote subtransactions * of the current level, and close them. */ curlevel = GetCurrentTransactionNestLevel(); hash_seq_init(&scan, ConnectionHash); while ((entry = (ConnCacheEntry *) hash_seq_search(&scan))) { PGresult *res; char sql[100]; /* * We only care about connections with open remote subtransactions of * the current level. */ if (entry->conn == NULL || entry->xact_depth < curlevel) continue; if (entry->xact_depth > curlevel) elog(ERROR, "missed cleaning up remote subtransaction at level %d", entry->xact_depth); if (event == SUBXACT_EVENT_PRE_COMMIT_SUB) { /* Commit all remote subtransactions during pre-commit */ snprintf(sql, sizeof(sql), "RELEASE SAVEPOINT s%d", curlevel); do_sql_command(entry->conn, sql); } else { /* Assume we might have lost track of prepared statements */ entry->have_error = true; /* * If a command has been submitted to the remote server by using * an asynchronous execution function, the command might not have * yet completed. Check to see if a command is still being * processed by the remote server, and if so, request cancellation * of the command. */ if (PQtransactionStatus(entry->conn) == PQTRANS_ACTIVE) { PGcancel *cancel; char errbuf[256]; if ((cancel = PQgetCancel(entry->conn))) { if (!PQcancel(cancel, errbuf, sizeof(errbuf))) ereport(WARNING, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not send cancel request: %s", errbuf))); PQfreeCancel(cancel); } } /* Rollback all remote subtransactions during abort */ snprintf(sql, sizeof(sql), "ROLLBACK TO SAVEPOINT s%d; RELEASE SAVEPOINT s%d", curlevel, curlevel); res = PQexec(entry->conn, sql); if (PQresultStatus(res) != PGRES_COMMAND_OK) pgfdw_report_error(WARNING, res, entry->conn, true, sql); else PQclear(res); } /* OK, we're outta that level of subtransaction */ entry->xact_depth--; } }
/* * Our caller already sent the query associated with this step. Wait for it * to either complete or (if given the STEP_NONBLOCK flag) to block while * waiting for a lock. We assume that any lock wait will persist until we * have executed additional steps in the permutation. * * When calling this function on behalf of a given step for a second or later * time, pass the STEP_RETRY flag. This only affects the messages printed. * * If the query returns an error, the message is saved in step->errormsg. * Caller should call report_error_message shortly after this, to have it * printed and cleared. * * If the STEP_NONBLOCK flag was specified and the query is waiting to acquire * a lock, returns true. Otherwise, returns false. */ static bool try_complete_step(Step *step, int flags) { PGconn *conn = conns[1 + step->session]; fd_set read_set; struct timeval start_time; struct timeval timeout; int sock = PQsocket(conn); int ret; PGresult *res; bool canceled = false; if (sock < 0) { fprintf(stderr, "invalid socket: %s", PQerrorMessage(conn)); exit_nicely(); } gettimeofday(&start_time, NULL); FD_ZERO(&read_set); while (PQisBusy(conn)) { FD_SET(sock, &read_set); timeout.tv_sec = 0; timeout.tv_usec = 10000; /* Check for lock waits every 10ms. */ ret = select(sock + 1, &read_set, NULL, NULL, &timeout); if (ret < 0) /* error in select() */ { if (errno == EINTR) continue; fprintf(stderr, "select failed: %s\n", strerror(errno)); exit_nicely(); } else if (ret == 0) /* select() timeout: check for lock wait */ { struct timeval current_time; int64 td; /* If it's OK for the step to block, check whether it has. */ if (flags & STEP_NONBLOCK) { bool waiting; res = PQexecPrepared(conns[0], PREP_WAITING, 1, &backend_pids[step->session + 1], NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 1) { fprintf(stderr, "lock wait query failed: %s", PQerrorMessage(conn)); exit_nicely(); } waiting = ((PQgetvalue(res, 0, 0))[0] == 't'); PQclear(res); if (waiting) /* waiting to acquire a lock */ { if (!(flags & STEP_RETRY)) printf("step %s: %s <waiting ...>\n", step->name, step->sql); return true; } /* else, not waiting */ } /* Figure out how long we've been waiting for this step. */ gettimeofday(¤t_time, NULL); td = (int64) current_time.tv_sec - (int64) start_time.tv_sec; td *= USECS_PER_SEC; td += (int64) current_time.tv_usec - (int64) start_time.tv_usec; /* * After 60 seconds, try to cancel the query. * * If the user tries to test an invalid permutation, we don't want * to hang forever, especially when this is running in the * buildfarm. So try to cancel it after a minute. This will * presumably lead to this permutation failing, but remaining * permutations and tests should still be OK. */ if (td > 60 * USECS_PER_SEC && !canceled) { PGcancel *cancel = PQgetCancel(conn); if (cancel != NULL) { char buf[256]; if (PQcancel(cancel, buf, sizeof(buf))) canceled = true; else fprintf(stderr, "PQcancel failed: %s\n", buf); PQfreeCancel(cancel); } } /* * After 75 seconds, just give up and die. * * Since cleanup steps won't be run in this case, this may cause * later tests to fail. That stinks, but it's better than waiting * forever for the server to respond to the cancel. */ if (td > 75 * USECS_PER_SEC) { fprintf(stderr, "step %s timed out after 75 seconds\n", step->name); exit_nicely(); } } else if (!PQconsumeInput(conn)) /* select(): data available */ { fprintf(stderr, "PQconsumeInput failed: %s\n", PQerrorMessage(conn)); exit_nicely(); } } if (flags & STEP_RETRY) printf("step %s: <... completed>\n", step->name); else printf("step %s: %s\n", step->name, step->sql); while ((res = PQgetResult(conn))) { switch (PQresultStatus(res)) { case PGRES_COMMAND_OK: break; case PGRES_TUPLES_OK: printResultSet(res); break; case PGRES_FATAL_ERROR: if (step->errormsg != NULL) { printf("WARNING: this step had a leftover error message\n"); printf("%s\n", step->errormsg); } /* * Detail may contain XID values, so we want to just show * primary. Beware however that libpq-generated error results * may not contain subfields, only an old-style message. */ { const char *sev = PQresultErrorField(res, PG_DIAG_SEVERITY); const char *msg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); if (sev && msg) step->errormsg = psprintf("%s: %s", sev, msg); else step->errormsg = pg_strdup(PQresultErrorMessage(res)); } break; default: printf("unexpected result status: %s\n", PQresStatus(PQresultStatus(res))); } PQclear(res); } return false; }
/* * pgfdw_xact_callback --- cleanup at main-transaction end. */ static void pgfdw_xact_callback(XactEvent event, void *arg) { HASH_SEQ_STATUS scan; ConnCacheEntry *entry; /* Quick exit if no connections were touched in this transaction. */ if (!xact_got_connection) return; /* * Scan all connection cache entries to find open remote transactions, and * close them. */ hash_seq_init(&scan, ConnectionHash); while ((entry = (ConnCacheEntry *) hash_seq_search(&scan))) { PGresult *res; /* Ignore cache entry if no open connection right now */ if (entry->conn == NULL) continue; /* If it has an open remote transaction, try to close it */ if (entry->xact_depth > 0) { elog(DEBUG3, "closing remote transaction on connection %p", entry->conn); switch (event) { case XACT_EVENT_PARALLEL_PRE_COMMIT: case XACT_EVENT_PRE_COMMIT: /* Commit all remote transactions during pre-commit */ do_sql_command(entry->conn, "COMMIT TRANSACTION"); /* * If there were any errors in subtransactions, and we * made prepared statements, do a DEALLOCATE ALL to make * sure we get rid of all prepared statements. This is * annoying and not terribly bulletproof, but it's * probably not worth trying harder. * * DEALLOCATE ALL only exists in 8.3 and later, so this * constrains how old a server postgres_fdw can * communicate with. We intentionally ignore errors in * the DEALLOCATE, so that we can hobble along to some * extent with older servers (leaking prepared statements * as we go; but we don't really support update operations * pre-8.3 anyway). */ if (entry->have_prep_stmt && entry->have_error) { res = PQexec(entry->conn, "DEALLOCATE ALL"); PQclear(res); } entry->have_prep_stmt = false; entry->have_error = false; break; case XACT_EVENT_PRE_PREPARE: /* * We disallow remote transactions that modified anything, * since it's not very reasonable to hold them open until * the prepared transaction is committed. For the moment, * throw error unconditionally; later we might allow * read-only cases. Note that the error will cause us to * come right back here with event == XACT_EVENT_ABORT, so * we'll clean up the connection state at that point. */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot prepare a transaction that modified remote tables"))); break; case XACT_EVENT_PARALLEL_COMMIT: case XACT_EVENT_COMMIT: case XACT_EVENT_PREPARE: /* Pre-commit should have closed the open transaction */ elog(ERROR, "missed cleaning up connection during pre-commit"); break; case XACT_EVENT_PARALLEL_ABORT: case XACT_EVENT_ABORT: /* Assume we might have lost track of prepared statements */ entry->have_error = true; /* * If a command has been submitted to the remote server by * using an asynchronous execution function, the command * might not have yet completed. Check to see if a * command is still being processed by the remote server, * and if so, request cancellation of the command. */ if (PQtransactionStatus(entry->conn) == PQTRANS_ACTIVE) { PGcancel *cancel; char errbuf[256]; if ((cancel = PQgetCancel(entry->conn))) { if (!PQcancel(cancel, errbuf, sizeof(errbuf))) ereport(WARNING, (errcode(ERRCODE_CONNECTION_FAILURE), errmsg("could not send cancel request: %s", errbuf))); PQfreeCancel(cancel); } } /* If we're aborting, abort all remote transactions too */ res = PQexec(entry->conn, "ABORT TRANSACTION"); /* Note: can't throw ERROR, it would be infinite loop */ if (PQresultStatus(res) != PGRES_COMMAND_OK) pgfdw_report_error(WARNING, res, entry->conn, true, "ABORT TRANSACTION"); else { PQclear(res); /* As above, make sure to clear any prepared stmts */ if (entry->have_prep_stmt && entry->have_error) { res = PQexec(entry->conn, "DEALLOCATE ALL"); PQclear(res); } entry->have_prep_stmt = false; entry->have_error = false; } break; } } /* Reset state to show we're out of a transaction */ entry->xact_depth = 0; /* * If the connection isn't in a good idle state, discard it to * recover. Next GetConnection will open a new connection. */ if (PQstatus(entry->conn) != CONNECTION_OK || PQtransactionStatus(entry->conn) != PQTRANS_IDLE) { elog(DEBUG3, "discarding connection %p", entry->conn); PQfinish(entry->conn); entry->conn = NULL; } } /* * Regardless of the event type, we can now mark ourselves as out of the * transaction. (Note: if we are here during PRE_COMMIT or PRE_PREPARE, * this saves a useless scan of the hashtable during COMMIT or PREPARE.) */ xact_got_connection = false; /* Also reset cursor numbering for next transaction */ cursor_number = 0; }