problem with PQsendQuery/PQgetResult and COPY FROM statement - Mailing list pgsql-hackers

From max.poletto@gmail.com
Subject problem with PQsendQuery/PQgetResult and COPY FROM statement
Date
Msg-id 1148064660.016529.192030@g10g2000cwb.googlegroups.com
Whole thread Raw
Responses Re: problem with PQsendQuery/PQgetResult and COPY FROM statement
Re: problem with PQsendQuery/PQgetResult and COPY FROM statement
Re: problem with PQsendQuery/PQgetResult and COPY FROM statement
List pgsql-hackers
I attempt to execute a "COPY test FROM STDIN" using PQsendQuery.
Subsequently, after the appropriate poll()/PQconsumeInput/PQisBusy
calls, PQgetResult returns tens of millions of (invalid?) non-null
PGresults.  This behavior seems incorrect, and sometimes causes my
application to exhaust memory and crash.

The postgres version is 8.1.3.

I can reproduce the problem in about 50 lines of C.  I include below
(1) the code, (2) a psql dump of the table in question, (3) the code's
output.

I'd appreciate any insight or suggestions you may have.

Thanks,
max poletto

======================================================================
(1) code

// compile with: g++ -Wall -O -o pgtest pgtest.cc -lpq

#include <cerrno>
#include <cstdio>
#include <ctime>
#include <vector>
using namespace std;
#include <libpq-fe.h>
#include <sys/poll.h>

void retrieve(PGconn *conn, time_t timeout)
{ vector<PGresult *> res; while (1) {   int r;   do {     struct pollfd pfds[1];     pfds[0].fd = PQsocket(conn);
pfds[0].events= POLLIN;     pfds[0].revents = 0;     r = poll(pfds, sizeof(pfds) / sizeof(struct pollfd), 1000 *
 
timeout);   } while (r < 0 && errno == EINTR);   if (r <= 0 || !PQconsumeInput(conn))     return;   int i = 0;
PGresult*oldr = 0;   while (!PQisBusy(conn)) {     PGresult *r = PQgetResult(conn);     if (r) {
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;
}   } }
 
}

int main()
{ PGconn *conn = PQconnectdb("dbname=testdb user=postgres"); if (!conn)   return -1; if (PQsendQuery(conn, "COPY test
FROMSTDIN") > 0) {   retrieve(conn, 20);   if (PQputCopyEnd(conn, 0) < 0)     return -1; } PQfinish(conn); return 0;
 
}


======================================================================
(2) psql session

root@tm01-5% psql testdb postgres
Welcome to psql 8.1.3, the PostgreSQL interactive terminal.

Type:  \copyright for distribution terms      \h for help with SQL commands      \? for help with psql commands      \g
orterminate with semicolon to execute query      \q to quit
 

testdb=# \d test    Table "public.test"Column |  Type   | Modifiers
--------+---------+-----------a      | integer |b      | integer |c      | integer |

testdb=# select * from test;a | b | c
---+---+---1 | 2 | 3
(1 row)

testdb=#


======================================================================
(3) output

root@tm01-5% ./pgtest
5000000 results
10000000 results
15000000 results
20000000 results
25000000 results
PQgetResult return 0 after 25649299 results
4.640u 4.696s 0:09.34 99.8%     0+0k 0+0io 0pf+0w

In this toy example, the process VM size exceeds 2GB before PQgetResult
finally returns 0.  The real application, which has already allocated
~1GB prior to the query, runs out of memory (3GB limit on 32-bit linux)
before PQgetResult ever returns 0.



pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: [ADMIN] does wal archiving block the current client connection?
Next
From: Mischa Sandberg
Date:
Subject: Porting MSSQL to PGSQL (Was: [OT] MySQL is bad, but THIS bad?)