Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
/*
 * 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
}
Esempio n. 4
0
/* 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;
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
void pgConn::ResetConnCancel(void)
{
	wxMutexLocker  lock(m_cancelConnMutex);
	PGcancel      *oldCancelConn = m_cancelConn;

	m_cancelConn = NULL;

	if (oldCancelConn != NULL)
		PQfreeCancel(oldCancelConn);
}
Esempio n. 7
0
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);
	}
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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);
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
/* 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;
}
Esempio n. 12
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;
   }
}
Esempio n. 13
0
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();
  }
}
Esempio n. 14
0
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);

}
Esempio n. 15
0
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;
}
Esempio n. 16
0
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);
}
Esempio n. 17
0
File: common.c Progetto: GisKook/Gis
/*
 * 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
}
Esempio n. 18
0
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
    }
}
Esempio n. 19
0
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);
	}
}
Esempio n. 20
0
/*
 * 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;
}
Esempio n. 21
0
/*
 * 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;
}
Esempio n. 22
0
/*
 * 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);
}
Esempio n. 23
0
File: common.c Progetto: GisKook/Gis
/*
 * 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
}
Esempio n. 24
0
/*
 * 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;
}
Esempio n. 26
0
/*
 * 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);
	}
}
Esempio n. 27
0
File: main.c Progetto: AnLingm/gpdb
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;
}
Esempio n. 28
0
/*
 * 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--;
	}
}
Esempio n. 29
0
/*
 * 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(&current_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;
}
Esempio n. 30
0
/*
 * 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;
}