LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-protocol3.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 63.2 % 1004 635
Test Date: 2026-03-10 06:14:44 Functions: 82.6 % 23 19
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * fe-protocol3.c
       4              :  *    functions that are specific to frontend/backend protocol version 3
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/interfaces/libpq/fe-protocol3.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "postgres_fe.h"
      16              : 
      17              : #include <ctype.h>
      18              : #include <fcntl.h>
      19              : #include <limits.h>
      20              : 
      21              : #ifdef WIN32
      22              : #include "win32.h"
      23              : #else
      24              : #include <unistd.h>
      25              : #include <netinet/tcp.h>
      26              : #endif
      27              : 
      28              : #include "common/int.h"
      29              : #include "libpq-fe.h"
      30              : #include "libpq-int.h"
      31              : #include "mb/pg_wchar.h"
      32              : #include "port/pg_bswap.h"
      33              : 
      34              : /*
      35              :  * This macro lists the backend message types that could be "long" (more
      36              :  * than a couple of kilobytes).
      37              :  */
      38              : #define VALID_LONG_MESSAGE_TYPE(id) \
      39              :     ((id) == PqMsg_CopyData || \
      40              :      (id) == PqMsg_DataRow || \
      41              :      (id) == PqMsg_ErrorResponse || \
      42              :      (id) == PqMsg_FunctionCallResponse || \
      43              :      (id) == PqMsg_NoticeResponse || \
      44              :      (id) == PqMsg_NotificationResponse || \
      45              :      (id) == PqMsg_RowDescription)
      46              : 
      47              : 
      48              : static void handleFatalError(PGconn *conn);
      49              : static void handleSyncLoss(PGconn *conn, char id, int msgLength);
      50              : static int  getRowDescriptions(PGconn *conn, int msgLength);
      51              : static int  getParamDescriptions(PGconn *conn, int msgLength);
      52              : static int  getAnotherTuple(PGconn *conn, int msgLength);
      53              : static int  getParameterStatus(PGconn *conn);
      54              : static int  getBackendKeyData(PGconn *conn, int msgLength);
      55              : static int  getNotify(PGconn *conn);
      56              : static int  getCopyStart(PGconn *conn, ExecStatusType copytype);
      57              : static int  getReadyForQuery(PGconn *conn);
      58              : static void reportErrorPosition(PQExpBuffer msg, const char *query,
      59              :                                 int loc, int encoding);
      60              : static size_t build_startup_packet(const PGconn *conn, char *packet,
      61              :                                    const PQEnvironmentOption *options);
      62              : 
      63              : 
      64              : /*
      65              :  * parseInput: if appropriate, parse input data from backend
      66              :  * until input is exhausted or a stopping state is reached.
      67              :  * Note that this function will NOT attempt to read more data from the backend.
      68              :  */
      69              : void
      70      1853245 : pqParseInput3(PGconn *conn)
      71              : {
      72              :     char        id;
      73              :     int         msgLength;
      74              :     int         avail;
      75              : 
      76              :     /*
      77              :      * Loop to parse successive complete messages available in the buffer.
      78              :      */
      79              :     for (;;)
      80              :     {
      81              :         /*
      82              :          * Try to read a message.  First get the type code and length. Return
      83              :          * if not enough data.
      84              :          */
      85      7589125 :         conn->inCursor = conn->inStart;
      86      7589125 :         if (pqGetc(&id, conn))
      87      1378899 :             return;
      88      6210226 :         if (pqGetInt(&msgLength, 4, conn))
      89         1139 :             return;
      90              : 
      91              :         /*
      92              :          * Try to validate message type/length here.  A length less than 4 is
      93              :          * definitely broken.  Large lengths should only be believed for a few
      94              :          * message types.
      95              :          */
      96      6209087 :         if (msgLength < 4)
      97              :         {
      98            0 :             handleSyncLoss(conn, id, msgLength);
      99            0 :             return;
     100              :         }
     101      6209087 :         if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
     102              :         {
     103            0 :             handleSyncLoss(conn, id, msgLength);
     104            0 :             return;
     105              :         }
     106              : 
     107              :         /*
     108              :          * Can't process if message body isn't all here yet.
     109              :          */
     110      6209087 :         msgLength -= 4;
     111      6209087 :         avail = conn->inEnd - conn->inCursor;
     112      6209087 :         if (avail < msgLength)
     113              :         {
     114              :             /*
     115              :              * Before returning, enlarge the input buffer if needed to hold
     116              :              * the whole message.  This is better than leaving it to
     117              :              * pqReadData because we can avoid multiple cycles of realloc()
     118              :              * when the message is large; also, we can implement a reasonable
     119              :              * recovery strategy if we are unable to make the buffer big
     120              :              * enough.
     121              :              */
     122        54970 :             if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
     123              :                                      conn))
     124              :             {
     125              :                 /*
     126              :                  * Abandon the connection.  There's not much else we can
     127              :                  * safely do; we can't just ignore the message or we could
     128              :                  * miss important changes to the connection state.
     129              :                  * pqCheckInBufferSpace() already reported the error.
     130              :                  */
     131            0 :                 handleFatalError(conn);
     132              :             }
     133        54970 :             return;
     134              :         }
     135              : 
     136              :         /*
     137              :          * NOTIFY and NOTICE messages can happen in any state; always process
     138              :          * them right away.
     139              :          *
     140              :          * Most other messages should only be processed while in BUSY state.
     141              :          * (In particular, in READY state we hold off further parsing until
     142              :          * the application collects the current PGresult.)
     143              :          *
     144              :          * However, if the state is IDLE then we got trouble; we need to deal
     145              :          * with the unexpected message somehow.
     146              :          *
     147              :          * ParameterStatus ('S') messages are a special case: in IDLE state we
     148              :          * must process 'em (this case could happen if a new value was adopted
     149              :          * from config file due to SIGHUP), but otherwise we hold off until
     150              :          * BUSY state.
     151              :          */
     152      6154117 :         if (id == PqMsg_NotificationResponse)
     153              :         {
     154           65 :             if (getNotify(conn))
     155            0 :                 return;
     156              :         }
     157      6154052 :         else if (id == PqMsg_NoticeResponse)
     158              :         {
     159        79493 :             if (pqGetErrorNotice3(conn, false))
     160            0 :                 return;
     161              :         }
     162      6074559 :         else if (conn->asyncStatus != PGASYNC_BUSY)
     163              :         {
     164              :             /* If not IDLE state, just wait ... */
     165       418237 :             if (conn->asyncStatus != PGASYNC_IDLE)
     166       418237 :                 return;
     167              : 
     168              :             /*
     169              :              * Unexpected message in IDLE state; need to recover somehow.
     170              :              * ERROR messages are handled using the notice processor;
     171              :              * ParameterStatus is handled normally; anything else is just
     172              :              * dropped on the floor after displaying a suitable warning
     173              :              * notice.  (An ERROR is very possibly the backend telling us why
     174              :              * it is about to close the connection, so we don't want to just
     175              :              * discard it...)
     176              :              */
     177            0 :             if (id == PqMsg_ErrorResponse)
     178              :             {
     179            0 :                 if (pqGetErrorNotice3(conn, false /* treat as notice */ ))
     180            0 :                     return;
     181              :             }
     182            0 :             else if (id == PqMsg_ParameterStatus)
     183              :             {
     184            0 :                 if (getParameterStatus(conn))
     185            0 :                     return;
     186              :             }
     187              :             else
     188              :             {
     189              :                 /* Any other case is unexpected and we summarily skip it */
     190            0 :                 pqInternalNotice(&conn->noticeHooks,
     191              :                                  "message type 0x%02x arrived from server while idle",
     192              :                                  id);
     193              :                 /* Discard the unexpected message */
     194            0 :                 conn->inCursor += msgLength;
     195              :             }
     196              :         }
     197              :         else
     198              :         {
     199              :             /*
     200              :              * In BUSY state, we can process everything.
     201              :              */
     202      5656322 :             switch (id)
     203              :             {
     204       336303 :                 case PqMsg_CommandComplete:
     205       336303 :                     if (pqGets(&conn->workBuffer, conn))
     206            0 :                         return;
     207       336303 :                     if (!pgHavePendingResult(conn))
     208              :                     {
     209       167583 :                         conn->result = PQmakeEmptyPGresult(conn,
     210              :                                                            PGRES_COMMAND_OK);
     211       167583 :                         if (!conn->result)
     212              :                         {
     213            0 :                             libpq_append_conn_error(conn, "out of memory");
     214            0 :                             pqSaveErrorResult(conn);
     215              :                         }
     216              :                     }
     217       336303 :                     if (conn->result)
     218       336303 :                         strlcpy(conn->result->cmdStatus, conn->workBuffer.data,
     219              :                                 CMDSTATUS_LEN);
     220       336303 :                     conn->asyncStatus = PGASYNC_READY;
     221       336303 :                     break;
     222        22850 :                 case PqMsg_ErrorResponse:
     223        22850 :                     if (pqGetErrorNotice3(conn, true))
     224            0 :                         return;
     225        22850 :                     conn->asyncStatus = PGASYNC_READY;
     226        22850 :                     break;
     227       354359 :                 case PqMsg_ReadyForQuery:
     228       354359 :                     if (getReadyForQuery(conn))
     229            0 :                         return;
     230       354359 :                     if (conn->pipelineStatus != PQ_PIPELINE_OFF)
     231              :                     {
     232          266 :                         conn->result = PQmakeEmptyPGresult(conn,
     233              :                                                            PGRES_PIPELINE_SYNC);
     234          266 :                         if (!conn->result)
     235              :                         {
     236            0 :                             libpq_append_conn_error(conn, "out of memory");
     237            0 :                             pqSaveErrorResult(conn);
     238              :                         }
     239              :                         else
     240              :                         {
     241          266 :                             conn->pipelineStatus = PQ_PIPELINE_ON;
     242          266 :                             conn->asyncStatus = PGASYNC_READY;
     243              :                         }
     244              :                     }
     245              :                     else
     246              :                     {
     247              :                         /* Advance the command queue and set us idle */
     248       354093 :                         pqCommandQueueAdvance(conn, true, false);
     249       354093 :                         conn->asyncStatus = PGASYNC_IDLE;
     250              :                     }
     251       354359 :                     break;
     252          996 :                 case PqMsg_EmptyQueryResponse:
     253          996 :                     if (!pgHavePendingResult(conn))
     254              :                     {
     255          996 :                         conn->result = PQmakeEmptyPGresult(conn,
     256              :                                                            PGRES_EMPTY_QUERY);
     257          996 :                         if (!conn->result)
     258              :                         {
     259            0 :                             libpq_append_conn_error(conn, "out of memory");
     260            0 :                             pqSaveErrorResult(conn);
     261              :                         }
     262              :                     }
     263          996 :                     conn->asyncStatus = PGASYNC_READY;
     264          996 :                     break;
     265         5574 :                 case PqMsg_ParseComplete:
     266              :                     /* If we're doing PQprepare, we're done; else ignore */
     267         5574 :                     if (conn->cmd_queue_head &&
     268         5574 :                         conn->cmd_queue_head->queryclass == PGQUERY_PREPARE)
     269              :                     {
     270         2233 :                         if (!pgHavePendingResult(conn))
     271              :                         {
     272         2233 :                             conn->result = PQmakeEmptyPGresult(conn,
     273              :                                                                PGRES_COMMAND_OK);
     274         2233 :                             if (!conn->result)
     275              :                             {
     276            0 :                                 libpq_append_conn_error(conn, "out of memory");
     277            0 :                                 pqSaveErrorResult(conn);
     278              :                             }
     279              :                         }
     280         2233 :                         conn->asyncStatus = PGASYNC_READY;
     281              :                     }
     282         5574 :                     break;
     283        11145 :                 case PqMsg_BindComplete:
     284              :                     /* Nothing to do for this message type */
     285        11145 :                     break;
     286           17 :                 case PqMsg_CloseComplete:
     287              :                     /* If we're doing PQsendClose, we're done; else ignore */
     288           17 :                     if (conn->cmd_queue_head &&
     289           17 :                         conn->cmd_queue_head->queryclass == PGQUERY_CLOSE)
     290              :                     {
     291           17 :                         if (!pgHavePendingResult(conn))
     292              :                         {
     293           17 :                             conn->result = PQmakeEmptyPGresult(conn,
     294              :                                                                PGRES_COMMAND_OK);
     295           17 :                             if (!conn->result)
     296              :                             {
     297            0 :                                 libpq_append_conn_error(conn, "out of memory");
     298            0 :                                 pqSaveErrorResult(conn);
     299              :                             }
     300              :                         }
     301           17 :                         conn->asyncStatus = PGASYNC_READY;
     302              :                     }
     303           17 :                     break;
     304       220634 :                 case PqMsg_ParameterStatus:
     305       220634 :                     if (getParameterStatus(conn))
     306            0 :                         return;
     307       220634 :                     break;
     308        14204 :                 case PqMsg_BackendKeyData:
     309              : 
     310              :                     /*
     311              :                      * This is expected only during backend startup, but it's
     312              :                      * just as easy to handle it as part of the main loop.
     313              :                      * Save the data and continue processing.
     314              :                      */
     315        14204 :                     if (getBackendKeyData(conn, msgLength))
     316            0 :                         return;
     317        14204 :                     break;
     318       172597 :                 case PqMsg_RowDescription:
     319       172597 :                     if (conn->error_result ||
     320       172597 :                         (conn->result != NULL &&
     321           64 :                          conn->result->resultStatus == PGRES_FATAL_ERROR))
     322              :                     {
     323              :                         /*
     324              :                          * We've already choked for some reason.  Just discard
     325              :                          * the data till we get to the end of the query.
     326              :                          */
     327            0 :                         conn->inCursor += msgLength;
     328              :                     }
     329       172597 :                     else if (conn->result == NULL ||
     330           64 :                              (conn->cmd_queue_head &&
     331           64 :                               conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE))
     332              :                     {
     333              :                         /* First 'T' in a query sequence */
     334       172597 :                         if (getRowDescriptions(conn, msgLength))
     335            0 :                             return;
     336              :                     }
     337              :                     else
     338              :                     {
     339              :                         /*
     340              :                          * A new 'T' message is treated as the start of
     341              :                          * another PGresult.  (It is not clear that this is
     342              :                          * really possible with the current backend.) We stop
     343              :                          * parsing until the application accepts the current
     344              :                          * result.
     345              :                          */
     346            0 :                         conn->asyncStatus = PGASYNC_READY;
     347            0 :                         return;
     348              :                     }
     349       172597 :                     break;
     350         6325 :                 case PqMsg_NoData:
     351              : 
     352              :                     /*
     353              :                      * NoData indicates that we will not be seeing a
     354              :                      * RowDescription message because the statement or portal
     355              :                      * inquired about doesn't return rows.
     356              :                      *
     357              :                      * If we're doing a Describe, we have to pass something
     358              :                      * back to the client, so set up a COMMAND_OK result,
     359              :                      * instead of PGRES_TUPLES_OK.  Otherwise we can just
     360              :                      * ignore this message.
     361              :                      */
     362         6325 :                     if (conn->cmd_queue_head &&
     363         6325 :                         conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE)
     364              :                     {
     365            6 :                         if (!pgHavePendingResult(conn))
     366              :                         {
     367            0 :                             conn->result = PQmakeEmptyPGresult(conn,
     368              :                                                                PGRES_COMMAND_OK);
     369            0 :                             if (!conn->result)
     370              :                             {
     371            0 :                                 libpq_append_conn_error(conn, "out of memory");
     372            0 :                                 pqSaveErrorResult(conn);
     373              :                             }
     374              :                         }
     375            6 :                         conn->asyncStatus = PGASYNC_READY;
     376              :                     }
     377         6325 :                     break;
     378           70 :                 case PqMsg_ParameterDescription:
     379           70 :                     if (getParamDescriptions(conn, msgLength))
     380            0 :                         return;
     381           70 :                     break;
     382      4499712 :                 case PqMsg_DataRow:
     383      4499712 :                     if (conn->result != NULL &&
     384      4499712 :                         (conn->result->resultStatus == PGRES_TUPLES_OK ||
     385           93 :                          conn->result->resultStatus == PGRES_TUPLES_CHUNK))
     386              :                     {
     387              :                         /* Read another tuple of a normal query response */
     388      4499712 :                         if (getAnotherTuple(conn, msgLength))
     389            0 :                             return;
     390              :                     }
     391            0 :                     else if (conn->error_result ||
     392            0 :                              (conn->result != NULL &&
     393            0 :                               conn->result->resultStatus == PGRES_FATAL_ERROR))
     394              :                     {
     395              :                         /*
     396              :                          * We've already choked for some reason.  Just discard
     397              :                          * tuples till we get to the end of the query.
     398              :                          */
     399            0 :                         conn->inCursor += msgLength;
     400              :                     }
     401              :                     else
     402              :                     {
     403              :                         /* Set up to report error at end of query */
     404            0 :                         libpq_append_conn_error(conn, "server sent data (\"D\" message) without prior row description (\"T\" message)");
     405            0 :                         pqSaveErrorResult(conn);
     406              :                         /* Discard the unexpected message */
     407            0 :                         conn->inCursor += msgLength;
     408              :                     }
     409      4499712 :                     break;
     410          564 :                 case PqMsg_CopyInResponse:
     411          564 :                     if (getCopyStart(conn, PGRES_COPY_IN))
     412            0 :                         return;
     413          564 :                     conn->asyncStatus = PGASYNC_COPY_IN;
     414          564 :                     break;
     415         4924 :                 case PqMsg_CopyOutResponse:
     416         4924 :                     if (getCopyStart(conn, PGRES_COPY_OUT))
     417            0 :                         return;
     418         4924 :                     conn->asyncStatus = PGASYNC_COPY_OUT;
     419         4924 :                     conn->copy_already_done = 0;
     420         4924 :                     break;
     421          759 :                 case PqMsg_CopyBothResponse:
     422          759 :                     if (getCopyStart(conn, PGRES_COPY_BOTH))
     423            0 :                         return;
     424          759 :                     conn->asyncStatus = PGASYNC_COPY_BOTH;
     425          759 :                     conn->copy_already_done = 0;
     426          759 :                     break;
     427           11 :                 case PqMsg_CopyData:
     428              : 
     429              :                     /*
     430              :                      * If we see Copy Data, just silently drop it.  This would
     431              :                      * only occur if application exits COPY OUT mode too
     432              :                      * early.
     433              :                      */
     434           11 :                     conn->inCursor += msgLength;
     435           11 :                     break;
     436         5278 :                 case PqMsg_CopyDone:
     437              : 
     438              :                     /*
     439              :                      * If we see Copy Done, just silently drop it.  This is
     440              :                      * the normal case during PQendcopy.  We will keep
     441              :                      * swallowing data, expecting to see command-complete for
     442              :                      * the COPY command.
     443              :                      */
     444         5278 :                     break;
     445            0 :                 default:
     446            0 :                     libpq_append_conn_error(conn, "unexpected response from server; first received character was \"%c\"", id);
     447              :                     /* build an error result holding the error message */
     448            0 :                     pqSaveErrorResult(conn);
     449              :                     /* not sure if we will see more, so go to ready state */
     450            0 :                     conn->asyncStatus = PGASYNC_READY;
     451              :                     /* Discard the unexpected message */
     452            0 :                     conn->inCursor += msgLength;
     453            0 :                     break;
     454              :             }                   /* switch on protocol character */
     455              :         }
     456              :         /* Successfully consumed this message */
     457      5735880 :         if (conn->inCursor == conn->inStart + 5 + msgLength)
     458              :         {
     459              :             /* Normal case: parsing agrees with specified length */
     460      5735880 :             pqParseDone(conn, conn->inCursor);
     461              :         }
     462            0 :         else if (conn->error_result && conn->status == CONNECTION_BAD)
     463              :         {
     464              :             /* The connection was abandoned and we already reported it */
     465            0 :             return;
     466              :         }
     467              :         else
     468              :         {
     469              :             /* Trouble --- report it */
     470            0 :             libpq_append_conn_error(conn, "message contents do not agree with length in message type \"%c\"", id);
     471              :             /* build an error result holding the error message */
     472            0 :             pqSaveErrorResult(conn);
     473            0 :             conn->asyncStatus = PGASYNC_READY;
     474              :             /* trust the specified message length as what to skip */
     475            0 :             conn->inStart += 5 + msgLength;
     476              :         }
     477              :     }
     478              : }
     479              : 
     480              : /*
     481              :  * handleFatalError: clean up after a nonrecoverable error
     482              :  *
     483              :  * This is for errors where we need to abandon the connection.  The caller has
     484              :  * already saved the error message in conn->errorMessage.
     485              :  */
     486              : static void
     487            0 : handleFatalError(PGconn *conn)
     488              : {
     489              :     /* build an error result holding the error message */
     490            0 :     pqSaveErrorResult(conn);
     491            0 :     conn->asyncStatus = PGASYNC_READY;   /* drop out of PQgetResult wait loop */
     492              :     /* flush input data since we're giving up on processing it */
     493            0 :     pqDropConnection(conn, true);
     494            0 :     conn->status = CONNECTION_BAD;   /* No more connection to backend */
     495            0 : }
     496              : 
     497              : /*
     498              :  * handleSyncLoss: clean up after loss of message-boundary sync
     499              :  *
     500              :  * There isn't really a lot we can do here except abandon the connection.
     501              :  */
     502              : static void
     503            0 : handleSyncLoss(PGconn *conn, char id, int msgLength)
     504              : {
     505            0 :     libpq_append_conn_error(conn, "lost synchronization with server: got message type \"%c\", length %d",
     506              :                             id, msgLength);
     507            0 :     handleFatalError(conn);
     508            0 : }
     509              : 
     510              : /*
     511              :  * parseInput subroutine to read a 'T' (row descriptions) message.
     512              :  * We'll build a new PGresult structure (unless called for a Describe
     513              :  * command for a prepared statement) containing the attribute data.
     514              :  * Returns: 0 if processed message successfully, EOF to suspend parsing
     515              :  * (the latter case is not actually used currently).
     516              :  */
     517              : static int
     518       172597 : getRowDescriptions(PGconn *conn, int msgLength)
     519              : {
     520              :     PGresult   *result;
     521              :     int         nfields;
     522              :     const char *errmsg;
     523              :     int         i;
     524              : 
     525              :     /*
     526              :      * When doing Describe for a prepared statement, there'll already be a
     527              :      * PGresult created by getParamDescriptions, and we should fill data into
     528              :      * that.  Otherwise, create a new, empty PGresult.
     529              :      */
     530       172597 :     if (!conn->cmd_queue_head ||
     531       172597 :         (conn->cmd_queue_head &&
     532       172597 :          conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE))
     533              :     {
     534           65 :         if (conn->result)
     535           64 :             result = conn->result;
     536              :         else
     537            1 :             result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
     538              :     }
     539              :     else
     540       172532 :         result = PQmakeEmptyPGresult(conn, PGRES_TUPLES_OK);
     541       172597 :     if (!result)
     542              :     {
     543            0 :         errmsg = NULL;          /* means "out of memory", see below */
     544            0 :         goto advance_and_error;
     545              :     }
     546              : 
     547              :     /* parseInput already read the 'T' label and message length. */
     548              :     /* the next two bytes are the number of fields */
     549       172597 :     if (pqGetInt(&(result->numAttributes), 2, conn))
     550              :     {
     551              :         /* We should not run out of data here, so complain */
     552            0 :         errmsg = libpq_gettext("insufficient data in \"T\" message");
     553            0 :         goto advance_and_error;
     554              :     }
     555       172597 :     nfields = result->numAttributes;
     556              : 
     557              :     /* allocate space for the attribute descriptors */
     558       172597 :     if (nfields > 0)
     559              :     {
     560       172399 :         result->attDescs = (PGresAttDesc *)
     561       172399 :             pqResultAlloc(result, nfields * sizeof(PGresAttDesc), true);
     562       172399 :         if (!result->attDescs)
     563              :         {
     564            0 :             errmsg = NULL;      /* means "out of memory", see below */
     565            0 :             goto advance_and_error;
     566              :         }
     567      2368627 :         MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
     568              :     }
     569              : 
     570              :     /* result->binary is true only if ALL columns are binary */
     571       172597 :     result->binary = (nfields > 0) ? 1 : 0;
     572              : 
     573              :     /* get type info */
     574       732784 :     for (i = 0; i < nfields; i++)
     575              :     {
     576              :         int         tableid;
     577              :         int         columnid;
     578              :         int         typid;
     579              :         int         typlen;
     580              :         int         atttypmod;
     581              :         int         format;
     582              : 
     583      1120374 :         if (pqGets(&conn->workBuffer, conn) ||
     584      1120374 :             pqGetInt(&tableid, 4, conn) ||
     585      1120374 :             pqGetInt(&columnid, 2, conn) ||
     586      1120374 :             pqGetInt(&typid, 4, conn) ||
     587      1120374 :             pqGetInt(&typlen, 2, conn) ||
     588      1120374 :             pqGetInt(&atttypmod, 4, conn) ||
     589       560187 :             pqGetInt(&format, 2, conn))
     590              :         {
     591              :             /* We should not run out of data here, so complain */
     592            0 :             errmsg = libpq_gettext("insufficient data in \"T\" message");
     593            0 :             goto advance_and_error;
     594              :         }
     595              : 
     596              :         /*
     597              :          * Since pqGetInt treats 2-byte integers as unsigned, we need to
     598              :          * coerce these results to signed form.
     599              :          */
     600       560187 :         columnid = (int) ((int16) columnid);
     601       560187 :         typlen = (int) ((int16) typlen);
     602       560187 :         format = (int) ((int16) format);
     603              : 
     604      1120374 :         result->attDescs[i].name = pqResultStrdup(result,
     605       560187 :                                                   conn->workBuffer.data);
     606       560187 :         if (!result->attDescs[i].name)
     607              :         {
     608            0 :             errmsg = NULL;      /* means "out of memory", see below */
     609            0 :             goto advance_and_error;
     610              :         }
     611       560187 :         result->attDescs[i].tableid = tableid;
     612       560187 :         result->attDescs[i].columnid = columnid;
     613       560187 :         result->attDescs[i].format = format;
     614       560187 :         result->attDescs[i].typid = typid;
     615       560187 :         result->attDescs[i].typlen = typlen;
     616       560187 :         result->attDescs[i].atttypmod = atttypmod;
     617              : 
     618       560187 :         if (format != 1)
     619       560144 :             result->binary = 0;
     620              :     }
     621              : 
     622              :     /* Success! */
     623       172597 :     conn->result = result;
     624              : 
     625              :     /*
     626              :      * If we're doing a Describe, we're done, and ready to pass the result
     627              :      * back to the client.
     628              :      */
     629       172597 :     if ((!conn->cmd_queue_head) ||
     630       172597 :         (conn->cmd_queue_head &&
     631       172597 :          conn->cmd_queue_head->queryclass == PGQUERY_DESCRIBE))
     632              :     {
     633           65 :         conn->asyncStatus = PGASYNC_READY;
     634           65 :         return 0;
     635              :     }
     636              : 
     637              :     /*
     638              :      * We could perform additional setup for the new result set here, but for
     639              :      * now there's nothing else to do.
     640              :      */
     641              : 
     642              :     /* And we're done. */
     643       172532 :     return 0;
     644              : 
     645            0 : advance_and_error:
     646              :     /* Discard unsaved result, if any */
     647            0 :     if (result && result != conn->result)
     648            0 :         PQclear(result);
     649              : 
     650              :     /*
     651              :      * Replace partially constructed result with an error result. First
     652              :      * discard the old result to try to win back some memory.
     653              :      */
     654            0 :     pqClearAsyncResult(conn);
     655              : 
     656              :     /*
     657              :      * If preceding code didn't provide an error message, assume "out of
     658              :      * memory" was meant.  The advantage of having this special case is that
     659              :      * freeing the old result first greatly improves the odds that gettext()
     660              :      * will succeed in providing a translation.
     661              :      */
     662            0 :     if (!errmsg)
     663            0 :         errmsg = libpq_gettext("out of memory for query result");
     664              : 
     665            0 :     appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
     666            0 :     pqSaveErrorResult(conn);
     667              : 
     668              :     /*
     669              :      * Show the message as fully consumed, else pqParseInput3 will overwrite
     670              :      * our error with a complaint about that.
     671              :      */
     672            0 :     conn->inCursor = conn->inStart + 5 + msgLength;
     673              : 
     674              :     /*
     675              :      * Return zero to allow input parsing to continue.  Subsequent "D"
     676              :      * messages will be ignored until we get to end of data, since an error
     677              :      * result is already set up.
     678              :      */
     679            0 :     return 0;
     680              : }
     681              : 
     682              : /*
     683              :  * parseInput subroutine to read a 't' (ParameterDescription) message.
     684              :  * We'll build a new PGresult structure containing the parameter data.
     685              :  * Returns: 0 if processed message successfully, EOF to suspend parsing
     686              :  * (the latter case is not actually used currently).
     687              :  */
     688              : static int
     689           70 : getParamDescriptions(PGconn *conn, int msgLength)
     690              : {
     691              :     PGresult   *result;
     692           70 :     const char *errmsg = NULL;  /* means "out of memory", see below */
     693              :     int         nparams;
     694              :     int         i;
     695              : 
     696           70 :     result = PQmakeEmptyPGresult(conn, PGRES_COMMAND_OK);
     697           70 :     if (!result)
     698            0 :         goto advance_and_error;
     699              : 
     700              :     /* parseInput already read the 't' label and message length. */
     701              :     /* the next two bytes are the number of parameters */
     702           70 :     if (pqGetInt(&(result->numParameters), 2, conn))
     703            0 :         goto not_enough_data;
     704           70 :     nparams = result->numParameters;
     705              : 
     706              :     /* allocate space for the parameter descriptors */
     707           70 :     if (nparams > 0)
     708              :     {
     709            4 :         result->paramDescs = (PGresParamDesc *)
     710            4 :             pqResultAlloc(result, nparams * sizeof(PGresParamDesc), true);
     711            4 :         if (!result->paramDescs)
     712            0 :             goto advance_and_error;
     713            7 :         MemSet(result->paramDescs, 0, nparams * sizeof(PGresParamDesc));
     714              :     }
     715              : 
     716              :     /* get parameter info */
     717           77 :     for (i = 0; i < nparams; i++)
     718              :     {
     719              :         int         typid;
     720              : 
     721            7 :         if (pqGetInt(&typid, 4, conn))
     722            0 :             goto not_enough_data;
     723            7 :         result->paramDescs[i].typid = typid;
     724              :     }
     725              : 
     726              :     /* Success! */
     727           70 :     conn->result = result;
     728              : 
     729           70 :     return 0;
     730              : 
     731            0 : not_enough_data:
     732            0 :     errmsg = libpq_gettext("insufficient data in \"t\" message");
     733              : 
     734            0 : advance_and_error:
     735              :     /* Discard unsaved result, if any */
     736            0 :     if (result && result != conn->result)
     737            0 :         PQclear(result);
     738              : 
     739              :     /*
     740              :      * Replace partially constructed result with an error result. First
     741              :      * discard the old result to try to win back some memory.
     742              :      */
     743            0 :     pqClearAsyncResult(conn);
     744              : 
     745              :     /*
     746              :      * If preceding code didn't provide an error message, assume "out of
     747              :      * memory" was meant.  The advantage of having this special case is that
     748              :      * freeing the old result first greatly improves the odds that gettext()
     749              :      * will succeed in providing a translation.
     750              :      */
     751            0 :     if (!errmsg)
     752            0 :         errmsg = libpq_gettext("out of memory");
     753            0 :     appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
     754            0 :     pqSaveErrorResult(conn);
     755              : 
     756              :     /*
     757              :      * Show the message as fully consumed, else pqParseInput3 will overwrite
     758              :      * our error with a complaint about that.
     759              :      */
     760            0 :     conn->inCursor = conn->inStart + 5 + msgLength;
     761              : 
     762              :     /*
     763              :      * Return zero to allow input parsing to continue.  Essentially, we've
     764              :      * replaced the COMMAND_OK result with an error result, but since this
     765              :      * doesn't affect the protocol state, it's fine.
     766              :      */
     767            0 :     return 0;
     768              : }
     769              : 
     770              : /*
     771              :  * parseInput subroutine to read a 'D' (row data) message.
     772              :  * We fill rowbuf with column pointers and then call the row processor.
     773              :  * Returns: 0 if processed message successfully, EOF to suspend parsing
     774              :  * (the latter case is not actually used currently).
     775              :  */
     776              : static int
     777      4499712 : getAnotherTuple(PGconn *conn, int msgLength)
     778              : {
     779      4499712 :     PGresult   *result = conn->result;
     780      4499712 :     int         nfields = result->numAttributes;
     781              :     const char *errmsg;
     782              :     PGdataValue *rowbuf;
     783              :     int         tupnfields;     /* # fields from tuple */
     784              :     int         vlen;           /* length of the current field value */
     785              :     int         i;
     786              : 
     787              :     /* Get the field count and make sure it's what we expect */
     788      4499712 :     if (pqGetInt(&tupnfields, 2, conn))
     789              :     {
     790              :         /* We should not run out of data here, so complain */
     791            0 :         errmsg = libpq_gettext("insufficient data in \"D\" message");
     792            0 :         goto advance_and_error;
     793              :     }
     794              : 
     795      4499712 :     if (tupnfields != nfields)
     796              :     {
     797            0 :         errmsg = libpq_gettext("unexpected field count in \"D\" message");
     798            0 :         goto advance_and_error;
     799              :     }
     800              : 
     801              :     /* Resize row buffer if needed */
     802      4499712 :     rowbuf = conn->rowBuf;
     803      4499712 :     if (nfields > conn->rowBufLen)
     804              :     {
     805          279 :         rowbuf = (PGdataValue *) realloc(rowbuf,
     806              :                                          nfields * sizeof(PGdataValue));
     807          279 :         if (!rowbuf)
     808              :         {
     809            0 :             errmsg = NULL;      /* means "out of memory", see below */
     810            0 :             goto advance_and_error;
     811              :         }
     812          279 :         conn->rowBuf = rowbuf;
     813          279 :         conn->rowBufLen = nfields;
     814              :     }
     815              : 
     816              :     /* Scan the fields */
     817     28112635 :     for (i = 0; i < nfields; i++)
     818              :     {
     819              :         /* get the value length */
     820     23612923 :         if (pqGetInt(&vlen, 4, conn))
     821              :         {
     822              :             /* We should not run out of data here, so complain */
     823            0 :             errmsg = libpq_gettext("insufficient data in \"D\" message");
     824            0 :             goto advance_and_error;
     825              :         }
     826     23612923 :         rowbuf[i].len = vlen;
     827              : 
     828              :         /*
     829              :          * rowbuf[i].value always points to the next address in the data
     830              :          * buffer even if the value is NULL.  This allows row processors to
     831              :          * estimate data sizes more easily.
     832              :          */
     833     23612923 :         rowbuf[i].value = conn->inBuffer + conn->inCursor;
     834              : 
     835              :         /* Skip over the data value */
     836     23612923 :         if (vlen > 0)
     837              :         {
     838     22213090 :             if (pqSkipnchar(vlen, conn))
     839              :             {
     840              :                 /* We should not run out of data here, so complain */
     841            0 :                 errmsg = libpq_gettext("insufficient data in \"D\" message");
     842            0 :                 goto advance_and_error;
     843              :             }
     844              :         }
     845              :     }
     846              : 
     847              :     /* Process the collected row */
     848      4499712 :     errmsg = NULL;
     849      4499712 :     if (pqRowProcessor(conn, &errmsg))
     850      4499712 :         return 0;               /* normal, successful exit */
     851              : 
     852              :     /* pqRowProcessor failed, fall through to report it */
     853              : 
     854            0 : advance_and_error:
     855              : 
     856              :     /*
     857              :      * Replace partially constructed result with an error result. First
     858              :      * discard the old result to try to win back some memory.
     859              :      */
     860            0 :     pqClearAsyncResult(conn);
     861              : 
     862              :     /*
     863              :      * If preceding code didn't provide an error message, assume "out of
     864              :      * memory" was meant.  The advantage of having this special case is that
     865              :      * freeing the old result first greatly improves the odds that gettext()
     866              :      * will succeed in providing a translation.
     867              :      */
     868            0 :     if (!errmsg)
     869            0 :         errmsg = libpq_gettext("out of memory for query result");
     870              : 
     871            0 :     appendPQExpBuffer(&conn->errorMessage, "%s\n", errmsg);
     872            0 :     pqSaveErrorResult(conn);
     873              : 
     874              :     /*
     875              :      * Show the message as fully consumed, else pqParseInput3 will overwrite
     876              :      * our error with a complaint about that.
     877              :      */
     878            0 :     conn->inCursor = conn->inStart + 5 + msgLength;
     879              : 
     880              :     /*
     881              :      * Return zero to allow input parsing to continue.  Subsequent "D"
     882              :      * messages will be ignored until we get to end of data, since an error
     883              :      * result is already set up.
     884              :      */
     885            0 :     return 0;
     886              : }
     887              : 
     888              : 
     889              : /*
     890              :  * Attempt to read an Error or Notice response message.
     891              :  * This is possible in several places, so we break it out as a subroutine.
     892              :  *
     893              :  * Entry: 'E' or 'N' message type and length have already been consumed.
     894              :  * Exit: returns 0 if successfully consumed message.
     895              :  *       returns EOF if not enough data.
     896              :  */
     897              : int
     898       102634 : pqGetErrorNotice3(PGconn *conn, bool isError)
     899              : {
     900       102634 :     PGresult   *res = NULL;
     901       102634 :     bool        have_position = false;
     902              :     PQExpBufferData workBuf;
     903              :     char        id;
     904              : 
     905              :     /* If in pipeline mode, set error indicator for it */
     906       102634 :     if (isError && conn->pipelineStatus != PQ_PIPELINE_OFF)
     907           49 :         conn->pipelineStatus = PQ_PIPELINE_ABORTED;
     908              : 
     909              :     /*
     910              :      * If this is an error message, pre-emptively clear any incomplete query
     911              :      * result we may have.  We'd just throw it away below anyway, and
     912              :      * releasing it before collecting the error might avoid out-of-memory.
     913              :      */
     914       102634 :     if (isError)
     915        23104 :         pqClearAsyncResult(conn);
     916              : 
     917              :     /*
     918              :      * Since the fields might be pretty long, we create a temporary
     919              :      * PQExpBuffer rather than using conn->workBuffer.  workBuffer is intended
     920              :      * for stuff that is expected to be short.  We shouldn't use
     921              :      * conn->errorMessage either, since this might be only a notice.
     922              :      */
     923       102634 :     initPQExpBuffer(&workBuf);
     924              : 
     925              :     /*
     926              :      * Make a PGresult to hold the accumulated fields.  We temporarily lie
     927              :      * about the result status, so that PQmakeEmptyPGresult doesn't uselessly
     928              :      * copy conn->errorMessage.
     929              :      *
     930              :      * NB: This allocation can fail, if you run out of memory. The rest of the
     931              :      * function handles that gracefully, and we still try to set the error
     932              :      * message as the connection's error message.
     933              :      */
     934       102634 :     res = PQmakeEmptyPGresult(conn, PGRES_EMPTY_QUERY);
     935       102634 :     if (res)
     936       102634 :         res->resultStatus = isError ? PGRES_FATAL_ERROR : PGRES_NONFATAL_ERROR;
     937              : 
     938              :     /*
     939              :      * Read the fields and save into res.
     940              :      *
     941              :      * While at it, save the SQLSTATE in conn->last_sqlstate, and note whether
     942              :      * we saw a PG_DIAG_STATEMENT_POSITION field.
     943              :      */
     944              :     for (;;)
     945              :     {
     946       916489 :         if (pqGetc(&id, conn))
     947            0 :             goto fail;
     948       916489 :         if (id == '\0')
     949       102634 :             break;              /* terminator found */
     950       813855 :         if (pqGets(&workBuf, conn))
     951            0 :             goto fail;
     952       813855 :         pqSaveMessageField(res, id, workBuf.data);
     953       813855 :         if (id == PG_DIAG_SQLSTATE)
     954       102634 :             strlcpy(conn->last_sqlstate, workBuf.data,
     955              :                     sizeof(conn->last_sqlstate));
     956       711221 :         else if (id == PG_DIAG_STATEMENT_POSITION)
     957         5698 :             have_position = true;
     958              :     }
     959              : 
     960              :     /*
     961              :      * Save the active query text, if any, into res as well; but only if we
     962              :      * might need it for an error cursor display, which is only true if there
     963              :      * is a PG_DIAG_STATEMENT_POSITION field.
     964              :      */
     965       102634 :     if (have_position && res && conn->cmd_queue_head && conn->cmd_queue_head->query)
     966         5698 :         res->errQuery = pqResultStrdup(res, conn->cmd_queue_head->query);
     967              : 
     968              :     /*
     969              :      * Now build the "overall" error message for PQresultErrorMessage.
     970              :      */
     971       102634 :     resetPQExpBuffer(&workBuf);
     972       102634 :     pqBuildErrorMessage3(&workBuf, res, conn->verbosity, conn->show_context);
     973              : 
     974              :     /*
     975              :      * Either save error as current async result, or just emit the notice.
     976              :      */
     977       102634 :     if (isError)
     978              :     {
     979        23104 :         pqClearAsyncResult(conn);   /* redundant, but be safe */
     980        23104 :         if (res)
     981              :         {
     982        23104 :             pqSetResultError(res, &workBuf, 0);
     983        23104 :             conn->result = res;
     984              :         }
     985              :         else
     986              :         {
     987              :             /* Fall back to using the internal-error processing paths */
     988            0 :             conn->error_result = true;
     989              :         }
     990              : 
     991        23104 :         if (PQExpBufferDataBroken(workBuf))
     992            0 :             libpq_append_conn_error(conn, "out of memory");
     993              :         else
     994        23104 :             appendPQExpBufferStr(&conn->errorMessage, workBuf.data);
     995              :     }
     996              :     else
     997              :     {
     998              :         /* if we couldn't allocate the result set, just discard the NOTICE */
     999        79530 :         if (res)
    1000              :         {
    1001              :             /*
    1002              :              * We can cheat a little here and not copy the message.  But if we
    1003              :              * were unlucky enough to run out of memory while filling workBuf,
    1004              :              * insert "out of memory", as in pqSetResultError.
    1005              :              */
    1006        79530 :             if (PQExpBufferDataBroken(workBuf))
    1007            0 :                 res->errMsg = libpq_gettext("out of memory\n");
    1008              :             else
    1009        79530 :                 res->errMsg = workBuf.data;
    1010        79530 :             if (res->noticeHooks.noticeRec != NULL)
    1011        79530 :                 res->noticeHooks.noticeRec(res->noticeHooks.noticeRecArg, res);
    1012        79530 :             PQclear(res);
    1013              :         }
    1014              :     }
    1015              : 
    1016       102634 :     termPQExpBuffer(&workBuf);
    1017       102634 :     return 0;
    1018              : 
    1019            0 : fail:
    1020            0 :     PQclear(res);
    1021            0 :     termPQExpBuffer(&workBuf);
    1022            0 :     return EOF;
    1023              : }
    1024              : 
    1025              : /*
    1026              :  * Construct an error message from the fields in the given PGresult,
    1027              :  * appending it to the contents of "msg".
    1028              :  */
    1029              : void
    1030       102637 : pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res,
    1031              :                      PGVerbosity verbosity, PGContextVisibility show_context)
    1032              : {
    1033              :     const char *val;
    1034       102637 :     const char *querytext = NULL;
    1035       102637 :     int         querypos = 0;
    1036              : 
    1037              :     /* If we couldn't allocate a PGresult, just say "out of memory" */
    1038       102637 :     if (res == NULL)
    1039              :     {
    1040            0 :         appendPQExpBufferStr(msg, libpq_gettext("out of memory\n"));
    1041            0 :         return;
    1042              :     }
    1043              : 
    1044              :     /*
    1045              :      * If we don't have any broken-down fields, just return the base message.
    1046              :      * This mainly applies if we're given a libpq-generated error result.
    1047              :      */
    1048       102637 :     if (res->errFields == NULL)
    1049              :     {
    1050            0 :         if (res->errMsg && res->errMsg[0])
    1051            0 :             appendPQExpBufferStr(msg, res->errMsg);
    1052              :         else
    1053            0 :             appendPQExpBufferStr(msg, libpq_gettext("no error message available\n"));
    1054            0 :         return;
    1055              :     }
    1056              : 
    1057              :     /* Else build error message from relevant fields */
    1058       102637 :     val = PQresultErrorField(res, PG_DIAG_SEVERITY);
    1059       102637 :     if (val)
    1060       102637 :         appendPQExpBuffer(msg, "%s:  ", val);
    1061              : 
    1062       102637 :     if (verbosity == PQERRORS_SQLSTATE)
    1063              :     {
    1064              :         /*
    1065              :          * If we have a SQLSTATE, print that and nothing else.  If not (which
    1066              :          * shouldn't happen for server-generated errors, but might possibly
    1067              :          * happen for libpq-generated ones), fall back to TERSE format, as
    1068              :          * that seems better than printing nothing at all.
    1069              :          */
    1070           33 :         val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
    1071           33 :         if (val)
    1072              :         {
    1073           33 :             appendPQExpBuffer(msg, "%s\n", val);
    1074           33 :             return;
    1075              :         }
    1076            0 :         verbosity = PQERRORS_TERSE;
    1077              :     }
    1078              : 
    1079       102604 :     if (verbosity == PQERRORS_VERBOSE)
    1080              :     {
    1081            3 :         val = PQresultErrorField(res, PG_DIAG_SQLSTATE);
    1082            3 :         if (val)
    1083            3 :             appendPQExpBuffer(msg, "%s: ", val);
    1084              :     }
    1085       102604 :     val = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
    1086       102604 :     if (val)
    1087       102604 :         appendPQExpBufferStr(msg, val);
    1088       102604 :     val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION);
    1089       102604 :     if (val)
    1090              :     {
    1091         5698 :         if (verbosity != PQERRORS_TERSE && res->errQuery != NULL)
    1092              :         {
    1093              :             /* emit position as a syntax cursor display */
    1094         5695 :             querytext = res->errQuery;
    1095         5695 :             querypos = atoi(val);
    1096              :         }
    1097              :         else
    1098              :         {
    1099              :             /* emit position as text addition to primary message */
    1100              :             /* translator: %s represents a digit string */
    1101            3 :             appendPQExpBuffer(msg, libpq_gettext(" at character %s"),
    1102              :                               val);
    1103              :         }
    1104              :     }
    1105              :     else
    1106              :     {
    1107        96906 :         val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION);
    1108        96906 :         if (val)
    1109              :         {
    1110           47 :             querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
    1111           47 :             if (verbosity != PQERRORS_TERSE && querytext != NULL)
    1112              :             {
    1113              :                 /* emit position as a syntax cursor display */
    1114           47 :                 querypos = atoi(val);
    1115              :             }
    1116              :             else
    1117              :             {
    1118              :                 /* emit position as text addition to primary message */
    1119              :                 /* translator: %s represents a digit string */
    1120            0 :                 appendPQExpBuffer(msg, libpq_gettext(" at character %s"),
    1121              :                                   val);
    1122              :             }
    1123              :         }
    1124              :     }
    1125       102604 :     appendPQExpBufferChar(msg, '\n');
    1126       102604 :     if (verbosity != PQERRORS_TERSE)
    1127              :     {
    1128       102297 :         if (querytext && querypos > 0)
    1129         5742 :             reportErrorPosition(msg, querytext, querypos,
    1130         5742 :                                 res->client_encoding);
    1131       102297 :         val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
    1132       102297 :         if (val)
    1133         6168 :             appendPQExpBuffer(msg, libpq_gettext("DETAIL:  %s\n"), val);
    1134       102297 :         val = PQresultErrorField(res, PG_DIAG_MESSAGE_HINT);
    1135       102297 :         if (val)
    1136        67816 :             appendPQExpBuffer(msg, libpq_gettext("HINT:  %s\n"), val);
    1137       102297 :         val = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
    1138       102297 :         if (val)
    1139           47 :             appendPQExpBuffer(msg, libpq_gettext("QUERY:  %s\n"), val);
    1140       102297 :         if (show_context == PQSHOW_CONTEXT_ALWAYS ||
    1141       102132 :             (show_context == PQSHOW_CONTEXT_ERRORS &&
    1142       102132 :              res->resultStatus == PGRES_FATAL_ERROR))
    1143              :         {
    1144        23042 :             val = PQresultErrorField(res, PG_DIAG_CONTEXT);
    1145        23042 :             if (val)
    1146         1291 :                 appendPQExpBuffer(msg, libpq_gettext("CONTEXT:  %s\n"),
    1147              :                                   val);
    1148              :         }
    1149              :     }
    1150       102604 :     if (verbosity == PQERRORS_VERBOSE)
    1151              :     {
    1152            3 :         val = PQresultErrorField(res, PG_DIAG_SCHEMA_NAME);
    1153            3 :         if (val)
    1154            0 :             appendPQExpBuffer(msg,
    1155            0 :                               libpq_gettext("SCHEMA NAME:  %s\n"), val);
    1156            3 :         val = PQresultErrorField(res, PG_DIAG_TABLE_NAME);
    1157            3 :         if (val)
    1158            0 :             appendPQExpBuffer(msg,
    1159            0 :                               libpq_gettext("TABLE NAME:  %s\n"), val);
    1160            3 :         val = PQresultErrorField(res, PG_DIAG_COLUMN_NAME);
    1161            3 :         if (val)
    1162            0 :             appendPQExpBuffer(msg,
    1163            0 :                               libpq_gettext("COLUMN NAME:  %s\n"), val);
    1164            3 :         val = PQresultErrorField(res, PG_DIAG_DATATYPE_NAME);
    1165            3 :         if (val)
    1166            0 :             appendPQExpBuffer(msg,
    1167            0 :                               libpq_gettext("DATATYPE NAME:  %s\n"), val);
    1168            3 :         val = PQresultErrorField(res, PG_DIAG_CONSTRAINT_NAME);
    1169            3 :         if (val)
    1170            0 :             appendPQExpBuffer(msg,
    1171            0 :                               libpq_gettext("CONSTRAINT NAME:  %s\n"), val);
    1172              :     }
    1173       102604 :     if (verbosity == PQERRORS_VERBOSE)
    1174              :     {
    1175              :         const char *valf;
    1176              :         const char *vall;
    1177              : 
    1178            3 :         valf = PQresultErrorField(res, PG_DIAG_SOURCE_FILE);
    1179            3 :         vall = PQresultErrorField(res, PG_DIAG_SOURCE_LINE);
    1180            3 :         val = PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION);
    1181            3 :         if (val || valf || vall)
    1182              :         {
    1183            3 :             appendPQExpBufferStr(msg, libpq_gettext("LOCATION:  "));
    1184            3 :             if (val)
    1185            3 :                 appendPQExpBuffer(msg, libpq_gettext("%s, "), val);
    1186            3 :             if (valf && vall)   /* unlikely we'd have just one */
    1187            3 :                 appendPQExpBuffer(msg, libpq_gettext("%s:%s"),
    1188              :                                   valf, vall);
    1189            3 :             appendPQExpBufferChar(msg, '\n');
    1190              :         }
    1191              :     }
    1192              : }
    1193              : 
    1194              : /*
    1195              :  * Add an error-location display to the error message under construction.
    1196              :  *
    1197              :  * The cursor location is measured in logical characters; the query string
    1198              :  * is presumed to be in the specified encoding.
    1199              :  */
    1200              : static void
    1201         5742 : reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
    1202              : {
    1203              : #define DISPLAY_SIZE    60      /* screen width limit, in screen cols */
    1204              : #define MIN_RIGHT_CUT   10      /* try to keep this far away from EOL */
    1205              : 
    1206              :     char       *wquery;
    1207              :     int         slen,
    1208              :                 cno,
    1209              :                 i,
    1210              :                *qidx,
    1211              :                *scridx,
    1212              :                 qoffset,
    1213              :                 scroffset,
    1214              :                 ibeg,
    1215              :                 iend,
    1216              :                 loc_line;
    1217              :     bool        mb_encoding,
    1218              :                 beg_trunc,
    1219              :                 end_trunc;
    1220              : 
    1221              :     /* Convert loc from 1-based to 0-based; no-op if out of range */
    1222         5742 :     loc--;
    1223         5742 :     if (loc < 0)
    1224            0 :         return;
    1225              : 
    1226              :     /* Need a writable copy of the query */
    1227         5742 :     wquery = strdup(query);
    1228         5742 :     if (wquery == NULL)
    1229            0 :         return;                 /* fail silently if out of memory */
    1230              : 
    1231              :     /*
    1232              :      * Each character might occupy multiple physical bytes in the string, and
    1233              :      * in some Far Eastern character sets it might take more than one screen
    1234              :      * column as well.  We compute the starting byte offset and starting
    1235              :      * screen column of each logical character, and store these in qidx[] and
    1236              :      * scridx[] respectively.
    1237              :      */
    1238              : 
    1239              :     /*
    1240              :      * We need a safe allocation size.
    1241              :      *
    1242              :      * The only caller of reportErrorPosition() is pqBuildErrorMessage3(); it
    1243              :      * gets its query from either a PQresultErrorField() or a PGcmdQueueEntry,
    1244              :      * both of which must have fit into conn->inBuffer/outBuffer. So slen fits
    1245              :      * inside an int, but we can't assume that (slen * sizeof(int)) fits
    1246              :      * inside a size_t.
    1247              :      */
    1248         5742 :     slen = strlen(wquery) + 1;
    1249         5742 :     if (slen > SIZE_MAX / sizeof(int))
    1250              :     {
    1251            0 :         free(wquery);
    1252            0 :         return;
    1253              :     }
    1254              : 
    1255         5742 :     qidx = (int *) malloc(slen * sizeof(int));
    1256         5742 :     if (qidx == NULL)
    1257              :     {
    1258            0 :         free(wquery);
    1259            0 :         return;
    1260              :     }
    1261         5742 :     scridx = (int *) malloc(slen * sizeof(int));
    1262         5742 :     if (scridx == NULL)
    1263              :     {
    1264            0 :         free(qidx);
    1265            0 :         free(wquery);
    1266            0 :         return;
    1267              :     }
    1268              : 
    1269              :     /* We can optimize a bit if it's a single-byte encoding */
    1270         5742 :     mb_encoding = (pg_encoding_max_length(encoding) != 1);
    1271              : 
    1272              :     /*
    1273              :      * Within the scanning loop, cno is the current character's logical
    1274              :      * number, qoffset is its offset in wquery, and scroffset is its starting
    1275              :      * logical screen column (all indexed from 0).  "loc" is the logical
    1276              :      * character number of the error location.  We scan to determine loc_line
    1277              :      * (the 1-based line number containing loc) and ibeg/iend (first character
    1278              :      * number and last+1 character number of the line containing loc). Note
    1279              :      * that qidx[] and scridx[] are filled only as far as iend.
    1280              :      */
    1281         5742 :     qoffset = 0;
    1282         5742 :     scroffset = 0;
    1283         5742 :     loc_line = 1;
    1284         5742 :     ibeg = 0;
    1285         5742 :     iend = -1;                  /* -1 means not set yet */
    1286              : 
    1287       326892 :     for (cno = 0; wquery[qoffset] != '\0'; cno++)
    1288              :     {
    1289       321789 :         char        ch = wquery[qoffset];
    1290              : 
    1291       321789 :         qidx[cno] = qoffset;
    1292       321789 :         scridx[cno] = scroffset;
    1293              : 
    1294              :         /*
    1295              :          * Replace tabs with spaces in the writable copy.  (Later we might
    1296              :          * want to think about coping with their variable screen width, but
    1297              :          * not today.)
    1298              :          */
    1299       321789 :         if (ch == '\t')
    1300          489 :             wquery[qoffset] = ' ';
    1301              : 
    1302              :         /*
    1303              :          * If end-of-line, count lines and mark positions. Each \r or \n
    1304              :          * counts as a line except when \r \n appear together.
    1305              :          */
    1306       321300 :         else if (ch == '\r' || ch == '\n')
    1307              :         {
    1308         2103 :             if (cno < loc)
    1309              :             {
    1310         1464 :                 if (ch == '\r' ||
    1311         1461 :                     cno == 0 ||
    1312         1461 :                     wquery[qidx[cno - 1]] != '\r')
    1313         1464 :                     loc_line++;
    1314              :                 /* extract beginning = last line start before loc. */
    1315         1464 :                 ibeg = cno + 1;
    1316              :             }
    1317              :             else
    1318              :             {
    1319              :                 /* set extract end. */
    1320          639 :                 iend = cno;
    1321              :                 /* done scanning. */
    1322          639 :                 break;
    1323              :             }
    1324              :         }
    1325              : 
    1326              :         /* Advance */
    1327       321150 :         if (mb_encoding)
    1328              :         {
    1329              :             int         w;
    1330              : 
    1331       320962 :             w = pg_encoding_dsplen(encoding, &wquery[qoffset]);
    1332              :             /* treat any non-tab control chars as width 1 */
    1333       320962 :             if (w <= 0)
    1334         1464 :                 w = 1;
    1335       320962 :             scroffset += w;
    1336       320962 :             qoffset += PQmblenBounded(&wquery[qoffset], encoding);
    1337              :         }
    1338              :         else
    1339              :         {
    1340              :             /* We assume wide chars only exist in multibyte encodings */
    1341          188 :             scroffset++;
    1342          188 :             qoffset++;
    1343              :         }
    1344              :     }
    1345              :     /* Fix up if we didn't find an end-of-line after loc */
    1346         5742 :     if (iend < 0)
    1347              :     {
    1348         5103 :         iend = cno;             /* query length in chars, +1 */
    1349         5103 :         qidx[iend] = qoffset;
    1350         5103 :         scridx[iend] = scroffset;
    1351              :     }
    1352              : 
    1353              :     /* Print only if loc is within computed query length */
    1354         5742 :     if (loc <= cno)
    1355              :     {
    1356              :         /* If the line extracted is too long, we truncate it. */
    1357         5733 :         beg_trunc = false;
    1358         5733 :         end_trunc = false;
    1359         5733 :         if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
    1360              :         {
    1361              :             /*
    1362              :              * We first truncate right if it is enough.  This code might be
    1363              :              * off a space or so on enforcing MIN_RIGHT_CUT if there's a wide
    1364              :              * character right there, but that should be okay.
    1365              :              */
    1366         1645 :             if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT)
    1367              :             {
    1368        17282 :                 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
    1369        16299 :                     iend--;
    1370          983 :                 end_trunc = true;
    1371              :             }
    1372              :             else
    1373              :             {
    1374              :                 /* Truncate right if not too close to loc. */
    1375         7927 :                 while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend])
    1376              :                 {
    1377         7265 :                     iend--;
    1378         7265 :                     end_trunc = true;
    1379              :                 }
    1380              : 
    1381              :                 /* Truncate left if still too long. */
    1382        13422 :                 while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
    1383              :                 {
    1384        12760 :                     ibeg++;
    1385        12760 :                     beg_trunc = true;
    1386              :                 }
    1387              :             }
    1388              :         }
    1389              : 
    1390              :         /* truncate working copy at desired endpoint */
    1391         5733 :         wquery[qidx[iend]] = '\0';
    1392              : 
    1393              :         /* Begin building the finished message. */
    1394         5733 :         i = msg->len;
    1395         5733 :         appendPQExpBuffer(msg, libpq_gettext("LINE %d: "), loc_line);
    1396         5733 :         if (beg_trunc)
    1397          662 :             appendPQExpBufferStr(msg, "...");
    1398              : 
    1399              :         /*
    1400              :          * While we have the prefix in the msg buffer, compute its screen
    1401              :          * width.
    1402              :          */
    1403         5733 :         scroffset = 0;
    1404        53589 :         for (; i < msg->len; i += PQmblenBounded(&msg->data[i], encoding))
    1405              :         {
    1406        47856 :             int         w = pg_encoding_dsplen(encoding, &msg->data[i]);
    1407              : 
    1408        47856 :             if (w <= 0)
    1409            0 :                 w = 1;
    1410        47856 :             scroffset += w;
    1411              :         }
    1412              : 
    1413              :         /* Finish up the LINE message line. */
    1414         5733 :         appendPQExpBufferStr(msg, &wquery[qidx[ibeg]]);
    1415         5733 :         if (end_trunc)
    1416         1463 :             appendPQExpBufferStr(msg, "...");
    1417         5733 :         appendPQExpBufferChar(msg, '\n');
    1418              : 
    1419              :         /* Now emit the cursor marker line. */
    1420         5733 :         scroffset += scridx[loc] - scridx[ibeg];
    1421       184168 :         for (i = 0; i < scroffset; i++)
    1422       178435 :             appendPQExpBufferChar(msg, ' ');
    1423         5733 :         appendPQExpBufferChar(msg, '^');
    1424         5733 :         appendPQExpBufferChar(msg, '\n');
    1425              :     }
    1426              : 
    1427              :     /* Clean up. */
    1428         5742 :     free(scridx);
    1429         5742 :     free(qidx);
    1430         5742 :     free(wquery);
    1431              : }
    1432              : 
    1433              : 
    1434              : /*
    1435              :  * Attempt to read a NegotiateProtocolVersion message.  Sets conn->pversion
    1436              :  * to the version that's negotiated by the server.
    1437              :  *
    1438              :  * Entry: 'v' message type and length have already been consumed.
    1439              :  * Exit: returns 0 if successfully consumed message.
    1440              :  *       returns 1 on failure. The error message is filled in.
    1441              :  */
    1442              : int
    1443        14491 : pqGetNegotiateProtocolVersion3(PGconn *conn)
    1444              : {
    1445              :     int         their_version;
    1446              :     int         num;
    1447              :     bool        found_test_protocol_negotiation;
    1448              :     bool        expect_test_protocol_negotiation;
    1449              : 
    1450              :     /*
    1451              :      * During 19beta only, if protocol grease is in use, assume that it's the
    1452              :      * cause of any invalid messages encountered below. We'll print extra
    1453              :      * information for the end user in that case.
    1454              :      */
    1455        14491 :     bool        need_grease_info = (conn->max_pversion == PG_PROTOCOL_GREASE);
    1456              : 
    1457        14491 :     if (pqGetInt(&their_version, 4, conn) != 0)
    1458            0 :         goto eof;
    1459              : 
    1460        14491 :     if (pqGetInt(&num, 4, conn) != 0)
    1461            0 :         goto eof;
    1462              : 
    1463              :     /*
    1464              :      * Check the protocol version.
    1465              :      *
    1466              :      * PG_PROTOCOL_GREASE is intentionally unsupported and reserved. It's
    1467              :      * higher than any real version, so check for that first, to get the most
    1468              :      * specific error message. Then check the upper and lower bounds.
    1469              :      */
    1470        14491 :     if (their_version == PG_PROTOCOL_GREASE)
    1471              :     {
    1472            0 :         libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested \"grease\" protocol version 3.9999");
    1473            0 :         goto failure;
    1474              :     }
    1475              : 
    1476        14491 :     if (their_version > conn->pversion)
    1477              :     {
    1478            0 :         libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to a higher-numbered version");
    1479            0 :         goto failure;
    1480              :     }
    1481              : 
    1482        14491 :     if (their_version < PG_PROTOCOL(3, 0))
    1483              :     {
    1484            0 :         libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to pre-3.0 protocol version");
    1485            0 :         goto failure;
    1486              :     }
    1487              : 
    1488              :     /* 3.1 never existed, we went straight from 3.0 to 3.2 */
    1489        14491 :     if (their_version == PG_PROTOCOL_RESERVED_31)
    1490              :     {
    1491            0 :         libpq_append_conn_error(conn, "received invalid protocol negotiation message: server requested downgrade to non-existent 3.1 protocol version");
    1492            0 :         goto failure;
    1493              :     }
    1494              : 
    1495        14491 :     if (num < 0)
    1496              :     {
    1497            0 :         libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported negative number of unsupported parameters");
    1498            0 :         goto failure;
    1499              :     }
    1500              : 
    1501        14491 :     if (their_version == conn->pversion && num == 0)
    1502              :     {
    1503            0 :         libpq_append_conn_error(conn, "received invalid protocol negotiation message: server negotiated but asks for no changes");
    1504            0 :         goto failure;
    1505              :     }
    1506              : 
    1507        14491 :     if (their_version < conn->min_pversion)
    1508              :     {
    1509            0 :         libpq_append_conn_error(conn, "server only supports protocol version %d.%d, but \"%s\" was set to %d.%d",
    1510              :                                 PG_PROTOCOL_MAJOR(their_version),
    1511              :                                 PG_PROTOCOL_MINOR(their_version),
    1512              :                                 "min_protocol_version",
    1513            0 :                                 PG_PROTOCOL_MAJOR(conn->min_pversion),
    1514            0 :                                 PG_PROTOCOL_MINOR(conn->min_pversion));
    1515              : 
    1516            0 :         need_grease_info = false;   /* this is valid server behavior */
    1517            0 :         goto failure;
    1518              :     }
    1519              : 
    1520              :     /* the version is acceptable */
    1521        14491 :     conn->pversion = their_version;
    1522              : 
    1523              :     /*
    1524              :      * Check that all expected unsupported parameters are reported by the
    1525              :      * server.
    1526              :      */
    1527        14491 :     found_test_protocol_negotiation = false;
    1528        14491 :     expect_test_protocol_negotiation = (conn->max_pversion == PG_PROTOCOL_GREASE);
    1529              : 
    1530        28982 :     for (int i = 0; i < num; i++)
    1531              :     {
    1532        14491 :         if (pqGets(&conn->workBuffer, conn))
    1533              :         {
    1534            0 :             goto eof;
    1535              :         }
    1536        14491 :         if (strncmp(conn->workBuffer.data, "_pq_.", 5) != 0)
    1537              :         {
    1538            0 :             libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported unsupported parameter name without a \"%s\" prefix (\"%s\")", "_pq_.", conn->workBuffer.data);
    1539            0 :             goto failure;
    1540              :         }
    1541              : 
    1542              :         /* Check if this is the expected test parameter */
    1543        14491 :         if (expect_test_protocol_negotiation &&
    1544        14491 :             strcmp(conn->workBuffer.data, "_pq_.test_protocol_negotiation") == 0)
    1545              :         {
    1546        14491 :             found_test_protocol_negotiation = true;
    1547              :         }
    1548              :         else
    1549              :         {
    1550            0 :             libpq_append_conn_error(conn, "received invalid protocol negotiation message: server reported an unsupported parameter that was not requested (\"%s\")",
    1551              :                                     conn->workBuffer.data);
    1552            0 :             goto failure;
    1553              :         }
    1554              :     }
    1555              : 
    1556              :     /*
    1557              :      * If we requested protocol grease, the server must report
    1558              :      * _pq_.test_protocol_negotiation as unsupported. This ensures
    1559              :      * comprehensive NegotiateProtocolVersion implementation.
    1560              :      */
    1561        14491 :     if (expect_test_protocol_negotiation && !found_test_protocol_negotiation)
    1562              :     {
    1563            0 :         libpq_append_conn_error(conn, "server did not report the unsupported `_pq_.test_protocol_negotiation` parameter in its protocol negotiation message");
    1564            0 :         goto failure;
    1565              :     }
    1566              : 
    1567        14491 :     return 0;
    1568              : 
    1569            0 : eof:
    1570            0 :     libpq_append_conn_error(conn, "received invalid protocol negotiation message: message too short");
    1571            0 : failure:
    1572            0 :     if (need_grease_info)
    1573            0 :         libpq_append_grease_info(conn);
    1574            0 :     conn->asyncStatus = PGASYNC_READY;
    1575            0 :     pqSaveErrorResult(conn);
    1576            0 :     return 1;
    1577              : }
    1578              : 
    1579              : 
    1580              : /*
    1581              :  * Attempt to read a ParameterStatus message.
    1582              :  * This is possible in several places, so we break it out as a subroutine.
    1583              :  *
    1584              :  * Entry: 'S' message type and length have already been consumed.
    1585              :  * Exit: returns 0 if successfully consumed message.
    1586              :  *       returns EOF if not enough data.
    1587              :  */
    1588              : static int
    1589       220634 : getParameterStatus(PGconn *conn)
    1590              : {
    1591              :     PQExpBufferData valueBuf;
    1592              : 
    1593              :     /* Get the parameter name */
    1594       220634 :     if (pqGets(&conn->workBuffer, conn))
    1595            0 :         return EOF;
    1596              :     /* Get the parameter value (could be large) */
    1597       220634 :     initPQExpBuffer(&valueBuf);
    1598       220634 :     if (pqGets(&valueBuf, conn))
    1599              :     {
    1600            0 :         termPQExpBuffer(&valueBuf);
    1601            0 :         return EOF;
    1602              :     }
    1603              :     /* And save it */
    1604       220634 :     if (!pqSaveParameterStatus(conn, conn->workBuffer.data, valueBuf.data))
    1605              :     {
    1606            0 :         libpq_append_conn_error(conn, "out of memory");
    1607            0 :         handleFatalError(conn);
    1608              :     }
    1609       220634 :     termPQExpBuffer(&valueBuf);
    1610       220634 :     return 0;
    1611              : }
    1612              : 
    1613              : /*
    1614              :  * parseInput subroutine to read a BackendKeyData message.
    1615              :  * Entry: 'v' message type and length have already been consumed.
    1616              :  * Exit: returns 0 if successfully consumed message.
    1617              :  *       returns EOF if not enough data.
    1618              :  */
    1619              : static int
    1620        14204 : getBackendKeyData(PGconn *conn, int msgLength)
    1621              : {
    1622              :     int         cancel_key_len;
    1623              : 
    1624        14204 :     if (conn->be_cancel_key)
    1625              :     {
    1626            0 :         free(conn->be_cancel_key);
    1627            0 :         conn->be_cancel_key = NULL;
    1628            0 :         conn->be_cancel_key_len = 0;
    1629              :     }
    1630              : 
    1631        14204 :     if (pqGetInt(&(conn->be_pid), 4, conn))
    1632            0 :         return EOF;
    1633              : 
    1634        14204 :     cancel_key_len = 5 + msgLength - (conn->inCursor - conn->inStart);
    1635              : 
    1636        14204 :     if (cancel_key_len != 4 && conn->pversion == PG_PROTOCOL(3, 0))
    1637              :     {
    1638            0 :         libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d not allowed in protocol version 3.0 (must be 4 bytes)", cancel_key_len);
    1639            0 :         handleFatalError(conn);
    1640            0 :         return 0;
    1641              :     }
    1642              : 
    1643        14204 :     if (cancel_key_len < 4)
    1644              :     {
    1645            0 :         libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d is too short (minimum 4 bytes)", cancel_key_len);
    1646            0 :         handleFatalError(conn);
    1647            0 :         return 0;
    1648              :     }
    1649              : 
    1650        14204 :     if (cancel_key_len > 256)
    1651              :     {
    1652            0 :         libpq_append_conn_error(conn, "received invalid BackendKeyData message: cancel key with length %d is too long (maximum 256 bytes)", cancel_key_len);
    1653            0 :         handleFatalError(conn);
    1654            0 :         return 0;
    1655              :     }
    1656              : 
    1657        14204 :     conn->be_cancel_key = malloc(cancel_key_len);
    1658        14204 :     if (conn->be_cancel_key == NULL)
    1659              :     {
    1660            0 :         libpq_append_conn_error(conn, "out of memory");
    1661            0 :         handleFatalError(conn);
    1662            0 :         return 0;
    1663              :     }
    1664        14204 :     if (pqGetnchar(conn->be_cancel_key, cancel_key_len, conn))
    1665              :     {
    1666            0 :         free(conn->be_cancel_key);
    1667            0 :         conn->be_cancel_key = NULL;
    1668            0 :         return EOF;
    1669              :     }
    1670        14204 :     conn->be_cancel_key_len = cancel_key_len;
    1671        14204 :     return 0;
    1672              : }
    1673              : 
    1674              : 
    1675              : /*
    1676              :  * Attempt to read a Notify response message.
    1677              :  * This is possible in several places, so we break it out as a subroutine.
    1678              :  *
    1679              :  * Entry: 'A' message type and length have already been consumed.
    1680              :  * Exit: returns 0 if successfully consumed Notify message.
    1681              :  *       returns EOF if not enough data.
    1682              :  */
    1683              : static int
    1684           65 : getNotify(PGconn *conn)
    1685              : {
    1686              :     int         be_pid;
    1687              :     char       *svname;
    1688              :     int         nmlen;
    1689              :     int         extralen;
    1690              :     PGnotify   *newNotify;
    1691              : 
    1692           65 :     if (pqGetInt(&be_pid, 4, conn))
    1693            0 :         return EOF;
    1694           65 :     if (pqGets(&conn->workBuffer, conn))
    1695            0 :         return EOF;
    1696              :     /* must save name while getting extra string */
    1697           65 :     svname = strdup(conn->workBuffer.data);
    1698           65 :     if (!svname)
    1699              :     {
    1700              :         /*
    1701              :          * Notify messages can arrive at any state, so we cannot associate the
    1702              :          * error with any particular query.  There's no way to return back an
    1703              :          * "async error", so the best we can do is drop the connection.  That
    1704              :          * seems better than silently ignoring the notification.
    1705              :          */
    1706            0 :         libpq_append_conn_error(conn, "out of memory");
    1707            0 :         handleFatalError(conn);
    1708            0 :         return 0;
    1709              :     }
    1710           65 :     if (pqGets(&conn->workBuffer, conn))
    1711              :     {
    1712            0 :         free(svname);
    1713            0 :         return EOF;
    1714              :     }
    1715              : 
    1716              :     /*
    1717              :      * Store the strings right after the PGnotify structure so it can all be
    1718              :      * freed at once.  We don't use NAMEDATALEN because we don't want to tie
    1719              :      * this interface to a specific server name length.
    1720              :      */
    1721           65 :     nmlen = strlen(svname);
    1722           65 :     extralen = strlen(conn->workBuffer.data);
    1723           65 :     newNotify = (PGnotify *) malloc(sizeof(PGnotify) + nmlen + extralen + 2);
    1724           65 :     if (!newNotify)
    1725              :     {
    1726            0 :         free(svname);
    1727            0 :         libpq_append_conn_error(conn, "out of memory");
    1728            0 :         handleFatalError(conn);
    1729            0 :         return 0;
    1730              :     }
    1731              : 
    1732           65 :     newNotify->relname = (char *) newNotify + sizeof(PGnotify);
    1733           65 :     strcpy(newNotify->relname, svname);
    1734           65 :     newNotify->extra = newNotify->relname + nmlen + 1;
    1735           65 :     strcpy(newNotify->extra, conn->workBuffer.data);
    1736           65 :     newNotify->be_pid = be_pid;
    1737           65 :     newNotify->next = NULL;
    1738           65 :     if (conn->notifyTail)
    1739           39 :         conn->notifyTail->next = newNotify;
    1740              :     else
    1741           26 :         conn->notifyHead = newNotify;
    1742           65 :     conn->notifyTail = newNotify;
    1743              : 
    1744           65 :     free(svname);
    1745           65 :     return 0;
    1746              : }
    1747              : 
    1748              : /*
    1749              :  * getCopyStart - process CopyInResponse, CopyOutResponse or
    1750              :  * CopyBothResponse message
    1751              :  *
    1752              :  * parseInput already read the message type and length.
    1753              :  */
    1754              : static int
    1755         6247 : getCopyStart(PGconn *conn, ExecStatusType copytype)
    1756              : {
    1757              :     PGresult   *result;
    1758              :     int         nfields;
    1759              :     int         i;
    1760              : 
    1761         6247 :     result = PQmakeEmptyPGresult(conn, copytype);
    1762         6247 :     if (!result)
    1763            0 :         goto failure;
    1764              : 
    1765         6247 :     if (pqGetc(&conn->copy_is_binary, conn))
    1766            0 :         goto failure;
    1767         6247 :     result->binary = conn->copy_is_binary;
    1768              :     /* the next two bytes are the number of fields  */
    1769         6247 :     if (pqGetInt(&(result->numAttributes), 2, conn))
    1770            0 :         goto failure;
    1771         6247 :     nfields = result->numAttributes;
    1772              : 
    1773              :     /* allocate space for the attribute descriptors */
    1774         6247 :     if (nfields > 0)
    1775              :     {
    1776         5174 :         result->attDescs = (PGresAttDesc *)
    1777         5174 :             pqResultAlloc(result, nfields * sizeof(PGresAttDesc), true);
    1778         5174 :         if (!result->attDescs)
    1779            0 :             goto failure;
    1780        56346 :         MemSet(result->attDescs, 0, nfields * sizeof(PGresAttDesc));
    1781              :     }
    1782              : 
    1783        23846 :     for (i = 0; i < nfields; i++)
    1784              :     {
    1785              :         int         format;
    1786              : 
    1787        17599 :         if (pqGetInt(&format, 2, conn))
    1788            0 :             goto failure;
    1789              : 
    1790              :         /*
    1791              :          * Since pqGetInt treats 2-byte integers as unsigned, we need to
    1792              :          * coerce these results to signed form.
    1793              :          */
    1794        17599 :         format = (int) ((int16) format);
    1795        17599 :         result->attDescs[i].format = format;
    1796              :     }
    1797              : 
    1798              :     /* Success! */
    1799         6247 :     conn->result = result;
    1800         6247 :     return 0;
    1801              : 
    1802            0 : failure:
    1803            0 :     PQclear(result);
    1804            0 :     return EOF;
    1805              : }
    1806              : 
    1807              : /*
    1808              :  * getReadyForQuery - process ReadyForQuery message
    1809              :  */
    1810              : static int
    1811       355429 : getReadyForQuery(PGconn *conn)
    1812              : {
    1813              :     char        xact_status;
    1814              : 
    1815       355429 :     if (pqGetc(&xact_status, conn))
    1816            0 :         return EOF;
    1817       355429 :     switch (xact_status)
    1818              :     {
    1819       264275 :         case 'I':
    1820       264275 :             conn->xactStatus = PQTRANS_IDLE;
    1821       264275 :             break;
    1822        90211 :         case 'T':
    1823        90211 :             conn->xactStatus = PQTRANS_INTRANS;
    1824        90211 :             break;
    1825          943 :         case 'E':
    1826          943 :             conn->xactStatus = PQTRANS_INERROR;
    1827          943 :             break;
    1828            0 :         default:
    1829            0 :             conn->xactStatus = PQTRANS_UNKNOWN;
    1830            0 :             break;
    1831              :     }
    1832              : 
    1833       355429 :     return 0;
    1834              : }
    1835              : 
    1836              : /*
    1837              :  * getCopyDataMessage - fetch next CopyData message, process async messages
    1838              :  *
    1839              :  * Returns length word of CopyData message (> 0), or 0 if no complete
    1840              :  * message available, -1 if end of copy, -2 if error.
    1841              :  */
    1842              : static int
    1843      2884214 : getCopyDataMessage(PGconn *conn)
    1844              : {
    1845              :     char        id;
    1846              :     int         msgLength;
    1847              :     int         avail;
    1848              : 
    1849              :     for (;;)
    1850              :     {
    1851              :         /*
    1852              :          * Do we have the next input message?  To make life simpler for async
    1853              :          * callers, we keep returning 0 until the next message is fully
    1854              :          * available, even if it is not Copy Data.
    1855              :          */
    1856      2884251 :         conn->inCursor = conn->inStart;
    1857      2884251 :         if (pqGetc(&id, conn))
    1858       188815 :             return 0;
    1859      2695436 :         if (pqGetInt(&msgLength, 4, conn))
    1860          552 :             return 0;
    1861      2694884 :         if (msgLength < 4)
    1862              :         {
    1863            0 :             handleSyncLoss(conn, id, msgLength);
    1864            0 :             return -2;
    1865              :         }
    1866      2694884 :         avail = conn->inEnd - conn->inCursor;
    1867      2694884 :         if (avail < msgLength - 4)
    1868              :         {
    1869              :             /*
    1870              :              * Before returning, enlarge the input buffer if needed to hold
    1871              :              * the whole message.  See notes in parseInput.
    1872              :              */
    1873       205813 :             if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength - 4,
    1874              :                                      conn))
    1875              :             {
    1876              :                 /*
    1877              :                  * Abandon the connection.  There's not much else we can
    1878              :                  * safely do; we can't just ignore the message or we could
    1879              :                  * miss important changes to the connection state.
    1880              :                  * pqCheckInBufferSpace() already reported the error.
    1881              :                  */
    1882            0 :                 handleFatalError(conn);
    1883            0 :                 return -2;
    1884              :             }
    1885       205813 :             return 0;
    1886              :         }
    1887              : 
    1888              :         /*
    1889              :          * If it's a legitimate async message type, process it.  (NOTIFY
    1890              :          * messages are not currently possible here, but we handle them for
    1891              :          * completeness.)  Otherwise, if it's anything except Copy Data,
    1892              :          * report end-of-copy.
    1893              :          */
    1894      2489071 :         switch (id)
    1895              :         {
    1896            0 :             case PqMsg_NotificationResponse:
    1897            0 :                 if (getNotify(conn))
    1898            0 :                     return 0;
    1899            0 :                 break;
    1900           37 :             case PqMsg_NoticeResponse:
    1901           37 :                 if (pqGetErrorNotice3(conn, false))
    1902            0 :                     return 0;
    1903           37 :                 break;
    1904            0 :             case PqMsg_ParameterStatus:
    1905            0 :                 if (getParameterStatus(conn))
    1906            0 :                     return 0;
    1907            0 :                 break;
    1908      2483895 :             case PqMsg_CopyData:
    1909      2483895 :                 return msgLength;
    1910         5083 :             case PqMsg_CopyDone:
    1911              : 
    1912              :                 /*
    1913              :                  * If this is a CopyDone message, exit COPY_OUT mode and let
    1914              :                  * caller read status with PQgetResult().  If we're in
    1915              :                  * COPY_BOTH mode, return to COPY_IN mode.
    1916              :                  */
    1917         5083 :                 if (conn->asyncStatus == PGASYNC_COPY_BOTH)
    1918           13 :                     conn->asyncStatus = PGASYNC_COPY_IN;
    1919              :                 else
    1920         5070 :                     conn->asyncStatus = PGASYNC_BUSY;
    1921         5083 :                 return -1;
    1922           56 :             default:            /* treat as end of copy */
    1923              : 
    1924              :                 /*
    1925              :                  * Any other message terminates either COPY_IN or COPY_BOTH
    1926              :                  * mode.
    1927              :                  */
    1928           56 :                 conn->asyncStatus = PGASYNC_BUSY;
    1929           56 :                 return -1;
    1930              :         }
    1931              : 
    1932              :         /* Drop the processed message and loop around for another */
    1933           37 :         pqParseDone(conn, conn->inCursor);
    1934              :     }
    1935              : }
    1936              : 
    1937              : /*
    1938              :  * PQgetCopyData - read a row of data from the backend during COPY OUT
    1939              :  * or COPY BOTH
    1940              :  *
    1941              :  * If successful, sets *buffer to point to a malloc'd row of data, and
    1942              :  * returns row length (always > 0) as result.
    1943              :  * Returns 0 if no row available yet (only possible if async is true),
    1944              :  * -1 if end of copy (consult PQgetResult), or -2 if error (consult
    1945              :  * PQerrorMessage).
    1946              :  */
    1947              : int
    1948      2786401 : pqGetCopyData3(PGconn *conn, char **buffer, int async)
    1949              : {
    1950              :     int         msgLength;
    1951              : 
    1952              :     for (;;)
    1953              :     {
    1954              :         /*
    1955              :          * Collect the next input message.  To make life simpler for async
    1956              :          * callers, we keep returning 0 until the next message is fully
    1957              :          * available, even if it is not Copy Data.
    1958              :          */
    1959      2884214 :         msgLength = getCopyDataMessage(conn);
    1960      2884214 :         if (msgLength < 0)
    1961         5139 :             return msgLength;   /* end-of-copy or error */
    1962      2879075 :         if (msgLength == 0)
    1963              :         {
    1964              :             /* Don't block if async read requested */
    1965       395180 :             if (async)
    1966       297367 :                 return 0;
    1967              :             /* Need to load more data */
    1968       195626 :             if (pqWait(true, false, conn) ||
    1969        97813 :                 pqReadData(conn) < 0)
    1970            0 :                 return -2;
    1971        97813 :             continue;
    1972              :         }
    1973              : 
    1974              :         /*
    1975              :          * Drop zero-length messages (shouldn't happen anyway).  Otherwise
    1976              :          * pass the data back to the caller.
    1977              :          */
    1978      2483895 :         msgLength -= 4;
    1979      2483895 :         if (msgLength > 0)
    1980              :         {
    1981      2483895 :             *buffer = (char *) malloc(msgLength + 1);
    1982      2483895 :             if (*buffer == NULL)
    1983              :             {
    1984            0 :                 libpq_append_conn_error(conn, "out of memory");
    1985            0 :                 return -2;
    1986              :             }
    1987      2483895 :             memcpy(*buffer, &conn->inBuffer[conn->inCursor], msgLength);
    1988      2483895 :             (*buffer)[msgLength] = '\0';    /* Add terminating null */
    1989              : 
    1990              :             /* Mark message consumed */
    1991      2483895 :             pqParseDone(conn, conn->inCursor + msgLength);
    1992              : 
    1993      2483895 :             return msgLength;
    1994              :         }
    1995              : 
    1996              :         /* Empty, so drop it and loop around for another */
    1997            0 :         pqParseDone(conn, conn->inCursor);
    1998              :     }
    1999              : }
    2000              : 
    2001              : /*
    2002              :  * PQgetline - gets a newline-terminated string from the backend.
    2003              :  *
    2004              :  * See fe-exec.c for documentation.
    2005              :  */
    2006              : int
    2007            0 : pqGetline3(PGconn *conn, char *s, int maxlen)
    2008              : {
    2009              :     int         status;
    2010              : 
    2011            0 :     if (conn->sock == PGINVALID_SOCKET ||
    2012            0 :         (conn->asyncStatus != PGASYNC_COPY_OUT &&
    2013            0 :          conn->asyncStatus != PGASYNC_COPY_BOTH) ||
    2014            0 :         conn->copy_is_binary)
    2015              :     {
    2016            0 :         libpq_append_conn_error(conn, "PQgetline: not doing text COPY OUT");
    2017            0 :         *s = '\0';
    2018            0 :         return EOF;
    2019              :     }
    2020              : 
    2021            0 :     while ((status = PQgetlineAsync(conn, s, maxlen - 1)) == 0)
    2022              :     {
    2023              :         /* need to load more data */
    2024            0 :         if (pqWait(true, false, conn) ||
    2025            0 :             pqReadData(conn) < 0)
    2026              :         {
    2027            0 :             *s = '\0';
    2028            0 :             return EOF;
    2029              :         }
    2030              :     }
    2031              : 
    2032            0 :     if (status < 0)
    2033              :     {
    2034              :         /* End of copy detected; gin up old-style terminator */
    2035            0 :         strcpy(s, "\\.");
    2036            0 :         return 0;
    2037              :     }
    2038              : 
    2039              :     /* Add null terminator, and strip trailing \n if present */
    2040            0 :     if (s[status - 1] == '\n')
    2041              :     {
    2042            0 :         s[status - 1] = '\0';
    2043            0 :         return 0;
    2044              :     }
    2045              :     else
    2046              :     {
    2047            0 :         s[status] = '\0';
    2048            0 :         return 1;
    2049              :     }
    2050              : }
    2051              : 
    2052              : /*
    2053              :  * PQgetlineAsync - gets a COPY data row without blocking.
    2054              :  *
    2055              :  * See fe-exec.c for documentation.
    2056              :  */
    2057              : int
    2058            0 : pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize)
    2059              : {
    2060              :     int         msgLength;
    2061              :     int         avail;
    2062              : 
    2063            0 :     if (conn->asyncStatus != PGASYNC_COPY_OUT
    2064            0 :         && conn->asyncStatus != PGASYNC_COPY_BOTH)
    2065            0 :         return -1;              /* we are not doing a copy... */
    2066              : 
    2067              :     /*
    2068              :      * Recognize the next input message.  To make life simpler for async
    2069              :      * callers, we keep returning 0 until the next message is fully available
    2070              :      * even if it is not Copy Data.  This should keep PQendcopy from blocking.
    2071              :      * (Note: unlike pqGetCopyData3, we do not change asyncStatus here.)
    2072              :      */
    2073            0 :     msgLength = getCopyDataMessage(conn);
    2074            0 :     if (msgLength < 0)
    2075            0 :         return -1;              /* end-of-copy or error */
    2076            0 :     if (msgLength == 0)
    2077            0 :         return 0;               /* no data yet */
    2078              : 
    2079              :     /*
    2080              :      * Move data from libpq's buffer to the caller's.  In the case where a
    2081              :      * prior call found the caller's buffer too small, we use
    2082              :      * conn->copy_already_done to remember how much of the row was already
    2083              :      * returned to the caller.
    2084              :      */
    2085            0 :     conn->inCursor += conn->copy_already_done;
    2086            0 :     avail = msgLength - 4 - conn->copy_already_done;
    2087            0 :     if (avail <= bufsize)
    2088              :     {
    2089              :         /* Able to consume the whole message */
    2090            0 :         memcpy(buffer, &conn->inBuffer[conn->inCursor], avail);
    2091              :         /* Mark message consumed */
    2092            0 :         conn->inStart = conn->inCursor + avail;
    2093              :         /* Reset state for next time */
    2094            0 :         conn->copy_already_done = 0;
    2095            0 :         return avail;
    2096              :     }
    2097              :     else
    2098              :     {
    2099              :         /* We must return a partial message */
    2100            0 :         memcpy(buffer, &conn->inBuffer[conn->inCursor], bufsize);
    2101              :         /* The message is NOT consumed from libpq's buffer */
    2102            0 :         conn->copy_already_done += bufsize;
    2103            0 :         return bufsize;
    2104              :     }
    2105              : }
    2106              : 
    2107              : /*
    2108              :  * PQendcopy
    2109              :  *
    2110              :  * See fe-exec.c for documentation.
    2111              :  */
    2112              : int
    2113          202 : pqEndcopy3(PGconn *conn)
    2114              : {
    2115              :     PGresult   *result;
    2116              : 
    2117          202 :     if (conn->asyncStatus != PGASYNC_COPY_IN &&
    2118          195 :         conn->asyncStatus != PGASYNC_COPY_OUT &&
    2119            0 :         conn->asyncStatus != PGASYNC_COPY_BOTH)
    2120              :     {
    2121            0 :         libpq_append_conn_error(conn, "no COPY in progress");
    2122            0 :         return 1;
    2123              :     }
    2124              : 
    2125              :     /* Send the CopyDone message if needed */
    2126          202 :     if (conn->asyncStatus == PGASYNC_COPY_IN ||
    2127          195 :         conn->asyncStatus == PGASYNC_COPY_BOTH)
    2128              :     {
    2129           14 :         if (pqPutMsgStart(PqMsg_CopyDone, conn) < 0 ||
    2130            7 :             pqPutMsgEnd(conn) < 0)
    2131            0 :             return 1;
    2132              : 
    2133              :         /*
    2134              :          * If we sent the COPY command in extended-query mode, we must issue a
    2135              :          * Sync as well.
    2136              :          */
    2137            7 :         if (conn->cmd_queue_head &&
    2138            7 :             conn->cmd_queue_head->queryclass != PGQUERY_SIMPLE)
    2139              :         {
    2140            0 :             if (pqPutMsgStart(PqMsg_Sync, conn) < 0 ||
    2141            0 :                 pqPutMsgEnd(conn) < 0)
    2142            0 :                 return 1;
    2143              :         }
    2144              :     }
    2145              : 
    2146              :     /*
    2147              :      * make sure no data is waiting to be sent, abort if we are non-blocking
    2148              :      * and the flush fails
    2149              :      */
    2150          202 :     if (pqFlush(conn) && pqIsnonblocking(conn))
    2151            0 :         return 1;
    2152              : 
    2153              :     /* Return to active duty */
    2154          202 :     conn->asyncStatus = PGASYNC_BUSY;
    2155              : 
    2156              :     /*
    2157              :      * Non blocking connections may have to abort at this point.  If everyone
    2158              :      * played the game there should be no problem, but in error scenarios the
    2159              :      * expected messages may not have arrived yet.  (We are assuming that the
    2160              :      * backend's packetizing will ensure that CommandComplete arrives along
    2161              :      * with the CopyDone; are there corner cases where that doesn't happen?)
    2162              :      */
    2163          202 :     if (pqIsnonblocking(conn) && PQisBusy(conn))
    2164            0 :         return 1;
    2165              : 
    2166              :     /* Wait for the completion response */
    2167          202 :     result = PQgetResult(conn);
    2168              : 
    2169              :     /* Expecting a successful result */
    2170          202 :     if (result && result->resultStatus == PGRES_COMMAND_OK)
    2171              :     {
    2172          202 :         PQclear(result);
    2173          202 :         return 0;
    2174              :     }
    2175              : 
    2176              :     /*
    2177              :      * Trouble. For backwards-compatibility reasons, we issue the error
    2178              :      * message as if it were a notice (would be nice to get rid of this
    2179              :      * silliness, but too many apps probably don't handle errors from
    2180              :      * PQendcopy reasonably).  Note that the app can still obtain the error
    2181              :      * status from the PGconn object.
    2182              :      */
    2183            0 :     if (conn->errorMessage.len > 0)
    2184              :     {
    2185              :         /* We have to strip the trailing newline ... pain in neck... */
    2186            0 :         char        svLast = conn->errorMessage.data[conn->errorMessage.len - 1];
    2187              : 
    2188            0 :         if (svLast == '\n')
    2189            0 :             conn->errorMessage.data[conn->errorMessage.len - 1] = '\0';
    2190            0 :         pqInternalNotice(&conn->noticeHooks, "%s", conn->errorMessage.data);
    2191            0 :         conn->errorMessage.data[conn->errorMessage.len - 1] = svLast;
    2192              :     }
    2193              : 
    2194            0 :     PQclear(result);
    2195              : 
    2196            0 :     return 1;
    2197              : }
    2198              : 
    2199              : 
    2200              : /*
    2201              :  * PQfn - Send a function call to the POSTGRES backend.
    2202              :  *
    2203              :  * See fe-exec.c for documentation.
    2204              :  */
    2205              : PGresult *
    2206         1070 : pqFunctionCall3(PGconn *conn, Oid fnid,
    2207              :                 int *result_buf, int *actual_result_len,
    2208              :                 int result_is_int,
    2209              :                 const PQArgBlock *args, int nargs)
    2210              : {
    2211         1070 :     bool        needInput = false;
    2212         1070 :     ExecStatusType status = PGRES_FATAL_ERROR;
    2213              :     char        id;
    2214              :     int         msgLength;
    2215              :     int         avail;
    2216              :     int         i;
    2217              : 
    2218              :     /* already validated by PQfn */
    2219              :     Assert(conn->pipelineStatus == PQ_PIPELINE_OFF);
    2220              : 
    2221              :     /* PQfn already validated connection state */
    2222              : 
    2223         2140 :     if (pqPutMsgStart(PqMsg_FunctionCall, conn) < 0 ||
    2224         2140 :         pqPutInt(fnid, 4, conn) < 0 ||   /* function id */
    2225         2140 :         pqPutInt(1, 2, conn) < 0 || /* # of format codes */
    2226         2140 :         pqPutInt(1, 2, conn) < 0 || /* format code: BINARY */
    2227         1070 :         pqPutInt(nargs, 2, conn) < 0)    /* # of args */
    2228              :     {
    2229              :         /* error message should be set up already */
    2230            0 :         return NULL;
    2231              :     }
    2232              : 
    2233         3100 :     for (i = 0; i < nargs; ++i)
    2234              :     {                           /* len.int4 + contents     */
    2235         2030 :         if (pqPutInt(args[i].len, 4, conn))
    2236            0 :             return NULL;
    2237         2030 :         if (args[i].len == -1)
    2238            0 :             continue;           /* it's NULL */
    2239              : 
    2240         2030 :         if (args[i].isint)
    2241              :         {
    2242         1537 :             if (pqPutInt(args[i].u.integer, args[i].len, conn))
    2243            0 :                 return NULL;
    2244              :         }
    2245              :         else
    2246              :         {
    2247          493 :             if (pqPutnchar(args[i].u.ptr, args[i].len, conn))
    2248            0 :                 return NULL;
    2249              :         }
    2250              :     }
    2251              : 
    2252         1070 :     if (pqPutInt(1, 2, conn) < 0)    /* result format code: BINARY */
    2253            0 :         return NULL;
    2254              : 
    2255         2140 :     if (pqPutMsgEnd(conn) < 0 ||
    2256         1070 :         pqFlush(conn))
    2257            0 :         return NULL;
    2258              : 
    2259              :     for (;;)
    2260              :     {
    2261         3210 :         if (needInput)
    2262              :         {
    2263              :             /* Wait for some data to arrive (or for the channel to close) */
    2264         2140 :             if (pqWait(true, false, conn) ||
    2265         1070 :                 pqReadData(conn) < 0)
    2266              :                 break;
    2267              :         }
    2268              : 
    2269              :         /*
    2270              :          * Scan the message. If we run out of data, loop around to try again.
    2271              :          */
    2272         3210 :         needInput = true;
    2273              : 
    2274         3210 :         conn->inCursor = conn->inStart;
    2275         3210 :         if (pqGetc(&id, conn))
    2276         1070 :             continue;
    2277         2140 :         if (pqGetInt(&msgLength, 4, conn))
    2278            0 :             continue;
    2279              : 
    2280              :         /*
    2281              :          * Try to validate message type/length here.  A length less than 4 is
    2282              :          * definitely broken.  Large lengths should only be believed for a few
    2283              :          * message types.
    2284              :          */
    2285         2140 :         if (msgLength < 4)
    2286              :         {
    2287            0 :             handleSyncLoss(conn, id, msgLength);
    2288            0 :             break;
    2289              :         }
    2290         2140 :         if (msgLength > 30000 && !VALID_LONG_MESSAGE_TYPE(id))
    2291              :         {
    2292            0 :             handleSyncLoss(conn, id, msgLength);
    2293            0 :             break;
    2294              :         }
    2295              : 
    2296              :         /*
    2297              :          * Can't process if message body isn't all here yet.
    2298              :          */
    2299         2140 :         msgLength -= 4;
    2300         2140 :         avail = conn->inEnd - conn->inCursor;
    2301         2140 :         if (avail < msgLength)
    2302              :         {
    2303              :             /*
    2304              :              * Before looping, enlarge the input buffer if needed to hold the
    2305              :              * whole message.  See notes in parseInput.
    2306              :              */
    2307            0 :             if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
    2308              :                                      conn))
    2309              :             {
    2310              :                 /*
    2311              :                  * Abandon the connection.  There's not much else we can
    2312              :                  * safely do; we can't just ignore the message or we could
    2313              :                  * miss important changes to the connection state.
    2314              :                  * pqCheckInBufferSpace() already reported the error.
    2315              :                  */
    2316            0 :                 handleFatalError(conn);
    2317            0 :                 break;
    2318              :             }
    2319            0 :             continue;
    2320              :         }
    2321              : 
    2322              :         /*
    2323              :          * We should see V or E response to the command, but might get N
    2324              :          * and/or A notices first. We also need to swallow the final Z before
    2325              :          * returning.
    2326              :          */
    2327         2140 :         switch (id)
    2328              :         {
    2329         1070 :             case PqMsg_FunctionCallResponse:
    2330         1070 :                 if (pqGetInt(actual_result_len, 4, conn))
    2331            0 :                     continue;
    2332         1070 :                 if (*actual_result_len != -1)
    2333              :                 {
    2334         1070 :                     if (result_is_int)
    2335              :                     {
    2336          694 :                         if (pqGetInt(result_buf, *actual_result_len, conn))
    2337            0 :                             continue;
    2338              :                     }
    2339              :                     else
    2340              :                     {
    2341          376 :                         if (pqGetnchar(result_buf,
    2342          376 :                                        *actual_result_len,
    2343              :                                        conn))
    2344            0 :                             continue;
    2345              :                     }
    2346              :                 }
    2347              :                 /* correctly finished function result message */
    2348         1070 :                 status = PGRES_COMMAND_OK;
    2349         1070 :                 break;
    2350            0 :             case PqMsg_ErrorResponse:
    2351            0 :                 if (pqGetErrorNotice3(conn, true))
    2352            0 :                     continue;
    2353            0 :                 status = PGRES_FATAL_ERROR;
    2354            0 :                 break;
    2355            0 :             case PqMsg_NotificationResponse:
    2356              :                 /* handle notify and go back to processing return values */
    2357            0 :                 if (getNotify(conn))
    2358            0 :                     continue;
    2359            0 :                 break;
    2360            0 :             case PqMsg_NoticeResponse:
    2361              :                 /* handle notice and go back to processing return values */
    2362            0 :                 if (pqGetErrorNotice3(conn, false))
    2363            0 :                     continue;
    2364            0 :                 break;
    2365         1070 :             case PqMsg_ReadyForQuery:
    2366         1070 :                 if (getReadyForQuery(conn))
    2367            0 :                     continue;
    2368              : 
    2369              :                 /* consume the message */
    2370         1070 :                 pqParseDone(conn, conn->inStart + 5 + msgLength);
    2371              : 
    2372              :                 /*
    2373              :                  * If we already have a result object (probably an error), use
    2374              :                  * that.  Otherwise, if we saw a function result message,
    2375              :                  * report COMMAND_OK.  Otherwise, the backend violated the
    2376              :                  * protocol, so complain.
    2377              :                  */
    2378         1070 :                 if (!pgHavePendingResult(conn))
    2379              :                 {
    2380         1070 :                     if (status == PGRES_COMMAND_OK)
    2381              :                     {
    2382         1070 :                         conn->result = PQmakeEmptyPGresult(conn, status);
    2383         1070 :                         if (!conn->result)
    2384              :                         {
    2385            0 :                             libpq_append_conn_error(conn, "out of memory");
    2386            0 :                             pqSaveErrorResult(conn);
    2387              :                         }
    2388              :                     }
    2389              :                     else
    2390              :                     {
    2391            0 :                         libpq_append_conn_error(conn, "protocol error: no function result");
    2392            0 :                         pqSaveErrorResult(conn);
    2393              :                     }
    2394              :                 }
    2395              :                 /* and we're out */
    2396         1070 :                 return pqPrepareAsyncResult(conn);
    2397            0 :             case PqMsg_ParameterStatus:
    2398            0 :                 if (getParameterStatus(conn))
    2399            0 :                     continue;
    2400            0 :                 break;
    2401            0 :             default:
    2402              :                 /* The backend violates the protocol. */
    2403            0 :                 libpq_append_conn_error(conn, "protocol error: id=0x%x", id);
    2404            0 :                 pqSaveErrorResult(conn);
    2405              : 
    2406              :                 /*
    2407              :                  * We can't call parsing done due to the protocol violation
    2408              :                  * (so message tracing wouldn't work), but trust the specified
    2409              :                  * message length as what to skip.
    2410              :                  */
    2411            0 :                 conn->inStart += 5 + msgLength;
    2412            0 :                 return pqPrepareAsyncResult(conn);
    2413              :         }
    2414              : 
    2415              :         /* Completed parsing this message, keep going */
    2416         1070 :         pqParseDone(conn, conn->inStart + 5 + msgLength);
    2417         1070 :         needInput = false;
    2418              :     }
    2419              : 
    2420              :     /*
    2421              :      * We fall out of the loop only upon failing to read data.
    2422              :      * conn->errorMessage has been set by pqWait or pqReadData. We want to
    2423              :      * append it to any already-received error message.
    2424              :      */
    2425            0 :     pqSaveErrorResult(conn);
    2426            0 :     return pqPrepareAsyncResult(conn);
    2427              : }
    2428              : 
    2429              : 
    2430              : /*
    2431              :  * Construct startup packet
    2432              :  *
    2433              :  * Returns a malloc'd packet buffer, or NULL if out of memory
    2434              :  */
    2435              : char *
    2436        14519 : pqBuildStartupPacket3(PGconn *conn, int *packetlen,
    2437              :                       const PQEnvironmentOption *options)
    2438              : {
    2439              :     char       *startpacket;
    2440              :     size_t      len;
    2441              : 
    2442        14519 :     len = build_startup_packet(conn, NULL, options);
    2443        14519 :     if (len == 0 || len > INT_MAX)
    2444            0 :         return NULL;
    2445              : 
    2446        14519 :     *packetlen = len;
    2447        14519 :     startpacket = (char *) malloc(*packetlen);
    2448        14519 :     if (!startpacket)
    2449            0 :         return NULL;
    2450              : 
    2451        14519 :     len = build_startup_packet(conn, startpacket, options);
    2452              :     Assert(*packetlen == len);
    2453              : 
    2454        14519 :     return startpacket;
    2455              : }
    2456              : 
    2457              : /*
    2458              :  * Build a startup packet given a filled-in PGconn structure.
    2459              :  *
    2460              :  * We need to figure out how much space is needed, then fill it in.
    2461              :  * To avoid duplicate logic, this routine is called twice: the first time
    2462              :  * (with packet == NULL) just counts the space needed, the second time
    2463              :  * (with packet == allocated space) fills it in.  Return value is the number
    2464              :  * of bytes used, or zero in the unlikely event of size_t overflow.
    2465              :  */
    2466              : static size_t
    2467        29038 : build_startup_packet(const PGconn *conn, char *packet,
    2468              :                      const PQEnvironmentOption *options)
    2469              : {
    2470        29038 :     size_t      packet_len = 0;
    2471              :     const PQEnvironmentOption *next_eo;
    2472              :     const char *val;
    2473              : 
    2474              :     /* Protocol version comes first. */
    2475        29038 :     if (packet)
    2476              :     {
    2477        14519 :         ProtocolVersion pv = pg_hton32(conn->pversion);
    2478              : 
    2479        14519 :         memcpy(packet + packet_len, &pv, sizeof(ProtocolVersion));
    2480              :     }
    2481        29038 :     packet_len += sizeof(ProtocolVersion);
    2482              : 
    2483              :     /* Add user name, database name, options */
    2484              : 
    2485              : #define ADD_STARTUP_OPTION(optname, optval) \
    2486              :     do { \
    2487              :         if (packet) \
    2488              :             strcpy(packet + packet_len, optname); \
    2489              :         if (pg_add_size_overflow(packet_len, strlen(optname) + 1, &packet_len)) \
    2490              :             return 0; \
    2491              :         if (packet) \
    2492              :             strcpy(packet + packet_len, optval); \
    2493              :         if (pg_add_size_overflow(packet_len, strlen(optval) + 1, &packet_len)) \
    2494              :             return 0; \
    2495              :     } while(0)
    2496              : 
    2497        29038 :     if (conn->pguser && conn->pguser[0])
    2498        29038 :         ADD_STARTUP_OPTION("user", conn->pguser);
    2499        29038 :     if (conn->dbName && conn->dbName[0])
    2500        29038 :         ADD_STARTUP_OPTION("database", conn->dbName);
    2501        29038 :     if (conn->replication && conn->replication[0])
    2502         3236 :         ADD_STARTUP_OPTION("replication", conn->replication);
    2503        29038 :     if (conn->pgoptions && conn->pgoptions[0])
    2504         8194 :         ADD_STARTUP_OPTION("options", conn->pgoptions);
    2505        29038 :     if (conn->send_appname)
    2506              :     {
    2507              :         /* Use appname if present, otherwise use fallback */
    2508        29038 :         val = conn->appname ? conn->appname : conn->fbappname;
    2509        29038 :         if (val && val[0])
    2510        29030 :             ADD_STARTUP_OPTION("application_name", val);
    2511              :     }
    2512              : 
    2513        29038 :     if (conn->client_encoding_initial && conn->client_encoding_initial[0])
    2514         1818 :         ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial);
    2515              : 
    2516              :     /*
    2517              :      * Add the test_protocol_negotiation option when greasing, to test that
    2518              :      * servers properly report unsupported protocol options in addition to
    2519              :      * unsupported minor versions.
    2520              :      */
    2521        29038 :     if (conn->pversion == PG_PROTOCOL_GREASE)
    2522        28996 :         ADD_STARTUP_OPTION("_pq_.test_protocol_negotiation", "");
    2523              : 
    2524              :     /* Add any environment-driven GUC settings needed */
    2525       116152 :     for (next_eo = options; next_eo->envName; next_eo++)
    2526              :     {
    2527        87114 :         if ((val = getenv(next_eo->envName)) != NULL)
    2528              :         {
    2529         9796 :             if (pg_strcasecmp(val, "default") != 0)
    2530         9796 :                 ADD_STARTUP_OPTION(next_eo->pgName, val);
    2531              :         }
    2532              :     }
    2533              : 
    2534              :     /* Add trailing terminator */
    2535        29038 :     if (packet)
    2536        14519 :         packet[packet_len] = '\0';
    2537        29038 :     if (pg_add_size_overflow(packet_len, 1, &packet_len))
    2538            0 :         return 0;
    2539              : 
    2540        29038 :     return packet_len;
    2541              : }
        

Generated by: LCOV version 2.0-1