On 2021-Mar-26, alvhe...@alvh.no-ip.org wrote: > Proposed changes on top of v29.
This last one uses libpq_pipeline -t and verifies the output against an expected trace file. Applies on top of all the previous patches. I attach the whole lot, so that the CF bot has a chance to run it. I did notice another problem for comparison of expected trace files, which is that RowDescription includes table OIDs for some columns. I think we would need to have a flag to suppress that too, somehow, although the answer to what should we do is not as clear as for the other two cases. I dodged the issue by just using -t for the pipeline cases that don't have OIDs in their output. This leaves us with no coverage for the ErrorResponse message, which I think is a shortcoming. If we fixed the OID problem and the ErrorResponse problem, we could add an expected trace for pipeline_abort. I think we should do that. Maybe the easiest way is to have a new flag PQTRACE_REGRESS_MODE. -- Álvaro Herrera 39°49'30"S 73°17'W Essentially, you're proposing Kevlar shoes as a solution for the problem that you want to walk around carrying a loaded gun aimed at your foot. (Tom Lane)
>From f239da90f069b19e1c2fa6b69bc7c6fd4be826b9 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 26 Mar 2021 11:10:52 -0300 Subject: [PATCH v30 1/7] libpq trace v29 --- doc/src/sgml/libpq.sgml | 39 +- src/interfaces/libpq/Makefile | 1 + src/interfaces/libpq/exports.txt | 1 + src/interfaces/libpq/fe-connect.c | 21 - src/interfaces/libpq/fe-exec.c | 4 - src/interfaces/libpq/fe-misc.c | 66 +-- src/interfaces/libpq/fe-protocol3.c | 8 + src/interfaces/libpq/libpq-fe.h | 2 + src/interfaces/libpq/libpq-int.h | 7 + src/interfaces/libpq/libpq-trace.c | 717 ++++++++++++++++++++++++++++ 10 files changed, 789 insertions(+), 77 deletions(-) create mode 100644 src/interfaces/libpq/libpq-trace.c diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index be674fbaa9..838e394d54 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -6459,12 +6459,27 @@ PGContextVisibility PQsetErrorContextVisibility(PGconn *conn, PGContextVisibilit <listitem> <para> - Enables tracing of the client/server communication to a debugging file stream. + Enables tracing of the client/server communication to a debugging file + stream. <synopsis> void PQtrace(PGconn *conn, FILE *stream); </synopsis> </para> + <para> + Each line consists of: an optional timestamp, a direction indicator + (<literal>></literal> for messages from client to server + or <literal><</literal> for messages from server to client), + message length, message type, and message contents. + Non-message contents fields (timestamp, direction, length and message type) + are separated by a tab. Message contents are separated by a space. + Protocol strings are enclosed in double quotes, while strings used as data + values are enclosed in single quotes. Non-printable chars are printed as + hexadecimal escapes. + Further message-type-specific detail can be found in + <xref linkend="protocol-message-formats"/>. + </para> + <note> <para> On Windows, if the <application>libpq</application> library and an application are @@ -6479,6 +6494,28 @@ void PQtrace(PGconn *conn, FILE *stream); </listitem> </varlistentry> + <varlistentry id="libpq-PQtraceSetFlags"> + <term><function>PQtraceSetFlags</function><indexterm><primary>PQtraceSetFlags</primary></indexterm></term> + + <listitem> + <para> + Controls the tracing behavior of client/server communication. +<synopsis> +void PQtraceSetFlags(PGconn *conn, int flags); +</synopsis> + </para> + + <para> + <literal>flags</literal> contains flag bits describing the operating mode + of tracing. + If <literal>flags</literal> contains <literal>PQTRACE_SUPPRESS_TIMESTAMPS</literal>, + then the timestamp is not included when printing each message. + This function must be called after calling <function>PQtrace</function>. + </para> + + </listitem> + </varlistentry> + <varlistentry id="libpq-PQuntrace"> <term><function>PQuntrace</function><indexterm><primary>PQuntrace</primary></indexterm></term> diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile index 2aca882a2b..0424523492 100644 --- a/src/interfaces/libpq/Makefile +++ b/src/interfaces/libpq/Makefile @@ -41,6 +41,7 @@ OBJS = \ fe-secure.o \ legacy-pqsignal.o \ libpq-events.o \ + libpq-trace.o \ pqexpbuffer.o \ fe-auth.o diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index 5c48c14191..a00701f2c5 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -183,3 +183,4 @@ PQenterPipelineMode 180 PQexitPipelineMode 181 PQpipelineSync 182 PQpipelineStatus 183 +PQtraceSetFlags 184 diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 53b354abb2..a90bdb8ab6 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -6859,27 +6859,6 @@ PQsetErrorContextVisibility(PGconn *conn, PGContextVisibility show_context) return old; } -void -PQtrace(PGconn *conn, FILE *debug_port) -{ - if (conn == NULL) - return; - PQuntrace(conn); - conn->Pfdebug = debug_port; -} - -void -PQuntrace(PGconn *conn) -{ - if (conn == NULL) - return; - if (conn->Pfdebug) - { - fflush(conn->Pfdebug); - conn->Pfdebug = NULL; - } -} - PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg) { diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c index f143b8b7fb..03592bdce9 100644 --- a/src/interfaces/libpq/fe-exec.c +++ b/src/interfaces/libpq/fe-exec.c @@ -970,10 +970,6 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value) pgParameterStatus *pstatus; pgParameterStatus *prev; - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "pqSaveParameterStatus: '%s' = '%s'\n", - name, value); - /* * Forget any old information about the parameter */ diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index ce2d24b91f..54d6a76246 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -84,9 +84,6 @@ pqGetc(char *result, PGconn *conn) *result = conn->inBuffer[conn->inCursor++]; - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "From backend> %c\n", *result); - return 0; } @@ -100,9 +97,6 @@ pqPutc(char c, PGconn *conn) if (pqPutMsgBytes(&c, 1, conn)) return EOF; - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend> %c\n", c); - return 0; } @@ -138,10 +132,6 @@ pqGets_internal(PQExpBuffer buf, PGconn *conn, bool resetbuffer) conn->inCursor = ++inCursor; - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "From backend> \"%s\"\n", - buf->data); - return 0; } @@ -167,9 +157,6 @@ pqPuts(const char *s, PGconn *conn) if (pqPutMsgBytes(s, strlen(s) + 1, conn)) return EOF; - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend> \"%s\"\n", s); - return 0; } @@ -188,13 +175,6 @@ pqGetnchar(char *s, size_t len, PGconn *conn) conn->inCursor += len; - if (conn->Pfdebug) - { - fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len); - fwrite(s, 1, len, conn->Pfdebug); - fprintf(conn->Pfdebug, "\n"); - } - return 0; } @@ -212,13 +192,6 @@ pqSkipnchar(size_t len, PGconn *conn) if (len > (size_t) (conn->inEnd - conn->inCursor)) return EOF; - if (conn->Pfdebug) - { - fprintf(conn->Pfdebug, "From backend (%lu)> ", (unsigned long) len); - fwrite(conn->inBuffer + conn->inCursor, 1, len, conn->Pfdebug); - fprintf(conn->Pfdebug, "\n"); - } - conn->inCursor += len; return 0; @@ -234,13 +207,6 @@ pqPutnchar(const char *s, size_t len, PGconn *conn) if (pqPutMsgBytes(s, len, conn)) return EOF; - if (conn->Pfdebug) - { - fprintf(conn->Pfdebug, "To backend> "); - fwrite(s, 1, len, conn->Pfdebug); - fprintf(conn->Pfdebug, "\n"); - } - return 0; } @@ -278,9 +244,6 @@ pqGetInt(int *result, size_t bytes, PGconn *conn) return EOF; } - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "From backend (#%lu)> %d\n", (unsigned long) bytes, *result); - return 0; } @@ -314,9 +277,6 @@ pqPutInt(int value, size_t bytes, PGconn *conn) return EOF; } - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend (%lu#)> %d\n", (unsigned long) bytes, value); - return 0; } @@ -525,10 +485,6 @@ pqPutMsgStart(char msg_type, PGconn *conn) conn->outMsgEnd = endPos; /* length word, if needed, will be filled in by pqPutMsgEnd */ - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend> Msg %c\n", - msg_type ? msg_type : ' '); - return 0; } @@ -563,10 +519,6 @@ pqPutMsgBytes(const void *buf, size_t len, PGconn *conn) int pqPutMsgEnd(PGconn *conn) { - if (conn->Pfdebug) - fprintf(conn->Pfdebug, "To backend> Msg complete, length %u\n", - conn->outMsgEnd - conn->outCount); - /* Fill in length word if needed */ if (conn->outMsgStart >= 0) { @@ -576,6 +528,16 @@ pqPutMsgEnd(PGconn *conn) memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4); } + /* Trace message only when there is first 1 byte */ + if (conn->Pfdebug) + { + if (conn->outCount < conn->outMsgStart) + pqTraceOutputMessage(conn, conn->outBuffer + conn->outCount, true); + else + pqTraceOutputNoTypeByteMessage(conn, + conn->outBuffer + conn->outMsgStart); + } + /* Make message eligible to send */ conn->outCount = conn->outMsgEnd; @@ -1002,11 +964,13 @@ pqSendSome(PGconn *conn, int len) int pqFlush(PGconn *conn) { - if (conn->Pfdebug) - fflush(conn->Pfdebug); - if (conn->outCount > 0) + { + if (conn->Pfdebug) + fflush(conn->Pfdebug); + return pqSendSome(conn, conn->outCount); + } return 0; } diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 306e89acfd..de77c06874 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -457,6 +457,9 @@ pqParseInput3(PGconn *conn) /* Successfully consumed this message */ if (conn->inCursor == conn->inStart + 5 + msgLength) { + if(conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + /* Normal case: parsing agrees with specified length */ conn->inStart = conn->inCursor; } @@ -1660,6 +1663,9 @@ getCopyDataMessage(PGconn *conn) return -1; } + if(conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + /* Drop the processed message and loop around for another */ conn->inStart = conn->inCursor; } @@ -2121,6 +2127,8 @@ pqFunctionCall3(PGconn *conn, Oid fnid, } /* Completed this message, keep going */ /* trust the specified message length as what to skip */ + if(conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); conn->inStart += 5 + msgLength; needInput = false; } diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index cee42d4843..d0decde2da 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -376,7 +376,9 @@ extern PGContextVisibility PQsetErrorContextVisibility(PGconn *conn, PGContextVisibility show_context); /* Enable/disable tracing */ +#define PQTRACE_SUPPRESS_TIMESTAMPS 1 extern void PQtrace(PGconn *conn, FILE *debug_port); +extern void PQtraceSetFlags(PGconn *conn, int flags); extern void PQuntrace(PGconn *conn); /* Override default notice handling routines */ diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 6374ec657a..1a1d0e1414 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -394,6 +394,7 @@ struct pg_conn /* Optional file to write trace info to */ FILE *Pfdebug; + int traceFlags; /* Callback procedures for notice message processing */ PGNoticeHooks noticeHooks; @@ -818,6 +819,12 @@ extern ssize_t pg_GSS_write(PGconn *conn, const void *ptr, size_t len); extern ssize_t pg_GSS_read(PGconn *conn, void *ptr, size_t len); #endif +/* === in libpq-trace.c === */ + +extern void pqTraceOutputMessage(PGconn *conn, const char *message, + bool toServer); +extern void pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message); + /* === miscellaneous macros === */ /* diff --git a/src/interfaces/libpq/libpq-trace.c b/src/interfaces/libpq/libpq-trace.c new file mode 100644 index 0000000000..bacb7903b9 --- /dev/null +++ b/src/interfaces/libpq/libpq-trace.c @@ -0,0 +1,717 @@ +/*------------------------------------------------------------------------- + * + * libpq-trace.c + * functions for libpq protocol tracing + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/interfaces/libpq/libpq-trace.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" + +#include <limits.h> +#include <time.h> + +#ifdef WIN32 +#include "win32.h" +#else +#include <unistd.h> +#include <sys/time.h> +#endif + +#include "libpq-fe.h" +#include "libpq-int.h" +#include "pgtime.h" +#include "port/pg_bswap.h" + +void +PQtrace(PGconn *conn, FILE *debug_port) +{ + if (conn == NULL) + return; + PQuntrace(conn); + if (debug_port == NULL) + return; + + setvbuf(debug_port, NULL, _IOLBF, 0); + conn->Pfdebug = debug_port; + conn->traceFlags = 0; +} + +void +PQuntrace(PGconn *conn) +{ + if (conn == NULL) + return; + if (conn->Pfdebug) + { + fflush(conn->Pfdebug); + conn->Pfdebug = NULL; + } + + conn->traceFlags = 0; +} + +void +PQtraceSetFlags(PGconn *conn, int flags) +{ + if (conn == NULL) + return; + /* If PQtrace() failed, do nothing. */ + if (conn->Pfdebug == NULL) + return; + conn->traceFlags = flags; +} + +/* + * Print the current time, with microseconds, into a caller-supplied + * buffer. + * Cribbed from setup_formatted_log_time, but much simpler. + */ +static void +pqTraceFormatTimestamp(char *timestr, size_t ts_len) +{ + struct timeval tval; + pg_time_t stamp_time; + + gettimeofday(&tval, NULL); + stamp_time = (pg_time_t) tval.tv_sec; + + strftime(timestr, ts_len, + "%Y-%m-%d %H:%M:%S", + localtime(&stamp_time)); + /* append microseconds */ + sprintf(timestr + strlen(timestr), ".%06d", (int) (tval.tv_usec)); +} + +/* + * pqTraceOutputByte1: output 1 char message to the log + */ +static void +pqTraceOutputByte1(const char *data, int *cursor, FILE *pfdebug) +{ + const char *v = data + *cursor; + + /* + * Show non-printable data in hex format, including the + * terminating \0 that completes ErrorResponse and NoticeResponse + * messages. + */ + if (!isprint(*v)) + fprintf(pfdebug, " \\x%02x", *v); + else + fprintf(pfdebug, " %c", *v); + ++*cursor; +} + +/* + * pqTraceOutputInt16: output a 2-byte integer message to the log + */ +static int +pqTraceOutputInt16(const char *data, int *cursor, FILE *pfdebug) +{ + uint16 tmp; + int result; + + memcpy(&tmp, data + *cursor , 2); + *cursor += 2; + result = (int) pg_ntoh16(tmp); + fprintf(pfdebug, " %d", result); + + return result; +} + +/* + * pqTraceOutputInt32: output a 4-byte integer message to the log + */ +static int +pqTraceOutputInt32(const char *data, int *cursor, FILE *pfdebug) +{ + int result; + + memcpy(&result, data + *cursor, 4); + *cursor += 4; + result = (int) pg_ntoh32(result); + fprintf(pfdebug, " %d", result); + + return result; +} + +/* + * pqTraceOutputString: output a string message to the log + */ +static void +pqTraceOutputString(const char *data, int *cursor, FILE *pfdebug) +{ + int len; + + len = fprintf(pfdebug, " \"%s\"", data + *cursor); + + /* + * This is null-terminated string. So add 1 after subtracting 3 + * which is the double quotes and space length from len. + */ + *cursor += (len - 3 + 1); +} + +/* + * pqTraceOutputNchar: output a string of exactly len bytes message to the log + */ +static void +pqTraceOutputNchar(const char *data, int *cursor, FILE *pfdebug, int len) +{ + int i, + next; /* first char not yet printed */ + const char *v = data + *cursor; + + fprintf(pfdebug, " \'"); + + for (next = i = 0; i < len; ++i) + { + if (isprint(v[i])) + continue; + else + { + fwrite(v + next, 1, i - next, pfdebug); + fprintf(pfdebug, "\\x%02x", v[i]); + next = i + 1; + } + } + if (next < len) + fwrite(v + next, 1, len - next, pfdebug); + + fprintf(pfdebug, "\'"); + *cursor += len; +} + +/* + * Output functions by protocol message type + */ + +/* Authentication */ +static void +pqTraceOutputR(const char *message, FILE *f) +{ + int cursor = 0; + + fprintf(f, "Authentication\t"); + pqTraceOutputInt32(message, &cursor, f); +} + +/* BackendKeyData */ +static void +pqTraceOutputK(const char *message, FILE *f) +{ + int cursor = 0; + + fprintf(f, "BackendKeyData\t"); + pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt32(message, &cursor, f); +} + +/* Bind */ +static void +pqTraceOutputB(const char *message, int end, FILE *f) +{ + int cursor = 0; + int nparams; + int nbytes; + int i; + + fprintf(f, "Bind\t"); + pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(message, &cursor, f); + nparams = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nparams; i++) + pqTraceOutputInt16(message, &cursor, f); + + nparams = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nparams; i++) + { + nbytes = pqTraceOutputInt32(message, &cursor, f); + if (nbytes == -1) + continue; + pqTraceOutputNchar(message, &cursor, f, nbytes); + } + + nparams = pqTraceOutputInt16(message, &cursor, f); + for (i = 0; i < nparams; i++) + pqTraceOutputInt16(message, &cursor, f); +} + +/* Close(F) or CommandComplete(B) */ +static void +pqTraceOutputC(const char *message, int end, FILE *f, bool toServer) +{ + int cursor = 0; + + if (toServer) + { + fprintf(f, "Close\t"); + pqTraceOutputByte1(message, &cursor, f); + pqTraceOutputString(message, &cursor, f); + } + else + { + fprintf(f, "CommandComplete\t"); + pqTraceOutputString(message, &cursor, f); + } +} + +/* CopyFail */ +static void +pqTraceOutputf(const char *message, int end, FILE *f) +{ + int cursor = 0; + + fprintf(f, "CopyFail\t"); + pqTraceOutputString(message, &cursor, f); +} + +/* CopyInResponse */ +static void +pqTraceOutputG(const char *message, int end, FILE *f) +{ + int cursor = 0; + int nfields; + int i; + + fprintf(f, "CopyInResponse\t"); + pqTraceOutputByte1(message, &cursor, f); + nfields = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nfields; i++) + pqTraceOutputInt16(message, &cursor, f); +} + +/* CopyOutResponse */ +static void +pqTraceOutputH(const char *message, int end, FILE *f) +{ + int cursor = 0; + int nfields; + int i; + + fprintf(f, "CopyOutResponse\t"); + pqTraceOutputByte1(message, &cursor, f); + nfields = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nfields; i++) + pqTraceOutputInt16(message, &cursor, f); +} + +/* CopyBothResponse */ +static void +pqTraceOutputW(const char *message, int end, FILE *f) +{ + int cursor = 0; + + fprintf(f, "CopyBothResponse\t"); + pqTraceOutputByte1(message, &cursor, f); + + while (end > cursor) + pqTraceOutputInt16(message, &cursor, f); +} + +/* Describe(F) or DataRow(B) */ +static void +pqTraceOutputD(const char *message, int end, FILE *f, bool toServer) +{ + int cursor = 0; + + if (toServer) + { + fprintf(f, "Describe\t"); + pqTraceOutputByte1(message, &cursor, f); + pqTraceOutputString(message, &cursor, f); + } + else + { + int nfields; + int len; + int i; + + fprintf(f, "DataRow\t"); + nfields = pqTraceOutputInt16(message, &cursor, f); + for (i = 0; i < nfields; i++) + { + len = pqTraceOutputInt32(message, &cursor, f); + if (len == -1) + continue; + pqTraceOutputNchar(message, &cursor, f, len); + } + } +} + +/* Execute(F) or ErrorResponse(B) */ +static void +pqTraceOutputE(const char *message, int end, FILE *f, bool toServer) +{ + int cursor = 0; + + if (toServer) + { + fprintf(f, "Execute\t"); + pqTraceOutputString(message, &cursor, f); + pqTraceOutputInt32(message, &cursor, f); + } + else + { + fprintf(f, "ErrorResponse\t"); + while (end > cursor) + { + pqTraceOutputByte1(message, &cursor, f); + if (message[cursor] == '\0') + continue; + pqTraceOutputString(message, &cursor, f); + } + } +} + +/* FunctionCall */ +static void +pqTraceOutputF(const char *message, FILE *f) +{ + int cursor = 0; + int nfields; + int nbytes; + int i; + + fprintf(f, "FunctionCall\t"); + pqTraceOutputInt32(message, &cursor, f); + nfields = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nfields; i++) + pqTraceOutputInt16(message, &cursor, f); + + nfields = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nfields; i++) + { + nbytes = pqTraceOutputInt32(message, &cursor, f); + if (nbytes == -1) + continue; + pqTraceOutputNchar(message, &cursor, f, nbytes); + } + + pqTraceOutputInt16(message, &cursor, f); +} + +/* FunctionCallResponse */ +static void +pqTraceOutputV(const char *message, FILE *f) +{ + int cursor = 0; + int len; + + fprintf(f, "FunctionCallResponse\t"); + len = pqTraceOutputInt32(message, &cursor, f); + if (len != -1) + pqTraceOutputNchar(message, &cursor, f, len); +} + +/* NegotiateProtocolVersion */ +static void +pqTraceOutputv(const char *message, FILE *f) +{ + int cursor = 0; + + fprintf(f, "NegotiateProtocolVersion\t"); + pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt32(message, &cursor, f); +} + +/* NoticeResponse */ +static void +pqTraceOutputN(const char *message, int end, FILE *f) +{ + int cursor = 0; + + fprintf(f, "NoticeResponse\t"); + while (end > cursor) + { + pqTraceOutputByte1(message, &cursor, f); + if (message[cursor] == '\0') + continue; + pqTraceOutputString(message, &cursor, f); + } +} + +/* NotificationResponse */ +static void +pqTraceOutputA(const char *message, int end, FILE *f) +{ + int cursor = 0; + + fprintf(f, "NotificationResponse\t"); + pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(message, &cursor, f); +} + +/* ParameterDescription */ +static void +pqTraceOutputt(const char *message, FILE *f) +{ + int cursor = 0; + int nfields; + int i; + + fprintf(f, "ParameterDescription\t"); + nfields = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nfields; i++) + pqTraceOutputInt32(message, &cursor, f); +} + +/* ParameterStatus */ +static void +pqTraceOutputS(const char *message, int end, FILE *f) +{ + int cursor = 0; + + fprintf(f, "ParameterStatus\t"); + pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(message, &cursor, f); +} + +/* Parse */ +static void +pqTraceOutputP(const char *message, int end, FILE *f) +{ + int cursor = 0; + int nparams; + int i; + + fprintf(f, "Parse\t"); + pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(message, &cursor, f); + nparams = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nparams; i++) + pqTraceOutputInt32(message, &cursor, f); +} + +/* Query */ +static void +pqTraceOutputQ(const char *message, int end, FILE *f) +{ + int cursor = 0; + + fprintf(f, "Query\t"); + pqTraceOutputString(message, &cursor, f); +} + +/* ReadyForQuery */ +static void +pqTraceOutputZ(const char *message, FILE *f) +{ + int cursor = 0; + + fprintf(f, "ReadyForQuery\t"); + pqTraceOutputByte1(message, &cursor, f); +} + +/* RowDescription */ +static void +pqTraceOutputT(const char *message, int end, FILE *f) +{ + int cursor = 0; + int nfields; + int i; + + fprintf(f, "RowDescription\t"); + nfields = pqTraceOutputInt16(message, &cursor, f); + + for (i = 0; i < nfields; i++) + { + pqTraceOutputString(message, &cursor, f); + pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt16(message, &cursor, f); + } +} + +void +pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) +{ + char timestr[128]; + char id; + int length; + char *prefix = toServer ? ">" : "<"; + int LogCursor = 0; + int LogEnd; + + if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0) + pqTraceFormatTimestamp(timestr, sizeof(timestr)); + else + timestr[0] = '\0'; + + id = message[LogCursor++]; + + memcpy(&length, message + LogCursor , 4); + length = (int) pg_ntoh32(length); + LogCursor += 4; + LogEnd = length - 4; + + fprintf(conn->Pfdebug, "%s\t%s\t%d\t", timestr, prefix, length); + + switch(id) + { + case 'R': /* Authentication */ + pqTraceOutputR(message + LogCursor, conn->Pfdebug); + break; + case 'K': /* secret key data from the backend */ + pqTraceOutputK(message + LogCursor, conn->Pfdebug); + break; + case 'B': /* Bind */ + pqTraceOutputB(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case 'C': /* Close(F) or Command Complete(B) */ + pqTraceOutputC(message + LogCursor, LogEnd, conn->Pfdebug, toServer); + break; + case 'd': /* Copy Data */ + /* Drop COPY data to reduce the overhead of logging. */ + break; + case 'f': /* Copy Fail */ + pqTraceOutputf(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case 'G': /* Start Copy In */ + pqTraceOutputG(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case 'H': /* Flush(F) or Start Copy Out(B) */ + if (!toServer) + pqTraceOutputH(message + LogCursor, LogEnd, conn->Pfdebug); + else + fprintf(conn->Pfdebug, "Flush"); + break; + case 'W': /* Start Copy Both */ + pqTraceOutputW(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case 'D': /* Describe(F) or Data Row(B) */ + pqTraceOutputD(message + LogCursor, LogEnd, conn->Pfdebug, toServer); + break; + case 'E': /* Execute(F) or Error Response(B) */ + pqTraceOutputE(message + LogCursor, LogEnd, conn->Pfdebug, toServer); + break; + case 'F': /* Function Call */ + pqTraceOutputF(message + LogCursor, conn->Pfdebug); + break; + case 'V': /* Function Call response */ + pqTraceOutputV(message + LogCursor, conn->Pfdebug); + break; + case 'v': /* Negotiate Protocol Version */ + pqTraceOutputv(message + LogCursor, conn->Pfdebug); + break; + case 'N': /* Notice Response */ + pqTraceOutputN(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case 'A': /* Notification Response */ + pqTraceOutputA(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case 't': /* Parameter Description */ + pqTraceOutputt(message + LogCursor, conn->Pfdebug); + break; + case 'S': /* Parameter Status(B) or Sync(F) */ + if (!toServer) + pqTraceOutputS(message + LogCursor, LogEnd, conn->Pfdebug); + else + fprintf(conn->Pfdebug, "Sync"); + break; + case 'P': /* Parse */ + pqTraceOutputP(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case 'Q': /* Query */ + pqTraceOutputQ(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case 'Z': /* Ready For Query */ + pqTraceOutputZ(message + LogCursor, conn->Pfdebug); + break; + case 'T': /* Row Description */ + pqTraceOutputT(message + LogCursor, LogEnd, conn->Pfdebug); + break; + case '2': /* Bind Complete */ + fprintf(conn->Pfdebug, "BindComplete"); + /* No message content */ + break; + case '3': /* Close Complete */ + fprintf(conn->Pfdebug, "CloseComplete"); + /* No message content */ + break; + case 'c': /* Copy Done */ + fprintf(conn->Pfdebug, "CopyDone"); + /* No message content */ + break; + case 'I': /* Empty Query Response */ + fprintf(conn->Pfdebug, "EmptyQueryResponse"); + /* No message content */ + break; + case 'n': /* No Data */ + fprintf(conn->Pfdebug, "NoData"); + /* No message content */ + break; + case '1': /* Parse Complete */ + fprintf(conn->Pfdebug, "ParseComplete"); + /* No message content */ + break; + case 's': /* Portal Suspended */ + fprintf(conn->Pfdebug, "PortalSuspended"); + /* No message content */ + break; + case 'X': /* Terminate */ + fprintf(conn->Pfdebug, "Terminate"); + /* No message content */ + break; + default: + fprintf(conn->Pfdebug, "Unknown message: %02x", id); + break; + } + + fputc('\n', conn->Pfdebug); +} + +void +pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message) +{ + char timestr[128]; + int length; + int LogCursor = 0; + + if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0) + pqTraceFormatTimestamp(timestr, sizeof(timestr)); + else + timestr[0] = '\0'; + + memcpy(&length, message + LogCursor , 4); + length = (int) pg_ntoh32(length); + LogCursor += 4; + + fprintf(conn->Pfdebug, "%s\t>\t%d\t", timestr, length); + + switch(length) + { + case 16: /* CancelRequest */ + fprintf(conn->Pfdebug, "CancelRequest\t"); + pqTraceOutputInt32(message, &LogCursor, conn->Pfdebug); + pqTraceOutputInt32(message, &LogCursor, conn->Pfdebug); + pqTraceOutputInt32(message, &LogCursor, conn->Pfdebug); + break; + case 8 : /* GSSENCRequest or SSLRequest */ + /* These messages do not reach here. */ + default: + fprintf(conn->Pfdebug, "Unknown message: length is %d", length); + break; + } + + fputc('\n', conn->Pfdebug); +} -- 2.20.1
>From b32ae3805bb28553c0a1cf308c6ed27f58576f3c Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 26 Mar 2021 19:12:12 -0300 Subject: [PATCH v30 2/7] libpq_pipeline: add -t support for PQtrace --- .../modules/libpq_pipeline/libpq_pipeline.c | 84 +++++++++++++------ 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c index 846ee9f5ab..34d085035b 100644 --- a/src/test/modules/libpq_pipeline/libpq_pipeline.c +++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c @@ -23,6 +23,7 @@ #include "catalog/pg_type_d.h" #include "common/fe_memutils.h" #include "libpq-fe.h" +#include "pg_getopt.h" #include "portability/instr_time.h" @@ -30,6 +31,9 @@ static void exit_nicely(PGconn *conn); const char *const progname = "libpq_pipeline"; +/* Options and defaults */ +char *tracefile = NULL; /* path to PQtrace() file */ + #define DEBUG #ifdef DEBUG @@ -1209,8 +1213,10 @@ usage(const char *progname) { fprintf(stderr, "%s tests libpq's pipeline mode.\n\n", progname); fprintf(stderr, "Usage:\n"); - fprintf(stderr, " %s tests", progname); - fprintf(stderr, " %s testname [conninfo [number_of_rows]]\n", progname); + fprintf(stderr, " %s [OPTION] tests\n", progname); + fprintf(stderr, " %s [OPTION] TESTNAME [CONNINFO [NUMBER_OF_ROWS]\n", progname); + fprintf(stderr, "\nOptions:\n"); + fprintf(stderr, " -t TRACEFILE generate a libpq trace to TRACEFILE\n"); } static void @@ -1231,37 +1237,54 @@ main(int argc, char **argv) { const char *conninfo = ""; PGconn *conn; + FILE *trace; + char *testname; int numrows = 10000; PGresult *res; + int c; - if (strcmp(argv[1], "tests") == 0) + while ((c = getopt(argc, argv, "t:")) != -1) { - print_test_list(); - exit(0); + switch (c) + { + case 't': /* trace file */ + tracefile = pg_strdup(optarg); + break; + } } - /* - * The testname parameter is mandatory; it can be followed by a conninfo - * string and number of rows. - */ - if (argc < 2 || argc > 4) + if (optind < argc) + { + testname = argv[optind]; + optind++; + } + else { usage(argv[0]); exit(1); } - if (argc >= 3) - conninfo = pg_strdup(argv[2]); + if (strcmp(testname, "tests") == 0) + { + print_test_list(); + exit(0); + } - if (argc >= 4) + if (optind < argc) + { + conninfo = argv[optind]; + optind++; + } + if (optind < argc) { errno = 0; - numrows = strtol(argv[3], NULL, 10); + numrows = strtol(argv[optind], NULL, 10); if (errno != 0 || numrows <= 0) { - fprintf(stderr, "couldn't parse \"%s\" as a positive integer\n", argv[3]); + fprintf(stderr, "couldn't parse \"%s\" as a positive integer\n", argv[optind]); exit(1); } + optind++; } /* Make a connection to the database */ @@ -1272,30 +1295,41 @@ main(int argc, char **argv) PQerrorMessage(conn)); exit_nicely(conn); } + + /* Set the trace file, if requested */ + if (tracefile != NULL) + { + trace = fopen(tracefile, "w+"); + + if (trace == NULL) + pg_fatal("could not open file \"%s\": %m", tracefile); + PQtrace(conn, trace); + PQtraceSetFlags(conn, PQTRACE_SUPPRESS_TIMESTAMPS); + } + res = PQexec(conn, "SET lc_messages TO \"C\""); if (PQresultStatus(res) != PGRES_COMMAND_OK) pg_fatal("failed to set lc_messages: %s", PQerrorMessage(conn)); - if (strcmp(argv[1], "disallowed_in_pipeline") == 0) + if (strcmp(testname, "disallowed_in_pipeline") == 0) test_disallowed_in_pipeline(conn); - else if (strcmp(argv[1], "multi_pipelines") == 0) + else if (strcmp(testname, "multi_pipelines") == 0) test_multi_pipelines(conn); - else if (strcmp(argv[1], "pipeline_abort") == 0) + else if (strcmp(testname, "pipeline_abort") == 0) test_pipeline_abort(conn); - else if (strcmp(argv[1], "pipelined_insert") == 0) + else if (strcmp(testname, "pipelined_insert") == 0) test_pipelined_insert(conn, numrows); - else if (strcmp(argv[1], "prepared") == 0) + else if (strcmp(testname, "prepared") == 0) test_prepared(conn); - else if (strcmp(argv[1], "simple_pipeline") == 0) + else if (strcmp(testname, "simple_pipeline") == 0) test_simple_pipeline(conn); - else if (strcmp(argv[1], "singlerow") == 0) + else if (strcmp(testname, "singlerow") == 0) test_singlerowmode(conn); - else if (strcmp(argv[1], "transaction") == 0) + else if (strcmp(testname, "transaction") == 0) test_transaction(conn); else { - fprintf(stderr, "\"%s\" is not a recognized test name\n", argv[1]); - usage(argv[0]); + fprintf(stderr, "\"%s\" is not a recognized test name\n", testname); exit(1); } -- 2.20.1
>From 4b62c3159fe3aa8445317a5d65b7e81d91c7fba6 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 26 Mar 2021 19:13:04 -0300 Subject: [PATCH v30 3/7] put FILE * arg always first --- src/interfaces/libpq/libpq-trace.c | 234 ++++++++++++++--------------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/src/interfaces/libpq/libpq-trace.c b/src/interfaces/libpq/libpq-trace.c index bacb7903b9..bff542cada 100644 --- a/src/interfaces/libpq/libpq-trace.c +++ b/src/interfaces/libpq/libpq-trace.c @@ -93,7 +93,7 @@ pqTraceFormatTimestamp(char *timestr, size_t ts_len) * pqTraceOutputByte1: output 1 char message to the log */ static void -pqTraceOutputByte1(const char *data, int *cursor, FILE *pfdebug) +pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor) { const char *v = data + *cursor; @@ -113,7 +113,7 @@ pqTraceOutputByte1(const char *data, int *cursor, FILE *pfdebug) * pqTraceOutputInt16: output a 2-byte integer message to the log */ static int -pqTraceOutputInt16(const char *data, int *cursor, FILE *pfdebug) +pqTraceOutputInt16(FILE *pfdebug, const char *data, int *cursor) { uint16 tmp; int result; @@ -130,7 +130,7 @@ pqTraceOutputInt16(const char *data, int *cursor, FILE *pfdebug) * pqTraceOutputInt32: output a 4-byte integer message to the log */ static int -pqTraceOutputInt32(const char *data, int *cursor, FILE *pfdebug) +pqTraceOutputInt32(FILE *pfdebug, const char *data, int *cursor) { int result; @@ -146,7 +146,7 @@ pqTraceOutputInt32(const char *data, int *cursor, FILE *pfdebug) * pqTraceOutputString: output a string message to the log */ static void -pqTraceOutputString(const char *data, int *cursor, FILE *pfdebug) +pqTraceOutputString(FILE *pfdebug, const char *data, int *cursor) { int len; @@ -163,7 +163,7 @@ pqTraceOutputString(const char *data, int *cursor, FILE *pfdebug) * pqTraceOutputNchar: output a string of exactly len bytes message to the log */ static void -pqTraceOutputNchar(const char *data, int *cursor, FILE *pfdebug, int len) +pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor) { int i, next; /* first char not yet printed */ @@ -195,28 +195,28 @@ pqTraceOutputNchar(const char *data, int *cursor, FILE *pfdebug, int len) /* Authentication */ static void -pqTraceOutputR(const char *message, FILE *f) +pqTraceOutputR(FILE *f, const char *message) { int cursor = 0; fprintf(f, "Authentication\t"); - pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt32(f, message, &cursor); } /* BackendKeyData */ static void -pqTraceOutputK(const char *message, FILE *f) +pqTraceOutputK(FILE *f, const char *message) { int cursor = 0; fprintf(f, "BackendKeyData\t"); - pqTraceOutputInt32(message, &cursor, f); - pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputInt32(f, message, &cursor); } /* Bind */ static void -pqTraceOutputB(const char *message, int end, FILE *f) +pqTraceOutputB(FILE *f, const char *message, int end) { int cursor = 0; int nparams; @@ -224,113 +224,113 @@ pqTraceOutputB(const char *message, int end, FILE *f) int i; fprintf(f, "Bind\t"); - pqTraceOutputString(message, &cursor, f); - pqTraceOutputString(message, &cursor, f); - nparams = pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); + pqTraceOutputString(f, message, &cursor); + nparams = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nparams; i++) - pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt16(f, message, &cursor); - nparams = pqTraceOutputInt16(message, &cursor, f); + nparams = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nparams; i++) { - nbytes = pqTraceOutputInt32(message, &cursor, f); + nbytes = pqTraceOutputInt32(f, message, &cursor); if (nbytes == -1) continue; - pqTraceOutputNchar(message, &cursor, f, nbytes); + pqTraceOutputNchar(f, nbytes, message, &cursor); } - nparams = pqTraceOutputInt16(message, &cursor, f); + nparams = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nparams; i++) - pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt16(f, message, &cursor); } /* Close(F) or CommandComplete(B) */ static void -pqTraceOutputC(const char *message, int end, FILE *f, bool toServer) +pqTraceOutputC(FILE *f, bool toServer, const char *message, int end) { int cursor = 0; if (toServer) { fprintf(f, "Close\t"); - pqTraceOutputByte1(message, &cursor, f); - pqTraceOutputString(message, &cursor, f); + pqTraceOutputByte1(f, message, &cursor); + pqTraceOutputString(f, message, &cursor); } else { fprintf(f, "CommandComplete\t"); - pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); } } /* CopyFail */ static void -pqTraceOutputf(const char *message, int end, FILE *f) +pqTraceOutputf(FILE *f, const char *message, int end) { int cursor = 0; fprintf(f, "CopyFail\t"); - pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); } /* CopyInResponse */ static void -pqTraceOutputG(const char *message, int end, FILE *f) +pqTraceOutputG(FILE *f, const char *message, int end) { int cursor = 0; int nfields; int i; fprintf(f, "CopyInResponse\t"); - pqTraceOutputByte1(message, &cursor, f); - nfields = pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputByte1(f, message, &cursor); + nfields = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nfields; i++) - pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt16(f, message, &cursor); } /* CopyOutResponse */ static void -pqTraceOutputH(const char *message, int end, FILE *f) +pqTraceOutputH(FILE *f, const char *message, int end) { int cursor = 0; int nfields; int i; fprintf(f, "CopyOutResponse\t"); - pqTraceOutputByte1(message, &cursor, f); - nfields = pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputByte1(f, message, &cursor); + nfields = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nfields; i++) - pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt16(f, message, &cursor); } /* CopyBothResponse */ static void -pqTraceOutputW(const char *message, int end, FILE *f) +pqTraceOutputW(FILE *f, const char *message, int end) { int cursor = 0; fprintf(f, "CopyBothResponse\t"); - pqTraceOutputByte1(message, &cursor, f); + pqTraceOutputByte1(f, message, &cursor); while (end > cursor) - pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt16(f, message, &cursor); } /* Describe(F) or DataRow(B) */ static void -pqTraceOutputD(const char *message, int end, FILE *f, bool toServer) +pqTraceOutputD(FILE *f, bool toServer, const char *message, int end) { int cursor = 0; if (toServer) { fprintf(f, "Describe\t"); - pqTraceOutputByte1(message, &cursor, f); - pqTraceOutputString(message, &cursor, f); + pqTraceOutputByte1(f, message, &cursor); + pqTraceOutputString(f, message, &cursor); } else { @@ -339,45 +339,45 @@ pqTraceOutputD(const char *message, int end, FILE *f, bool toServer) int i; fprintf(f, "DataRow\t"); - nfields = pqTraceOutputInt16(message, &cursor, f); + nfields = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nfields; i++) { - len = pqTraceOutputInt32(message, &cursor, f); + len = pqTraceOutputInt32(f, message, &cursor); if (len == -1) continue; - pqTraceOutputNchar(message, &cursor, f, len); + pqTraceOutputNchar(f, len, message, &cursor); } } } /* Execute(F) or ErrorResponse(B) */ static void -pqTraceOutputE(const char *message, int end, FILE *f, bool toServer) +pqTraceOutputE(FILE *f, bool toServer, const char *message, int end) { int cursor = 0; if (toServer) { fprintf(f, "Execute\t"); - pqTraceOutputString(message, &cursor, f); - pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); + pqTraceOutputInt32(f, message, &cursor); } else { fprintf(f, "ErrorResponse\t"); while (end > cursor) { - pqTraceOutputByte1(message, &cursor, f); + pqTraceOutputByte1(f, message, &cursor); if (message[cursor] == '\0') continue; - pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); } } } /* FunctionCall */ static void -pqTraceOutputF(const char *message, FILE *f) +pqTraceOutputF(FILE *f, const char *message) { int cursor = 0; int nfields; @@ -385,160 +385,160 @@ pqTraceOutputF(const char *message, FILE *f) int i; fprintf(f, "FunctionCall\t"); - pqTraceOutputInt32(message, &cursor, f); - nfields = pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt32(f, message, &cursor); + nfields = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nfields; i++) - pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt16(f, message, &cursor); - nfields = pqTraceOutputInt16(message, &cursor, f); + nfields = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nfields; i++) { - nbytes = pqTraceOutputInt32(message, &cursor, f); + nbytes = pqTraceOutputInt32(f, message, &cursor); if (nbytes == -1) continue; - pqTraceOutputNchar(message, &cursor, f, nbytes); + pqTraceOutputNchar(f, nbytes, message, &cursor); } - pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputInt16(f, message, &cursor); } /* FunctionCallResponse */ static void -pqTraceOutputV(const char *message, FILE *f) +pqTraceOutputV(FILE *f, const char *message) { int cursor = 0; int len; fprintf(f, "FunctionCallResponse\t"); - len = pqTraceOutputInt32(message, &cursor, f); + len = pqTraceOutputInt32(f, message, &cursor); if (len != -1) - pqTraceOutputNchar(message, &cursor, f, len); + pqTraceOutputNchar(f, len, message, &cursor); } /* NegotiateProtocolVersion */ static void -pqTraceOutputv(const char *message, FILE *f) +pqTraceOutputv(FILE *f, const char *message) { int cursor = 0; fprintf(f, "NegotiateProtocolVersion\t"); - pqTraceOutputInt32(message, &cursor, f); - pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputInt32(f, message, &cursor); } /* NoticeResponse */ static void -pqTraceOutputN(const char *message, int end, FILE *f) +pqTraceOutputN(FILE *f, const char *message, int end) { int cursor = 0; fprintf(f, "NoticeResponse\t"); while (end > cursor) { - pqTraceOutputByte1(message, &cursor, f); + pqTraceOutputByte1(f, message, &cursor); if (message[cursor] == '\0') continue; - pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); } } /* NotificationResponse */ static void -pqTraceOutputA(const char *message, int end, FILE *f) +pqTraceOutputA(FILE *f, const char *message, int end) { int cursor = 0; fprintf(f, "NotificationResponse\t"); - pqTraceOutputInt32(message, &cursor, f); - pqTraceOutputString(message, &cursor, f); - pqTraceOutputString(message, &cursor, f); + pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputString(f, message, &cursor); + pqTraceOutputString(f, message, &cursor); } /* ParameterDescription */ static void -pqTraceOutputt(const char *message, FILE *f) +pqTraceOutputt(FILE *f, const char *message) { int cursor = 0; int nfields; int i; fprintf(f, "ParameterDescription\t"); - nfields = pqTraceOutputInt16(message, &cursor, f); + nfields = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nfields; i++) - pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt32(f, message, &cursor); } /* ParameterStatus */ static void -pqTraceOutputS(const char *message, int end, FILE *f) +pqTraceOutputS(FILE *f, const char *message, int end) { int cursor = 0; fprintf(f, "ParameterStatus\t"); - pqTraceOutputString(message, &cursor, f); - pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); + pqTraceOutputString(f, message, &cursor); } /* Parse */ static void -pqTraceOutputP(const char *message, int end, FILE *f) +pqTraceOutputP(FILE *f, const char *message, int end) { int cursor = 0; int nparams; int i; fprintf(f, "Parse\t"); - pqTraceOutputString(message, &cursor, f); - pqTraceOutputString(message, &cursor, f); - nparams = pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); + pqTraceOutputString(f, message, &cursor); + nparams = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nparams; i++) - pqTraceOutputInt32(message, &cursor, f); + pqTraceOutputInt32(f, message, &cursor); } /* Query */ static void -pqTraceOutputQ(const char *message, int end, FILE *f) +pqTraceOutputQ(FILE *f, const char *message, int end) { int cursor = 0; fprintf(f, "Query\t"); - pqTraceOutputString(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); } /* ReadyForQuery */ static void -pqTraceOutputZ(const char *message, FILE *f) +pqTraceOutputZ(FILE *f, const char *message) { int cursor = 0; fprintf(f, "ReadyForQuery\t"); - pqTraceOutputByte1(message, &cursor, f); + pqTraceOutputByte1(f, message, &cursor); } /* RowDescription */ static void -pqTraceOutputT(const char *message, int end, FILE *f) +pqTraceOutputT(FILE *f, const char *message, int end) { int cursor = 0; int nfields; int i; fprintf(f, "RowDescription\t"); - nfields = pqTraceOutputInt16(message, &cursor, f); + nfields = pqTraceOutputInt16(f, message, &cursor); for (i = 0; i < nfields; i++) { - pqTraceOutputString(message, &cursor, f); - pqTraceOutputInt32(message, &cursor, f); - pqTraceOutputInt16(message, &cursor, f); - pqTraceOutputInt32(message, &cursor, f); - pqTraceOutputInt16(message, &cursor, f); - pqTraceOutputInt32(message, &cursor, f); - pqTraceOutputInt16(message, &cursor, f); + pqTraceOutputString(f, message, &cursor); + pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputInt16(f, message, &cursor); } } @@ -569,76 +569,76 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) switch(id) { case 'R': /* Authentication */ - pqTraceOutputR(message + LogCursor, conn->Pfdebug); + pqTraceOutputR(conn->Pfdebug, message + LogCursor); break; case 'K': /* secret key data from the backend */ - pqTraceOutputK(message + LogCursor, conn->Pfdebug); + pqTraceOutputK(conn->Pfdebug, message + LogCursor); break; case 'B': /* Bind */ - pqTraceOutputB(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputB(conn->Pfdebug, message + LogCursor, LogEnd); break; case 'C': /* Close(F) or Command Complete(B) */ - pqTraceOutputC(message + LogCursor, LogEnd, conn->Pfdebug, toServer); + pqTraceOutputC(conn->Pfdebug, toServer, message + LogCursor, LogEnd); break; case 'd': /* Copy Data */ /* Drop COPY data to reduce the overhead of logging. */ break; case 'f': /* Copy Fail */ - pqTraceOutputf(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputf(conn->Pfdebug, message + LogCursor, LogEnd); break; case 'G': /* Start Copy In */ - pqTraceOutputG(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputG(conn->Pfdebug, message + LogCursor, LogEnd); break; case 'H': /* Flush(F) or Start Copy Out(B) */ if (!toServer) - pqTraceOutputH(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputH(conn->Pfdebug, message + LogCursor, LogEnd); else fprintf(conn->Pfdebug, "Flush"); break; case 'W': /* Start Copy Both */ - pqTraceOutputW(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputW(conn->Pfdebug, message + LogCursor, LogEnd); break; case 'D': /* Describe(F) or Data Row(B) */ - pqTraceOutputD(message + LogCursor, LogEnd, conn->Pfdebug, toServer); + pqTraceOutputD(conn->Pfdebug, toServer, message + LogCursor, LogEnd); break; case 'E': /* Execute(F) or Error Response(B) */ - pqTraceOutputE(message + LogCursor, LogEnd, conn->Pfdebug, toServer); + pqTraceOutputE(conn->Pfdebug, toServer, message + LogCursor, LogEnd); break; case 'F': /* Function Call */ - pqTraceOutputF(message + LogCursor, conn->Pfdebug); + pqTraceOutputF(conn->Pfdebug, message + LogCursor); break; case 'V': /* Function Call response */ - pqTraceOutputV(message + LogCursor, conn->Pfdebug); + pqTraceOutputV(conn->Pfdebug, message + LogCursor); break; case 'v': /* Negotiate Protocol Version */ - pqTraceOutputv(message + LogCursor, conn->Pfdebug); + pqTraceOutputv(conn->Pfdebug, message + LogCursor); break; case 'N': /* Notice Response */ - pqTraceOutputN(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputN(conn->Pfdebug, message + LogCursor, LogEnd); break; case 'A': /* Notification Response */ - pqTraceOutputA(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputA(conn->Pfdebug, message + LogCursor, LogEnd); break; case 't': /* Parameter Description */ - pqTraceOutputt(message + LogCursor, conn->Pfdebug); + pqTraceOutputt(conn->Pfdebug, message + LogCursor); break; case 'S': /* Parameter Status(B) or Sync(F) */ if (!toServer) - pqTraceOutputS(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputS(conn->Pfdebug, message + LogCursor, LogEnd); else fprintf(conn->Pfdebug, "Sync"); break; case 'P': /* Parse */ - pqTraceOutputP(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputP(conn->Pfdebug, message + LogCursor, LogEnd); break; case 'Q': /* Query */ - pqTraceOutputQ(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputQ(conn->Pfdebug, message + LogCursor, LogEnd); break; case 'Z': /* Ready For Query */ - pqTraceOutputZ(message + LogCursor, conn->Pfdebug); + pqTraceOutputZ(conn->Pfdebug, message + LogCursor); break; case 'T': /* Row Description */ - pqTraceOutputT(message + LogCursor, LogEnd, conn->Pfdebug); + pqTraceOutputT(conn->Pfdebug, message + LogCursor, LogEnd); break; case '2': /* Bind Complete */ fprintf(conn->Pfdebug, "BindComplete"); @@ -702,9 +702,9 @@ pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message) { case 16: /* CancelRequest */ fprintf(conn->Pfdebug, "CancelRequest\t"); - pqTraceOutputInt32(message, &LogCursor, conn->Pfdebug); - pqTraceOutputInt32(message, &LogCursor, conn->Pfdebug); - pqTraceOutputInt32(message, &LogCursor, conn->Pfdebug); + pqTraceOutputInt32(conn->Pfdebug, message, &LogCursor); + pqTraceOutputInt32(conn->Pfdebug, message, &LogCursor); + pqTraceOutputInt32(conn->Pfdebug, message, &LogCursor); break; case 8 : /* GSSENCRequest or SSLRequest */ /* These messages do not reach here. */ -- 2.20.1
>From d44009a25de3af549dfa528a4fa44c9ebf785c42 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 26 Mar 2021 19:13:16 -0300 Subject: [PATCH v30 4/7] use F/B instead of </> --- src/interfaces/libpq/libpq-trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/libpq/libpq-trace.c b/src/interfaces/libpq/libpq-trace.c index bff542cada..94f28f04a8 100644 --- a/src/interfaces/libpq/libpq-trace.c +++ b/src/interfaces/libpq/libpq-trace.c @@ -548,7 +548,7 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) char timestr[128]; char id; int length; - char *prefix = toServer ? ">" : "<"; + char *prefix = toServer ? "F" : "B"; int LogCursor = 0; int LogEnd; -- 2.20.1
>From 39a5e0c6b5559a0fb9a6c376e493e4ee4bc980fb Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 26 Mar 2021 20:04:53 -0300 Subject: [PATCH v30 5/7] pass *cursor to printing routines --- src/interfaces/libpq/libpq-trace.c | 309 +++++++++++++---------------- 1 file changed, 134 insertions(+), 175 deletions(-) diff --git a/src/interfaces/libpq/libpq-trace.c b/src/interfaces/libpq/libpq-trace.c index 94f28f04a8..06d8d981a3 100644 --- a/src/interfaces/libpq/libpq-trace.c +++ b/src/interfaces/libpq/libpq-trace.c @@ -106,7 +106,7 @@ pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor) fprintf(pfdebug, " \\x%02x", *v); else fprintf(pfdebug, " %c", *v); - ++*cursor; + *cursor += 1; } /* @@ -195,142 +195,125 @@ pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor) /* Authentication */ static void -pqTraceOutputR(FILE *f, const char *message) +pqTraceOutputR(FILE *f, const char *message, int *cursor) { - int cursor = 0; - fprintf(f, "Authentication\t"); - pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputInt32(f, message, cursor); } /* BackendKeyData */ static void -pqTraceOutputK(FILE *f, const char *message) +pqTraceOutputK(FILE *f, const char *message, int *cursor) { - int cursor = 0; - fprintf(f, "BackendKeyData\t"); - pqTraceOutputInt32(f, message, &cursor); - pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputInt32(f, message, cursor); + pqTraceOutputInt32(f, message, cursor); } /* Bind */ static void -pqTraceOutputB(FILE *f, const char *message, int end) +pqTraceOutputB(FILE *f, const char *message, int *cursor) { - int cursor = 0; int nparams; - int nbytes; - int i; fprintf(f, "Bind\t"); - pqTraceOutputString(f, message, &cursor); - pqTraceOutputString(f, message, &cursor); - nparams = pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputString(f, message, cursor); + pqTraceOutputString(f, message, cursor); + nparams = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nparams; i++) - pqTraceOutputInt16(f, message, &cursor); + for (int i = 0; i < nparams; i++) + pqTraceOutputInt16(f, message, cursor); - nparams = pqTraceOutputInt16(f, message, &cursor); + nparams = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nparams; i++) + for (int i = 0; i < nparams; i++) { - nbytes = pqTraceOutputInt32(f, message, &cursor); + int nbytes; + + nbytes = pqTraceOutputInt32(f, message, cursor); if (nbytes == -1) continue; - pqTraceOutputNchar(f, nbytes, message, &cursor); + pqTraceOutputNchar(f, nbytes, message, cursor); } - nparams = pqTraceOutputInt16(f, message, &cursor); - for (i = 0; i < nparams; i++) - pqTraceOutputInt16(f, message, &cursor); + nparams = pqTraceOutputInt16(f, message, cursor); + for (int i = 0; i < nparams; i++) + pqTraceOutputInt16(f, message, cursor); } /* Close(F) or CommandComplete(B) */ static void -pqTraceOutputC(FILE *f, bool toServer, const char *message, int end) +pqTraceOutputC(FILE *f, bool toServer, const char *message, int *cursor) { - int cursor = 0; - if (toServer) { fprintf(f, "Close\t"); - pqTraceOutputByte1(f, message, &cursor); - pqTraceOutputString(f, message, &cursor); + pqTraceOutputByte1(f, message, cursor); + pqTraceOutputString(f, message, cursor); } else { fprintf(f, "CommandComplete\t"); - pqTraceOutputString(f, message, &cursor); + pqTraceOutputString(f, message, cursor); } } /* CopyFail */ static void -pqTraceOutputf(FILE *f, const char *message, int end) +pqTraceOutputf(FILE *f, const char *message, int *cursor) { - int cursor = 0; - fprintf(f, "CopyFail\t"); - pqTraceOutputString(f, message, &cursor); + pqTraceOutputString(f, message, cursor); } /* CopyInResponse */ static void -pqTraceOutputG(FILE *f, const char *message, int end) +pqTraceOutputG(FILE *f, const char *message, int *cursor) { - int cursor = 0; int nfields; - int i; fprintf(f, "CopyInResponse\t"); - pqTraceOutputByte1(f, message, &cursor); - nfields = pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputByte1(f, message, cursor); + nfields = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nfields; i++) - pqTraceOutputInt16(f, message, &cursor); + for (int i = 0; i < nfields; i++) + pqTraceOutputInt16(f, message, cursor); } /* CopyOutResponse */ static void -pqTraceOutputH(FILE *f, const char *message, int end) +pqTraceOutputH(FILE *f, const char *message, int *cursor) { - int cursor = 0; int nfields; - int i; fprintf(f, "CopyOutResponse\t"); - pqTraceOutputByte1(f, message, &cursor); - nfields = pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputByte1(f, message, cursor); + nfields = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nfields; i++) - pqTraceOutputInt16(f, message, &cursor); + for (int i = 0; i < nfields; i++) + pqTraceOutputInt16(f, message, cursor); } /* CopyBothResponse */ static void -pqTraceOutputW(FILE *f, const char *message, int end) +pqTraceOutputW(FILE *f, const char *message, int *cursor, int length) { - int cursor = 0; - fprintf(f, "CopyBothResponse\t"); - pqTraceOutputByte1(f, message, &cursor); + pqTraceOutputByte1(f, message, cursor); - while (end > cursor) - pqTraceOutputInt16(f, message, &cursor); + while (length > *cursor) + pqTraceOutputInt16(f, message, cursor); } /* Describe(F) or DataRow(B) */ static void -pqTraceOutputD(FILE *f, bool toServer, const char *message, int end) +pqTraceOutputD(FILE *f, bool toServer, const char *message, int *cursor) { - int cursor = 0; - if (toServer) { fprintf(f, "Describe\t"); - pqTraceOutputByte1(f, message, &cursor); - pqTraceOutputString(f, message, &cursor); + pqTraceOutputByte1(f, message, cursor); + pqTraceOutputString(f, message, cursor); } else { @@ -339,206 +322,183 @@ pqTraceOutputD(FILE *f, bool toServer, const char *message, int end) int i; fprintf(f, "DataRow\t"); - nfields = pqTraceOutputInt16(f, message, &cursor); + nfields = pqTraceOutputInt16(f, message, cursor); for (i = 0; i < nfields; i++) { - len = pqTraceOutputInt32(f, message, &cursor); + len = pqTraceOutputInt32(f, message, cursor); if (len == -1) continue; - pqTraceOutputNchar(f, len, message, &cursor); + pqTraceOutputNchar(f, len, message, cursor); } } } /* Execute(F) or ErrorResponse(B) */ static void -pqTraceOutputE(FILE *f, bool toServer, const char *message, int end) +pqTraceOutputE(FILE *f, bool toServer, const char *message, int *cursor, int length) { - int cursor = 0; - if (toServer) { fprintf(f, "Execute\t"); - pqTraceOutputString(f, message, &cursor); - pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputString(f, message, cursor); + pqTraceOutputInt32(f, message, cursor); } else { fprintf(f, "ErrorResponse\t"); - while (end > cursor) + for (;;) { - pqTraceOutputByte1(f, message, &cursor); - if (message[cursor] == '\0') - continue; - pqTraceOutputString(f, message, &cursor); + pqTraceOutputByte1(f, message, cursor); + if (message[*cursor - 1] == '\0') + break; + pqTraceOutputString(f, message, cursor); } } } /* FunctionCall */ static void -pqTraceOutputF(FILE *f, const char *message) +pqTraceOutputF(FILE *f, const char *message, int *cursor) { - int cursor = 0; int nfields; int nbytes; - int i; fprintf(f, "FunctionCall\t"); - pqTraceOutputInt32(f, message, &cursor); - nfields = pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputInt32(f, message, cursor); + nfields = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nfields; i++) - pqTraceOutputInt16(f, message, &cursor); + for (int i = 0; i < nfields; i++) + pqTraceOutputInt16(f, message, cursor); - nfields = pqTraceOutputInt16(f, message, &cursor); + nfields = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nfields; i++) + for (int i = 0; i < nfields; i++) { - nbytes = pqTraceOutputInt32(f, message, &cursor); + nbytes = pqTraceOutputInt32(f, message, cursor); if (nbytes == -1) continue; - pqTraceOutputNchar(f, nbytes, message, &cursor); + pqTraceOutputNchar(f, nbytes, message, cursor); } - pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputInt16(f, message, cursor); } /* FunctionCallResponse */ static void -pqTraceOutputV(FILE *f, const char *message) +pqTraceOutputV(FILE *f, const char *message, int *cursor) { - int cursor = 0; int len; fprintf(f, "FunctionCallResponse\t"); - len = pqTraceOutputInt32(f, message, &cursor); + len = pqTraceOutputInt32(f, message, cursor); if (len != -1) - pqTraceOutputNchar(f, len, message, &cursor); + pqTraceOutputNchar(f, len, message, cursor); } /* NegotiateProtocolVersion */ static void -pqTraceOutputv(FILE *f, const char *message) +pqTraceOutputv(FILE *f, const char *message, int *cursor) { - int cursor = 0; - fprintf(f, "NegotiateProtocolVersion\t"); - pqTraceOutputInt32(f, message, &cursor); - pqTraceOutputInt32(f, message, &cursor); + pqTraceOutputInt32(f, message, cursor); + pqTraceOutputInt32(f, message, cursor); } /* NoticeResponse */ static void -pqTraceOutputN(FILE *f, const char *message, int end) +pqTraceOutputN(FILE *f, const char *message, int *cursor, int length) { - int cursor = 0; - fprintf(f, "NoticeResponse\t"); - while (end > cursor) + for (;;) { - pqTraceOutputByte1(f, message, &cursor); - if (message[cursor] == '\0') - continue; - pqTraceOutputString(f, message, &cursor); + pqTraceOutputByte1(f, message, cursor); + if (message[*cursor - 1] == '\0') + break; + pqTraceOutputString(f, message, cursor); } } /* NotificationResponse */ static void -pqTraceOutputA(FILE *f, const char *message, int end) +pqTraceOutputA(FILE *f, const char *message, int *cursor) { - int cursor = 0; - fprintf(f, "NotificationResponse\t"); - pqTraceOutputInt32(f, message, &cursor); - pqTraceOutputString(f, message, &cursor); - pqTraceOutputString(f, message, &cursor); + pqTraceOutputInt32(f, message, cursor); + pqTraceOutputString(f, message, cursor); + pqTraceOutputString(f, message, cursor); } /* ParameterDescription */ static void -pqTraceOutputt(FILE *f, const char *message) +pqTraceOutputt(FILE *f, const char *message, int *cursor) { - int cursor = 0; int nfields; - int i; fprintf(f, "ParameterDescription\t"); - nfields = pqTraceOutputInt16(f, message, &cursor); + nfields = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nfields; i++) - pqTraceOutputInt32(f, message, &cursor); + for (int i = 0; i < nfields; i++) + pqTraceOutputInt32(f, message, cursor); } /* ParameterStatus */ static void -pqTraceOutputS(FILE *f, const char *message, int end) +pqTraceOutputS(FILE *f, const char *message, int *cursor) { - int cursor = 0; - fprintf(f, "ParameterStatus\t"); - pqTraceOutputString(f, message, &cursor); - pqTraceOutputString(f, message, &cursor); + pqTraceOutputString(f, message, cursor); + pqTraceOutputString(f, message, cursor); } /* Parse */ static void -pqTraceOutputP(FILE *f, const char *message, int end) +pqTraceOutputP(FILE *f, const char *message, int *cursor) { - int cursor = 0; int nparams; - int i; fprintf(f, "Parse\t"); - pqTraceOutputString(f, message, &cursor); - pqTraceOutputString(f, message, &cursor); - nparams = pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputString(f, message, cursor); + pqTraceOutputString(f, message, cursor); + nparams = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nparams; i++) - pqTraceOutputInt32(f, message, &cursor); + for (int i = 0; i < nparams; i++) + pqTraceOutputInt32(f, message, cursor); } /* Query */ static void -pqTraceOutputQ(FILE *f, const char *message, int end) +pqTraceOutputQ(FILE *f, const char *message, int *cursor) { - int cursor = 0; - fprintf(f, "Query\t"); - pqTraceOutputString(f, message, &cursor); + pqTraceOutputString(f, message, cursor); } /* ReadyForQuery */ static void -pqTraceOutputZ(FILE *f, const char *message) +pqTraceOutputZ(FILE *f, const char *message, int *cursor) { - int cursor = 0; - fprintf(f, "ReadyForQuery\t"); - pqTraceOutputByte1(f, message, &cursor); + pqTraceOutputByte1(f, message, cursor); } /* RowDescription */ static void -pqTraceOutputT(FILE *f, const char *message, int end) +pqTraceOutputT(FILE *f, const char *message, int *cursor) { - int cursor = 0; int nfields; - int i; fprintf(f, "RowDescription\t"); - nfields = pqTraceOutputInt16(f, message, &cursor); + nfields = pqTraceOutputInt16(f, message, cursor); - for (i = 0; i < nfields; i++) + for (int i = 0; i < nfields; i++) { - pqTraceOutputString(f, message, &cursor); - pqTraceOutputInt32(f, message, &cursor); - pqTraceOutputInt16(f, message, &cursor); - pqTraceOutputInt32(f, message, &cursor); - pqTraceOutputInt16(f, message, &cursor); - pqTraceOutputInt32(f, message, &cursor); - pqTraceOutputInt16(f, message, &cursor); + pqTraceOutputString(f, message, cursor); + pqTraceOutputInt32(f, message, cursor); + pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt32(f, message, cursor); + pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt32(f, message, cursor); + pqTraceOutputInt16(f, message, cursor); } } @@ -550,95 +510,94 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) int length; char *prefix = toServer ? "F" : "B"; int LogCursor = 0; - int LogEnd; if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0) + { pqTraceFormatTimestamp(timestr, sizeof(timestr)); - else - timestr[0] = '\0'; + fprintf(conn->Pfdebug, "%s\t", timestr); + } id = message[LogCursor++]; - memcpy(&length, message + LogCursor , 4); + memcpy(&length, message + LogCursor, 4); length = (int) pg_ntoh32(length); LogCursor += 4; - LogEnd = length - 4; - fprintf(conn->Pfdebug, "%s\t%s\t%d\t", timestr, prefix, length); + fprintf(conn->Pfdebug, "%s\t%d\t", prefix, length); switch(id) { case 'R': /* Authentication */ - pqTraceOutputR(conn->Pfdebug, message + LogCursor); + pqTraceOutputR(conn->Pfdebug, message, &LogCursor); break; case 'K': /* secret key data from the backend */ - pqTraceOutputK(conn->Pfdebug, message + LogCursor); + pqTraceOutputK(conn->Pfdebug, message, &LogCursor); break; case 'B': /* Bind */ - pqTraceOutputB(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputB(conn->Pfdebug, message, &LogCursor); break; case 'C': /* Close(F) or Command Complete(B) */ - pqTraceOutputC(conn->Pfdebug, toServer, message + LogCursor, LogEnd); + pqTraceOutputC(conn->Pfdebug, toServer, message, &LogCursor); break; case 'd': /* Copy Data */ /* Drop COPY data to reduce the overhead of logging. */ break; case 'f': /* Copy Fail */ - pqTraceOutputf(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputf(conn->Pfdebug, message, &LogCursor); break; case 'G': /* Start Copy In */ - pqTraceOutputG(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputG(conn->Pfdebug, message, &LogCursor); break; case 'H': /* Flush(F) or Start Copy Out(B) */ if (!toServer) - pqTraceOutputH(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputH(conn->Pfdebug, message, &LogCursor); else fprintf(conn->Pfdebug, "Flush"); break; case 'W': /* Start Copy Both */ - pqTraceOutputW(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputW(conn->Pfdebug, message, &LogCursor, length); break; case 'D': /* Describe(F) or Data Row(B) */ - pqTraceOutputD(conn->Pfdebug, toServer, message + LogCursor, LogEnd); + pqTraceOutputD(conn->Pfdebug, toServer, message, &LogCursor); break; case 'E': /* Execute(F) or Error Response(B) */ - pqTraceOutputE(conn->Pfdebug, toServer, message + LogCursor, LogEnd); + pqTraceOutputE(conn->Pfdebug, toServer, message, &LogCursor, length); break; case 'F': /* Function Call */ - pqTraceOutputF(conn->Pfdebug, message + LogCursor); + pqTraceOutputF(conn->Pfdebug, message, &LogCursor); break; case 'V': /* Function Call response */ - pqTraceOutputV(conn->Pfdebug, message + LogCursor); + pqTraceOutputV(conn->Pfdebug, message, &LogCursor); break; case 'v': /* Negotiate Protocol Version */ - pqTraceOutputv(conn->Pfdebug, message + LogCursor); + pqTraceOutputv(conn->Pfdebug, message, &LogCursor); break; case 'N': /* Notice Response */ - pqTraceOutputN(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputN(conn->Pfdebug, message, &LogCursor, length); break; case 'A': /* Notification Response */ - pqTraceOutputA(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputA(conn->Pfdebug, message, &LogCursor); break; case 't': /* Parameter Description */ - pqTraceOutputt(conn->Pfdebug, message + LogCursor); + pqTraceOutputt(conn->Pfdebug, message, &LogCursor); break; case 'S': /* Parameter Status(B) or Sync(F) */ if (!toServer) - pqTraceOutputS(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputS(conn->Pfdebug, message, &LogCursor); else fprintf(conn->Pfdebug, "Sync"); break; case 'P': /* Parse */ - pqTraceOutputP(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputP(conn->Pfdebug, message, &LogCursor); break; case 'Q': /* Query */ - pqTraceOutputQ(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputQ(conn->Pfdebug, message, &LogCursor); break; case 'Z': /* Ready For Query */ - pqTraceOutputZ(conn->Pfdebug, message + LogCursor); + pqTraceOutputZ(conn->Pfdebug, message, &LogCursor); break; case 'T': /* Row Description */ - pqTraceOutputT(conn->Pfdebug, message + LogCursor, LogEnd); + pqTraceOutputT(conn->Pfdebug, message, &LogCursor); break; case '2': /* Bind Complete */ fprintf(conn->Pfdebug, "BindComplete"); -- 2.20.1
>From 4d645bdf08de419b207b0064986d81f758900809 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 26 Mar 2021 20:05:10 -0300 Subject: [PATCH v30 6/7] add length check --- src/interfaces/libpq/libpq-trace.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/interfaces/libpq/libpq-trace.c b/src/interfaces/libpq/libpq-trace.c index 06d8d981a3..6c58a578ac 100644 --- a/src/interfaces/libpq/libpq-trace.c +++ b/src/interfaces/libpq/libpq-trace.c @@ -637,6 +637,16 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) } fputc('\n', conn->Pfdebug); + + /* + * Verify the printing routine did it right. Note that the one-byte + * message identifier is not included in the length, but our cursor + * does include it. + */ + if (LogCursor - 1 != length) + fprintf(conn->Pfdebug, + "mismatched message length: consumed %d, expected %d\n", + LogCursor - 1, length); } void -- 2.20.1
>From d040e90b1ed206a14b031ac92f494b87b1d32ae8 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Sat, 27 Mar 2021 16:10:08 -0300 Subject: [PATCH v30 7/7] Use libpq_pipeline to test PQtrace --- .../libpq_pipeline/t/001_libpq_pipeline.pl | 24 ++++++++++- .../traces/multi_pipelines.trace | 26 ++++++++++++ .../libpq_pipeline/traces/prepared.trace | 21 ++++++++++ .../traces/simple_pipeline.trace | 15 +++++++ .../libpq_pipeline/traces/singlerow.trace | 42 +++++++++++++++++++ 5 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 src/test/modules/libpq_pipeline/traces/multi_pipelines.trace create mode 100644 src/test/modules/libpq_pipeline/traces/prepared.trace create mode 100644 src/test/modules/libpq_pipeline/traces/simple_pipeline.trace create mode 100644 src/test/modules/libpq_pipeline/traces/singlerow.trace diff --git a/src/test/modules/libpq_pipeline/t/001_libpq_pipeline.pl b/src/test/modules/libpq_pipeline/t/001_libpq_pipeline.pl index 0213f21ee8..a0ee8640a7 100644 --- a/src/test/modules/libpq_pipeline/t/001_libpq_pipeline.pl +++ b/src/test/modules/libpq_pipeline/t/001_libpq_pipeline.pl @@ -4,7 +4,7 @@ use warnings; use Config; use PostgresNode; use TestLib; -use Test::More tests => 8; +use Test::More tests => 12; use Cwd; my $node = get_new_node('main'); @@ -20,9 +20,29 @@ my @tests = split(/\s+/, $out); for my $testname (@tests) { + my @extraargs = (); + my $cmptrace = grep(/^$testname$/, + qw(simple_pipeline multi_pipelines prepared singlerow)) > 0; + my $traceout = "$TestLib::log_path/$testname.trace"; + + # For a bunch of tests, generate a libpq trace file too. + if ($cmptrace) + { + push @extraargs, "-t", $traceout; + } + + $node->command_ok( - [ 'libpq_pipeline', $testname, $node->connstr('postgres'), $numrows ], + [ 'libpq_pipeline', @extraargs, $testname, $node->connstr('postgres'), $numrows ], "libpq_pipeline $testname"); + + if ($cmptrace) + { + my $expected = slurp_file("traces/$testname.trace"); + my $result = slurp_file($traceout); + + is($expected, $result, "$testname trace match"); + } } $node->stop('fast'); diff --git a/src/test/modules/libpq_pipeline/traces/multi_pipelines.trace b/src/test/modules/libpq_pipeline/traces/multi_pipelines.trace new file mode 100644 index 0000000000..f7dfbef11f --- /dev/null +++ b/src/test/modules/libpq_pipeline/traces/multi_pipelines.trace @@ -0,0 +1,26 @@ +F 27 Query "SET lc_messages TO "C"" +B 8 CommandComplete "SET" +B 5 ReadyForQuery I +F 21 Parse "" "SELECT $1" 1 23 +F 19 Bind "" "" 0 1 1 '1' 1 0 +F 6 Describe P "" +F 9 Execute "" 0 +F 4 Sync +F 21 Parse "" "SELECT $1" 1 23 +F 19 Bind "" "" 0 1 1 '1' 1 0 +F 6 Describe P "" +F 9 Execute "" 0 +F 4 Sync +B 4 ParseComplete +B 4 BindComplete +B 33 RowDescription 1 "?column?" 0 0 23 4 -1 0 +B 11 DataRow 1 1 '1' +B 13 CommandComplete "SELECT 1" +B 5 ReadyForQuery I +B 4 ParseComplete +B 4 BindComplete +B 33 RowDescription 1 "?column?" 0 0 23 4 -1 0 +B 11 DataRow 1 1 '1' +B 13 CommandComplete "SELECT 1" +B 5 ReadyForQuery I +F 4 Terminate diff --git a/src/test/modules/libpq_pipeline/traces/prepared.trace b/src/test/modules/libpq_pipeline/traces/prepared.trace new file mode 100644 index 0000000000..62c5c38b6a --- /dev/null +++ b/src/test/modules/libpq_pipeline/traces/prepared.trace @@ -0,0 +1,21 @@ +F 27 Query "SET lc_messages TO "C"" +B 8 CommandComplete "SET" +B 5 ReadyForQuery I +F 68 Parse "select_one" "SELECT $1, '42', $1::numeric, interval '1 sec'" 1 23 +F 16 Describe S "select_one" +F 4 Sync +B 4 ParseComplete +B 10 ParameterDescription 1 23 +B 113 RowDescription 4 "?column?" 0 0 23 4 -1 0 "?column?" 0 0 25 65535 -1 0 "numeric" 0 0 1700 65535 -1 0 "interval" 0 0 1186 16 -1 0 +B 5 ReadyForQuery I +F 10 Query "BEGIN" +B 10 CommandComplete "BEGIN" +B 5 ReadyForQuery T +F 43 Query "DECLARE cursor_one CURSOR FOR SELECT 1" +B 19 CommandComplete "DECLARE CURSOR" +B 5 ReadyForQuery T +F 16 Describe P "cursor_one" +F 4 Sync +B 33 RowDescription 1 "?column?" 0 0 23 4 -1 0 +B 5 ReadyForQuery T +F 4 Terminate diff --git a/src/test/modules/libpq_pipeline/traces/simple_pipeline.trace b/src/test/modules/libpq_pipeline/traces/simple_pipeline.trace new file mode 100644 index 0000000000..82a80c9191 --- /dev/null +++ b/src/test/modules/libpq_pipeline/traces/simple_pipeline.trace @@ -0,0 +1,15 @@ +F 27 Query "SET lc_messages TO "C"" +B 8 CommandComplete "SET" +B 5 ReadyForQuery I +F 21 Parse "" "SELECT $1" 1 23 +F 19 Bind "" "" 0 1 1 '1' 1 0 +F 6 Describe P "" +F 9 Execute "" 0 +F 4 Sync +B 4 ParseComplete +B 4 BindComplete +B 33 RowDescription 1 "?column?" 0 0 23 4 -1 0 +B 11 DataRow 1 1 '1' +B 13 CommandComplete "SELECT 1" +B 5 ReadyForQuery I +F 4 Terminate diff --git a/src/test/modules/libpq_pipeline/traces/singlerow.trace b/src/test/modules/libpq_pipeline/traces/singlerow.trace new file mode 100644 index 0000000000..7708569f39 --- /dev/null +++ b/src/test/modules/libpq_pipeline/traces/singlerow.trace @@ -0,0 +1,42 @@ +F 27 Query "SET lc_messages TO "C"" +B 8 CommandComplete "SET" +B 5 ReadyForQuery I +F 38 Parse "" "SELECT generate_series(42, $1)" 0 +F 20 Bind "" "" 0 1 2 '44' 1 0 +F 6 Describe P "" +F 9 Execute "" 0 +F 38 Parse "" "SELECT generate_series(42, $1)" 0 +F 20 Bind "" "" 0 1 2 '45' 1 0 +F 6 Describe P "" +F 9 Execute "" 0 +F 38 Parse "" "SELECT generate_series(42, $1)" 0 +F 20 Bind "" "" 0 1 2 '46' 1 0 +F 6 Describe P "" +F 9 Execute "" 0 +F 4 Sync +B 4 ParseComplete +B 4 BindComplete +B 40 RowDescription 1 "generate_series" 0 0 23 4 -1 0 +B 12 DataRow 1 2 '42' +B 12 DataRow 1 2 '43' +B 12 DataRow 1 2 '44' +B 13 CommandComplete "SELECT 3" +B 4 ParseComplete +B 4 BindComplete +B 40 RowDescription 1 "generate_series" 0 0 23 4 -1 0 +B 12 DataRow 1 2 '42' +B 12 DataRow 1 2 '43' +B 12 DataRow 1 2 '44' +B 12 DataRow 1 2 '45' +B 13 CommandComplete "SELECT 4" +B 4 ParseComplete +B 4 BindComplete +B 40 RowDescription 1 "generate_series" 0 0 23 4 -1 0 +B 12 DataRow 1 2 '42' +B 12 DataRow 1 2 '43' +B 12 DataRow 1 2 '44' +B 12 DataRow 1 2 '45' +B 12 DataRow 1 2 '46' +B 13 CommandComplete "SELECT 5" +B 5 ReadyForQuery I +F 4 Terminate -- 2.20.1