8000 libpq: revert row processor API patch · markokr/postgres@5b1fb57 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5b1fb57

Browse files
committed
libpq: revert row processor API patch
Row processor callback has proved to be confusing API. Original commit: 92785da
1 parent 555d2f5 commit 5b1fb57

File tree

10 files changed

+201
-992
lines changed

10 files changed

+201
-992
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 0 additions & 268 deletions
Original file line numberDiff line numberDiff line change
@@ -5700,274 +5700,6 @@ defaultNoticeProcessor(void *arg, const char *message)
57005700

57015701
</sect1>
57025702

5703-
<sect1 id="libpq-row-processor">
5704-
<title>Custom Row Processing</title>
5705-
5706-
<indexterm zone="libpq-row-processor">
5707-
<primary>PQrowProcessor</primary>
5708-
</indexterm>
5709-
5710-
<indexterm zone="libpq-row-processor">
5711-
<primary>row processor</primary>
5712-
<secondary>in libpq</secondary>
5713-
</indexterm>
5714-
5715-
<para>
5716-
Ordinarily, when receiving a query result from the server,
5717-
<application>libpq</> adds each row value to the current
5718-
<type>PGresult</type> until the entire result set is received; then
5719-
the <type>PGresult</type> is returned to the application as a unit.
5720-
This approach is simple to work with, but becomes inefficient for large
5721-
result sets. To improve performance, an application can register a
5722-
custom <firstterm>row processor</> function that processes each row
5723-
as the data is received from the network. The custom row processor could
5724-
process the data fully, or store it into some application-specific data
5725-
structure for later processing.
5726-
</para>
5727-
5728-
<caution>
5729-
<para>
5730-
The row processor function sees the rows before it is known whether the
5731-
query will succeed overall, since the server might return some rows before
5732-
encountering an error. For proper transactional behavior, it must be
5733-
possible to discard or undo whatever the row processor has done, if the
5734-
query ultimately fails.
5735-
</para>
5736-
</caution>
5737-
5738-
<para>
5739-
When using a custom row processor, row data is not accumulated into the
5740-
<type>PGresult</type>, so the <type>PGresult</type> ultimately delivered to
5741-
the application will contain no rows (<function>PQntuples</> =
5742-
<literal>0</>). However, it still has <function>PQresultStatus</> =
5743-
<literal>PGRES_TUPLES_OK</>, and it contains correct information about the
5744-
set of columns in the query result. On the other hand, if the query fails
5745-
partway through, the returned <type>PGresult</type> has
5746-
<function>PQresultStatus</> = <literal>PGRES_FATAL_ERROR</>. The
5747-
application must be prepared to undo any actions of the row processor
5748-
whenever it gets a <literal>PGRES_FATAL_ERROR</> result.
5749-
</para>
5750-
5751-
<para>
5752-
A custom row processor is registered for a particular connection by
5753-
calling <function>PQsetRowProcessor</function>, described below.
5754-
This row processor will be used for all subsequent query results on that
5755-
connection until changed again. A row processor function must have a
5756-
signature matching
5757-
5758-
<synopsis>
5759-
typedef int (*PQrowProcessor) (PGresult *res, const PGdataValue *columns,
5760-
const char **errmsgp, void *param);
5761-
</synopsis>
5762-
where <type>PGdataValue</> is described by
5763-
<synopsis>
5764-
typedef struct pgDataValue
5765-
{
5766-
int len; /* data length in bytes, or <0 if NULL */
5767-
const char *value; /* data value, without zero-termination */
5768-
} PGdataValue;
5769-
</synopsis>
5770-
</para>
5771-
5772-
<para>
5773-
The <parameter>res</> parameter is the <literal>PGRES_TUPLES_OK</>
5774-
<type>PGresult</type> that will eventually be delivered to the calling
5775-
application (if no error intervenes). It contains information about
5776-
the set of columns in the query result, but no row data. In particular the
5777-
row processor must fetch <literal>PQnfields(res)</> to know the number of
5778-
data columns.
5779-
</para>
5780-
5781-
<para>
5782-
Immediately after <application>libpq</> has determined the result set's
5783-
column information, it will make a call to the row processor with
5784-
<parameter>columns</parameter> set to NULL, but the other parameters as
5785-
usual. The row processor can use this call to initialize for a new result
5786-
set; if it has nothing to do, it can just return <literal>1</>. In
5787-
subsequent calls, one per received row, <parameter>columns</parameter>
5788-
is non-NULL and points to an array of <type>PGdataValue</> structs, one per
5789-
data column.
5790-
</para>
5791-
5792-
<para>
5793-
<parameter>errmsgp</parameter> is an output parameter used only for error
5794-
reporting. If the row processor needs to report an error, it can set
5795-
<literal>*</><parameter>errmsgp</parameter> to point to a suitable message
5796-
string (and then return <literal>-1</>). As a special case, returning
5797-
<literal>-1</> without changing <literal>*</><parameter>errmsgp</parameter>
5798-
from its initial value of NULL is taken to mean <quote>out of memory</>.
5799-
</para>
5800-
5801-
<para>
5802-
The last parameter, <parameter>param</parameter>, is just a void pointer
5803-
passed through from <function>PQsetRowProcessor</function>. This can be
5804-
used for communication between the row processor function and the
5805-
surrounding application.
5806-
</para>
5807-
5808-
<para>
5809-
In the <type>PGdataValue</> array passed to a row processor, data values
5810-
cannot be assumed to be zero-terminated, whether the data format is text
5811-
or binary. A SQL NULL value is indicated by a negative length field.
5812-
</para>
5813-
5814-
<para>
5815-
The row processor <emphasis>must</> process the row data values
5816-
immediately, or else copy them into application-controlled storage.
5817-
The value pointers passed to the row processor point into
5818-
<application>libpq</>'s internal data input buffer, which will be
5819-
overwritten by the next packet fetch.
5820-
</para>
5821-
5822-
<para>
5823-
The row processor function must return either <literal>1</> or
5824-
<literal>-1</>.
5825-
<literal>1</> is the normal, successful result value; <application>libpq</>
5826-
will continue with receiving row values from the server and passing them to
5827-
the row processor. <literal>-1</> indicates that the row processor has
5828-
encountered an error. In that case,
5829-
<application>libpq</> will discard all remaining rows in the result set
5830-
and then return a <literal>PGRES_FATAL_ERROR</> <type>PGresult</type> to
5831-
the application (containing the specified error message, or <quote>out of
5832-
memory for query result</> if <literal>*</><parameter>errmsgp</parameter>
5833-
was left as NULL).
5834-
</para>
5835-
5836-
<para>
5837-
Another option for exiting a row processor is to throw an exception using
5838-
C's <function>longjmp()</> or C++'s <literal>throw</>. If this is done,
5839-
processing of the incoming data can be resumed later by calling
5840-
<function>PQgetResult</>; the row processor will be invoked as normal for
5841-
any remaining rows in the current result.
5842-
As with any usage of <function>PQgetResult</>, the application
5843-
should continue calling <function>PQgetResult</> until it gets a NULL
5844-
result before issuing any new query.
5845-
</para>
5846-
5847-
<para>
5848-
In some cases, an exception may mean that the remainder of the
5849-
query result is not interesting. In such cases the application can discard
5850-
the remaining rows with <function>PQskipResult</>, described below.
5851-
Another possible recovery option is to close the connection altogether with
5852-
<function>PQfinish</>.
5853-
</para>
5854-
5855-
<para>
5856-
<variablelist>
5857-
<varlistentry id="libpq-pqsetrowprocessor">
5858-
<term>
5859-
<function>PQsetRowProcessor</function>
5860-
<indexterm>
5861-
<primary>PQsetRowProcessor</primary>
5862-
</indexterm>
5863-
</term>
5864-
5865-
<listitem>
5866-
<para>
5867-
Sets a callback function to process each row.
5868-
5869-
<synopsis>
5870-
void PQsetRowProcessor(PGconn *conn, PQrowProcessor func, void *param);
5871-
</synopsis>
5872-
</para>
5873-
5874-
<para>
5875-
The specified row processor function <parameter>func</> is installed as
5876-
the active row processor for the given connection <parameter>conn</>.
5877-
Also, <parameter>param</> is installed as the passthrough pointer to
5878-
pass to it. Alternatively, if <parameter>func</> is NULL, the standard
5879-
row processor is reinstalled on the given connection (and
5880-
<parameter>param</> is ignored).
5881-
</para>
5882-
5883-
<para>
5884-
Although the row processor can be changed at any time in the life of a
5885-
connection, it's generally unwise to do so while a query is active.
5886-
In particular, when using asynchronous mode, be aware that both
5887-
<function>PQisBusy</> and <function>PQgetResult</> can call the current
5888-
row processor.
5889-
</para>
5890-
</listitem>
5891-
</varlistentry>
5892-
5893-
<varlistentry id="libpq-pqgetrowprocessor">
5894-
<term>
5895-
<function>PQgetRowProcessor</function>
5896-
<indexterm>
5897-
<primary>PQgetRowProcessor</primary>
5898-
</indexterm>
5899-
</term>
5900-
5901-
<listitem>
5902-
<para>
5903-
Fetches the current row processor for the specified connection.
5904-
5905-
<synopsis>
5906-
PQrowProcessor PQgetRowProcessor(const PGconn *conn, void **param);
5907-
</synopsis>
5908-
</para>
5909-
5910-
<para>
5911-
In addition to returning the row processor function pointer, the
5912-
current passthrough pointer will be returned at
5913-
<literal>*</><parameter>param</>, if <parameter>param</> is not NULL.
5914-
</para>
5915-
</listitem>
5916-
</varlistentry>
5917-
5918-
<varlistentry id="libpq-pqskipresult">
5919-
<term>
5920-
<function>PQskipResult</function>
5921-
<indexterm>
5922-
<primary>PQskipResult</primary>
5923-
</indexterm>
5924-
</term>
5925-
5926-
<listitem>
5927-
<para>
5928-
Discard all the remaining rows in the incoming result set.
5929-
5930-
<synopsis>
5931-
PGresult *PQskipResult(PGconn *conn);
5932-
</synopsis>
5933-
</para>
5934-
5935-
<para>
5936-
This is a simple convenience function to discard incoming data after a
5937-
row processor has failed or it's determined that the rest of the result
5938-
set is not interesting. <function>PQskipResult</> is exactly
5939-
equivalent to <function>PQgetResult</> except that it transiently
5940-
installs a dummy row processor function that just discards data.
5941-
The returned <type>PGresult</> can be discarded without further ado
5942-
if it has status <literal>PGRES_TUPLES_OK</>; but other status values
5943-
should be handled normally. (In particular,
5944-
<literal>PGRES_FATAL_ERROR</> indicates a server-reported error that
5945-
will still need to be dealt with.)
5946-
As when using <function>PQgetResult</>, one should usually repeat the
5947-
call until NULL is returned to ensure the connection has reached an
5948-
idle state. Another possible usage is to call
5949-
<function>PQskipResult</> just once, and then resume using
5950-
<function>PQgetResult</> to process subsequent result sets normally.
5951-
</para>
5952-
5953-
<para>
5954-
Because <function>PQskipResult</> will wait for server input, it is not
5955-
very useful in asynchronous applications. In particular you should not
5956-
code a loop of <function>PQisBusy</> and <function>PQskipResult</>,
5957-
because that will result in the installed row processor being called
5958-
within <function>PQisBusy</>. To get the proper behavior in an
5959-
asynchronous application, you'll need to install a dummy row processor
5960-
(or set a flag to make your normal row processor do nothing) and leave
5961-
it that way until you have discarded all incoming data via your normal
5962-
<function>PQisBusy</> and <function>PQgetResult</> loop.
5963-
</para>
5964-
</listitem>
5965-
</varlistentry>
5966-
</variablelist>
5967-
</para>
5968-
5969-
</sect1>
5970-
59715703
<sect1 id="libpq-events">
59725704
<title>Event System</title>
59735705

