Re: Speed dblink using alternate libpq tuple storage - Mailing list pgsql-hackers

From Marko Kreen
Subject Re: Speed dblink using alternate libpq tuple storage
Date
Msg-id 20120224154616.GA16985@gmail.com
Whole thread Raw
In response to Re: Speed dblink using alternate libpq tuple storage  (Marko Kreen <markokr@gmail.com>)
Responses Re: Speed dblink using alternate libpq tuple storage  (Marko Kreen <markokr@gmail.com>)
List pgsql-hackers
On Tue, Feb 14, 2012 at 01:39:06AM +0200, Marko Kreen wrote:
> I tried imaging some sort of getFoo() style API for fetching in-flight
> row data, but I always ended up with "rewrite libpq" step, so I feel
> it's not productive to go there.
> 
> Instead I added simple feature: rowProcessor can return '2',
> in which case getAnotherTuple() does early exit without setting
> any error state.  In user side it appears as PQisBusy() returned
> with TRUE result.  All pointers stay valid, so callback can just
> stuff them into some temp area.  ATM there is not indication though
> whether the exit was due to callback or other reasons, so user
> must detect it based on whether new temp pointers appeares,
> which means those must be cleaned before calling PQisBusy() again.
> This actually feels like feature, those must not stay around
> after single call.

To see how iterating a resultset would look like I implemented PQgetRow()
function using the currently available public API:
/* * Wait and return next row in resultset. * * returns: *   1 - row data available, the pointers are owned by PGconn *
 0 - result done, use PQgetResult() to get final result *  -1 - some problem, check connection error */int
PQgetRow(PGconn*db, PGresult **hdr_p, PGrowValue **row_p);
 

code at:
 https://github.com/markokr/libpq-rowproc-demos/blob/master/getrow.c

usage:
/* send query */if (!PQsendQuery(db, q))    die(db, "PQsendQuery");
/* fetch rows one-by-one */while (1) {    rc = PQgetRow(db, &hdr, &row);    if (rc > 0)        proc_row(hdr, row);
elseif (rc == 0)        break;    else        die(db, "streamResult");}/* final PGresult, either PGRES_TUPLES_OK or
error*/final = PQgetResult(db);
 


It does not look like it can replace the public callback API,
because it does not work with fully-async connections well.
But it *does* continue the line of synchronous APIs:

- PQexec(): last result only
- PQsendQuery() + PQgetResult(): each result separately
- PQsendQuery() + PQgetRow() + PQgetResult(): each row separately

Also the generic implementation is slightly messy, because
it cannot assume anything about surrounding usage patterns,
while same code living in some user framework can.  But
for simple users who just want to synchronously iterate
over resultset, it might be good enough API?


It does have a inconsistency problem - the row data does
not live in PGresult but in custom container.  Proper
API pattern would be to have PQgetRow() that gives
functional PGresult, but that is not interesting for
high-performace users.  Solutions:

- rename to PQrecvRow()
- rename to PQrecvRow() and additionally provide PQgetRow()
- Don't bother, let users implement it themselves via callback API.

Comments?

-- 
marko



pgsql-hackers by date:

Previous
From: Rosario Borda
Date:
Subject: Format of raw files
Next
From: Tom Lane
Date:
Subject: Re: incompatible pointer types with newer zlib