diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-08-02 13:10:30 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-08-02 13:10:30 -0400 |
commit | 41b9c8452b9df3a431dffc346890f926d17d47ad (patch) | |
tree | ba726ebe6aa14b99688d51293d6c81f4151f3378 /src/interfaces/libpq/fe-protocol3.c | |
parent | 7c0fecdaefb10212d65652607833a4c8061e64e9 (diff) |
Replace libpq's "row processor" API with a "single row" mode.
After taking awhile to digest the row-processor feature that was added to
libpq in commit 92785dac2ee7026948962cd61c4cd84a2d052772, we've concluded
it is over-complicated and too hard to use. Leave the core infrastructure
changes in place (that is, there's still a row processor function inside
libpq), but remove the exposed API pieces, and instead provide a "single
row" mode switch that causes PQgetResult to return one row at a time in
separate PGresult objects.
This approach incurs more overhead than proper use of a row processor
callback would, since construction of a PGresult per row adds extra cycles.
However, it is far easier to use and harder to break. The single-row mode
still affords applications the primary benefit that the row processor API
was meant to provide, namely not having to accumulate large result sets in
memory before processing them. Preliminary testing suggests that we can
probably buy back most of the extra cycles by micro-optimizing construction
of the extra results, but that task will be left for another day.
Marko Kreen
Diffstat (limited to 'src/interfaces/libpq/fe-protocol3.c')
-rw-r--r-- | src/interfaces/libpq/fe-protocol3.c | 76 |
1 files changed, 17 insertions, 59 deletions
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 173af2e0a79..d289f82285f 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -61,9 +61,6 @@ static int build_startup_packet(const PGconn *conn, char *packet, * parseInput: if appropriate, parse input data from backend * until input is exhausted or a stopping state is reached. * Note that this function will NOT attempt to read more data from the backend. - * - * Note: callers of parseInput must be prepared for a longjmp exit when we are - * in PGASYNC_BUSY state, since an external row processor might do that. */ void pqParseInput3(PGconn *conn) @@ -446,10 +443,6 @@ handleSyncLoss(PGconn *conn, char id, int msgLength) * Returns: 0 if processed message successfully, EOF to suspend parsing * (the latter case is not actually used currently). * In either case, conn->inStart has been advanced past the message. - * - * Note: the row processor could also choose to longjmp out of libpq, - * in which case the library's state must allow for resumption at the - * next message. */ static int getRowDescriptions(PGconn *conn, int msgLength) @@ -564,10 +557,7 @@ getRowDescriptions(PGconn *conn, int msgLength) /* Success! */ conn->result = result; - /* - * Advance inStart to show that the "T" message has been processed. We - * must do this before calling the row processor, in case it longjmps. - */ + /* Advance inStart to show that the "T" message has been processed. */ conn->inStart = conn->inCursor; /* @@ -580,25 +570,13 @@ getRowDescriptions(PGconn *conn, int msgLength) return 0; } - /* Give the row processor a chance to initialize for new result set */ - errmsg = NULL; - switch ((*conn->rowProcessor) (result, NULL, &errmsg, - conn->rowProcessorParam)) - { - case 1: - /* everything is good */ - return 0; - - case -1: - /* error, report the errmsg below */ - break; + /* + * We could perform additional setup for the new result set here, but for + * now there's nothing else to do. + */ - default: - /* unrecognized return code */ - errmsg = libpq_gettext("unrecognized return value from row processor"); - break; - } - goto set_error_result; + /* And we're done. */ + return 0; advance_and_error: /* Discard unsaved result, if any */ @@ -608,8 +586,6 @@ advance_and_error: /* Discard the failed message by pretending we read it */ conn->inStart += 5 + msgLength; -set_error_result: - /* * Replace partially constructed result with an error result. First * discard the old result to try to win back some memory. @@ -617,8 +593,10 @@ set_error_result: pqClearAsyncResult(conn); /* - * If row processor didn't provide an error message, assume "out of - * memory" was meant. + * If preceding code didn't provide an error message, assume "out of + * memory" was meant. The advantage of having this special case is that + * freeing the old result first greatly improves the odds that gettext() + * will succeed in providing a translation. */ if (!errmsg) errmsg = libpq_gettext("out of memory for query result"); @@ -695,10 +673,6 @@ failure: * Returns: 0 if processed message successfully, EOF to suspend parsing * (the latter case is not actually used currently). * In either case, conn->inStart has been advanced past the message. - * - * Note: the row processor could also choose to longjmp out of libpq, - * in which case the library's state must allow for resumption at the - * next message. */ static int getAnotherTuple(PGconn *conn, int msgLength) @@ -778,31 +752,15 @@ getAnotherTuple(PGconn *conn, int msgLength) goto advance_and_error; } - /* - * Advance inStart to show that the "D" message has been processed. We - * must do this before calling the row processor, in case it longjmps. - */ + /* Advance inStart to show that the "D" message has been processed. */ conn->inStart = conn->inCursor; - /* Pass the completed row values to rowProcessor */ + /* Process the collected row */ errmsg = NULL; - switch ((*conn->rowProcessor) (result, rowbuf, &errmsg, - conn->rowProcessorParam)) - { - case 1: - /* everything is good */ - return 0; - - case -1: - /* error, report the errmsg below */ - break; + if (pqRowProcessor(conn, &errmsg)) + return 0; /* normal, successful exit */ - default: - /* unrecognized return code */ - errmsg = libpq_gettext("unrecognized return value from row processor"); - break; - } - goto set_error_result; + goto set_error_result; /* pqRowProcessor failed, report it */ advance_and_error: /* Discard the failed message by pretending we read it */ @@ -817,7 +775,7 @@ set_error_result: pqClearAsyncResult(conn); /* - * If row processor didn't provide an error message, assume "out of + * If preceding code didn't provide an error message, assume "out of * memory" was meant. The advantage of having this special case is that * freeing the old result first greatly improves the odds that gettext() * will succeed in providing a translation. |