LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-protocol3.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 63.3 % 1008 638
Test Date: 2026-05-30 00:16:21 Functions: 82.6 % 23 19
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1