LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-trace.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 205 365 56.2 %
Date: 2021-12-09 03:08:47 Functions: 19 32 59.4 %
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-2021, 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          16 : PQtrace(PGconn *conn, FILE *debug_port)
      36             : {
      37          16 :     if (conn == NULL)
      38           0 :         return;
      39          16 :     PQuntrace(conn);
      40          16 :     if (debug_port == NULL)
      41           0 :         return;
      42             : 
      43          16 :     conn->Pfdebug = debug_port;
      44          16 :     conn->traceFlags = 0;
      45             : }
      46             : 
      47             : /* Disable tracing */
      48             : void
      49          16 : PQuntrace(PGconn *conn)
      50             : {
      51          16 :     if (conn == NULL)
      52           0 :         return;
      53          16 :     if (conn->Pfdebug)
      54             :     {
      55           0 :         fflush(conn->Pfdebug);
      56           0 :         conn->Pfdebug = NULL;
      57             :     }
      58             : 
      59          16 :     conn->traceFlags = 0;
      60             : }
      61             : 
      62             : /* Set flags for current tracing session */
      63             : void
      64          16 : PQsetTraceFlags(PGconn *conn, int flags)
      65             : {
      66          16 :     if (conn == NULL)
      67           0 :         return;
      68             :     /* If PQtrace() failed, do nothing. */
      69          16 :     if (conn->Pfdebug == NULL)
      70           0 :         return;
      71          16 :     conn->traceFlags = flags;
      72             : }
      73             : 
      74             : /*
      75             :  * Print the current time, with microseconds, into a caller-supplied
      76             :  * buffer.
      77             :  * Cribbed from setup_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         226 : pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor)
     107             : {
     108         226 :     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         226 :     if (!isprint((unsigned char) *v))
     115          14 :         fprintf(pfdebug, " \\x%02x", *v);
     116             :     else
     117         212 :         fprintf(pfdebug, " %c", *v);
     118         226 :     *cursor += 1;
     119         226 : }
     120             : 
     121             : /*
     122             :  *   pqTraceOutputInt16: output a 2-byte integer message to the log
     123             :  */
     124             : static int
     125         544 : pqTraceOutputInt16(FILE *pfdebug, const char *data, int *cursor)
     126             : {
     127             :     uint16      tmp;
     128             :     int         result;
     129             : 
     130         544 :     memcpy(&tmp, data + *cursor, 2);
     131         544 :     *cursor += 2;
     132         544 :     result = (int) pg_ntoh16(tmp);
     133         544 :     fprintf(pfdebug, " %d", result);
     134             : 
     135         544 :     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         308 : pqTraceOutputInt32(FILE *pfdebug, const char *data, int *cursor, bool suppress)
     145             : {
     146             :     int         result;
     147             : 
     148         308 :     memcpy(&result, data + *cursor, 4);
     149         308 :     *cursor += 4;
     150         308 :     result = (int) pg_ntoh32(result);
     151         308 :     if (suppress)
     152         118 :         fprintf(pfdebug, " NNNN");
     153             :     else
     154         190 :         fprintf(pfdebug, " %d", result);
     155             : 
     156         308 :     return result;
     157             : }
     158             : 
     159             : /*
     160             :  *   pqTraceOutputString: output a string message to the log
     161             :  */
     162             : static void
     163         584 : pqTraceOutputString(FILE *pfdebug, const char *data, int *cursor, bool suppress)
     164             : {
     165             :     int         len;
     166             : 
     167         584 :     if (suppress)
     168             :     {
     169          42 :         fprintf(pfdebug, " \"SSSS\"");
     170          42 :         *cursor += strlen(data + *cursor) + 1;
     171             :     }
     172             :     else
     173             :     {
     174         542 :         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         542 :         *cursor += (len - 3 + 1);
     181             :     }
     182         584 : }
     183             : 
     184             : /*
     185             :  * pqTraceOutputNchar: output a string of exactly len bytes message to the log
     186             :  */
     187             : static void
     188          82 : pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor)
     189             : {
     190             :     int         i,
     191             :                 next;           /* first char not yet printed */
     192          82 :     const char *v = data + *cursor;
     193             : 
     194          82 :     fprintf(pfdebug, " \'");
     195             : 
     196        1500 :     for (next = i = 0; i < len; ++i)
     197             :     {
     198        1418 :         if (isprint((unsigned char) v[i]))
     199        1418 :             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          82 :     if (next < len)
     208          82 :         fwrite(v + next, 1, len - next, pfdebug);
     209             : 
     210          82 :     fprintf(pfdebug, "\'");
     211          82 :     *cursor += len;
     212          82 : }
     213             : 
     214             : /*
     215             :  * Output functions by protocol message type
     216             :  */
     217             : 
     218             : /* NotificationResponse */
     219             : static void
     220           0 : pqTraceOutputA(FILE *f, const char *message, int *cursor, bool regress)
     221             : {
     222           0 :     fprintf(f, "NotificationResponse\t");
     223           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     224           0 :     pqTraceOutputString(f, message, cursor, false);
     225           0 :     pqTraceOutputString(f, message, cursor, false);
     226           0 : }
     227             : 
     228             : /* Bind */
     229             : static void
     230          58 : pqTraceOutputB(FILE *f, const char *message, int *cursor)
     231             : {
     232             :     int         nparams;
     233             : 
     234          58 :     fprintf(f, "Bind\t");
     235          58 :     pqTraceOutputString(f, message, cursor, false);
     236          58 :     pqTraceOutputString(f, message, cursor, false);
     237          58 :     nparams = pqTraceOutputInt16(f, message, cursor);
     238             : 
     239          58 :     for (int i = 0; i < nparams; i++)
     240           0 :         pqTraceOutputInt16(f, message, cursor);
     241             : 
     242          58 :     nparams = pqTraceOutputInt16(f, message, cursor);
     243             : 
     244          78 :     for (int i = 0; i < nparams; i++)
     245             :     {
     246             :         int         nbytes;
     247             : 
     248          20 :         nbytes = pqTraceOutputInt32(f, message, cursor, false);
     249          20 :         if (nbytes == -1)
     250           0 :             continue;
     251          20 :         pqTraceOutputNchar(f, nbytes, message, cursor);
     252             :     }
     253             : 
     254          58 :     nparams = pqTraceOutputInt16(f, message, cursor);
     255         112 :     for (int i = 0; i < nparams; i++)
     256          54 :         pqTraceOutputInt16(f, message, cursor);
     257          58 : }
     258             : 
     259             : /* Close(F) or CommandComplete(B) */
     260             : static void
     261          64 : pqTraceOutputC(FILE *f, bool toServer, const char *message, int *cursor)
     262             : {
     263          64 :     if (toServer)
     264             :     {
     265           4 :         fprintf(f, "Close\t");
     266           4 :         pqTraceOutputByte1(f, message, cursor);
     267           4 :         pqTraceOutputString(f, message, cursor, false);
     268             :     }
     269             :     else
     270             :     {
     271          60 :         fprintf(f, "CommandComplete\t");
     272          60 :         pqTraceOutputString(f, message, cursor, false);
     273             :     }
     274          64 : }
     275             : 
     276             : /* Describe(F) or DataRow(B) */
     277             : static void
     278         124 : pqTraceOutputD(FILE *f, bool toServer, const char *message, int *cursor)
     279             : {
     280         124 :     if (toServer)
     281             :     {
     282          62 :         fprintf(f, "Describe\t");
     283          62 :         pqTraceOutputByte1(f, message, cursor);
     284          62 :         pqTraceOutputString(f, message, cursor, false);
     285             :     }
     286             :     else
     287             :     {
     288             :         int         nfields;
     289             :         int         len;
     290             :         int         i;
     291             : 
     292          62 :         fprintf(f, "DataRow\t");
     293          62 :         nfields = pqTraceOutputInt16(f, message, cursor);
     294         124 :         for (i = 0; i < nfields; i++)
     295             :         {
     296          62 :             len = pqTraceOutputInt32(f, message, cursor, false);
     297          62 :             if (len == -1)
     298           0 :                 continue;
     299          62 :             pqTraceOutputNchar(f, len, message, cursor);
     300             :         }
     301             :     }
     302         124 : }
     303             : 
     304             : /* NoticeResponse / ErrorResponse */
     305             : static void
     306          14 : pqTraceOutputNR(FILE *f, const char *type, const char *message, int *cursor,
     307             :                 bool regress)
     308             : {
     309          14 :     fprintf(f, "%s\t", type);
     310             :     for (;;)
     311         102 :     {
     312             :         char        field;
     313             :         bool        suppress;
     314             : 
     315         116 :         pqTraceOutputByte1(f, message, cursor);
     316         116 :         field = message[*cursor - 1];
     317         116 :         if (field == '\0')
     318          14 :             break;
     319             : 
     320         102 :         suppress = regress && (field == 'L' || field == 'F' || field == 'R');
     321         102 :         pqTraceOutputString(f, message, cursor, suppress);
     322             :     }
     323          14 : }
     324             : 
     325             : /* Execute(F) or ErrorResponse(B) */
     326             : static void
     327          68 : pqTraceOutputE(FILE *f, bool toServer, const char *message, int *cursor, bool regress)
     328             : {
     329          68 :     if (toServer)
     330             :     {
     331          58 :         fprintf(f, "Execute\t");
     332          58 :         pqTraceOutputString(f, message, cursor, false);
     333          58 :         pqTraceOutputInt32(f, message, cursor, false);
     334             :     }
     335             :     else
     336          10 :         pqTraceOutputNR(f, "ErrorResponse", message, cursor, regress);
     337          68 : }
     338             : 
     339             : /* CopyFail */
     340             : static void
     341           0 : pqTraceOutputf(FILE *f, const char *message, int *cursor)
     342             : {
     343           0 :     fprintf(f, "CopyFail\t");
     344           0 :     pqTraceOutputString(f, message, cursor, false);
     345           0 : }
     346             : 
     347             : /* FunctionCall */
     348             : static void
     349           0 : pqTraceOutputF(FILE *f, const char *message, int *cursor, bool regress)
     350             : {
     351             :     int         nfields;
     352             :     int         nbytes;
     353             : 
     354           0 :     fprintf(f, "FunctionCall\t");
     355           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     356           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     357             : 
     358           0 :     for (int i = 0; i < nfields; i++)
     359           0 :         pqTraceOutputInt16(f, message, cursor);
     360             : 
     361           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     362             : 
     363           0 :     for (int i = 0; i < nfields; i++)
     364             :     {
     365           0 :         nbytes = pqTraceOutputInt32(f, message, cursor, false);
     366           0 :         if (nbytes == -1)
     367           0 :             continue;
     368           0 :         pqTraceOutputNchar(f, nbytes, message, cursor);
     369             :     }
     370             : 
     371           0 :     pqTraceOutputInt16(f, message, cursor);
     372           0 : }
     373             : 
     374             : /* CopyInResponse */
     375             : static void
     376           0 : pqTraceOutputG(FILE *f, const char *message, int *cursor)
     377             : {
     378             :     int         nfields;
     379             : 
     380           0 :     fprintf(f, "CopyInResponse\t");
     381           0 :     pqTraceOutputByte1(f, message, cursor);
     382           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     383             : 
     384           0 :     for (int i = 0; i < nfields; i++)
     385           0 :         pqTraceOutputInt16(f, message, cursor);
     386           0 : }
     387             : 
     388             : /* CopyOutResponse */
     389             : static void
     390           0 : pqTraceOutputH(FILE *f, const char *message, int *cursor)
     391             : {
     392             :     int         nfields;
     393             : 
     394           0 :     fprintf(f, "CopyOutResponse\t");
     395           0 :     pqTraceOutputByte1(f, message, cursor);
     396           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     397             : 
     398           0 :     for (int i = 0; i < nfields; i++)
     399           0 :         pqTraceOutputInt16(f, message, cursor);
     400           0 : }
     401             : 
     402             : /* BackendKeyData */
     403             : static void
     404           0 : pqTraceOutputK(FILE *f, const char *message, int *cursor, bool regress)
     405             : {
     406           0 :     fprintf(f, "BackendKeyData\t");
     407           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     408           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     409           0 : }
     410             : 
     411             : /* Parse */
     412             : static void
     413          58 : pqTraceOutputP(FILE *f, const char *message, int *cursor, bool regress)
     414             : {
     415             :     int         nparams;
     416             : 
     417          58 :     fprintf(f, "Parse\t");
     418          58 :     pqTraceOutputString(f, message, cursor, false);
     419          58 :     pqTraceOutputString(f, message, cursor, false);
     420          58 :     nparams = pqTraceOutputInt16(f, message, cursor);
     421             : 
     422          74 :     for (int i = 0; i < nparams; i++)
     423          16 :         pqTraceOutputInt32(f, message, cursor, regress);
     424          58 : }
     425             : 
     426             : /* Query */
     427             : static void
     428          16 : pqTraceOutputQ(FILE *f, const char *message, int *cursor)
     429             : {
     430          16 :     fprintf(f, "Query\t");
     431          16 :     pqTraceOutputString(f, message, cursor, false);
     432          16 : }
     433             : 
     434             : /* Authentication */
     435             : static void
     436           0 : pqTraceOutputR(FILE *f, const char *message, int *cursor)
     437             : {
     438           0 :     fprintf(f, "Authentication\t");
     439           0 :     pqTraceOutputInt32(f, message, cursor, false);
     440           0 : }
     441             : 
     442             : /* ParameterStatus */
     443             : static void
     444           0 : pqTraceOutputS(FILE *f, const char *message, int *cursor)
     445             : {
     446           0 :     fprintf(f, "ParameterStatus\t");
     447           0 :     pqTraceOutputString(f, message, cursor, false);
     448           0 :     pqTraceOutputString(f, message, cursor, false);
     449           0 : }
     450             : 
     451             : /* ParameterDescription */
     452             : static void
     453           2 : pqTraceOutputt(FILE *f, const char *message, int *cursor, bool regress)
     454             : {
     455             :     int         nfields;
     456             : 
     457           2 :     fprintf(f, "ParameterDescription\t");
     458           2 :     nfields = pqTraceOutputInt16(f, message, cursor);
     459             : 
     460           4 :     for (int i = 0; i < nfields; i++)
     461           2 :         pqTraceOutputInt32(f, message, cursor, regress);
     462           2 : }
     463             : 
     464             : /* RowDescription */
     465             : static void
     466          44 : pqTraceOutputT(FILE *f, const char *message, int *cursor, bool regress)
     467             : {
     468             :     int         nfields;
     469             : 
     470          44 :     fprintf(f, "RowDescription\t");
     471          44 :     nfields = pqTraceOutputInt16(f, message, cursor);
     472             : 
     473          94 :     for (int i = 0; i < nfields; i++)
     474             :     {
     475          50 :         pqTraceOutputString(f, message, cursor, false);
     476          50 :         pqTraceOutputInt32(f, message, cursor, regress);
     477          50 :         pqTraceOutputInt16(f, message, cursor);
     478          50 :         pqTraceOutputInt32(f, message, cursor, regress);
     479          50 :         pqTraceOutputInt16(f, message, cursor);
     480          50 :         pqTraceOutputInt32(f, message, cursor, false);
     481          50 :         pqTraceOutputInt16(f, message, cursor);
     482             :     }
     483          44 : }
     484             : 
     485             : /* NegotiateProtocolVersion */
     486             : static void
     487           0 : pqTraceOutputv(FILE *f, const char *message, int *cursor)
     488             : {
     489           0 :     fprintf(f, "NegotiateProtocolVersion\t");
     490           0 :     pqTraceOutputInt32(f, message, cursor, false);
     491           0 :     pqTraceOutputInt32(f, message, cursor, false);
     492           0 : }
     493             : 
     494             : /* FunctionCallResponse */
     495             : static void
     496           0 : pqTraceOutputV(FILE *f, const char *message, int *cursor)
     497             : {
     498             :     int         len;
     499             : 
     500           0 :     fprintf(f, "FunctionCallResponse\t");
     501           0 :     len = pqTraceOutputInt32(f, message, cursor, false);
     502           0 :     if (len != -1)
     503           0 :         pqTraceOutputNchar(f, len, message, cursor);
     504           0 : }
     505             : 
     506             : /* CopyBothResponse */
     507             : static void
     508           0 : pqTraceOutputW(FILE *f, const char *message, int *cursor, int length)
     509             : {
     510           0 :     fprintf(f, "CopyBothResponse\t");
     511           0 :     pqTraceOutputByte1(f, message, cursor);
     512             : 
     513           0 :     while (length > *cursor)
     514           0 :         pqTraceOutputInt16(f, message, cursor);
     515           0 : }
     516             : 
     517             : /* ReadyForQuery */
     518             : static void
     519          44 : pqTraceOutputZ(FILE *f, const char *message, int *cursor)
     520             : {
     521          44 :     fprintf(f, "ReadyForQuery\t");
     522          44 :     pqTraceOutputByte1(f, message, cursor);
     523          44 : }
     524             : 
     525             : /*
     526             :  * Print the given message to the trace output stream.
     527             :  */
     528             : void
     529         630 : pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer)
     530             : {
     531             :     char        id;
     532             :     int         length;
     533         630 :     char       *prefix = toServer ? "F" : "B";
     534         630 :     int         logCursor = 0;
     535             :     bool        regress;
     536             : 
     537         630 :     if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0)
     538             :     {
     539             :         char        timestr[128];
     540             : 
     541           0 :         pqTraceFormatTimestamp(timestr, sizeof(timestr));
     542           0 :         fprintf(conn->Pfdebug, "%s\t", timestr);
     543             :     }
     544         630 :     regress = (conn->traceFlags & PQTRACE_REGRESS_MODE) != 0;
     545             : 
     546         630 :     id = message[logCursor++];
     547             : 
     548         630 :     memcpy(&length, message + logCursor, 4);
     549         630 :     length = (int) pg_ntoh32(length);
     550         630 :     logCursor += 4;
     551             : 
     552             :     /*
     553             :      * In regress mode, suppress the length of ErrorResponse and
     554             :      * NoticeResponse.  The F (file name), L (line number) and R (routine
     555             :      * name) fields can change as server code is modified, and if their
     556             :      * lengths differ from the originals, that would break tests.
     557             :      */
     558         630 :     if (regress && !toServer && (id == 'E' || id == 'N'))
     559          14 :         fprintf(conn->Pfdebug, "%s\tNN\t", prefix);
     560             :     else
     561         616 :         fprintf(conn->Pfdebug, "%s\t%d\t", prefix, length);
     562             : 
     563         630 :     switch (id)
     564             :     {
     565          48 :         case '1':
     566          48 :             fprintf(conn->Pfdebug, "ParseComplete");
     567             :             /* No message content */
     568          48 :             break;
     569          44 :         case '2':
     570          44 :             fprintf(conn->Pfdebug, "BindComplete");
     571             :             /* No message content */
     572          44 :             break;
     573           0 :         case '3':
     574           0 :             fprintf(conn->Pfdebug, "CloseComplete");
     575             :             /* No message content */
     576           0 :             break;
     577           0 :         case 'A':               /* Notification Response */
     578           0 :             pqTraceOutputA(conn->Pfdebug, message, &logCursor, regress);
     579           0 :             break;
     580          58 :         case 'B':               /* Bind */
     581          58 :             pqTraceOutputB(conn->Pfdebug, message, &logCursor);
     582          58 :             break;
     583           0 :         case 'c':
     584           0 :             fprintf(conn->Pfdebug, "CopyDone");
     585             :             /* No message content */
     586           0 :             break;
     587          64 :         case 'C':               /* Close(F) or Command Complete(B) */
     588          64 :             pqTraceOutputC(conn->Pfdebug, toServer, message, &logCursor);
     589          64 :             break;
     590           0 :         case 'd':               /* Copy Data */
     591             :             /* Drop COPY data to reduce the overhead of logging. */
     592           0 :             break;
     593         124 :         case 'D':               /* Describe(F) or Data Row(B) */
     594         124 :             pqTraceOutputD(conn->Pfdebug, toServer, message, &logCursor);
     595         124 :             break;
     596          68 :         case 'E':               /* Execute(F) or Error Response(B) */
     597          68 :             pqTraceOutputE(conn->Pfdebug, toServer, message, &logCursor,
     598             :                            regress);
     599          68 :             break;
     600           0 :         case 'f':               /* Copy Fail */
     601           0 :             pqTraceOutputf(conn->Pfdebug, message, &logCursor);
     602           0 :             break;
     603           0 :         case 'F':               /* Function Call */
     604           0 :             pqTraceOutputF(conn->Pfdebug, message, &logCursor, regress);
     605           0 :             break;
     606           0 :         case 'G':               /* Start Copy In */
     607           0 :             pqTraceOutputG(conn->Pfdebug, message, &logCursor);
     608           0 :             break;
     609           2 :         case 'H':               /* Flush(F) or Start Copy Out(B) */
     610           2 :             if (!toServer)
     611           0 :                 pqTraceOutputH(conn->Pfdebug, message, &logCursor);
     612             :             else
     613           2 :                 fprintf(conn->Pfdebug, "Flush");   /* no message content */
     614           2 :             break;
     615           0 :         case 'I':
     616           0 :             fprintf(conn->Pfdebug, "EmptyQueryResponse");
     617             :             /* No message content */
     618           0 :             break;
     619           0 :         case 'K':               /* secret key data from the backend */
     620           0 :             pqTraceOutputK(conn->Pfdebug, message, &logCursor, regress);
     621           0 :             break;
     622          10 :         case 'n':
     623          10 :             fprintf(conn->Pfdebug, "NoData");
     624             :             /* No message content */
     625          10 :             break;
     626           4 :         case 'N':
     627           4 :             pqTraceOutputNR(conn->Pfdebug, "NoticeResponse", message,
     628             :                             &logCursor, regress);
     629           4 :             break;
     630          58 :         case 'P':               /* Parse */
     631          58 :             pqTraceOutputP(conn->Pfdebug, message, &logCursor, regress);
     632          58 :             break;
     633          16 :         case 'Q':               /* Query */
     634          16 :             pqTraceOutputQ(conn->Pfdebug, message, &logCursor);
     635          16 :             break;
     636           0 :         case 'R':               /* Authentication */
     637           0 :             pqTraceOutputR(conn->Pfdebug, message, &logCursor);
     638           0 :             break;
     639           0 :         case 's':
     640           0 :             fprintf(conn->Pfdebug, "PortalSuspended");
     641             :             /* No message content */
     642           0 :             break;
     643          28 :         case 'S':               /* Parameter Status(B) or Sync(F) */
     644          28 :             if (!toServer)
     645           0 :                 pqTraceOutputS(conn->Pfdebug, message, &logCursor);
     646             :             else
     647          28 :                 fprintf(conn->Pfdebug, "Sync"); /* no message content */
     648          28 :             break;
     649           2 :         case 't':               /* Parameter Description */
     650           2 :             pqTraceOutputt(conn->Pfdebug, message, &logCursor, regress);
     651           2 :             break;
     652          44 :         case 'T':               /* Row Description */
     653          44 :             pqTraceOutputT(conn->Pfdebug, message, &logCursor, regress);
     654          44 :             break;
     655           0 :         case 'v':               /* Negotiate Protocol Version */
     656           0 :             pqTraceOutputv(conn->Pfdebug, message, &logCursor);
     657           0 :             break;
     658           0 :         case 'V':               /* Function Call response */
     659           0 :             pqTraceOutputV(conn->Pfdebug, message, &logCursor);
     660           0 :             break;
     661           0 :         case 'W':               /* Start Copy Both */
     662           0 :             pqTraceOutputW(conn->Pfdebug, message, &logCursor, length);
     663           0 :             break;
     664          16 :         case 'X':
     665          16 :             fprintf(conn->Pfdebug, "Terminate");
     666             :             /* No message content */
     667          16 :             break;
     668          44 :         case 'Z':               /* Ready For Query */
     669          44 :             pqTraceOutputZ(conn->Pfdebug, message, &logCursor);
     670          44 :             break;
     671           0 :         default:
     672           0 :             fprintf(conn->Pfdebug, "Unknown message: %02x", id);
     673           0 :             break;
     674             :     }
     675             : 
     676         630 :     fputc('\n', conn->Pfdebug);
     677             : 
     678             :     /*
     679             :      * Verify the printing routine did it right.  Note that the one-byte
     680             :      * message identifier is not included in the length, but our cursor does
     681             :      * include it.
     682             :      */
     683         630 :     if (logCursor - 1 != length)
     684           0 :         fprintf(conn->Pfdebug,
     685             :                 "mismatched message length: consumed %d, expected %d\n",
     686             :                 logCursor - 1, length);
     687         630 : }
     688             : 
     689             : /*
     690             :  * Print special messages (those containing no type byte) to the trace output
     691             :  * stream.
     692             :  */
     693             : void
     694           0 : pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message)
     695             : {
     696             :     int         length;
     697           0 :     int         logCursor = 0;
     698             : 
     699           0 :     if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0)
     700             :     {
     701             :         char        timestr[128];
     702             : 
     703           0 :         pqTraceFormatTimestamp(timestr, sizeof(timestr));
     704           0 :         fprintf(conn->Pfdebug, "%s\t", timestr);
     705             :     }
     706             : 
     707           0 :     memcpy(&length, message + logCursor, 4);
     708           0 :     length = (int) pg_ntoh32(length);
     709           0 :     logCursor += 4;
     710             : 
     711           0 :     fprintf(conn->Pfdebug, "F\t%d\t", length);
     712             : 
     713           0 :     switch (length)
     714             :     {
     715           0 :         case 16:                /* CancelRequest */
     716           0 :             fprintf(conn->Pfdebug, "CancelRequest\t");
     717           0 :             pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false);
     718           0 :             pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false);
     719           0 :             pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, false);
     720           0 :             break;
     721           0 :         case 8:                 /* GSSENCRequest or SSLRequest */
     722             :             /* These messages do not reach here. */
     723             :         default:
     724           0 :             fprintf(conn->Pfdebug, "Unknown message: length is %d", length);
     725           0 :             break;
     726             :     }
     727             : 
     728           0 :     fputc('\n', conn->Pfdebug);
     729           0 : }

Generated by: LCOV version 1.14