Re: libpq: How are result sets fetched behind the scene?
Christian Barthel <[email protected]> Sat, 07 Sep 2019 14:43:58 +0200
| Newsgroups | gmane.comp.db.postgresql.sql |
|---|---|
| Message-ID | <[email protected]> |
Sebastien FLAESCH <[email protected]> writes: > Is the whole result set fetched to the client app, not matter what row > number is provided to the first PQgetvalue() call (or similar API call > on result set data or meta-data)? I have tested this as well and came to the same result as you. The entire result set seems to be fetched at once. Attached is a test program: I have loaded 30MB of random strings and did a simple SELECT on the random data. I stopped the output with getchar() and looked at the network traffic and the memory usage with top(1). Everything gets allocated and fetched at once as far as I can see. However, I would not build an application that "depends" on this behavior. I think that it is better to use a declared cursor and use FETCH. -- Christian Barthel <[email protected]>
pg-fetchtest.c
(text/x-csrc, 2.1 KB)
#include <stdio.h>
#include <stdlib.h>
#include "libpq-fe.h"
/* Source Code based on PostgreSQL/libpq Example Code */
/*
begin;
create table string_test (s char(32));
BEGIN
CREATE TABLE
insert into string_test(s) SELECT md5(random()::text) from generate_series(1,1000000);
commit;
*/
static void
exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(1);
}
int
main(int argc, char **argv)
{
const char *conninfo;
PGconn *conn;
PGresult *res;
int nFields;
int i,
j;
if (argc > 1)
conninfo = argv[1];
else
conninfo = "host=192.168.4.102 dbname=dbname";
conn = PQconnectdb(conninfo);
/* Check to see that the backend connection was successfully made */
if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection to database failed: %s",
PQerrorMessage(conn));
exit_nicely(conn);
}
res = PQexec(conn,
"SELECT pg_catalog.set_config('search_path', '', false)");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
res = PQexec(conn, "BEGIN");
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
PQclear(res);
res = PQexec(conn, "select s from public.string_test");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "PQexec failed: %s", PQerrorMessage(conn));
PQclear(res);
exit_nicely(conn);
}
nFields = PQnfields(res);
for (i = 0; i < nFields; i++)
printf("%-15s", PQfname(res, i));
printf("\n-----\n");
for (i = 0; i < PQntuples(res); i++)
{
for (j = 0; j < nFields; j++)
printf("%-15s", PQgetvalue(res, i, j));
printf("\n");
getchar();
}
PQclear(res);
res = PQexec(conn, "ABORT");
PQclear(res);
PQfinish(conn);
return 0;
}