Permalink
Browse files

Fix the query editor behaviour with COPY

If you run something like:

copy (select * from pg_stat_activity) to stdout;

in the query editor, it will hang forever. The code in
pgQueryThread::execute() doesn't check for a PGRES_COPY_OUT result, and
calls PQgetResult() repeatedly. PQgetResult() will keep on returning
PGRES_COPY_OUT until the copy output is read with PQgetCopyData(), so it
gets stuck. COPY FROM STDIN has a similar problem.

This patch fixes that. For COPY TO STDOUT, it prints the first
100 rows to the message display. For COPY FROM STDIN, it throws an error.
  • Loading branch information...
1 parent 35666a6 commit ea8fcb232324194614e99c54109232efc8157729 Heikki Linnakangas committed with gleu Nov 29, 2012
Showing with 63 additions and 3 deletions.
  1. +2 −0 CHANGELOG
  2. +59 −3 pgadmin/db/pgQueryThread.cpp
  3. +2 −0 pgadmin/include/db/pgQueryThread.h
View
@@ -37,6 +37,8 @@ Changes
Date Dev Ver Change details
---------- --- ------ --------------
+2012-11-29 GL 1.16.1 Fix the query editor behaviour when executing COPY TO
+ stdout and COPY FROM stdin [Heikki Linnakangas]
2012-11-28 AV 1.16.1 Date picker controls returns a full timestamp by
default, which can cause inadvertent date changes
on jobs and role validty dates. Ignore the time part.
@@ -76,14 +76,19 @@ wxString pgQueryThread::GetMessagesAndClear()
void pgQueryThread::appendMessage(const wxString &str)
{
- wxCriticalSectionLocker cs(criticalSection);
if (messages.IsEmpty())
{
if (str != wxT("\n"))
- messages.Append(str);
+ appendMessageRaw(str);
}
else
- messages.Append(wxT("\n") + str);
+ appendMessageRaw(wxT("\n") + str);
+}
+
+void pgQueryThread::appendMessageRaw(const wxString &str)
+{
+ wxCriticalSectionLocker cs(criticalSection);
+ messages.Append(str);
}
@@ -138,6 +143,57 @@ int pgQueryThread::execute()
if (!res)
break;
+ if (PQresultStatus(res) == PGRES_COPY_IN)
+ {
+ PQputCopyEnd(conn->conn, "not supported by pgAdmin");
+ }
+ if (PQresultStatus(res) == PGRES_COPY_OUT)
+ {
+ int copyrc;
+ char *buf;
+ int copyrows = 0;
+ int lastcopyrc = 0;
+
+ appendMessage(_("Query returned COPY data:\n"));
+
+ while((copyrc = PQgetCopyData(conn->conn, &buf, 1)) >= 0)
+ {
+ if (buf != NULL)
+ {
+ if (copyrows < 100)
+ {
+ wxString str(buf, wxConvUTF8);
+ appendMessageRaw(str);
+ } else if (copyrows == 100)
+ appendMessage(_("Query returned more than 100 COPY rows, discarding the rest...\n"));
+
+ PQfreemem(buf);
+ }
+ if (copyrc > 0)
+ copyrows++;
+ if (TestDestroy() && rc != -3)
+ {
+ if (!PQrequestCancel(conn->conn)) // could not abort; abort failed.
+ return(raiseEvent(-1));
+ rc = -3;
+ }
+ if (lastcopyrc == 0 && copyrc == 0)
+ {
+ Yield();
+ this->Sleep(10);
+ }
+ if (copyrc == 0)
+ {
+ if (!PQconsumeInput(conn->conn))
+ return(raiseEvent(0));
+ }
+ lastcopyrc = copyrc;
+ }
+ res = PQgetResult(conn->conn);
+ if (!res)
+ break;
+ }
+
resultsRetrieved++;
if (resultsRetrieved == resultToRetrieve)
{
@@ -63,6 +63,8 @@ class pgQueryThread : public wxThread
int execute();
int raiseEvent(int retval = 0);
+
+ void appendMessageRaw(const wxString &str);
};
#endif

0 comments on commit ea8fcb2

Please sign in to comment.