From 83253fc28dbf76df9f1718f6f6d8a3e644ddb494 Mon Sep 17 00:00:00 2001 From: Anthonin Bonnefoy Date: Wed, 8 Jul 2026 08:39:07 +0200 Subject: Make pqtrace write lines atomically Currently, pqtrace writes are done by doing multiple fprintf per line to the Pfdebug fd. This commit changes fe-trace.c to buffer each line in a PQExpBuffer, and write lines in Pfdebug in a single fwrite. This allows multiple connections to write on stdout without interfering with each other. --- 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..383a924d5c5 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); + + fwrite(buf.data, 1, buf.len, conn->Pfdebug); + 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); + + fwrite(buf.data, 1, buf.len, conn->Pfdebug); + 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.55.0