src/interfaces/libpq/exports.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,3 @@ PQconnectStartParams 157
160160
PQping 158
161161
PQpingParams 159
162162
PQlibVersion 160
163-
PQsetRowProcessor 161
164-
PQgetRowProcessor 162
165-
PQskipResult 163

src/interfaces/libpq/fe-connect.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,8 +2709,7 @@ makeEmptyPGconn(void)
27092709
/* Zero all pointers and booleans */
27102710
MemSet(conn, 0, sizeof(PGconn));
27112711

2712-
/* install default row processor and notice hooks */
2713-
PQsetRowProcessor(conn, NULL, NULL);
2712+
/* install default notice hooks */
27142713
conn->noticeHooks.noticeRec = defaultNoticeReceiver;
27152714
conn->noticeHooks.noticeProc = defaultNoticeProcessor;
27162715

@@ -2747,14 +2746,11 @@ makeEmptyPGconn(void)
27472746
conn->inBuffer = (char *) malloc(conn->inBufSize);
27482747
conn->outBufSize = 16 * 1024;
27492748
conn->outBuffer = (char *) malloc(conn->outBufSize);
2750-
conn->rowBufLen = 32;
2751-
conn->rowBuf = (PGdataValue *) malloc(conn->rowBufLen * sizeof(PGdataValue));
27522749
initPQExpBuffer(&conn->errorMessage);
27532750
initPQExpBuffer(&conn->workBuffer);
27542751

27552752
if (conn->inBuffer == NULL ||
27562753
conn->outBuffer == NULL ||
2757-
conn->rowBuf == NULL ||
27582754
PQExpBufferBroken(&conn->errorMessage) ||
27592755
PQExpBufferBroken(&conn->workBuffer))
27602756
{
@@ -2858,8 +2854,6 @@ freePGconn(PGconn *conn)
28582854
free(conn->inBuffer);
28592855
if (conn->outBuffer)
28602856
free(conn->outBuffer);
2861-
if (conn->rowBuf)
2862-
free(conn->rowBuf);
28632857
termPQExpBuffer(&conn->errorMessage);
28642858
termPQExpBuffer(&conn->workBuffer);
28652859

@@ -2919,7 +2913,7 @@ closePGconn(PGconn *conn)
29192913
conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just
29202914
* absent */
29212915
conn->asyncStatus = PGASYNC_IDLE;
2922-
pqClearAsyncResult(conn); /* deallocate result */
2916+
pqClearAsyncResult(conn); /* deallocate result and curTuple */
29232917
pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist);
29242918
conn->addrlist = NULL;
29252919
conn->addr_cur = NULL;

0 commit comments

Comments
 (0)
0