LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-protocol3.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 63.3 % 1008 638
Test Date: 2026-07-22 18:15:44 Functions: 82.6 % 23 19
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 57.9 % 862 499

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

Generated by: LCOV version 2.0-1