Example #1
0
static PGresult*
wait_for_result(PlxFn *plx_fn, PlxConn *plx_conn)
{
    struct epoll_event  listenev;
    struct epoll_event  event;
    PGconn             *pq_conn   = plx_conn->pq_conn;
    PGresult           *pg_result = NULL;

    listenev.events = EPOLLIN;
    listenev.data.fd = PQsocket(pq_conn);

    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listenev.data.fd, &listenev) < 0)
        plx_error(plx_fn, "epoll: socket adding failed");

    PG_TRY();
    {
        int tmp;

        while ((tmp = is_pq_busy(pq_conn)))
        {
            if (tmp == -1)
            {
                epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listenev.data.fd, &listenev);
                plx_error(plx_fn, "%s", PQerrorMessage(pq_conn));
            }
            CHECK_FOR_INTERRUPTS();
            epoll_wait(epoll_fd, &event, 1, 10000);
        }
    }
    PG_CATCH();
    {
        epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listenev.data.fd, &listenev);

        if (geterrcode() == ERRCODE_QUERY_CANCELED)
            PQrequestCancel(pq_conn);
        pg_result = PQgetResult(pq_conn);
        if (pg_result)
            PQclear(pg_result);
        PG_RE_THROW();
    }
    PG_END_TRY();

    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listenev.data.fd, &listenev);
    return PQgetResult(pq_conn);
}
Example #2
0
void
handle_sigint(SIGNAL_ARGS)
{
	int			save_errno = errno;

	/* Don't muck around if prompting for a password. */
	if (prompt_state)
		return;

	if (cancelConn == NULL)
		siglongjmp(main_loop_jmp, 1);

	cancel_pressed = true;

	if (PQrequestCancel(cancelConn))
		write_stderr("Cancel request sent\n");
	else
	{
		write_stderr("Could not send cancel request: ");
		write_stderr(PQerrorMessage(cancelConn));
	}
	errno = save_errno;			/* just in case the write changed it */
}
Example #3
0
void
pgConnection::cancelRequest()
{
  PQrequestCancel(m_pgConn);
}
Example #4
0
int pgQueryThread::execute()
{
	rowsInserted = -1L;

	if (!conn->conn)
		return(raiseEvent(0));

	wxCharBuffer queryBuf = query.mb_str(*conn->conv);
	if (!queryBuf && !query.IsEmpty())
	{
		conn->SetLastResultError(NULL, _("The query could not be converted to the required encoding."));
		return(raiseEvent(0));
	}

	if (!PQsendQuery(conn->conn, queryBuf))
	{
		conn->SetLastResultError(NULL);
		conn->IsAlive();
		return(raiseEvent(0));
	}
	int resultsRetrieved = 0;
	PGresult *lastResult = 0;
	while (true)
	{
		if (TestDestroy())
		{
			if (rc != -3)
			{
				if (!PQrequestCancel(conn->conn)) // could not abort; abort failed.
					return(raiseEvent(-1));

				rc = -3;
			}
		}
		if (!PQconsumeInput(conn->conn))
			return(raiseEvent(0));
		if (PQisBusy(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(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))));
			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))));
			PQclear(lastResult);
		}
		lastResult = res;
	}

	if (!result)
		result = lastResult;

	conn->SetLastResultError(result);

	appendMessage(wxT("\n"));
	rc = PQresultStatus(result);
	insertedOid = PQoidValue(result);
	if (insertedOid == (OID) - 1)
		insertedOid = 0;

	if (rc == PGRES_TUPLES_OK)
	{
		dataSet = new pgSet(result, conn, *conn->conv, 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)
	{
		appendMessage(conn->GetLastError() + wxT("\n"));
	}
	return(raiseEvent(1));
}
Example #5
0
void *dbgPgThread::Entry( void )
{

	wxLogInfo( wxT( "worker thread waiting for some work to do..." ));

	// This thread should hang at the call to m_condition.Wait()
	// When m_condition is signaled, we wake up, send a command
	// to the PostgreSQL server, and wait for a result.

	while( m_queueCounter.Wait() == wxSEMA_NO_ERROR && !die && !TestDestroy() )
	{
		m_owner.setNoticeHandler( noticeHandler, this );

		m_currentCommand = getNextCommand();
		wxString command = m_currentCommand->getCommand();

		wxLogInfo( wxT( "Executing: %s" ), command.c_str());

		// This call to PQexec() will hang until we've received
		// a complete result set from the server.
		PGresult *result = 0;

#if defined (__WXMSW__) || (EDB_LIBPQ)
		// If we have a set of params, and we have the required functions...
		dbgPgParams *params = m_currentCommand->getParams();
		bool use_callable = true;

		// we do not need all of PQi stuff AS90 onwards
		if (m_owner.EdbMinimumVersion(9, 0))
			use_callable = false;

#ifdef EDB_LIBPQ
		if (params && use_callable)
#else
		if (PQiGetOutResult && PQiPrepareOut && PQiSendQueryPreparedOut && params && use_callable)
#endif
		{
			wxLogInfo(wxT("Using an EnterpriseDB callable statement"));
			wxString stmt = wxString::Format(wxT("DebugStmt-%d-%d"), this->GetId(), ++run);
			PGresult *res = PQiPrepareOut(m_owner.getConnection(),
			                              stmt.mb_str(wxConvUTF8),
			                              command.mb_str(wxConvUTF8),
			                              params->nParams,
			                              params->paramTypes,
			                              params->paramModes);

			if( PQresultStatus(res) != PGRES_COMMAND_OK)
			{
				wxLogError(_( "Could not prepare the callable statement: %s, error: %s" ), stmt.c_str(), wxString(PQresultErrorMessage(res), *conv).c_str());
				PQclear(res);
				return this;
			}

			int ret = PQiSendQueryPreparedOut(m_owner.getConnection(),
			                                  stmt.mb_str(wxConvUTF8),
			                                  params->nParams,
			                                  params->paramValues,
			                                  NULL, // Can be null - all params are text
			                                  NULL, // Can be null - all params are text
			                                  1);
			if (ret != 1)
			{
				wxLogError(_( "Couldn't execute the callable statement: %s" ), stmt.c_str());
				PQclear(res);
				return this;
			}

			// We need to call PQgetResult before we can call PQgetOutResult
			// Note that this is all async code as far as libpq is concerned to
			// ensure we can always bail out when required, without leaving threads
			// hanging around.
			PGresult *dummy;
			while(true)
			{
				if (die || TestDestroy())
				{
					PQrequestCancel(m_owner.getConnection());
					return this;
				}

				PQconsumeInput(m_owner.getConnection());

				if (PQisBusy(m_owner.getConnection()))
				{
					Yield();
					wxMilliSleep(10);
					continue;
				}

				dummy = PQgetResult(m_owner.getConnection());

				// There should be 2 results - the first is the dummy, the second
				// contains our out params.
				if (dummy)
					break;
			}

			if((PQresultStatus(dummy) == PGRES_NONFATAL_ERROR) || (PQresultStatus(dummy) == PGRES_FATAL_ERROR))
				result = dummy;
			else
			{
				PQclear(dummy);
				result = PQiGetOutResult(m_owner.getConnection());
			}
		}
		else
		{
#endif
			// This is the normal case for a pl/pgsql function, or if we don't
			// have access to PQgetOutResult.
			// Note that this is all async code as far as libpq is concerned to
			// ensure we can always bail out when required, without leaving threads
			// hanging around.
			int ret = PQsendQuery(m_owner.getConnection(), command.mb_str(wxConvUTF8));

			if (ret != 1)
			{
				wxLogError(_( "Couldn't execute the query (%s): %s" ), command.c_str(), wxString(PQerrorMessage(m_owner.getConnection()), *conv).c_str());
				return this;
			}

			PGresult *part;
			while(true)
			{
				if (die || TestDestroy())
				{
					PQrequestCancel(m_owner.getConnection());
					return this;
				}

				PQconsumeInput(m_owner.getConnection());

				if (PQisBusy(m_owner.getConnection()))
				{
					Yield();
					wxMilliSleep(10);
					continue;
				}

				// In theory we should only get one result here, but we'll loop
				// anyway until we get the last one.
				part = PQgetResult(m_owner.getConnection());

				if (!part)
					break;

				result = part;
			}

#if defined (__WXMSW__) || (EDB_LIBPQ)
		}
#endif

		if(!result)
		{
			wxLogInfo(wxT( "NULL PGresult - user abort?" ));
			return this;
		}

		wxLogInfo(wxT( "Complete: %s" ), wxString(PQresStatus(PQresultStatus(result)), *conv).c_str());

		// Notify the GUI thread that a result set is ready for display

		if( m_currentCommand->getEventType() == wxEVT_NULL )
		{
			wxCommandEvent resultEvent( wxEVT_COMMAND_MENU_SELECTED, RESULT_ID_DIRECT_TARGET_COMPLETE );
			resultEvent.SetClientData( result );
			m_currentCommand->getCaller()->AddPendingEvent( resultEvent );
		}
		else
		{
			wxCommandEvent resultEvent( wxEVT_COMMAND_MENU_SELECTED, m_currentCommand->getEventType());
			resultEvent.SetClientData( result );
			m_currentCommand->getCaller()->AddPendingEvent( resultEvent );
		}
	}

	return this;
}
Example #6
0
/********************************************************************************
 * Request that Postgres abandon processing of the current query.
 
 int PQrequestCancel(PGconn *conn);

 The return value is 1 if the cancel request was successfully
 dispatched, 0 if not. (If not, PQerrorMessage tells why not.)
 Successful dispatch is no guarantee that the request will have any
 effect, however. Regardless of the return value of PQrequestCancel,
 the application must continue with the normal result-reading sequence
 using PQgetResult. If the cancellation is effective, the current
 query will terminate early and return an error result. If the
 cancellation fails (say, because the backend was already done
 processing the query), then there will be no visible result at all.

 Note that if the current query is part of a transaction, cancellation
 will abort the whole transaction.

 PQrequestCancel can safely be invoked from a signal handler. So, it
 is also possible to use it in conjunction with plain PQexec, if the
 decision to cancel can be made in a signal handler. For example, psql
 invokes PQrequestCancel from a SIGINT signal handler, thus allowing
 interactive cancellation of queries that it issues through
 PQexec. Note that PQrequestCancel will have no effect if the
 connection is not currently open or the backend is not currently
 processing a query.
 ********************************************************************************/
int
dbi_requestcancel(DBI_conn *conn)
{
    return PQrequestCancel(conn);
}