LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-trace.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 220 482 45.6 %
Date: 2024-11-21 08:14:44 Functions: 23 42 54.8 %
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             :     struct tm   tmbuf;
      85             : 
      86           0 :     gettimeofday(&tval, NULL);
      87             : 
      88             :     /*
      89             :      * MSVC's implementation of timeval uses a long for tv_sec, however,
      90             :      * localtime() expects a time_t pointer.  Here we'll assign tv_sec to a
      91             :      * local time_t variable so that we pass localtime() the correct pointer
      92             :      * type.
      93             :      */
      94           0 :     now = tval.tv_sec;
      95           0 :     strftime(timestr, ts_len,
      96             :              "%Y-%m-%d %H:%M:%S",
      97           0 :              localtime_r(&now, &tmbuf));
      98             :     /* append microseconds */
      99           0 :     snprintf(timestr + strlen(timestr), ts_len - strlen(timestr),
     100           0 :              ".%06u", (unsigned int) (tval.tv_usec));
     101           0 : }
     102             : 
     103             : /*
     104             :  *   pqTraceOutputByte1: output a 1-char message to the log
     105             :  */
     106             : static void
     107         310 : pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor)
     108             : {
     109         310 :     const char *v = data + *cursor;
     110             : 
     111             :     /*
     112             :      * Show non-printable data in hex format, including the terminating \0
     113             :      * that completes ErrorResponse and NoticeResponse messages.
     114             :      */
     115         310 :     if (!isprint((unsigned char) *v))
     116          20 :         fprintf(pfdebug, " \\x%02x", *v);
     117             :     else
     118         290 :         fprintf(pfdebug, " %c", *v);
     119         310 :     *cursor += 1;
     120         310 : }
     121             : 
     122             : /*
     123             :  *   pqTraceOutputInt16: output a 2-byte integer message to the log
     124             :  */
     125             : static int
     126         696 : pqTraceOutputInt16(FILE *pfdebug, const char *data, int *cursor)
     127             : {
     128             :     uint16      tmp;
     129             :     int         result;
     130             : 
     131         696 :     memcpy(&tmp, data + *cursor, 2);
     132         696 :     *cursor += 2;
     133         696 :     result = (int) pg_ntoh16(tmp);
     134         696 :     fprintf(pfdebug, " %d", result);
     135             : 
     136         696 :     return result;
     137             : }
     138             : 
     139             : /*
     140             :  *   pqTraceOutputInt32: output a 4-byte integer message to the log
     141             :  *
     142             :  * If 'suppress' is true, print a literal NNNN instead of the actual number.
     143             :  */
     144             : static int
     145         390 : pqTraceOutputInt32(FILE *pfdebug, const char *data, int *cursor, bool suppress)
     146             : {
     147             :     int         result;
     148             : 
     149         390 :     memcpy(&result, data + *cursor, 4);
     150         390 :     *cursor += 4;
     151         390 :     result = (int) pg_ntoh32(result);
     152         390 :     if (suppress)
     153         148 :         fprintf(pfdebug, " NNNN");
     154             :     else
     155         242 :         fprintf(pfdebug, " %d", result);
     156             : 
     157         390 :     return result;
     158             : }
     159             : 
     160             : /*
     161             :  *   pqTraceOutputString: output a string message to the log
     162             :  *
     163             :  * If 'suppress' is true, print a literal "SSSS" instead of the actual string.
     164             :  */
     165             : static void
     166         746 : pqTraceOutputString(FILE *pfdebug, const char *data, int *cursor, bool suppress)
     167             : {
     168             :     int         len;
     169             : 
     170         746 :     if (suppress)
     171             :     {
     172          60 :         fprintf(pfdebug, " \"SSSS\"");
     173          60 :         *cursor += strlen(data + *cursor) + 1;
     174             :     }
     175             :     else
     176             :     {
     177         686 :         len = fprintf(pfdebug, " \"%s\"", data + *cursor);
     178             : 
     179             :         /*
     180             :          * This is a null-terminated string. So add 1 after subtracting 3
     181             :          * which is the double quotes and space length from len.
     182             :          */
     183         686 :         *cursor += (len - 3 + 1);
     184             :     }
     185         746 : }
     186             : 
     187             : /*
     188             :  * pqTraceOutputNchar: output a string of exactly len bytes message to the log
     189             :  *
     190             :  * If 'suppress' is true, print a literal 'BBBB' instead of the actual bytes.
     191             :  */
     192             : static void
     193         106 : pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor, bool suppress)
     194             : {
     195             :     int         i,
     196             :                 next;           /* first char not yet printed */
     197         106 :     const char *v = data + *cursor;
     198             : 
     199         106 :     if (suppress)
     200             :     {
     201           0 :         fprintf(pfdebug, " 'BBBB'");
     202           0 :         *cursor += len;
     203           0 :         return;
     204             :     }
     205             : 
     206         106 :     fprintf(pfdebug, " \'");
     207             : 
     208        1548 :     for (next = i = 0; i < len; ++i)
     209             :     {
     210        1442 :         if (isprint((unsigned char) v[i]))
     211        1442 :             continue;
     212             :         else
     213             :         {
     214           0 :             fwrite(v + next, 1, i - next, pfdebug);
     215           0 :             fprintf(pfdebug, "\\x%02x", v[i]);
     216           0 :             next = i + 1;
     217             :         }
     218             :     }
     219         106 :     if (next < len)
     220         106 :         fwrite(v + next, 1, len - next, pfdebug);
     221             : 
     222         106 :     fprintf(pfdebug, "\'");
     223         106 :     *cursor += len;
     224             : }
     225             : 
     226             : /*
     227             :  * Output functions by protocol message type
     228             :  */
     229             : 
     230             : static void
     231           0 : pqTraceOutput_NotificationResponse(FILE *f, const char *message, int *cursor, bool regress)
     232             : {
     233           0 :     fprintf(f, "NotificationResponse\t");
     234           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     235           0 :     pqTraceOutputString(f, message, cursor, false);
     236           0 :     pqTraceOutputString(f, message, cursor, false);
     237           0 : }
     238             : 
     239             : static void
     240          72 : pqTraceOutput_Bind(FILE *f, const char *message, int *cursor)
     241             : {
     242             :     int         nparams;
     243             : 
     244          72 :     fprintf(f, "Bind\t");
     245          72 :     pqTraceOutputString(f, message, cursor, false);
     246          72 :     pqTraceOutputString(f, message, cursor, false);
     247          72 :     nparams = pqTraceOutputInt16(f, message, cursor);
     248             : 
     249          72 :     for (int i = 0; i < nparams; i++)
     250           0 :         pqTraceOutputInt16(f, message, cursor);
     251             : 
     252          72 :     nparams = pqTraceOutputInt16(f, message, cursor);
     253             : 
     254          94 :     for (int i = 0; i < nparams; i++)
     255             :     {
     256             :         int         nbytes;
     257             : 
     258          22 :         nbytes = pqTraceOutputInt32(f, message, cursor, false);
     259          22 :         if (nbytes == -1)
     260           0 :             continue;
     261          22 :         pqTraceOutputNchar(f, nbytes, message, cursor, false);
     262             :     }
     263             : 
     264          72 :     nparams = pqTraceOutputInt16(f, message, cursor);
     265         144 :     for (int i = 0; i < nparams; i++)
     266          72 :         pqTraceOutputInt16(f, message, cursor);
     267          72 : }
     268             : 
     269             : static void
     270           8 : pqTraceOutput_Close(FILE *f, const char *message, int *cursor)
     271             : {
     272           8 :     fprintf(f, "Close\t");
     273           8 :     pqTraceOutputByte1(f, message, cursor);
     274           8 :     pqTraceOutputString(f, message, cursor, false);
     275           8 : }
     276             : 
     277             : static void
     278          74 : pqTraceOutput_CommandComplete(FILE *f, const char *message, int *cursor)
     279             : {
     280          74 :     fprintf(f, "CommandComplete\t");
     281          74 :     pqTraceOutputString(f, message, cursor, false);
     282          74 : }
     283             : 
     284             : static void
     285           0 : pqTraceOutput_CopyData(FILE *f, const char *message, int *cursor, int length,
     286             :                        bool suppress)
     287             : {
     288           0 :     fprintf(f, "CopyData\t");
     289           0 :     pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, suppress);
     290           0 : }
     291             : 
     292             : static void
     293          84 : pqTraceOutput_DataRow(FILE *f, const char *message, int *cursor)
     294             : {
     295             :     int         nfields;
     296             :     int         len;
     297             :     int         i;
     298             : 
     299          84 :     fprintf(f, "DataRow\t");
     300          84 :     nfields = pqTraceOutputInt16(f, message, cursor);
     301         168 :     for (i = 0; i < nfields; i++)
     302             :     {
     303          84 :         len = pqTraceOutputInt32(f, message, cursor, false);
     304          84 :         if (len == -1)
     305           0 :             continue;
     306          84 :         pqTraceOutputNchar(f, len, message, cursor, false);
     307             :     }
     308          84 : }
     309             : 
     310             : static void
     311          80 : pqTraceOutput_Describe(FILE *f, const char *message, int *cursor)
     312             : {
     313          80 :     fprintf(f, "Describe\t");
     314          80 :     pqTraceOutputByte1(f, message, cursor);
     315          80 :     pqTraceOutputString(f, message, cursor, false);
     316          80 : }
     317             : 
     318             : /* shared code NoticeResponse / ErrorResponse */
     319             : static void
     320          20 : pqTraceOutputNR(FILE *f, const char *type, const char *message, int *cursor,
     321             :                 bool regress)
     322             : {
     323          20 :     fprintf(f, "%s\t", type);
     324             :     for (;;)
     325         144 :     {
     326             :         char        field;
     327             :         bool        suppress;
     328             : 
     329         164 :         pqTraceOutputByte1(f, message, cursor);
     330         164 :         field = message[*cursor - 1];
     331         164 :         if (field == '\0')
     332          20 :             break;
     333             : 
     334         144 :         suppress = regress && (field == 'L' || field == 'F' || field == 'R');
     335         144 :         pqTraceOutputString(f, message, cursor, suppress);
     336             :     }
     337          20 : }
     338             : 
     339             : static void
     340          14 : pqTraceOutput_ErrorResponse(FILE *f, const char *message, int *cursor, bool regress)
     341             : {
     342          14 :     pqTraceOutputNR(f, "ErrorResponse", message, cursor, regress);
     343          14 : }
     344             : 
     345             : static void
     346           6 : pqTraceOutput_NoticeResponse(FILE *f, const char *message, int *cursor, bool regress)
     347             : {
     348           6 :     pqTraceOutputNR(f, "NoticeResponse", message, cursor, regress);
     349           6 : }
     350             : 
     351             : static void
     352          72 : pqTraceOutput_Execute(FILE *f, const char *message, int *cursor, bool regress)
     353             : {
     354          72 :     fprintf(f, "Execute\t");
     355          72 :     pqTraceOutputString(f, message, cursor, false);
     356          72 :     pqTraceOutputInt32(f, message, cursor, false);
     357          72 : }
     358             : 
     359             : static void
     360           0 : pqTraceOutput_CopyFail(FILE *f, const char *message, int *cursor)
     361             : {
     362           0 :     fprintf(f, "CopyFail\t");
     363           0 :     pqTraceOutputString(f, message, cursor, false);
     364           0 : }
     365             : 
     366             : static void
     367           0 : pqTraceOutput_GSSResponse(FILE *f, const char *message, int *cursor,
     368             :                           int length, bool regress)
     369             : {
     370           0 :     fprintf(f, "GSSResponse\t");
     371           0 :     pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, regress);
     372           0 : }
     373             : 
     374             : static void
     375           0 : pqTraceOutput_PasswordMessage(FILE *f, const char *message, int *cursor)
     376             : {
     377           0 :     fprintf(f, "PasswordMessage\t");
     378           0 :     pqTraceOutputString(f, message, cursor, false);
     379           0 : }
     380             : 
     381             : static void
     382           0 : pqTraceOutput_SASLInitialResponse(FILE *f, const char *message, int *cursor,
     383             :                                   bool regress)
     384             : {
     385             :     int         initialResponse;
     386             : 
     387           0 :     fprintf(f, "SASLInitialResponse\t");
     388           0 :     pqTraceOutputString(f, message, cursor, false);
     389           0 :     initialResponse = pqTraceOutputInt32(f, message, cursor, false);
     390           0 :     if (initialResponse != -1)
     391           0 :         pqTraceOutputNchar(f, initialResponse, message, cursor, regress);
     392           0 : }
     393             : 
     394             : static void
     395           0 : pqTraceOutput_SASLResponse(FILE *f, const char *message, int *cursor,
     396             :                            int length, bool regress)
     397             : {
     398           0 :     fprintf(f, "SASLResponse\t");
     399           0 :     pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, regress);
     400           0 : }
     401             : 
     402             : static void
     403           0 : pqTraceOutput_FunctionCall(FILE *f, const char *message, int *cursor, bool regress)
     404             : {
     405             :     int         nfields;
     406             :     int         nbytes;
     407             : 
     408           0 :     fprintf(f, "FunctionCall\t");
     409           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     410           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     411             : 
     412           0 :     for (int i = 0; i < nfields; i++)
     413           0 :         pqTraceOutputInt16(f, message, cursor);
     414             : 
     415           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     416             : 
     417           0 :     for (int i = 0; i < nfields; i++)
     418             :     {
     419           0 :         nbytes = pqTraceOutputInt32(f, message, cursor, false);
     420           0 :         if (nbytes == -1)
     421           0 :             continue;
     422           0 :         pqTraceOutputNchar(f, nbytes, message, cursor, false);
     423             :     }
     424             : 
     425           0 :     pqTraceOutputInt16(f, message, cursor);
     426           0 : }
     427             : 
     428             : static void
     429           0 : pqTraceOutput_CopyInResponse(FILE *f, const char *message, int *cursor)
     430             : {
     431             :     int         nfields;
     432             : 
     433           0 :     fprintf(f, "CopyInResponse\t");
     434           0 :     pqTraceOutputByte1(f, message, cursor);
     435           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     436             : 
     437           0 :     for (int i = 0; i < nfields; i++)
     438           0 :         pqTraceOutputInt16(f, message, cursor);
     439           0 : }
     440             : 
     441             : static void
     442           0 : pqTraceOutput_CopyOutResponse(FILE *f, const char *message, int *cursor)
     443             : {
     444             :     int         nfields;
     445             : 
     446           0 :     fprintf(f, "CopyOutResponse\t");
     447           0 :     pqTraceOutputByte1(f, message, cursor);
     448           0 :     nfields = pqTraceOutputInt16(f, message, cursor);
     449             : 
     450           0 :     for (int i = 0; i < nfields; i++)
     451           0 :         pqTraceOutputInt16(f, message, cursor);
     452           0 : }
     453             : 
     454             : static void
     455           0 : pqTraceOutput_BackendKeyData(FILE *f, const char *message, int *cursor, bool regress)
     456             : {
     457           0 :     fprintf(f, "BackendKeyData\t");
     458           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     459           0 :     pqTraceOutputInt32(f, message, cursor, regress);
     460           0 : }
     461             : 
     462             : static void
     463          72 : pqTraceOutput_Parse(FILE *f, const char *message, int *cursor, bool regress)
     464             : {
     465             :     int         nparams;
     466             : 
     467          72 :     fprintf(f, "Parse\t");
     468          72 :     pqTraceOutputString(f, message, cursor, false);
     469          72 :     pqTraceOutputString(f, message, cursor, false);
     470          72 :     nparams = pqTraceOutputInt16(f, message, cursor);
     471             : 
     472          90 :     for (int i = 0; i < nparams; i++)
     473          18 :         pqTraceOutputInt32(f, message, cursor, regress);
     474          72 : }
     475             : 
     476             : static void
     477          16 : pqTraceOutput_Query(FILE *f, const char *message, int *cursor)
     478             : {
     479          16 :     fprintf(f, "Query\t");
     480          16 :     pqTraceOutputString(f, message, cursor, false);
     481          16 : }
     482             : 
     483             : static void
     484           0 : pqTraceOutput_Authentication(FILE *f, const char *message, int *cursor,
     485             :                              int length, bool suppress)
     486             : {
     487           0 :     int         authType = 0;
     488             : 
     489           0 :     memcpy(&authType, message + *cursor, 4);
     490           0 :     authType = (int) pg_ntoh32(authType);
     491           0 :     *cursor += 4;
     492           0 :     switch (authType)
     493             :     {
     494           0 :         case AUTH_REQ_OK:
     495           0 :             fprintf(f, "AuthenticationOk");
     496           0 :             break;
     497             :             /* AUTH_REQ_KRB4 not supported */
     498             :             /* AUTH_REQ_KRB5 not supported */
     499           0 :         case AUTH_REQ_PASSWORD:
     500           0 :             fprintf(f, "AuthenticationCleartextPassword");
     501           0 :             break;
     502             :             /* AUTH_REQ_CRYPT not supported */
     503           0 :         case AUTH_REQ_MD5:
     504           0 :             fprintf(f, "AuthenticationMD5Password");
     505           0 :             break;
     506           0 :         case AUTH_REQ_GSS:
     507           0 :             fprintf(f, "AuthenticationGSS");
     508           0 :             break;
     509           0 :         case AUTH_REQ_GSS_CONT:
     510           0 :             fprintf(f, "AuthenticationGSSContinue\t");
     511           0 :             pqTraceOutputNchar(f, length - *cursor + 1, message, cursor,
     512             :                                suppress);
     513           0 :             break;
     514           0 :         case AUTH_REQ_SSPI:
     515           0 :             fprintf(f, "AuthenticationSSPI");
     516           0 :             break;
     517           0 :         case AUTH_REQ_SASL:
     518           0 :             fprintf(f, "AuthenticationSASL\t");
     519           0 :             while (message[*cursor] != '\0')
     520           0 :                 pqTraceOutputString(f, message, cursor, false);
     521           0 :             pqTraceOutputString(f, message, cursor, false);
     522           0 :             break;
     523           0 :         case AUTH_REQ_SASL_CONT:
     524           0 :             fprintf(f, "AuthenticationSASLContinue\t");
     525           0 :             pqTraceOutputNchar(f, length - *cursor + 1, message, cursor,
     526             :                                suppress);
     527           0 :             break;
     528           0 :         case AUTH_REQ_SASL_FIN:
     529           0 :             fprintf(f, "AuthenticationSASLFinal\t");
     530           0 :             pqTraceOutputNchar(f, length - *cursor + 1, message, cursor,
     531             :                                suppress);
     532           0 :             break;
     533           0 :         default:
     534           0 :             fprintf(f, "Unknown authentication message %d", authType);
     535             :     }
     536           0 : }
     537             : 
     538             : static void
     539           0 : pqTraceOutput_ParameterStatus(FILE *f, const char *message, int *cursor)
     540             : {
     541           0 :     fprintf(f, "ParameterStatus\t");
     542           0 :     pqTraceOutputString(f, message, cursor, false);
     543           0 :     pqTraceOutputString(f, message, cursor, false);
     544           0 : }
     545             : 
     546             : static void
     547           2 : pqTraceOutput_ParameterDescription(FILE *f, const char *message, int *cursor, bool regress)
     548             : {
     549             :     int         nfields;
     550             : 
     551           2 :     fprintf(f, "ParameterDescription\t");
     552           2 :     nfields = pqTraceOutputInt16(f, message, cursor);
     553             : 
     554           4 :     for (int i = 0; i < nfields; i++)
     555           2 :         pqTraceOutputInt32(f, message, cursor, regress);
     556           2 : }
     557             : 
     558             : static void
     559          58 : pqTraceOutput_RowDescription(FILE *f, const char *message, int *cursor, bool regress)
     560             : {
     561             :     int         nfields;
     562             : 
     563          58 :     fprintf(f, "RowDescription\t");
     564          58 :     nfields = pqTraceOutputInt16(f, message, cursor);
     565             : 
     566         122 :     for (int i = 0; i < nfields; i++)
     567             :     {
     568          64 :         pqTraceOutputString(f, message, cursor, false);
     569          64 :         pqTraceOutputInt32(f, message, cursor, regress);
     570          64 :         pqTraceOutputInt16(f, message, cursor);
     571          64 :         pqTraceOutputInt32(f, message, cursor, regress);
     572          64 :         pqTraceOutputInt16(f, message, cursor);
     573          64 :         pqTraceOutputInt32(f, message, cursor, false);
     574          64 :         pqTraceOutputInt16(f, message, cursor);
     575             :     }
     576          58 : }
     577             : 
     578             : static void
     579           0 : pqTraceOutput_NegotiateProtocolVersion(FILE *f, const char *message, int *cursor)
     580             : {
     581           0 :     fprintf(f, "NegotiateProtocolVersion\t");
     582           0 :     pqTraceOutputInt32(f, message, cursor, false);
     583           0 :     pqTraceOutputInt32(f, message, cursor, false);
     584           0 : }
     585             : 
     586             : static void
     587           0 : pqTraceOutput_FunctionCallResponse(FILE *f, const char *message, int *cursor)
     588             : {
     589             :     int         len;
     590             : 
     591           0 :     fprintf(f, "FunctionCallResponse\t");
     592           0 :     len = pqTraceOutputInt32(f, message, cursor, false);
     593           0 :     if (len != -1)
     594           0 :         pqTraceOutputNchar(f, len, message, cursor, false);
     595           0 : }
     596             : 
     597             : static void
     598           0 : pqTraceOutput_CopyBothResponse(FILE *f, const char *message, int *cursor, int length)
     599             : {
     600           0 :     fprintf(f, "CopyBothResponse\t");
     601           0 :     pqTraceOutputByte1(f, message, cursor);
     602             : 
     603           0 :     while (length > *cursor)
     604           0 :         pqTraceOutputInt16(f, message, cursor);
     605           0 : }
     606             : 
     607             : static void
     608          58 : pqTraceOutput_ReadyForQuery(FILE *f, const char *message, int *cursor)
     609             : {
     610          58 :     fprintf(f, "ReadyForQuery\t");
     611          58 :     pqTraceOutputByte1(f, message, cursor);
     612          58 : }
     613             : 
     614             : /*
     615             :  * Print the given message to the trace output stream.
     616             :  */
     617             : void
     618         828 : pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer)
     619             : {
     620             :     char        id;
     621             :     int         length;
     622         828 :     char       *prefix = toServer ? "F" : "B";
     623         828 :     int         logCursor = 0;
     624             :     bool        regress;
     625             : 
     626         828 :     if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0)
     627             :     {
     628             :         char        timestr[128];
     629             : 
     630           0 :         pqTraceFormatTimestamp(timestr, sizeof(timestr));
     631           0 :         fprintf(conn->Pfdebug, "%s\t", timestr);
     632             :     }
     633         828 :     regress = (conn->traceFlags & PQTRACE_REGRESS_MODE) != 0;
     634             : 
     635         828 :     id = message[logCursor++];
     636             : 
     637         828 :     memcpy(&length, message + logCursor, 4);
     638         828 :     length = (int) pg_ntoh32(length);
     639         828 :     logCursor += 4;
     640             : 
     641             :     /*
     642             :      * In regress mode, suppress the length of ErrorResponse and
     643             :      * NoticeResponse.  The F (file name), L (line number) and R (routine
     644             :      * name) fields can change as server code is modified, and if their
     645             :      * lengths differ from the originals, that would break tests.
     646             :      */
     647         828 :     if (regress && !toServer && (id == PqMsg_ErrorResponse || id == PqMsg_NoticeResponse))
     648          20 :         fprintf(conn->Pfdebug, "%s\tNN\t", prefix);
     649             :     else
     650         808 :         fprintf(conn->Pfdebug, "%s\t%d\t", prefix, length);
     651             : 
     652         828 :     switch (id)
     653             :     {
     654          62 :         case PqMsg_ParseComplete:
     655          62 :             fprintf(conn->Pfdebug, "ParseComplete");
     656             :             /* No message content */
     657          62 :             break;
     658          58 :         case PqMsg_BindComplete:
     659          58 :             fprintf(conn->Pfdebug, "BindComplete");
     660             :             /* No message content */
     661          58 :             break;
     662           8 :         case PqMsg_CloseComplete:
     663           8 :             fprintf(conn->Pfdebug, "CloseComplete");
     664             :             /* No message content */
     665           8 :             break;
     666           0 :         case PqMsg_NotificationResponse:
     667           0 :             pqTraceOutput_NotificationResponse(conn->Pfdebug, message, &logCursor, regress);
     668           0 :             break;
     669          72 :         case PqMsg_Bind:
     670          72 :             pqTraceOutput_Bind(conn->Pfdebug, message, &logCursor);
     671          72 :             break;
     672           0 :         case PqMsg_CopyDone:
     673           0 :             fprintf(conn->Pfdebug, "CopyDone");
     674             :             /* No message content */
     675           0 :             break;
     676          82 :         case PqMsg_CommandComplete:
     677             :             /* Close(F) and CommandComplete(B) use the same identifier. */
     678             :             Assert(PqMsg_Close == PqMsg_CommandComplete);
     679          82 :             if (toServer)
     680           8 :                 pqTraceOutput_Close(conn->Pfdebug, message, &logCursor);
     681             :             else
     682          74 :                 pqTraceOutput_CommandComplete(conn->Pfdebug, message, &logCursor);
     683          82 :             break;
     684           0 :         case PqMsg_CopyData:
     685           0 :             pqTraceOutput_CopyData(conn->Pfdebug, message, &logCursor,
     686             :                                    length, regress);
     687           0 :             break;
     688         164 :         case PqMsg_Describe:
     689             :             /* Describe(F) and DataRow(B) use the same identifier. */
     690             :             Assert(PqMsg_Describe == PqMsg_DataRow);
     691         164 :             if (toServer)
     692          80 :                 pqTraceOutput_Describe(conn->Pfdebug, message, &logCursor);
     693             :             else
     694          84 :                 pqTraceOutput_DataRow(conn->Pfdebug, message, &logCursor);
     695         164 :             break;
     696          86 :         case PqMsg_Execute:
     697             :             /* Execute(F) and ErrorResponse(B) use the same identifier. */
     698             :             Assert(PqMsg_Execute == PqMsg_ErrorResponse);
     699          86 :             if (toServer)
     700          72 :                 pqTraceOutput_Execute(conn->Pfdebug, message, &logCursor, regress);
     701             :             else
     702          14 :                 pqTraceOutput_ErrorResponse(conn->Pfdebug, message, &logCursor, regress);
     703          86 :             break;
     704           0 :         case PqMsg_CopyFail:
     705           0 :             pqTraceOutput_CopyFail(conn->Pfdebug, message, &logCursor);
     706           0 :             break;
     707           0 :         case PqMsg_GSSResponse:
     708             :             Assert(PqMsg_GSSResponse == PqMsg_PasswordMessage);
     709             :             Assert(PqMsg_GSSResponse == PqMsg_SASLInitialResponse);
     710             :             Assert(PqMsg_GSSResponse == PqMsg_SASLResponse);
     711             : 
     712             :             /*
     713             :              * These messages share a common type byte, so we discriminate by
     714             :              * having the code store the auth type separately.
     715             :              */
     716           0 :             switch (conn->current_auth_response)
     717             :             {
     718           0 :                 case AUTH_RESPONSE_GSS:
     719           0 :                     pqTraceOutput_GSSResponse(conn->Pfdebug, message,
     720             :                                               &logCursor, length, regress);
     721           0 :                     break;
     722           0 :                 case AUTH_RESPONSE_PASSWORD:
     723           0 :                     pqTraceOutput_PasswordMessage(conn->Pfdebug, message,
     724             :                                                   &logCursor);
     725           0 :                     break;
     726           0 :                 case AUTH_RESPONSE_SASL_INITIAL:
     727           0 :                     pqTraceOutput_SASLInitialResponse(conn->Pfdebug, message,
     728             :                                                       &logCursor, regress);
     729           0 :                     break;
     730           0 :                 case AUTH_RESPONSE_SASL:
     731           0 :                     pqTraceOutput_SASLResponse(conn->Pfdebug, message,
     732             :                                                &logCursor, length, regress);
     733           0 :                     break;
     734           0 :                 default:
     735           0 :                     fprintf(conn->Pfdebug, "UnknownAuthenticationResponse");
     736           0 :                     break;
     737             :             }
     738           0 :             conn->current_auth_response = '\0';
     739           0 :             break;
     740           0 :         case PqMsg_FunctionCall:
     741           0 :             pqTraceOutput_FunctionCall(conn->Pfdebug, message, &logCursor, regress);
     742           0 :             break;
     743           0 :         case PqMsg_CopyInResponse:
     744           0 :             pqTraceOutput_CopyInResponse(conn->Pfdebug, message, &logCursor);
     745           0 :             break;
     746          14 :         case PqMsg_Flush:
     747             :             /* Flush(F) and CopyOutResponse(B) use the same identifier */
     748             :             Assert(PqMsg_CopyOutResponse == PqMsg_Flush);
     749          14 :             if (toServer)
     750          14 :                 fprintf(conn->Pfdebug, "Flush");   /* no message content */
     751             :             else
     752           0 :                 pqTraceOutput_CopyOutResponse(conn->Pfdebug, message, &logCursor);
     753          14 :             break;
     754           0 :         case PqMsg_EmptyQueryResponse:
     755           0 :             fprintf(conn->Pfdebug, "EmptyQueryResponse");
     756             :             /* No message content */
     757           0 :             break;
     758           0 :         case PqMsg_BackendKeyData:
     759           0 :             pqTraceOutput_BackendKeyData(conn->Pfdebug, message, &logCursor, regress);
     760           0 :             break;
     761          10 :         case PqMsg_NoData:
     762          10 :             fprintf(conn->Pfdebug, "NoData");
     763             :             /* No message content */
     764          10 :             break;
     765           6 :         case PqMsg_NoticeResponse:
     766           6 :             pqTraceOutput_NoticeResponse(conn->Pfdebug, message, &logCursor, regress);
     767           6 :             break;
     768          72 :         case PqMsg_Parse:
     769          72 :             pqTraceOutput_Parse(conn->Pfdebug, message, &logCursor, regress);
     770          72 :             break;
     771          16 :         case PqMsg_Query:
     772          16 :             pqTraceOutput_Query(conn->Pfdebug, message, &logCursor);
     773          16 :             break;
     774           0 :         case PqMsg_AuthenticationRequest:
     775           0 :             pqTraceOutput_Authentication(conn->Pfdebug, message, &logCursor,
     776             :                                          length, regress);
     777           0 :             break;
     778           0 :         case PqMsg_PortalSuspended:
     779           0 :             fprintf(conn->Pfdebug, "PortalSuspended");
     780             :             /* No message content */
     781           0 :             break;
     782          42 :         case PqMsg_Sync:
     783             :             /* ParameterStatus(B) and Sync(F) use the same identifier */
     784             :             Assert(PqMsg_ParameterStatus == PqMsg_Sync);
     785          42 :             if (toServer)
     786          42 :                 fprintf(conn->Pfdebug, "Sync"); /* no message content */
     787             :             else
     788           0 :                 pqTraceOutput_ParameterStatus(conn->Pfdebug, message, &logCursor);
     789          42 :             break;
     790           2 :         case PqMsg_ParameterDescription:
     791           2 :             pqTraceOutput_ParameterDescription(conn->Pfdebug, message, &logCursor, regress);
     792           2 :             break;
     793          58 :         case PqMsg_RowDescription:
     794          58 :             pqTraceOutput_RowDescription(conn->Pfdebug, message, &logCursor, regress);
     795          58 :             break;
     796           0 :         case PqMsg_NegotiateProtocolVersion:
     797           0 :             pqTraceOutput_NegotiateProtocolVersion(conn->Pfdebug, message, &logCursor);
     798           0 :             break;
     799           0 :         case PqMsg_FunctionCallResponse:
     800           0 :             pqTraceOutput_FunctionCallResponse(conn->Pfdebug, message, &logCursor);
     801           0 :             break;
     802           0 :         case PqMsg_CopyBothResponse:
     803           0 :             pqTraceOutput_CopyBothResponse(conn->Pfdebug, message, &logCursor, length);
     804           0 :             break;
     805          18 :         case PqMsg_Terminate:
     806          18 :             fprintf(conn->Pfdebug, "Terminate");
     807             :             /* No message content */
     808          18 :             break;
     809          58 :         case PqMsg_ReadyForQuery:
     810          58 :             pqTraceOutput_ReadyForQuery(conn->Pfdebug, message, &logCursor);
     811          58 :             break;
     812           0 :         default:
     813           0 :             fprintf(conn->Pfdebug, "Unknown message: %02x", id);
     814           0 :             break;
     815             :     }
     816             : 
     817         828 :     fputc('\n', conn->Pfdebug);
     818             : 
     819             :     /*
     820             :      * Verify the printing routine did it right.  Note that the one-byte
     821             :      * message identifier is not included in the length, but our cursor does
     822             :      * include it.
     823             :      */
     824         828 :     if (logCursor - 1 != length)
     825           0 :         fprintf(conn->Pfdebug,
     826             :                 "mismatched message length: consumed %d, expected %d\n",
     827             :                 logCursor - 1, length);
     828         828 : }
     829             : 
     830             : /*
     831             :  * Print special messages (those containing no type byte) to the trace output
     832             :  * stream.
     833             :  */
     834             : void
     835           0 : pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message)
     836             : {
     837             :     int         length;
     838             :     int         version;
     839             :     bool        regress;
     840           0 :     int         logCursor = 0;
     841             : 
     842           0 :     regress = (conn->traceFlags & PQTRACE_REGRESS_MODE) != 0;
     843             : 
     844           0 :     if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0)
     845             :     {
     846             :         char        timestr[128];
     847             : 
     848           0 :         pqTraceFormatTimestamp(timestr, sizeof(timestr));
     849           0 :         fprintf(conn->Pfdebug, "%s\t", timestr);
     850             :     }
     851             : 
     852           0 :     memcpy(&length, message + logCursor, 4);
     853           0 :     length = (int) pg_ntoh32(length);
     854           0 :     logCursor += 4;
     855             : 
     856           0 :     fprintf(conn->Pfdebug, "F\t%d\t", length);
     857             : 
     858           0 :     if (length < 8)
     859             :     {
     860           0 :         fprintf(conn->Pfdebug, "Unknown message\n");
     861           0 :         return;
     862             :     }
     863             : 
     864           0 :     memcpy(&version, message + logCursor, 4);
     865           0 :     version = (int) pg_ntoh32(version);
     866             : 
     867           0 :     if (version == CANCEL_REQUEST_CODE && length >= 16)
     868             :     {
     869           0 :         fprintf(conn->Pfdebug, "CancelRequest\t");
     870           0 :         pqTraceOutputInt16(conn->Pfdebug, message, &logCursor);
     871           0 :         pqTraceOutputInt16(conn->Pfdebug, message, &logCursor);
     872           0 :         pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, regress);
     873           0 :         pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, regress);
     874             :     }
     875           0 :     else if (version == NEGOTIATE_SSL_CODE)
     876             :     {
     877           0 :         fprintf(conn->Pfdebug, "SSLRequest\t");
     878           0 :         pqTraceOutputInt16(conn->Pfdebug, message, &logCursor);
     879           0 :         pqTraceOutputInt16(conn->Pfdebug, message, &logCursor);
     880             :     }
     881           0 :     else if (version == NEGOTIATE_GSS_CODE)
     882             :     {
     883           0 :         fprintf(conn->Pfdebug, "GSSENCRequest\t");
     884           0 :         pqTraceOutputInt16(conn->Pfdebug, message, &logCursor);
     885           0 :         pqTraceOutputInt16(conn->Pfdebug, message, &logCursor);
     886             :     }
     887             :     else
     888             :     {
     889           0 :         fprintf(conn->Pfdebug, "StartupMessage\t");
     890           0 :         pqTraceOutputInt16(conn->Pfdebug, message, &logCursor);
     891           0 :         pqTraceOutputInt16(conn->Pfdebug, message, &logCursor);
     892           0 :         while (message[logCursor] != '\0')
     893             :         {
     894             :             /* XXX should we suppress anything in regress mode? */
     895           0 :             pqTraceOutputString(conn->Pfdebug, message, &logCursor, false);
     896           0 :             pqTraceOutputString(conn->Pfdebug, message, &logCursor, false);
     897             :         }
     898             :     }
     899             : 
     900           0 :     fputc('\n', conn->Pfdebug);
     901             : }
     902             : 
     903             : /*
     904             :  * Trace a single-byte backend response received for a known request
     905             :  * type the frontend previously sent.  Only useful for the simplest of
     906             :  * FE/BE interaction workflows such as SSL/GSS encryption requests.
     907             :  */
     908             : void
     909           0 : pqTraceOutputCharResponse(PGconn *conn, const char *responseType,
     910             :                           char response)
     911             : {
     912           0 :     if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0)
     913             :     {
     914             :         char        timestr[128];
     915             : 
     916           0 :         pqTraceFormatTimestamp(timestr, sizeof(timestr));
     917           0 :         fprintf(conn->Pfdebug, "%s\t", timestr);
     918             :     }
     919             : 
     920           0 :     fprintf(conn->Pfdebug, "B\t1\t%s\t %c\n", responseType, response);
     921           0 : }

Generated by: LCOV version 1.14