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

Generated by: LCOV version 2.0-1