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 : }
|