LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-trace.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 220 377 58.4 %
Date: 2024-05-08 01:11:38 Functions: 23 36 63.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  *  fe-trace.c
       4             :  *    functions for libpq protocol tracing
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/interfaces/libpq/fe-trace.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : 
      15             : #include "postgres_fe.h"
      16             : 
      17             : #include <ctype.h>
      18             : #include <limits.h>
      19             : #include <sys/time.h>
      20             : #include <time.h>
      21             : 
      22             : #ifdef WIN32
      23             : #include "win32.h"
      24             : #else
      25             : #include <unistd.h>
      26             : #endif
      27             : 
      28             : #include "libpq-fe.h"
      29             : #include "libpq-int.h"
      30             : #include "port/pg_bswap.h"
      31             : 
      32             : 
      33             : /* Enable tracing */
      34             : void
      35          18 : PQtrace(PGconn *conn, FILE *debug_port)
      36             : {
      37          18 :     if (conn == NULL)
      38           0 :         return;
      39          18 :     PQuntrace(conn);
      40          18 :     if (debug_port == NULL)
      41           0 :         return;
      42             : 
      43          18 :     conn->Pfdebug = debug_port;
      44          18 :     conn->traceFlags = 0;
      45             : }
      46             : 
      47             : /* Disable tracing */
      48             : void
      49          18 : PQuntrace(PGconn *conn)
      50             : {
      51          18 :     if (conn == NULL)
      52           0 :         return;
      53          18 :     if (conn->Pfdebug)
      54             :     {
      55           0 :         fflush(conn->Pfdebug);
      56           0 :         conn->Pfdebug = NULL;
      57             :     }
      58             : 
      59          18 :     conn->traceFlags = 0;
      60             : }
      61             : 
      62             : /* Set flags for current tracing session */
      63             : void
      64          18 : PQsetTraceFlags(PGconn *conn, int flags)
      65             : {
      66          18 :     if (conn == NULL)
      67           0 :         return;
      68             :     /* If PQtrace() failed, do nothing. */
      69          18 :     if (conn->Pfdebug == NULL)
      70           0 :         return;
      71          18 :     conn->traceFlags = flags;
      72             : }
      73             : 
      74             : /*
      75             :  * Print the current time, with microseconds, into a caller-supplied
      76             :  * buffer.
      77             :  * Cribbed from get_formatted_log_time, but much simpler.
      78             :  */
      79             : static void
      80           0 : pqTraceFormatTimestamp(char *timestr, size_t ts_len)
      81             : {
      82             :     struct timeval tval;
      83             :     time_t      now;
      84             : 
      85           0 :     gettimeofday(&tval, NULL);
      86             : 
      87             :     /*
      88             :      * MSVC's implementation of timeval uses a long for tv_sec, however,
      89             :      * localtime() expects a time_t pointer.  Here we'll assign tv_sec to a
      90             :      * local time_t variable so that we pass localtime() the correct pointer
      91             :      * type.
      92             :      */
      93           0 :     now = tval.tv_sec;
      94           0 :     strftime(timestr, ts_len,
      95             :              "%Y-%m-%d %H:%M:%S",
      96           0 :              localtime(&now));
      97             :     /* append microseconds */
      98           0 :     snprintf(timestr + strlen(timestr), ts_len - strlen(timestr),
      99           0 :              ".%06u", (unsigned int) (tval.tv_usec));
     100           0 : }
     101             : 
     102             : /*
     103             :  *   pqTraceOutputByte1: output a 1-char message to the log
     104             :  */
     105             : static void
     106         310 : pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor)
     107             : {
     108         310 :     const char *v = data + *cursor;
     109             : 
     110             :     /*
     111             :      * Show non-printable data in hex format, including the terminating \0
     112             :      * that completes ErrorResponse and NoticeResponse messages.
     113             :      */
     114         310 :     if (!isprint((unsigned char) *v))
     115          20 :         fprintf(pfdebug, " \\x%02x", *v);
     116             :     else
     117         290 :         fprintf(pfdebug, " %c", *v);
     118         310 :     *cursor += 1;
     119         310 : }
     120             : 
     121             : /*
     122             :  *   pqTraceOutputInt16: output a 2-byte integer message to the log
     123             :  */
     124             : static int
     125         696 : pqTraceOutputInt16(FILE *pfdebug, const char *data, int *cursor)
     126             : {
     127             :     uint16      tmp;
     128             :     int         result;
     129             : 
     130         696 :     memcpy(&tmp, data + *cursor, 2);
     131         696 :     *cursor += 2;
     132         696 :     result = (int) pg_ntoh16(tmp);
     133         696 :     fprintf(pfdebug, " %d", result);
     134             : 
     135         696 :     return result;
     136             : }
     137             : 
     138             : /*
     139             :  *   pqTraceOutputInt32: output a 4-byte integer message to the log
     140             :  *
     141             :  * If 'suppress' is true, print a literal NNNN instead of the actual number.
     142             :  */
     143             : static int
     144         390 : pqTraceOutputInt32(FILE *pfdebug, const char *data, int *cursor, bool suppress)
     145             : {
     146             :     int         result;
     147             : 
     148         390 :     memcpy(&result, data + *cursor, 4);
     149         390 :     *cursor += 4;
     150         390 :     result = (int) pg_ntoh32(result);
     151         390 :     if (suppress)
     152         148 :         fprintf(pfdebug, " NNNN");
     153             :     else
     154         242 :         fprintf(pfdebug, " %d", result);
     155             : 
     156         390 :     return result;
     157             : }
     158             : 
     159             : /*
     160             :  *   pqTraceOutputString: output a string message to the log
     161             :  */
     162             : static void
     163         746 : pqTraceOutputString(FILE *pfdebug, const char *data, int *cursor, bool suppress)
     164             : {
     165             :     int         len;
     166             : 
     167         746 :     if (suppress)
     168             :     {
     169          60 :         fprintf(pfdebug, " \"SSSS\"");
     170          60 :         *cursor += strlen(data + *cursor) + 1;
     171             :     }
     172             :     else
     173             :     {
     174         686 :         len = fprintf(pfdebug, " \"%s\"", data + *cursor);
     175             : 
     176             :         /*
     177             :          * This is a null-terminated string. So add 1 after subtracting 3
     178             :          * which is the double quotes and space length from len.
     179             :          */
     180         686 :         *cursor += (len - 3 + 1);
     181             :     }
     182         746 : }
     183             : 
     184             : /*
     185             :  * pqTraceOutputNchar: output a string of exactly len bytes message to the log
     186             :  */
     187             : static void
     188         106 : pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor)
     189             : {
     190             :     int         i,
     191             :                 next;           /* first char not yet printed */
     192         106 :     const char *v = data + *cursor;
     193             : 
     194         106 :     fprintf(pfdebug, " \'");
     195             : 
     196        1548 :     for (next = i = 0; i < len; ++i)
     197             :     {
     198        1442 :         if (isprint((unsigned char) v[i]))
     199        1442 :             continue;
     200             :         else
     201             :         {
     202           0 :             fwrite(v + next, 1, i - next, pfdebug);
     203           0 :             fprintf(pfdebug, "\\x%02x", v[i]);
     204           0 :             next = i + 1;
     205             :         }
     206             :     }
     207         106 :     if (next < len)
     208         106 :         fwrite(v + next, 1, len - next, pfdebug);
     209             : 
     210         106 :     fprintf(pfdebug, "\'");
     211         106 :     *cursor += len;
     212         106 : }
     213             : 
     214             : /*
     215             :  * Output functions by protocol message type
     216             :  */
     217             : 
     218             : static void
     219           0 : pqTraceOutput_NotificationResponse(FILE *f, const char *message, int *cursor, bool regress)
     220             : {
     221           0 :     fprintf(f, "NotificationResponse\t");
     222           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     223           0 :     pqTraceOutputString(f, message, cursor, false);
     224           0 :     pqTraceOutputString(f, message, cursor, false);
     225           0 : }
     226             : 
     227             : static void
     228          72 : pqTraceOutput_Bind(FILE *f, const char *message, int *cursor)
     229             : {
     230             :     int         nparams;
     231             : 
     232          72 :     fprintf(f, "Bind\t");
     233          72 :     pqTraceOutputString(f, message, cursor, false);
     234          72 :     pqTraceOutputString(f, message, cursor, false);
     235          72 :     nparams = pqTraceOutputInt16(f, message, cursor);
     236             : 
     237          72 :     for (int i = 0; i < nparams; i++)
     238           0 :         pqTraceOutputInt16(f, message, cursor);
     239             : 
     240          72 :     nparams = pqTraceOutputInt16(f, message, cursor);
     241             : 
     242          94 :     for (int i = 0; i < nparams; i++)
     243             :     {
     244             :         int         nbytes;
     245             : 
     246          22 :         nbytes = pqTraceOutputInt32(f, message, cursor, false);
     247          22 :         if (nbytes == -1)
     248           0 :             continue;
     249          22 :         pqTraceOutputNchar(f, nbytes, message, cursor);
     250             :     }
     251             : 
     252          72 :     nparams = pqTraceOutputInt16(f, message, cursor);
     253         144 :     for (int i = 0; i < nparams; i++)
     254          72 :         pqTraceOutputInt16(f, message, cursor);
     255          72 : }
     256             : 
     257             : static void
     258           8 : pqTraceOutput_Close(FILE *f, const char *message, int *cursor)
     259             : {
     260           8 :     fprintf(f, "Close\t");
     261           8 :     pqTraceOutputByte1(f, message, cursor);
     262           8 :     pqTraceOutputString(f, message, cursor, false);
     263           8 : }
     264             : 
     265             : static void
     266          74 : pqTraceOutput_CommandComplete(FILE *f, const char *message, int *cursor)
     267             : {
     268          74 :     fprintf(f, "CommandComplete\t");
     269          74 :     pqTraceOutputString(f, message, cursor, false);
     270          74 : }
     271             : 
     272             : static void
     273          84 : pqTraceOutput_DataRow(FILE *f, const char *message, int *cursor)
     274             : {
     275             :     int         nfields;
     276             :     int         len;
     277             :     int         i;
     278             : 
     279          84 :     fprintf(f, "DataRow\t");
     280          84 :     nfields = pqTraceOutputInt16(f, message, cursor);
     281         168 :     for (i = 0; i < nfields; i++)
     282             :     {
     283          84 :         len = pqTraceOutputInt32(f, message, cursor, false);
     284          84 :         if (len == -1)
     285           0 :             continue;
     286          84 :         pqTraceOutputNchar(f, len, message, cursor);
     287             :     }
     288          84 : }
     289             : 
     290             : static void
     291          80 : pqTraceOutput_Describe(FILE *f, const char *message, int *cursor)
     292             : {
     293          80 :     fprintf(f, "Describe\t");
     294          80 :     pqTraceOutputByte1(f, message, cursor);
     295          80 :     pqTraceOutputString(f, message, cursor, false);
     296          80 : }
     297             : 
     298             : /* shared code NoticeResponse / ErrorResponse */
     299             : static void
     300          20 : pqTraceOutputNR(FILE *f, const char *type, const char *message, int *cursor,
     301             :                 bool regress)
     302             : {
     303          20 :     fprintf(f, "%s\t", type);
     304             :     for (;;)
     305         144 :     {
     306             :         char        field;
     307             :         bool        suppress;
     308             : 
     309         164 :         pqTraceOutputByte1(f, message, cursor);
     310         164 :         field = message[*cursor - 1];
     311         164 :         if (field == '\0')
     312          20 :             break;
     313             : 
     314         144 :         suppress = regress && (field == 'L' || field == 'F' || field == 'R');
     315         144 :         pqTraceOutputString(f, message, cursor, suppress);
     316             :     }
     317          20 : }
     318             : 
     319             : static void
     320          14 : pqTraceOutput_ErrorResponse(FILE *f, const char *message, int *cursor, bool regress)
     321             : {
     322          14 :     pqTraceOutputNR(f, "ErrorResponse", message, cursor, regress);
     323          14 : }
     324             : 
     325             : static void
     326           6 : pqTraceOutput_NoticeResponse(FILE *f, const char *message, int *cursor, bool regress)
     327             : {
     328           6 :     pqTraceOutputNR(f, "NoticeResponse", message, cursor, regress);
     329           6 : }
     330             : 
     331             : static void
     332          72 : pqTraceOutput_Execute(FILE *f, const char *message, int *cursor, bool regress)
     333             : {
     334          72 :     fprintf(f, "Execute\t");
     335          72 :     pqTraceOutputString(f, message, cursor, false);
     336          72 :     pqTraceOutputInt32(f, message, cursor, false);
     337          72 : }
     338             : 
     339             : static void
     340           0 : pqTraceOutput_CopyFail(FILE *f, const char *message, int *cursor)
     341             : {
     342           0 :     fprintf(f, "CopyFail\t");
     343           0 :     pqTraceOutputString(f, message, cursor, false);
     344           0 : }
     345             : 
     346             : static void
     347           0 : pqTraceOutput_FunctionCall(FILE *f, const char *message, int *cursor, bool regress)
     348             : {
     349             :     int         nfields;
     350             :     int         nbytes;
     351             : 
     352           0 :     fprintf(f, "FunctionCall\t");
     353           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     354           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     355             : 
     356           0 :     for (int i = 0; i < nfields; i++)
     357           0 :         pqTraceOutputInt16(f, message, cursor);
     358             : 
     359           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     360             : 
     361           0 :     for (int i = 0; i < nfields; i++)
     362             :     {
     363           0 :         nbytes = pqTraceOutputInt32(f, message, cursor, false);
     364           0 :         if (nbytes == -1)
     365           0 :             continue;
     366           0 :         pqTraceOutputNchar(f, nbytes, message, cursor);
     367             :     }
     368             : 
     369           0 :     pqTraceOutputInt16(f, message, cursor);
     370           0 : }
     371             : 
     372             : static void
     373           0 : pqTraceOutput_CopyInResponse(FILE *f, const char *message, int *cursor)
     374             : {
     375             :     int         nfields;
     376             : 
     377           0 :     fprintf(f, "CopyInResponse\t");
     378           0 :     pqTraceOutputByte1(f, message, cursor);
     379           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     380             : 
     381           0 :     for (int i = 0; i < nfields; i++)
     382           0 :         pqTraceOutputInt16(f, message, cursor);
     383           0 : }
     384             : 
     385             : static void
     386           0 : pqTraceOutput_CopyOutResponse(FILE *f, const char *message, int *cursor)
     387             : {
     388             :     int         nfields;
     389             : 
     390           0 :     fprintf(f, "CopyOutResponse\t");
     391           0 :     pqTraceOutputByte1(f, message, cursor);
     392           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     393             : 
     394           0 :     for (int i = 0; i < nfields; i++)
     395           0 :         pqTraceOutputInt16(f, message, cursor);
     396           0 : }
     397             : 
     398             : static void
     399           0 : pqTraceOutput_BackendKeyData(FILE *f, const char *message, int *cursor, bool regress)
     400             : {
     401           0 :     fprintf(f, "BackendKeyData\t");
     402           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     403           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     404           0 : }
     405             : 
     406             : static void
     407          72 : pqTraceOutput_Parse(FILE *f, const char *message, int *cursor, bool regress)
     408             : {
     409             :     int         nparams;
     410             : 
     411          72 :     fprintf(f, "Parse\t");
     412          72 :     pqTraceOutputString(f, message, cursor, false);
     413          72 :     pqTraceOutputString(f, message, cursor, false);
     414          72 :     nparams = pqTraceOutputInt16(f, message, cursor);
     415             : 
     416          90 :     for (int i = 0; i < nparams; i++)
     417          18 :         pqTraceOutputInt32(f, message, cursor, regress);
     418          72 : }
     419             : 
     420             : static void
     421          16 : pqTraceOutput_Query(FILE *f, const char *message, int *cursor)
     422             : {
     423          16 :     fprintf(f, "Query\t");
     424          16 :     pqTraceOutputString(f, message, cursor, false);
     425          16 : }
     426             : 
     427             : static void
     428           0 : pqTraceOutput_Authentication(FILE *f, const char *message, int *cursor)
     429             : {
     430           0 :     fprintf(f, "Authentication\t");
     431           0 :     pqTraceOutputInt32(f, message, cursor, false);
     432           0 : }
     433             : 
     434             : static void
     435           0 : pqTraceOutput_ParameterStatus(FILE *f, const char *message, int *cursor)
     436             : {
     437           0 :     fprintf(f, "ParameterStatus\t");
     438           0 :     pqTraceOutputString(f, message, cursor, false);
     439           0 :     pqTraceOutputString(f, message, cursor, false);
     440           0 : }
     441             : 
     442             : static void
     443           2 : pqTraceOutput_ParameterDescription(FILE *f, const char *message, int *cursor, bool regress)
     444             : {
     445             :     int         nfields;
     446             : 
     447           2 :     fprintf(f, "ParameterDescription\t");
     448           2 :     nfields = pqTraceOutputInt16(f, message, cursor);
     449             : 
     450           4 :     for (int i = 0; i < nfields; i++)
     451           2 :         pqTraceOutputInt32(f, message, cursor, regress);
     452           2 : }
     453             : 
     454             : static void
     455          58 : pqTraceOutput_RowDescription(FILE *f, const char *message, int *cursor, bool regress)
     456             : {
     457             :     int         nfields;
     458             : 
     459          58 :     fprintf(f, "RowDescription\t");
     460          58 :     nfields = pqTraceOutputInt16(f, message, cursor);
     461             : 
     462         122 :     for (int i = 0; i < nfields; i++)
     463             :     {
     464          64 :         pqTraceOutputString(f, message, cursor, false);
     465          64 :         pqTraceOutputInt32(f, message, cursor, regress);
     466          64 :         pqTraceOutputInt16(f, message, cursor);
     467          64 :         pqTraceOutputInt32(f, message, cursor, regress);
     468          64 :         pqTraceOutputInt16(f, message, cursor);
     469          64 :         pqTraceOutputInt32(f, message, cursor, false);
     470          64 :         pqTraceOutputInt16(f, message, cursor);
     471             :     }
     472          58 : }
     473             : 
     474             : static void
     475           0 : pqTraceOutput_NegotiateProtocolVersion(FILE *f, const char *message, int *cursor)
     476             : {
     477           0 :     fprintf(f, "NegotiateProtocolVersion\t");
     478           0 :     pqTraceOutputInt32(f, message, cursor, false);
     479           0 :     pqTraceOutputInt32(f, message, cursor, false);
     480           0 : }
     481             : 
     482             : static void
     483           0 : pqTraceOutput_FunctionCallResponse(FILE *f, const char *message, int *cursor)
     484             : {
     485             :     int         len;
     486             : 
     487           0 :     fprintf(f, "FunctionCallResponse\t");
     488           0 :     len = pqTraceOutputInt32(f, message, cursor, false);
     489           0 :     if (len != -1)
     490           0 :         pqTraceOutputNchar(f, len, message, cursor);
     491           0 : }
     492             : 
     493             : static void
     494           0 : pqTraceOutput_CopyBothResponse(FILE *f, const char *message, int *cursor, int length)
     495             : {
     496           0 :     fprintf(f, "CopyBothResponse\t");
     497           0 :     pqTraceOutputByte1(f, message, cursor);
     498             : 
     499           0 :     while (length > *cursor)
     500           0 :         pqTraceOutputInt16(f, message, cursor);
     501           0 : }
     502             : 
     503             : static void
     504          58 : pqTraceOutput_ReadyForQuery(FILE *f, const char *message, int *cursor)
     505             : {
     506          58 :     fprintf(f, "ReadyForQuery\t");
     507          58 :     pqTraceOutputByte1(f, message, cursor);
     508          58 : }
     509             : 
     510             : /*
     511             :  * Print the given message to the trace output stream.
     512             :  */
     513             : void
     514         828 : pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer)
     515             : {
     516             :     char        id;
     517             :     int         length;
     518         828 :     char       *prefix = toServer ? "F" : "B";
     519         828 :     int         logCursor = 0;
     520             :     bool        regress;
     521             : 
     522         828 :     if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0)
     523             :     {
     524             :         char        timestr[128];
     525             : 
     526           0 :         pqTraceFormatTimestamp(timestr, sizeof(timestr));
     527           0 :         fprintf(conn->Pfdebug, "%s\t", timestr);
     528             :     }
     529         828 :     regress = (conn->traceFlags & PQTRACE_REGRESS_MODE) != 0;
     530             : 
     531         828 :     id = message[logCursor++];
     532             : 
     533         828 :     memcpy(&length, message + logCursor, 4);
     534         828 :     length = (int) pg_ntoh32(length);
     535         828 :     logCursor += 4;
     536             : 
     537             :     /*
     538             :      * In regress mode, suppress the length of ErrorResponse and
     539             :      * NoticeResponse.  The F (file name), L (line number) and R (routine
     540             :      * name) fields can change as server code is modified, and if their
     541             :      * lengths differ from the originals, that would break tests.
     542             :      */
     543         828 :     if (regress && !toServer && (id == PqMsg_ErrorResponse || id == PqMsg_NoticeResponse))
     544          20 :         fprintf(conn->Pfdebug, "%s\tNN\t", prefix);
     545             :     else
     546         808 :         fprintf(conn->Pfdebug, "%s\t%d\t", prefix, length);
     547             : 
     548         828 :     switch (id)
     549             :     {
     550          62 :         case PqMsg_ParseComplete:
     551          62 :             fprintf(conn->Pfdebug, "ParseComplete");
     552             :             /* No message content */
     553          62 :             break;
     554          58 :         case PqMsg_BindComplete:
     555          58 :             fprintf(conn->Pfdebug, "BindComplete");
     556             :             /* No message content */
     557          58 :             break;
     558           8 :         case PqMsg_CloseComplete:
     559           8 :             fprintf(conn->Pfdebug, "CloseComplete");
     560             :             /* No message content */
     561           8 :             break;
     562           0 :         case PqMsg_NotificationResponse:
     563           0 :             pqTraceOutput_NotificationResponse(conn->Pfdebug, message, &logCursor, regress);
     564           0 :             break;
     565          72 :         case PqMsg_Bind:
     566          72 :             pqTraceOutput_Bind(conn->Pfdebug, message, &logCursor);
     567          72 :             break;
     568           0 :         case PqMsg_CopyDone:
     569           0 :             fprintf(conn->Pfdebug, "CopyDone");
     570             :             /* No message content */
     571           0 :             break;
     572          82 :         case PqMsg_CommandComplete:
     573             :             /* Close(F) and CommandComplete(B) use the same identifier. */
     574             :             Assert(PqMsg_Close == PqMsg_CommandComplete);
     575          82 :             if (toServer)
     576           8 :                 pqTraceOutput_Close(conn->Pfdebug, message, &logCursor);
     577             :             else
     578          74 :                 pqTraceOutput_CommandComplete(conn->Pfdebug, message, &logCursor);
     579          82 :             break;
     580           0 :         case PqMsg_CopyData:
     581             :             /* Drop COPY data to reduce the overhead of logging. */
     582           0 :             break;
     583         164 :         case PqMsg_Describe:
     584             :             /* Describe(F) and DataRow(B) use the same identifier. */
     585             :             Assert(PqMsg_Describe == PqMsg_DataRow);
     586         164 :             if (toServer)
     587          80 :                 pqTraceOutput_Describe(conn->Pfdebug, message, &logCursor);
     588             :             else
     589          84 :                 pqTraceOutput_DataRow(conn->Pfdebug, message, &logCursor);
     590         164 :             break;
     591          86 :         case PqMsg_Execute:
     592             :             /* Execute(F) and ErrorResponse(B) use the same identifier. */
     593             :             Assert(PqMsg_Execute == PqMsg_ErrorResponse);
     594          86 :             if (toServer)
     595          72 :                 pqTraceOutput_Execute(conn->Pfdebug, message, &logCursor, regress);
     596             :             else
     597          14 :                 pqTraceOutput_ErrorResponse(conn->Pfdebug, message, &logCursor, regress);
     598          86 :             break;
     599           0 :         case PqMsg_CopyFail:
     600           0 :             pqTraceOutput_CopyFail(conn->Pfdebug, message, &logCursor);
     601           0 :             break;
     602           0 :         case PqMsg_FunctionCall:
     603           0 :             pqTraceOutput_FunctionCall(conn->Pfdebug, message, &logCursor, regress);
     604           0 :             break;
     605           0 :         case PqMsg_CopyInResponse:
     606           0 :             pqTraceOutput_CopyInResponse(conn->Pfdebug, message, &logCursor);
     607           0 :             break;
     608          14 :         case PqMsg_Flush:
     609             :             /* Flush(F) and CopyOutResponse(B) use the same identifier */
     610             :             Assert(PqMsg_CopyOutResponse == PqMsg_Flush);
     611          14 :             if (toServer)
     612          14 :                 fprintf(conn->Pfdebug, "Flush");   /* no message content */
     613             :             else
     614           0 :                 pqTraceOutput_CopyOutResponse(conn->Pfdebug, message, &logCursor);
     615          14 :             break;
     616           0 :         case PqMsg_EmptyQueryResponse:
     617           0 :             fprintf(conn->Pfdebug, "EmptyQueryResponse");
     618             :             /* No message content */
     619           0 :             break;
     620           0 :         case PqMsg_BackendKeyData:
     621           0 :             pqTraceOutput_BackendKeyData(conn->Pfdebug, message, &logCursor, regress);
     622           0 :             break;
     623          10 :         case PqMsg_NoData:
     624          10 :             fprintf(conn->Pfdebug, "NoData");
     625             :             /* No message content */
     626          10 :             break;
     627           6 :         case PqMsg_NoticeResponse:
     628           6 :             pqTraceOutput_NoticeResponse(conn->Pfdebug, message, &logCursor, regress);
     629           6 :             break;
     630          72 :         case PqMsg_Parse:
     631          72 :             pqTraceOutput_Parse(conn->Pfdebug, message, &logCursor, regress);
     632          72 :             break;
     633          16 :         case PqMsg_Query:
     634          16 :             pqTraceOutput_Query(conn->Pfdebug, message, &logCursor);
     635          16 :             break;
     636           0 :         case PqMsg_AuthenticationRequest:
     637           0 :             pqTraceOutput_Authentication(conn->Pfdebug, message, &logCursor);
     638           0 :             break;
     639           0 :         case PqMsg_PortalSuspended:
     640           0 :             fprintf(conn->Pfdebug, "PortalSuspended");
     641             :             /* No message content */
     642           0 :             break;
     643          42 :         case PqMsg_Sync:
     644             :             /* ParameterStatus(B) and Sync(F) use the same identifier */
     645             :             Assert(PqMsg_ParameterStatus == PqMsg_Sync);
     646          42 :             if (toServer)
     647          42 :                 fprintf(conn->Pfdebug, "Sync"); /* no message content */
     648             :             else
     649           0 :                 pqTraceOutput_ParameterStatus(conn->Pfdebug, message, &logCursor);
     650          42 :             break;
     651           2 :         case PqMsg_ParameterDescription:
     652           2 :             pqTraceOutput_ParameterDescription(conn->Pfdebug, message, &logCursor, regress);
     653           2 :             break;
     654          58 :         case PqMsg_RowDescription:
     655          58 :             pqTraceOutput_RowDescription(conn->Pfdebug, message, &logCursor, regress);
     656          58 :             break;
     657           0 :         case PqMsg_NegotiateProtocolVersion:
     658           0 :             pqTraceOutput_NegotiateProtocolVersion(conn->Pfdebug, message, &logCursor);
     659           0 :             break;
     660           0 :         case PqMsg_FunctionCallResponse:
     661           0 :             pqTraceOutput_FunctionCallResponse(conn->Pfdebug, message, &logCursor);
     662           0 :             break;
     663           0 :         case PqMsg_CopyBothResponse:
     664           0 :             pqTraceOutput_CopyBothResponse(conn->Pfdebug, message, &logCursor, length);
     665           0 :             break;
     666          18 :         case PqMsg_Terminate:
     667          18 :             fprintf(conn->Pfdebug, "Terminate");
     668             :             /* No message content */
     669          18 :             break;
     670          58 :         case PqMsg_ReadyForQuery:
     671          58 :             pqTraceOutput_ReadyForQuery(conn->Pfdebug, message, &logCursor);
     672          58 :             break;
     673           0 :         default:
     674           0 :             fprintf(conn->Pfdebug, "Unknown message: %02x", id);
     675           0 :             break;
     676             :     }
     677             : 
     678         828 :     fputc('\n', conn->Pfdebug);
     679             : 
     680             :     /*
     681             :      * Verify the printing routine did it right.  Note that the one-byte
     682             :      * message identifier is not included in the length, but our cursor does
     683             :      * include it.
     684             :      */
     685         828 :     if (logCursor - 1 != length)
     686           0 :         fprintf(conn->Pfdebug,
     687             :                 "mismatched message length: consumed %d, expected %d\n",
     688             :                 logCursor - 1, length);
     689         828 : }
     690             : 
     691             : /*
     692             :  * Print special messages (those containing no type byte) to the trace output
     693             :  * stream.
     694             :  */
     695             : void
     696           0 : pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message)
     697             : {
     698             :     int         length;
     699           0 :     int         logCursor = 0;
     700             : 
     701           0 :     if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0)
     702             :     {
     703             :         char        timestr[128];
     704             : 
     705           0 :         pqTraceFormatTimestamp(timestr, sizeof(timestr));
     706           0 :         fprintf(conn->Pfdebug, "%s\t", timestr);
     707             :     }
     708             : 
     709           0 :     memcpy(&length, message + logCursor, 4);
     710           0 :     length = (int) pg_ntoh32(length);
     711           0 :     logCursor += 4;
     712             : 
     713           0 :     fprintf(conn->Pfdebug, "F\t%d\t", length);
     714             : 
     715           0 :     switch (length)
     716             :     {
     717           0 :         case 16:                /* CancelRequest */
     718           0 :             fprintf(conn->Pfdebug, "CancelRequest\t");
     719           0 :             pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false);
     720           0 :             pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false);
     721           0 :             pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false);
     722           0 :             break;
     723           0 :         case 8:                 /* GSSENCRequest or SSLRequest */
     724             :             /* These messages do not reach here. */
     725             :         default:
     726           0 :             fprintf(conn->Pfdebug, "Unknown message: length is %d", length);
     727           0 :             break;
     728             :     }
     729             : 
     730           0 :     fputc('\n', conn->Pfdebug);
     731           0 : }

Generated by: LCOV version 1.14