Thread: error handling in pqRowProcessor broken

error handling in pqRowProcessor broken

From
Peter Eisentraut
Date:
The error handling for pqRowProcessor is described as

  *    Add the received row to the current async result (conn->result).
  *    Returns 1 if OK, 0 if error occurred.
  *
  * On error, *errmsgp can be set to an error string to be returned.
  * If it is left NULL, the error is presumed to be "out of memory".

I find that this doesn't work anymore.  If you set *errmsgp = "some 
message" and return 0, then psql will just print a result set with zero 
rows.

Bisecting points to

commit 618c16707a6d6e8f5c83ede2092975e4670201ad
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date:   Fri Feb 18 15:35:15 2022 -0500

     Rearrange libpq's error reporting to avoid duplicated error text.

It is very uncommon to get an error from pqRowProcessor().  To 
reproduce, I inserted this code:

diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index c7c48d07dc..9c1b33c6e2 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -1124,6 +1124,12 @@ pqRowProcessor(PGconn *conn, const char **errmsgp)
             return 0;
     }

+   if (nfields == 7)
+   {
+       *errmsgp = "gotcha";
+       goto fail;
+   }
+
     /*
      * Basically we just allocate space in the PGresult for each field and
      * copy the data over.

This will produce assorted failures in the regression tests that 
illustrate the effect.

(Even before the above commit, the handling of the returned message was 
a bit weird:  The error output was just the message string, without any 
prefix like "ERROR:".)



Re: error handling in pqRowProcessor broken

From
Tom Lane
Date:
Peter Eisentraut <peter.eisentraut@enterprisedb.com> writes:
> The error handling for pqRowProcessor is described as
>   *    Add the received row to the current async result (conn->result).
>   *    Returns 1 if OK, 0 if error occurred.
>   *
>   * On error, *errmsgp can be set to an error string to be returned.
>   * If it is left NULL, the error is presumed to be "out of memory".

> I find that this doesn't work anymore.

Will look into it, thanks for reporting.

(Hmm, seems like this API spec is deficient anyway.  Is the error
string to be freed later?  Is it already translated?)

            regards, tom lane



Re: error handling in pqRowProcessor broken

From
Tom Lane
Date:
Peter Eisentraut <peter.eisentraut@enterprisedb.com> writes:
> I find that this doesn't work anymore.  If you set *errmsgp = "some
> message" and return 0, then psql will just print a result set with zero
> rows.

Ah, I see the problem: a few places in fe-protocol3 didn't get the memo
that conn->error_result represents a "pending" PGresult that hasn't
been constructed yet.  The attached fixes it for me --- can you try it
on whatever test case led you to this?

> (Even before the above commit, the handling of the returned message was
> a bit weird: The error output was just the message string, without any
> prefix like "ERROR:".)

libpq's always acted that way for internally-generated messages.
Most of them are so rare that we're probably not used to seeing 'em.
Perhaps there's a case for making it more verbose, but right now
doesn't seem like the time to undertake that.

            regards, tom lane

diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 78cff4475c..1b9c04f47e 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -1196,6 +1196,7 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
  *      Returns 1 if OK, 0 if error occurred.
  *
  * On error, *errmsgp can be set to an error string to be returned.
+ * (Such a string should already be translated via libpq_gettext().)
  * If it is left NULL, the error is presumed to be "out of memory".
  *
  * In single-row mode, we create a new result holding just the current row,
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 94b4a448b9..e0da22dba7 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -209,7 +209,7 @@ pqParseInput3(PGconn *conn)
                 case 'C':        /* command complete */
                     if (pqGets(&conn->workBuffer, conn))
                         return;
-                    if (conn->result == NULL)
+                    if (conn->result == NULL && !conn->error_result)
                     {
                         conn->result = PQmakeEmptyPGresult(conn,
                                                            PGRES_COMMAND_OK);
@@ -263,7 +263,7 @@ pqParseInput3(PGconn *conn)
                     }
                     break;
                 case 'I':        /* empty query */
-                    if (conn->result == NULL)
+                    if (conn->result == NULL && !conn->error_result)
                     {
                         conn->result = PQmakeEmptyPGresult(conn,
                                                            PGRES_EMPTY_QUERY);
@@ -281,7 +281,7 @@ pqParseInput3(PGconn *conn)
                     if (conn->cmd_queue_head &&
                         conn->cmd_queue_head->queryclass == PGQUERY_PREPARE)
                     {
-                        if (conn->result == NULL)
+                        if (conn->result == NULL && !conn->error_result)
                         {
                             conn->result = PQmakeEmptyPGresult(conn,
                                                                PGRES_COMMAND_OK);
@@ -362,7 +362,7 @@ pqParseInput3(PGconn *conn)
                     if (conn->cmd_queue_head &&
                         conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE)
                     {
-                        if (conn->result == NULL)
+                        if (conn->result == NULL && !conn->error_result)
                         {
                             conn->result = PQmakeEmptyPGresult(conn,
                                                                PGRES_COMMAND_OK);

Re: error handling in pqRowProcessor broken

From
Peter Eisentraut
Date:
On 19.04.22 21:16, Tom Lane wrote:
> Peter Eisentraut<peter.eisentraut@enterprisedb.com>  writes:
>> I find that this doesn't work anymore.  If you set *errmsgp = "some
>> message" and return 0, then psql will just print a result set with zero
>> rows.
> Ah, I see the problem: a few places in fe-protocol3 didn't get the memo
> that conn->error_result represents a "pending" PGresult that hasn't
> been constructed yet.  The attached fixes it for me --- can you try it
> on whatever test case led you to this?

Your patch fixes it for me.



Re: error handling in pqRowProcessor broken

From
Tom Lane
Date:
Peter Eisentraut <peter.eisentraut@enterprisedb.com> writes:
> On 19.04.22 21:16, Tom Lane wrote:
>> Ah, I see the problem: a few places in fe-protocol3 didn't get the memo
>> that conn->error_result represents a "pending" PGresult that hasn't
>> been constructed yet.  The attached fixes it for me --- can you try it
>> on whatever test case led you to this?

> Your patch fixes it for me.

Thanks for testing.  I pushed a cosmetically-polished version of that.

            regards, tom lane