Re: problem with PQsendQuery/PQgetResult and COPY FROM statement

From: max(dot)poletto(at)gmail(dot)com
To: pgsql-hackers(at)postgresql(dot)org
Subject: Re: problem with PQsendQuery/PQgetResult and COPY FROM statement
Date: 2006-05-24 02:13:11
Message-ID: 1148436791.766986.35330@j33g2000cwa.googlegroups.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Thanks for all your replies, but I must clarify some things.

First, note that what I posted is just a small example that reproduces
behavior that appears incorrect. The real code is a C++ wrapper
around libpq that supports non-blocking queries and reuses open
connections.

Volkan and Martijn: I know about PQ{put,get}CopyData, but my example
never gets to that point. I must first determine whether the
(asynchronous) PQsendQuery() of "COPY test FROM STDIN" succeeded.
That's all that retrieve() tries to do in my example.

Tom: of course I should (and eventually do) use PQclear(), but I may
not want to right away, because I must return to the user a vector of
result objects (for example, all the result rows from a query).

I do not expect PQgetResult to return millions of non-null PGresult
objects after a PQsendQuery("COPY test FROM STDIN"). I expect exactly
one non-null result, with a result status of PGRES_COPY_IN. Moreover,
the manual says:

If a COPY command is issued via PQexec in a string that could
contain
additional commands, the application must continue fetching results
via PQgetResult after completing the COPY sequence. Only when
PQgetResult returns NULL is it certain that the PQexec command
string
is done and it is safe to issue more commands.

I assumed this to be true for PQexec or "one of the equivalent
functions" mentioned in the manual, such as PQsendQuery. However, if
I add the following switch statement to my example:

while (!PQisBusy(conn)) {
PGresult *r = PQgetResult(conn);
if (r) {
switch (PQresultStatus(r)) {
case PGRES_COPY_IN:
break;
case PGRES_EMPTY_QUERY:
printf("PGRES_EMPTY_QUERY\n");
break;
case PGRES_COMMAND_OK:
printf("PGRES_COMMAND_OK\n");
break;
case PGRES_TUPLES_OK:
printf("PGRES_TUPLES_OK\n");
break;
case PGRES_COPY_OUT:
printf("PGRES_COPY_OUT\n");
break;
case PGRES_BAD_RESPONSE:
printf("PGRES_BAD_RESPONSE\n");
break;
case PGRES_NONFATAL_ERROR:
printf("PGRES_NONFATAL_ERROR\n");
break;
case PGRES_FATAL_ERROR:
printf("PGRES_FATAL_ERROR\n");
break;
}
res.push_back(r);
if (++i % 5000000 == 0) { printf("%d results\n", i); }
if (r == oldr) { printf("r==oldr (%p)\n", r); }
oldr = r;
} else {
printf("PQgetResult return 0 after %d results\n", i);
return;
}
}

the code still prints only:

5000000 results
10000000 results
15000000 results
20000000 results
25000000 results
PQgetResult return 0 after 25649299 results

In other words, there are >25M distinct non-null results, and all of
them have status code PGRES_COPY_IN, and none of them have errors.

So it appears that I should check whether the first PGresult object
has a status code of PGRES_COPY_IN, and ignore subsequent PGresults
even if they are not NULL. I don't object to this interface, but it
is not what I would conclude after RTFM.

max

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Tom Lane 2006-05-24 02:55:23 Re: LIKE, leading percent, bind parameters and indexes
Previous Message Josh Berkus 2006-05-24 01:21:12 Re: Why is CVS server so slow?