Proposed changes on top of v29.

-- 
Álvaro Herrera       Valdivia, Chile
>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 1/5] 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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

Reply via email to