Thread

  1. [PATCH v2] Make PQgetResult() not return NULL on out-of-memory error

    Yugo Nagata <nagata@sraoss.co.jp> — 2025-11-10T16:51:01Z

    Previously, PQgetResult() returned NULL not only when no results remained
    for a sent query, but also when an out-of-memory error occurred, except when
    PGconn itself was NULL. As a result, users could not distinguish between query
    completion and an out-of-memory error when PQgetResult() returned NULL.
    
    This commit changes PQgetResult() to not return NULL in the case of an
    out-of-memory error by modifying getCopyResult() so that it never returns
    NULL, but instead returns OOM_result, as pqPipelineProcessQueue() does.
    ---
     src/interfaces/libpq/fe-exec.c | 45 +++++++++++++++++++++++++++++-----
     1 file changed, 39 insertions(+), 6 deletions(-)
    
    diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
    index 0b1e37ec30b..8ca306687bf 100644
    --- a/src/interfaces/libpq/fe-exec.c
    +++ b/src/interfaces/libpq/fe-exec.c
    @@ -905,6 +905,10 @@ pqPrepareAsyncResult(PGconn *conn)
     			 */
     			res = unconstify(PGresult *, &OOM_result);
     
    +			pqDropConnection(conn, true);
    +			conn->status = CONNECTION_BAD;	/* No more connection to backend */
    +			conn->asyncStatus = PGASYNC_IDLE;
    +
     			/*
     			 * Don't advance errorReported.  Perhaps we'll be able to report
     			 * the text later.
    @@ -2061,8 +2065,7 @@ PQisBusy(PGconn *conn)
     /*
      * PQgetResult
      *	  Get the next PGresult produced by a query.  Returns NULL if no
    - *	  query work remains or an error has occurred (e.g. out of
    - *	  memory).
    + *	  query work remains.
      *
      *	  In pipeline mode, once all the result of a query have been returned,
      *	  PQgetResult returns NULL to let the user know that the next
    @@ -2170,7 +2173,12 @@ PQgetResult(PGconn *conn)
     			pqCommandQueueAdvance(conn, false,
     								  res->resultStatus == PGRES_PIPELINE_SYNC);
     
    -			if (conn->pipelineStatus != PQ_PIPELINE_OFF)
    +			if ((const PGresult *) res == &OOM_result)
    +			{
    +				/* In the OOM case, set the state to IDLE */
    +				conn->asyncStatus = PGASYNC_IDLE;
    +			}
    +			else if (conn->pipelineStatus != PQ_PIPELINE_OFF)
     			{
     				/*
     				 * We're about to send the results of the current query.  Set
    @@ -2200,8 +2208,16 @@ PQgetResult(PGconn *conn)
     			break;
     		case PGASYNC_READY_MORE:
     			res = pqPrepareAsyncResult(conn);
    -			/* Set the state back to BUSY, allowing parsing to proceed. */
    -			conn->asyncStatus = PGASYNC_BUSY;
    +			if ((const PGresult *) res == &OOM_result)
    +			{
    +				/* In the OOM case, set the state to IDLE */
    +				conn->asyncStatus = PGASYNC_IDLE;
    +			}
    +			else
    +			{
    +				/* Set the state back to BUSY, allowing parsing to proceed. */
    +				conn->asyncStatus = PGASYNC_BUSY;
    +			}
     			break;
     		case PGASYNC_COPY_IN:
     			res = getCopyResult(conn, PGRES_COPY_IN);
    @@ -2234,6 +2250,8 @@ PQgetResult(PGconn *conn)
     static PGresult *
     getCopyResult(PGconn *conn, ExecStatusType copytype)
     {
    +	PGresult   *res;
    +
     	/*
     	 * If the server connection has been lost, don't pretend everything is
     	 * hunky-dory; instead return a PGRES_FATAL_ERROR result, and reset the
    @@ -2254,7 +2272,22 @@ getCopyResult(PGconn *conn, ExecStatusType copytype)
     		return pqPrepareAsyncResult(conn);
     
     	/* Otherwise, invent a suitable PGresult */
    -	return PQmakeEmptyPGresult(conn, copytype);
    +	res = PQmakeEmptyPGresult(conn, copytype);
    +
    +	/*
    +	 * Return the static OOM_result if out-of-memory. See the comments
    +	 * in pqPrepareAsyncResult().
    +	 */
    +	if (!res)
    +	{
    +		res = unconstify(PGresult *, &OOM_result);
    +
    +		pqDropConnection(conn, true);
    +		conn->status = CONNECTION_BAD;	/* No more connection to backend */
    +		conn->asyncStatus = PGASYNC_IDLE;
    +	}
    +
    +	return res;
     }
     
     
    -- 
    2.43.0
    
    
    --Multipart=_Wed__12_Nov_2025_16_52_16_+0900_7X=O1DT3LSl/qfnM--