From 834363b5a3951fb8e641f3b2bac55d2b01ff84a2 Mon Sep 17 00:00:00 2001 From: Anthonin Bonnefoy Date: Wed, 8 Jul 2026 08:39:07 +0200 Subject: Make pqtrace write line atomically Currently, pqtrace writes are done by doing multiple fprintf per line to the Pfdebug fd. This prevents multiple connections from writing on the same Pfdebug, as they may be writing on the same line at the same time. This commit changes fe-trace.c to buffer each line in a PQExpBuffer, and write a line in Pfdebug in a single fprintf. This will allow cancel connections to reuse the source connection's Pfdebug to trace the cancel request. --- src/interfaces/libpq/fe-trace.c | 513 +++++++++++++++++--------------- 1 file changed, 265 insertions(+), 248 deletions(-) diff --git a/src/interfaces/libpq/fe-trace.c b/src/interfaces/libpq/fe-trace.c index e136c77e6b0..eeda6bc3d85 100644 --- a/src/interfaces/libpq/fe-trace.c +++ b/src/interfaces/libpq/fe-trace.c @@ -104,7 +104,7 @@ pqTraceFormatTimestamp(char *timestr, size_t ts_len) * pqTraceOutputByte1: output a 1-char message to the log */ static void -pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor) +pqTraceOutputByte1(PQExpBuffer buf, const char *data, int *cursor) { const char *v = data + *cursor; @@ -113,9 +113,9 @@ pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor) * that completes ErrorResponse and NoticeResponse messages. */ if (!isprint((unsigned char) *v)) - fprintf(pfdebug, " \\x%02x", (unsigned char) *v); + appendPQExpBuffer(buf, " \\x%02x", (unsigned char) *v); else - fprintf(pfdebug, " %c", *v); + appendPQExpBuffer(buf, " %c", *v); *cursor += 1; } @@ -123,7 +123,7 @@ pqTraceOutputByte1(FILE *pfdebug, const char *data, int *cursor) * pqTraceOutputInt16: output a 2-byte integer message to the log */ static int -pqTraceOutputInt16(FILE *pfdebug, const char *data, int *cursor) +pqTraceOutputInt16(PQExpBuffer buf, const char *data, int *cursor) { uint16 tmp; int result; @@ -131,7 +131,7 @@ pqTraceOutputInt16(FILE *pfdebug, const char *data, int *cursor) memcpy(&tmp, data + *cursor, 2); *cursor += 2; result = (int) pg_ntoh16(tmp); - fprintf(pfdebug, " %d", result); + appendPQExpBuffer(buf, " %d", result); return result; } @@ -142,7 +142,7 @@ pqTraceOutputInt16(FILE *pfdebug, const char *data, int *cursor) * If 'suppress' is true, print a literal NNNN instead of the actual number. */ static int -pqTraceOutputInt32(FILE *pfdebug, const char *data, int *cursor, bool suppress) +pqTraceOutputInt32(PQExpBuffer buf, const char *data, int *cursor, bool suppress) { int result; @@ -150,9 +150,9 @@ pqTraceOutputInt32(FILE *pfdebug, const char *data, int *cursor, bool suppress) *cursor += 4; result = (int) pg_ntoh32(result); if (suppress) - fprintf(pfdebug, " NNNN"); + appendPQExpBufferStr(buf, " NNNN"); else - fprintf(pfdebug, " %d", result); + appendPQExpBuffer(buf, " %d", result); return result; } @@ -163,24 +163,21 @@ pqTraceOutputInt32(FILE *pfdebug, const char *data, int *cursor, bool suppress) * If 'suppress' is true, print a literal "SSSS" instead of the actual string. */ static void -pqTraceOutputString(FILE *pfdebug, const char *data, int *cursor, bool suppress) +pqTraceOutputString(PQExpBuffer buf, const char *data, int *cursor, bool suppress) { - int len; - if (suppress) { - fprintf(pfdebug, " \"SSSS\""); + appendPQExpBufferStr(buf, " \"SSSS\""); *cursor += strlen(data + *cursor) + 1; } else { - len = fprintf(pfdebug, " \"%s\"", data + *cursor); + appendPQExpBuffer(buf, " \"%s\"", data + *cursor); /* - * This is a null-terminated string. So add 1 after subtracting 3 - * which is the double quotes and space length from len. + * This is a null-terminated string. So add 1. */ - *cursor += (len - 3 + 1); + *cursor += strlen(data + *cursor) + 1; } } @@ -190,7 +187,7 @@ pqTraceOutputString(FILE *pfdebug, const char *data, int *cursor, bool suppress) * If 'suppress' is true, print a literal 'BBBB' instead of the actual bytes. */ static void -pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor, bool suppress) +pqTraceOutputNchar(PQExpBuffer buf, int len, const char *data, int *cursor, bool suppress) { int i, next; /* first char not yet printed */ @@ -198,12 +195,12 @@ pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor, bool s if (suppress) { - fprintf(pfdebug, " 'BBBB'"); + appendPQExpBufferStr(buf, " 'BBBB'"); *cursor += len; return; } - fprintf(pfdebug, " \'"); + appendPQExpBufferStr(buf, " \'"); for (next = i = 0; i < len; ++i) { @@ -211,15 +208,15 @@ pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor, bool s continue; else { - fwrite(v + next, 1, i - next, pfdebug); - fprintf(pfdebug, "\\x%02x", (unsigned char) v[i]); + appendBinaryPQExpBuffer(buf, v + next, i - next); + appendPQExpBuffer(buf, "\\x%02x", (unsigned char) v[i]); next = i + 1; } } if (next < len) - fwrite(v + next, 1, len - next, pfdebug); + appendBinaryPQExpBuffer(buf, v + next, len - next); - fprintf(pfdebug, "\'"); + appendPQExpBufferStr(buf, "\'"); *cursor += len; } @@ -229,24 +226,24 @@ pqTraceOutputNchar(FILE *pfdebug, int len, const char *data, int *cursor, bool s * If 'suppress' is true, print a literal 'BBBB' instead of the actual bytes. */ static void -pqTraceOutputNbyte(FILE *pfdebug, int len, const char *data, int *cursor, bool suppress) +pqTraceOutputNbyte(PQExpBuffer buf, int len, const char *data, int *cursor, bool suppress) { int i; const char *v = data + *cursor; if (suppress) { - fprintf(pfdebug, " 'BBBB'"); + appendPQExpBufferStr(buf, " 'BBBB'"); *cursor += len; return; } - fprintf(pfdebug, " \'"); + appendPQExpBufferStr(buf, " \'"); for (i = 0; i < len; ++i) - fprintf(pfdebug, "\\x%02x", (unsigned char) v[i]); + appendPQExpBuffer(buf, "\\x%02x", (unsigned char) v[i]); - fprintf(pfdebug, "\'"); + appendPQExpBufferStr(buf, "\'"); *cursor += len; } @@ -255,261 +252,261 @@ pqTraceOutputNbyte(FILE *pfdebug, int len, const char *data, int *cursor, bool s */ static void -pqTraceOutput_NotificationResponse(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_NotificationResponse(PQExpBuffer buf, const char *message, int *cursor, bool regress) { - fprintf(f, "NotificationResponse\t"); - pqTraceOutputInt32(f, message, cursor, regress); - pqTraceOutputString(f, message, cursor, false); - pqTraceOutputString(f, message, cursor, false); + appendPQExpBufferStr(buf, "NotificationResponse\t"); + pqTraceOutputInt32(buf, message, cursor, regress); + pqTraceOutputString(buf, message, cursor, false); + pqTraceOutputString(buf, message, cursor, false); } static void -pqTraceOutput_Bind(FILE *f, const char *message, int *cursor) +pqTraceOutput_Bind(PQExpBuffer buf, const char *message, int *cursor) { int nparams; - fprintf(f, "Bind\t"); - pqTraceOutputString(f, message, cursor, false); - pqTraceOutputString(f, message, cursor, false); - nparams = pqTraceOutputInt16(f, message, cursor); + appendPQExpBufferStr(buf, "Bind\t"); + pqTraceOutputString(buf, message, cursor, false); + pqTraceOutputString(buf, message, cursor, false); + nparams = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nparams; i++) - pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt16(buf, message, cursor); - nparams = pqTraceOutputInt16(f, message, cursor); + nparams = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nparams; i++) { int nbytes; - nbytes = pqTraceOutputInt32(f, message, cursor, false); + nbytes = pqTraceOutputInt32(buf, message, cursor, false); if (nbytes == -1) continue; - pqTraceOutputNchar(f, nbytes, message, cursor, false); + pqTraceOutputNchar(buf, nbytes, message, cursor, false); } - nparams = pqTraceOutputInt16(f, message, cursor); + nparams = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nparams; i++) - pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt16(buf, message, cursor); } static void -pqTraceOutput_Close(FILE *f, const char *message, int *cursor) +pqTraceOutput_Close(PQExpBuffer buf, const char *message, int *cursor) { - fprintf(f, "Close\t"); - pqTraceOutputByte1(f, message, cursor); - pqTraceOutputString(f, message, cursor, false); + appendPQExpBufferStr(buf, "Close\t"); + pqTraceOutputByte1(buf, message, cursor); + pqTraceOutputString(buf, message, cursor, false); } static void -pqTraceOutput_CommandComplete(FILE *f, const char *message, int *cursor) +pqTraceOutput_CommandComplete(PQExpBuffer buf, const char *message, int *cursor) { - fprintf(f, "CommandComplete\t"); - pqTraceOutputString(f, message, cursor, false); + appendPQExpBufferStr(buf, "CommandComplete\t"); + pqTraceOutputString(buf, message, cursor, false); } static void -pqTraceOutput_CopyData(FILE *f, const char *message, int *cursor, int length, +pqTraceOutput_CopyData(PQExpBuffer buf, const char *message, int *cursor, int length, bool suppress) { - fprintf(f, "CopyData\t"); - pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, suppress); + appendPQExpBufferStr(buf, "CopyData\t"); + pqTraceOutputNchar(buf, length - *cursor + 1, message, cursor, suppress); } static void -pqTraceOutput_DataRow(FILE *f, const char *message, int *cursor) +pqTraceOutput_DataRow(PQExpBuffer buf, const char *message, int *cursor) { int nfields; int len; int i; - fprintf(f, "DataRow\t"); - nfields = pqTraceOutputInt16(f, message, cursor); + appendPQExpBufferStr(buf, "DataRow\t"); + nfields = pqTraceOutputInt16(buf, message, cursor); for (i = 0; i < nfields; i++) { - len = pqTraceOutputInt32(f, message, cursor, false); + len = pqTraceOutputInt32(buf, message, cursor, false); if (len == -1) continue; - pqTraceOutputNchar(f, len, message, cursor, false); + pqTraceOutputNchar(buf, len, message, cursor, false); } } static void -pqTraceOutput_Describe(FILE *f, const char *message, int *cursor) +pqTraceOutput_Describe(PQExpBuffer buf, const char *message, int *cursor) { - fprintf(f, "Describe\t"); - pqTraceOutputByte1(f, message, cursor); - pqTraceOutputString(f, message, cursor, false); + appendPQExpBufferStr(buf, "Describe\t"); + pqTraceOutputByte1(buf, message, cursor); + pqTraceOutputString(buf, message, cursor, false); } /* shared code NoticeResponse / ErrorResponse */ static void -pqTraceOutputNR(FILE *f, const char *type, const char *message, int *cursor, +pqTraceOutputNR(PQExpBuffer buf, const char *type, const char *message, int *cursor, bool regress) { - fprintf(f, "%s\t", type); + appendPQExpBuffer(buf, "%s\t", type); for (;;) { char field; bool suppress; - pqTraceOutputByte1(f, message, cursor); + pqTraceOutputByte1(buf, message, cursor); field = message[*cursor - 1]; if (field == '\0') break; suppress = regress && (field == 'L' || field == 'F' || field == 'R'); - pqTraceOutputString(f, message, cursor, suppress); + pqTraceOutputString(buf, message, cursor, suppress); } } static void -pqTraceOutput_ErrorResponse(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_ErrorResponse(PQExpBuffer buf, const char *message, int *cursor, bool regress) { - pqTraceOutputNR(f, "ErrorResponse", message, cursor, regress); + pqTraceOutputNR(buf, "ErrorResponse", message, cursor, regress); } static void -pqTraceOutput_NoticeResponse(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_NoticeResponse(PQExpBuffer buf, const char *message, int *cursor, bool regress) { - pqTraceOutputNR(f, "NoticeResponse", message, cursor, regress); + pqTraceOutputNR(buf, "NoticeResponse", message, cursor, regress); } static void -pqTraceOutput_Execute(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_Execute(PQExpBuffer buf, const char *message, int *cursor, bool regress) { - fprintf(f, "Execute\t"); - pqTraceOutputString(f, message, cursor, false); - pqTraceOutputInt32(f, message, cursor, false); + appendPQExpBufferStr(buf, "Execute\t"); + pqTraceOutputString(buf, message, cursor, false); + pqTraceOutputInt32(buf, message, cursor, false); } static void -pqTraceOutput_CopyFail(FILE *f, const char *message, int *cursor) +pqTraceOutput_CopyFail(PQExpBuffer buf, const char *message, int *cursor) { - fprintf(f, "CopyFail\t"); - pqTraceOutputString(f, message, cursor, false); + appendPQExpBufferStr(buf, "CopyFail\t"); + pqTraceOutputString(buf, message, cursor, false); } static void -pqTraceOutput_GSSResponse(FILE *f, const char *message, int *cursor, +pqTraceOutput_GSSResponse(PQExpBuffer buf, const char *message, int *cursor, int length, bool regress) { - fprintf(f, "GSSResponse\t"); - pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, regress); + appendPQExpBufferStr(buf, "GSSResponse\t"); + pqTraceOutputNchar(buf, length - *cursor + 1, message, cursor, regress); } static void -pqTraceOutput_PasswordMessage(FILE *f, const char *message, int *cursor) +pqTraceOutput_PasswordMessage(PQExpBuffer buf, const char *message, int *cursor) { - fprintf(f, "PasswordMessage\t"); - pqTraceOutputString(f, message, cursor, false); + appendPQExpBufferStr(buf, "PasswordMessage\t"); + pqTraceOutputString(buf, message, cursor, false); } static void -pqTraceOutput_SASLInitialResponse(FILE *f, const char *message, int *cursor, +pqTraceOutput_SASLInitialResponse(PQExpBuffer buf, const char *message, int *cursor, bool regress) { int initialResponse; - fprintf(f, "SASLInitialResponse\t"); - pqTraceOutputString(f, message, cursor, false); - initialResponse = pqTraceOutputInt32(f, message, cursor, false); + appendPQExpBufferStr(buf, "SASLInitialResponse\t"); + pqTraceOutputString(buf, message, cursor, false); + initialResponse = pqTraceOutputInt32(buf, message, cursor, false); if (initialResponse != -1) - pqTraceOutputNchar(f, initialResponse, message, cursor, regress); + pqTraceOutputNchar(buf, initialResponse, message, cursor, regress); } static void -pqTraceOutput_SASLResponse(FILE *f, const char *message, int *cursor, +pqTraceOutput_SASLResponse(PQExpBuffer buf, const char *message, int *cursor, int length, bool regress) { - fprintf(f, "SASLResponse\t"); - pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, regress); + appendPQExpBufferStr(buf, "SASLResponse\t"); + pqTraceOutputNchar(buf, length - *cursor + 1, message, cursor, regress); } static void -pqTraceOutput_FunctionCall(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_FunctionCall(PQExpBuffer buf, const char *message, int *cursor, bool regress) { int nfields; int nbytes; - fprintf(f, "FunctionCall\t"); - pqTraceOutputInt32(f, message, cursor, regress); - nfields = pqTraceOutputInt16(f, message, cursor); + appendPQExpBufferStr(buf, "FunctionCall\t"); + pqTraceOutputInt32(buf, message, cursor, regress); + nfields = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nfields; i++) - pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt16(buf, message, cursor); - nfields = pqTraceOutputInt16(f, message, cursor); + nfields = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nfields; i++) { - nbytes = pqTraceOutputInt32(f, message, cursor, false); + nbytes = pqTraceOutputInt32(buf, message, cursor, false); if (nbytes == -1) continue; - pqTraceOutputNchar(f, nbytes, message, cursor, false); + pqTraceOutputNchar(buf, nbytes, message, cursor, false); } - pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt16(buf, message, cursor); } static void -pqTraceOutput_CopyInResponse(FILE *f, const char *message, int *cursor) +pqTraceOutput_CopyInResponse(PQExpBuffer buf, const char *message, int *cursor) { int nfields; - fprintf(f, "CopyInResponse\t"); - pqTraceOutputByte1(f, message, cursor); - nfields = pqTraceOutputInt16(f, message, cursor); + appendPQExpBufferStr(buf, "CopyInResponse\t"); + pqTraceOutputByte1(buf, message, cursor); + nfields = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nfields; i++) - pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt16(buf, message, cursor); } static void -pqTraceOutput_CopyOutResponse(FILE *f, const char *message, int *cursor) +pqTraceOutput_CopyOutResponse(PQExpBuffer buf, const char *message, int *cursor) { int nfields; - fprintf(f, "CopyOutResponse\t"); - pqTraceOutputByte1(f, message, cursor); - nfields = pqTraceOutputInt16(f, message, cursor); + appendPQExpBufferStr(buf, "CopyOutResponse\t"); + pqTraceOutputByte1(buf, message, cursor); + nfields = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nfields; i++) - pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt16(buf, message, cursor); } static void -pqTraceOutput_BackendKeyData(FILE *f, const char *message, int *cursor, int length, +pqTraceOutput_BackendKeyData(PQExpBuffer buf, const char *message, int *cursor, int length, bool regress) { - fprintf(f, "BackendKeyData\t"); - pqTraceOutputInt32(f, message, cursor, regress); - pqTraceOutputNbyte(f, length - *cursor + 1, message, cursor, regress); + appendPQExpBufferStr(buf, "BackendKeyData\t"); + pqTraceOutputInt32(buf, message, cursor, regress); + pqTraceOutputNbyte(buf, length - *cursor + 1, message, cursor, regress); } static void -pqTraceOutput_Parse(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_Parse(PQExpBuffer buf, const char *message, int *cursor, bool regress) { int nparams; - fprintf(f, "Parse\t"); - pqTraceOutputString(f, message, cursor, false); - pqTraceOutputString(f, message, cursor, false); - nparams = pqTraceOutputInt16(f, message, cursor); + appendPQExpBufferStr(buf, "Parse\t"); + pqTraceOutputString(buf, message, cursor, false); + pqTraceOutputString(buf, message, cursor, false); + nparams = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nparams; i++) - pqTraceOutputInt32(f, message, cursor, regress); + pqTraceOutputInt32(buf, message, cursor, regress); } static void -pqTraceOutput_Query(FILE *f, const char *message, int *cursor) +pqTraceOutput_Query(PQExpBuffer buf, const char *message, int *cursor) { - fprintf(f, "Query\t"); - pqTraceOutputString(f, message, cursor, false); + appendPQExpBufferStr(buf, "Query\t"); + pqTraceOutputString(buf, message, cursor, false); } static void -pqTraceOutput_Authentication(FILE *f, const char *message, int *cursor, +pqTraceOutput_Authentication(PQExpBuffer buf, const char *message, int *cursor, int length, bool suppress) { int authType = 0; @@ -520,129 +517,129 @@ pqTraceOutput_Authentication(FILE *f, const char *message, int *cursor, switch (authType) { case AUTH_REQ_OK: - fprintf(f, "AuthenticationOk"); + appendPQExpBufferStr(buf, "AuthenticationOk"); break; /* AUTH_REQ_KRB4 not supported */ /* AUTH_REQ_KRB5 not supported */ case AUTH_REQ_PASSWORD: - fprintf(f, "AuthenticationCleartextPassword"); + appendPQExpBufferStr(buf, "AuthenticationCleartextPassword"); break; /* AUTH_REQ_CRYPT not supported */ case AUTH_REQ_MD5: - fprintf(f, "AuthenticationMD5Password"); + appendPQExpBufferStr(buf, "AuthenticationMD5Password"); break; case AUTH_REQ_GSS: - fprintf(f, "AuthenticationGSS"); + appendPQExpBufferStr(buf, "AuthenticationGSS"); break; case AUTH_REQ_GSS_CONT: - fprintf(f, "AuthenticationGSSContinue\t"); - pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, + appendPQExpBufferStr(buf, "AuthenticationGSSContinue\t"); + pqTraceOutputNchar(buf, length - *cursor + 1, message, cursor, suppress); break; case AUTH_REQ_SSPI: - fprintf(f, "AuthenticationSSPI"); + appendPQExpBufferStr(buf, "AuthenticationSSPI"); break; case AUTH_REQ_SASL: - fprintf(f, "AuthenticationSASL\t"); + appendPQExpBufferStr(buf, "AuthenticationSASL\t"); while (message[*cursor] != '\0') - pqTraceOutputString(f, message, cursor, false); - pqTraceOutputString(f, message, cursor, false); + pqTraceOutputString(buf, message, cursor, false); + pqTraceOutputString(buf, message, cursor, false); break; case AUTH_REQ_SASL_CONT: - fprintf(f, "AuthenticationSASLContinue\t"); - pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, + appendPQExpBufferStr(buf, "AuthenticationSASLContinue\t"); + pqTraceOutputNchar(buf, length - *cursor + 1, message, cursor, suppress); break; case AUTH_REQ_SASL_FIN: - fprintf(f, "AuthenticationSASLFinal\t"); - pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, + appendPQExpBufferStr(buf, "AuthenticationSASLFinal\t"); + pqTraceOutputNchar(buf, length - *cursor + 1, message, cursor, suppress); break; default: - fprintf(f, "Unknown authentication message %d", authType); + appendPQExpBuffer(buf, "Unknown authentication message %d", authType); } } static void -pqTraceOutput_ParameterStatus(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_ParameterStatus(PQExpBuffer buf, const char *message, int *cursor, bool regress) { - fprintf(f, "ParameterStatus\t"); - pqTraceOutputString(f, message, cursor, false); - pqTraceOutputString(f, message, cursor, regress); + appendPQExpBufferStr(buf, "ParameterStatus\t"); + pqTraceOutputString(buf, message, cursor, false); + pqTraceOutputString(buf, message, cursor, regress); } static void -pqTraceOutput_ParameterDescription(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_ParameterDescription(PQExpBuffer buf, const char *message, int *cursor, bool regress) { int nfields; - fprintf(f, "ParameterDescription\t"); - nfields = pqTraceOutputInt16(f, message, cursor); + appendPQExpBufferStr(buf, "ParameterDescription\t"); + nfields = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nfields; i++) - pqTraceOutputInt32(f, message, cursor, regress); + pqTraceOutputInt32(buf, message, cursor, regress); } static void -pqTraceOutput_RowDescription(FILE *f, const char *message, int *cursor, bool regress) +pqTraceOutput_RowDescription(PQExpBuffer buf, const char *message, int *cursor, bool regress) { int nfields; - fprintf(f, "RowDescription\t"); - nfields = pqTraceOutputInt16(f, message, cursor); + appendPQExpBufferStr(buf, "RowDescription\t"); + nfields = pqTraceOutputInt16(buf, message, cursor); for (int i = 0; i < nfields; i++) { - pqTraceOutputString(f, message, cursor, false); - pqTraceOutputInt32(f, message, cursor, regress); - pqTraceOutputInt16(f, message, cursor); - pqTraceOutputInt32(f, message, cursor, regress); - pqTraceOutputInt16(f, message, cursor); - pqTraceOutputInt32(f, message, cursor, false); - pqTraceOutputInt16(f, message, cursor); + pqTraceOutputString(buf, message, cursor, false); + pqTraceOutputInt32(buf, message, cursor, regress); + pqTraceOutputInt16(buf, message, cursor); + pqTraceOutputInt32(buf, message, cursor, regress); + pqTraceOutputInt16(buf, message, cursor); + pqTraceOutputInt32(buf, message, cursor, false); + pqTraceOutputInt16(buf, message, cursor); } } static void -pqTraceOutput_NegotiateProtocolVersion(FILE *f, const char *message, int *cursor) +pqTraceOutput_NegotiateProtocolVersion(PQExpBuffer buf, const char *message, int *cursor) { int nparams; - fprintf(f, "NegotiateProtocolVersion\t"); - pqTraceOutputInt32(f, message, cursor, false); - nparams = pqTraceOutputInt32(f, message, cursor, false); + appendPQExpBufferStr(buf, "NegotiateProtocolVersion\t"); + pqTraceOutputInt32(buf, message, cursor, false); + nparams = pqTraceOutputInt32(buf, message, cursor, false); for (int i = 0; i < nparams; i++) { - pqTraceOutputString(f, message, cursor, false); + pqTraceOutputString(buf, message, cursor, false); } } static void -pqTraceOutput_FunctionCallResponse(FILE *f, const char *message, int *cursor) +pqTraceOutput_FunctionCallResponse(PQExpBuffer buf, const char *message, int *cursor) { int len; - fprintf(f, "FunctionCallResponse\t"); - len = pqTraceOutputInt32(f, message, cursor, false); + appendPQExpBufferStr(buf, "FunctionCallResponse\t"); + len = pqTraceOutputInt32(buf, message, cursor, false); if (len != -1) - pqTraceOutputNchar(f, len, message, cursor, false); + pqTraceOutputNchar(buf, len, message, cursor, false); } static void -pqTraceOutput_CopyBothResponse(FILE *f, const char *message, int *cursor, int length) +pqTraceOutput_CopyBothResponse(PQExpBuffer buf, const char *message, int *cursor, int length) { - fprintf(f, "CopyBothResponse\t"); - pqTraceOutputByte1(f, message, cursor); + appendPQExpBufferStr(buf, "CopyBothResponse\t"); + pqTraceOutputByte1(buf, message, cursor); while (length > *cursor) - pqTraceOutputInt16(f, message, cursor); + pqTraceOutputInt16(buf, message, cursor); } static void -pqTraceOutput_ReadyForQuery(FILE *f, const char *message, int *cursor) +pqTraceOutput_ReadyForQuery(PQExpBuffer buf, const char *message, int *cursor) { - fprintf(f, "ReadyForQuery\t"); - pqTraceOutputByte1(f, message, cursor); + appendPQExpBufferStr(buf, "ReadyForQuery\t"); + pqTraceOutputByte1(buf, message, cursor); } /* @@ -656,13 +653,16 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) char *prefix = toServer ? "F" : "B"; int logCursor = 0; bool regress; + PQExpBufferData buf; + + initPQExpBuffer(&buf); if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0) { char timestr[128]; pqTraceFormatTimestamp(timestr, sizeof(timestr)); - fprintf(conn->Pfdebug, "%s\t", timestr); + appendPQExpBuffer(&buf, "%s\t", timestr); } regress = (conn->traceFlags & PQTRACE_REGRESS_MODE) != 0; @@ -683,64 +683,64 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) if (regress && !toServer && (id == PqMsg_ErrorResponse || id == PqMsg_NoticeResponse || id == PqMsg_ParameterStatus)) - fprintf(conn->Pfdebug, "%s\tNN\t", prefix); + appendPQExpBuffer(&buf, "%s\tNN\t", prefix); else - fprintf(conn->Pfdebug, "%s\t%d\t", prefix, length); + appendPQExpBuffer(&buf, "%s\t%d\t", prefix, length); switch (id) { case PqMsg_ParseComplete: - fprintf(conn->Pfdebug, "ParseComplete"); + appendPQExpBufferStr(&buf, "ParseComplete"); /* No message content */ break; case PqMsg_BindComplete: - fprintf(conn->Pfdebug, "BindComplete"); + appendPQExpBufferStr(&buf, "BindComplete"); /* No message content */ break; case PqMsg_CloseComplete: - fprintf(conn->Pfdebug, "CloseComplete"); + appendPQExpBufferStr(&buf, "CloseComplete"); /* No message content */ break; case PqMsg_NotificationResponse: - pqTraceOutput_NotificationResponse(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_NotificationResponse(&buf, message, &logCursor, regress); break; case PqMsg_Bind: - pqTraceOutput_Bind(conn->Pfdebug, message, &logCursor); + pqTraceOutput_Bind(&buf, message, &logCursor); break; case PqMsg_CopyDone: - fprintf(conn->Pfdebug, "CopyDone"); + appendPQExpBufferStr(&buf, "CopyDone"); /* No message content */ break; case PqMsg_CommandComplete: /* Close(F) and CommandComplete(B) use the same identifier. */ Assert(PqMsg_Close == PqMsg_CommandComplete); if (toServer) - pqTraceOutput_Close(conn->Pfdebug, message, &logCursor); + pqTraceOutput_Close(&buf, message, &logCursor); else - pqTraceOutput_CommandComplete(conn->Pfdebug, message, &logCursor); + pqTraceOutput_CommandComplete(&buf, message, &logCursor); break; case PqMsg_CopyData: - pqTraceOutput_CopyData(conn->Pfdebug, message, &logCursor, + pqTraceOutput_CopyData(&buf, message, &logCursor, length, regress); break; case PqMsg_Describe: /* Describe(F) and DataRow(B) use the same identifier. */ Assert(PqMsg_Describe == PqMsg_DataRow); if (toServer) - pqTraceOutput_Describe(conn->Pfdebug, message, &logCursor); + pqTraceOutput_Describe(&buf, message, &logCursor); else - pqTraceOutput_DataRow(conn->Pfdebug, message, &logCursor); + pqTraceOutput_DataRow(&buf, message, &logCursor); break; case PqMsg_Execute: /* Execute(F) and ErrorResponse(B) use the same identifier. */ Assert(PqMsg_Execute == PqMsg_ErrorResponse); if (toServer) - pqTraceOutput_Execute(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_Execute(&buf, message, &logCursor, regress); else - pqTraceOutput_ErrorResponse(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_ErrorResponse(&buf, message, &logCursor, regress); break; case PqMsg_CopyFail: - pqTraceOutput_CopyFail(conn->Pfdebug, message, &logCursor); + pqTraceOutput_CopyFail(&buf, message, &logCursor); break; case PqMsg_GSSResponse: Assert(PqMsg_GSSResponse == PqMsg_PasswordMessage); @@ -754,106 +754,106 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) switch (conn->current_auth_response) { case AUTH_RESPONSE_GSS: - pqTraceOutput_GSSResponse(conn->Pfdebug, message, + pqTraceOutput_GSSResponse(&buf, message, &logCursor, length, regress); break; case AUTH_RESPONSE_PASSWORD: - pqTraceOutput_PasswordMessage(conn->Pfdebug, message, + pqTraceOutput_PasswordMessage(&buf, message, &logCursor); break; case AUTH_RESPONSE_SASL_INITIAL: - pqTraceOutput_SASLInitialResponse(conn->Pfdebug, message, + pqTraceOutput_SASLInitialResponse(&buf, message, &logCursor, regress); break; case AUTH_RESPONSE_SASL: - pqTraceOutput_SASLResponse(conn->Pfdebug, message, + pqTraceOutput_SASLResponse(&buf, message, &logCursor, length, regress); break; default: - fprintf(conn->Pfdebug, "UnknownAuthenticationResponse"); + appendPQExpBufferStr(&buf, "UnknownAuthenticationResponse"); break; } conn->current_auth_response = '\0'; break; case PqMsg_FunctionCall: - pqTraceOutput_FunctionCall(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_FunctionCall(&buf, message, &logCursor, regress); break; case PqMsg_CopyInResponse: - pqTraceOutput_CopyInResponse(conn->Pfdebug, message, &logCursor); + pqTraceOutput_CopyInResponse(&buf, message, &logCursor); break; case PqMsg_Flush: /* Flush(F) and CopyOutResponse(B) use the same identifier */ Assert(PqMsg_CopyOutResponse == PqMsg_Flush); if (toServer) - fprintf(conn->Pfdebug, "Flush"); /* no message content */ + appendPQExpBufferStr(&buf, "Flush"); /* no message content */ else - pqTraceOutput_CopyOutResponse(conn->Pfdebug, message, &logCursor); + pqTraceOutput_CopyOutResponse(&buf, message, &logCursor); break; case PqMsg_EmptyQueryResponse: - fprintf(conn->Pfdebug, "EmptyQueryResponse"); + appendPQExpBufferStr(&buf, "EmptyQueryResponse"); /* No message content */ break; case PqMsg_BackendKeyData: - pqTraceOutput_BackendKeyData(conn->Pfdebug, message, &logCursor, + pqTraceOutput_BackendKeyData(&buf, message, &logCursor, length, regress); break; case PqMsg_NoData: - fprintf(conn->Pfdebug, "NoData"); + appendPQExpBufferStr(&buf, "NoData"); /* No message content */ break; case PqMsg_NoticeResponse: - pqTraceOutput_NoticeResponse(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_NoticeResponse(&buf, message, &logCursor, regress); break; case PqMsg_Parse: - pqTraceOutput_Parse(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_Parse(&buf, message, &logCursor, regress); break; case PqMsg_Query: - pqTraceOutput_Query(conn->Pfdebug, message, &logCursor); + pqTraceOutput_Query(&buf, message, &logCursor); break; case PqMsg_AuthenticationRequest: - pqTraceOutput_Authentication(conn->Pfdebug, message, &logCursor, + pqTraceOutput_Authentication(&buf, message, &logCursor, length, regress); break; case PqMsg_PortalSuspended: - fprintf(conn->Pfdebug, "PortalSuspended"); + appendPQExpBufferStr(&buf, "PortalSuspended"); /* No message content */ break; case PqMsg_Sync: /* ParameterStatus(B) and Sync(F) use the same identifier */ Assert(PqMsg_ParameterStatus == PqMsg_Sync); if (toServer) - fprintf(conn->Pfdebug, "Sync"); /* no message content */ + appendPQExpBufferStr(&buf, "Sync"); /* no message content */ else - pqTraceOutput_ParameterStatus(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_ParameterStatus(&buf, message, &logCursor, regress); break; case PqMsg_ParameterDescription: - pqTraceOutput_ParameterDescription(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_ParameterDescription(&buf, message, &logCursor, regress); break; case PqMsg_RowDescription: - pqTraceOutput_RowDescription(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutput_RowDescription(&buf, message, &logCursor, regress); break; case PqMsg_NegotiateProtocolVersion: - pqTraceOutput_NegotiateProtocolVersion(conn->Pfdebug, message, &logCursor); + pqTraceOutput_NegotiateProtocolVersion(&buf, message, &logCursor); break; case PqMsg_FunctionCallResponse: - pqTraceOutput_FunctionCallResponse(conn->Pfdebug, message, &logCursor); + pqTraceOutput_FunctionCallResponse(&buf, message, &logCursor); break; case PqMsg_CopyBothResponse: - pqTraceOutput_CopyBothResponse(conn->Pfdebug, message, &logCursor, length); + pqTraceOutput_CopyBothResponse(&buf, message, &logCursor, length); break; case PqMsg_Terminate: - fprintf(conn->Pfdebug, "Terminate"); + appendPQExpBufferStr(&buf, "Terminate"); /* No message content */ break; case PqMsg_ReadyForQuery: - pqTraceOutput_ReadyForQuery(conn->Pfdebug, message, &logCursor); + pqTraceOutput_ReadyForQuery(&buf, message, &logCursor); break; default: - fprintf(conn->Pfdebug, "Unknown message: %02x", id); + appendPQExpBuffer(&buf, "Unknown message: %02x", id); break; } - fputc('\n', conn->Pfdebug); + appendPQExpBufferChar(&buf, '\n'); /* * Verify the printing routine did it right. Note that the one-byte @@ -861,9 +861,12 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) * include it. */ if (logCursor - 1 != length) - fprintf(conn->Pfdebug, - "mismatched message length: consumed %d, expected %d\n", - logCursor - 1, length); + appendPQExpBuffer(&buf, + "mismatched message length: consumed %d, expected %d\n", + logCursor - 1, length); + + fprintf(conn->Pfdebug, "%s", buf.data); + termPQExpBuffer(&buf); } /* @@ -877,7 +880,9 @@ pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message) int version; bool regress; int logCursor = 0; + PQExpBufferData buf; + initPQExpBuffer(&buf); regress = (conn->traceFlags & PQTRACE_REGRESS_MODE) != 0; if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0) @@ -885,7 +890,7 @@ pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message) char timestr[128]; pqTraceFormatTimestamp(timestr, sizeof(timestr)); - fprintf(conn->Pfdebug, "%s\t", timestr); + appendPQExpBuffer(&buf, "%s\t", timestr); } memcpy(&length, message + logCursor, 4); @@ -894,7 +899,9 @@ pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message) if (length < 8) { - fprintf(conn->Pfdebug, "F\t%d\tUnknown message\n", length); + appendPQExpBuffer(&buf, "F\t%d\tUnknown message\n", length); + fprintf(conn->Pfdebug, "%s", buf.data); + termPQExpBuffer(&buf); return; } @@ -909,40 +916,40 @@ pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message) if (regress && (version != CANCEL_REQUEST_CODE && version != NEGOTIATE_SSL_CODE && version != NEGOTIATE_GSS_CODE)) - fprintf(conn->Pfdebug, "F\tNN\t"); + appendPQExpBufferStr(&buf, "F\tNN\t"); else - fprintf(conn->Pfdebug, "F\t%d\t", length); + appendPQExpBuffer(&buf, "F\t%d\t", length); if (version == CANCEL_REQUEST_CODE && length >= 16) { - fprintf(conn->Pfdebug, "CancelRequest\t"); - pqTraceOutputInt16(conn->Pfdebug, message, &logCursor); - pqTraceOutputInt16(conn->Pfdebug, message, &logCursor); - pqTraceOutputInt32(conn->Pfdebug, message, &logCursor, regress); - pqTraceOutputNbyte(conn->Pfdebug, length - logCursor, message, + appendPQExpBufferStr(&buf, "CancelRequest\t"); + pqTraceOutputInt16(&buf, message, &logCursor); + pqTraceOutputInt16(&buf, message, &logCursor); + pqTraceOutputInt32(&buf, message, &logCursor, regress); + pqTraceOutputNbyte(&buf, length - logCursor, message, &logCursor, regress); } else if (version == NEGOTIATE_SSL_CODE) { - fprintf(conn->Pfdebug, "SSLRequest\t"); - pqTraceOutputInt16(conn->Pfdebug, message, &logCursor); - pqTraceOutputInt16(conn->Pfdebug, message, &logCursor); + appendPQExpBufferStr(&buf, "SSLRequest\t"); + pqTraceOutputInt16(&buf, message, &logCursor); + pqTraceOutputInt16(&buf, message, &logCursor); } else if (version == NEGOTIATE_GSS_CODE) { - fprintf(conn->Pfdebug, "GSSENCRequest\t"); - pqTraceOutputInt16(conn->Pfdebug, message, &logCursor); - pqTraceOutputInt16(conn->Pfdebug, message, &logCursor); + appendPQExpBufferStr(&buf, "GSSENCRequest\t"); + pqTraceOutputInt16(&buf, message, &logCursor); + pqTraceOutputInt16(&buf, message, &logCursor); } else { - fprintf(conn->Pfdebug, "StartupMessage\t"); - pqTraceOutputInt16(conn->Pfdebug, message, &logCursor); - pqTraceOutputInt16(conn->Pfdebug, message, &logCursor); + appendPQExpBufferStr(&buf, "StartupMessage\t"); + pqTraceOutputInt16(&buf, message, &logCursor); + pqTraceOutputInt16(&buf, message, &logCursor); while (message[logCursor] != '\0') { - pqTraceOutputString(conn->Pfdebug, message, &logCursor, false); - pqTraceOutputString(conn->Pfdebug, message, &logCursor, regress); + pqTraceOutputString(&buf, message, &logCursor, false); + pqTraceOutputString(&buf, message, &logCursor, regress); } /* @@ -952,16 +959,19 @@ pqTraceOutputNoTypeByteMessage(PGconn *conn, const char *message) logCursor++; } - fputc('\n', conn->Pfdebug); + appendPQExpBufferChar(&buf, '\n'); /* * Verify the printing routine did it right. There's no one-byte message * identifier here, so logCursor should match the length */ if (logCursor != length) - fprintf(conn->Pfdebug, - "mismatched message length: consumed %d, expected %d\n", - logCursor, length); + appendPQExpBuffer(&buf, + "mismatched message length: consumed %d, expected %d\n", + logCursor, length); + + fprintf(conn->Pfdebug, "%s", buf.data); + termPQExpBuffer(&buf); } /* @@ -973,13 +983,20 @@ void pqTraceOutputCharResponse(PGconn *conn, const char *responseType, char response) { + PQExpBufferData buf; + + initPQExpBuffer(&buf); + if ((conn->traceFlags & PQTRACE_SUPPRESS_TIMESTAMPS) == 0) { char timestr[128]; pqTraceFormatTimestamp(timestr, sizeof(timestr)); - fprintf(conn->Pfdebug, "%s\t", timestr); + appendPQExpBuffer(&buf, "%s\t", timestr); } - fprintf(conn->Pfdebug, "B\t1\t%s\t %c\n", responseType, response); + appendPQExpBuffer(&buf, "B\t1\t%s\t %c\n", responseType, response); + + fprintf(conn->Pfdebug, "%s", buf.data); + termPQExpBuffer(&buf); } -- 2.54.0