diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 4da07c1f986..5c8f404463f 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -94,6 +94,10 @@ pg_GSS_continue(PGconn *conn, int payloadlen) ginbuf.value = NULL; } + /* finished parsing, trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + /* Only try to acquire credentials if GSS delegation isn't disabled. */ if (!pg_GSS_have_cred_cache(&conn->gcred)) conn->gcred = GSS_C_NO_CREDENTIAL; @@ -258,6 +262,10 @@ pg_SSPI_continue(PGconn *conn, int payloadlen) InBuffers[0].BufferType = SECBUFFER_TOKEN; } + /* finished parsing, trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + OutBuffers[0].pvBuffer = NULL; OutBuffers[0].BufferType = SECBUFFER_TOKEN; OutBuffers[0].cbBuffer = 0; @@ -563,6 +571,10 @@ pg_SASL_init(PGconn *conn, int payloadlen) } } + /* finished parsing, trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + Assert(conn->sasl); /* @@ -651,6 +663,11 @@ pg_SASL_continue(PGconn *conn, int payloadlen, bool final) free(challenge); return STATUS_ERROR; } + + /* finished parsing, trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + /* For safety and convenience, ensure the buffer is NULL-terminated. */ challenge[payloadlen] = '\0'; @@ -716,6 +733,10 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq) return STATUS_ERROR; /* shouldn't happen */ } + /* finished parsing, trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + /* Encrypt the password if needed. */ switch (areq) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 246055df960..ab308a0580f 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -3797,7 +3797,7 @@ keep_going: /* We will come back to here until there is return PGRES_POLLING_READING; } /* OK, we read the message; mark data consumed */ - conn->inStart = conn->inCursor; + pqParseDone(conn, conn->inCursor); /* * Before 7.2, the postmaster didn't always end its @@ -3847,7 +3847,7 @@ keep_going: /* We will come back to here until there is goto error_return; } /* OK, we read the message; mark data consumed */ - conn->inStart = conn->inCursor; + pqParseDone(conn, conn->inCursor); /* * If error is "cannot connect now", try the next host if @@ -3876,7 +3876,7 @@ keep_going: /* We will come back to here until there is goto error_return; } /* OK, we read the message; mark data consumed */ - conn->inStart = conn->inCursor; + pqParseDone(conn, conn->inCursor); goto error_return; } @@ -3901,7 +3901,11 @@ keep_going: /* We will come back to here until there is */ res = pg_fe_sendauth(areq, msgLength, conn); - /* OK, we have processed the message; mark data consumed */ + /* + * OK, we have processed the message; mark data consumed. We + * don't call pqParseDone here because we already traced this + * message inside pg_fe_sendauth. + */ conn->inStart = conn->inCursor; if (res != STATUS_OK) diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index f235bfbb41f..928a47162d1 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -435,6 +435,21 @@ pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn) return EOF; } +/* + * pqParseDone: after a server-to-client message has successfully + * been parsed, advance conn->inStart to account for it. + */ +void +pqParseDone(PGconn *conn, int newInStart) +{ + /* trace server-to-client message */ + if (conn->Pfdebug) + pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); + + /* Mark message as done */ + conn->inStart = newInStart; +} + /* * pqPutMsgStart: begin construction of a message to the server * diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c index 3170d484f02..8c5ac1729f0 100644 --- a/src/interfaces/libpq/fe-protocol3.c +++ b/src/interfaces/libpq/fe-protocol3.c @@ -454,12 +454,8 @@ pqParseInput3(PGconn *conn) /* Successfully consumed this message */ if (conn->inCursor == conn->inStart + 5 + msgLength) { - /* trace server-to-client message */ - if (conn->Pfdebug) - pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); - /* Normal case: parsing agrees with specified length */ - conn->inStart = conn->inCursor; + pqParseDone(conn, conn->inCursor); } else { @@ -1728,12 +1724,8 @@ getCopyDataMessage(PGconn *conn) return -1; } - /* trace server-to-client message */ - if (conn->Pfdebug) - pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); - /* Drop the processed message and loop around for another */ - conn->inStart = conn->inCursor; + pqParseDone(conn, conn->inCursor); } } @@ -1791,13 +1783,13 @@ pqGetCopyData3(PGconn *conn, char **buffer, int async) (*buffer)[msgLength] = '\0'; /* Add terminating null */ /* Mark message consumed */ - conn->inStart = conn->inCursor + msgLength; + pqParseDone(conn, conn->inCursor + msgLength); return msgLength; } /* Empty, so drop it and loop around for another */ - conn->inStart = conn->inCursor; + pqParseDone(conn, conn->inCursor); } } @@ -2168,8 +2160,9 @@ pqFunctionCall3(PGconn *conn, Oid fnid, case 'Z': /* backend is ready for new query */ if (getReadyForQuery(conn)) continue; - /* consume the message and exit */ - conn->inStart += 5 + msgLength; + + /* consume the message */ + pqParseDone(conn, conn->inStart + 5 + msgLength); /* * If we already have a result object (probably an error), use @@ -2194,6 +2187,7 @@ pqFunctionCall3(PGconn *conn, Oid fnid, pqSaveErrorResult(conn); } } + /* and we're out */ return pqPrepareAsyncResult(conn); case 'S': /* parameter status */ if (getParameterStatus(conn)) @@ -2203,18 +2197,18 @@ pqFunctionCall3(PGconn *conn, Oid fnid, /* The backend violates the protocol. */ libpq_append_conn_error(conn, "protocol error: id=0x%x", id); pqSaveErrorResult(conn); - /* trust the specified message length as what to skip */ + + /* + * We can't call parsing done due to the protocol violation + * (so message tracing wouldn't work), but trust the specified + * message length as what to skip. + */ conn->inStart += 5 + msgLength; return pqPrepareAsyncResult(conn); } - /* trace server-to-client message */ - if (conn->Pfdebug) - pqTraceOutputMessage(conn, conn->inBuffer + conn->inStart, false); - - /* Completed this message, keep going */ - /* trust the specified message length as what to skip */ - conn->inStart += 5 + msgLength; + /* Completed parsing this message, keep going */ + pqParseDone(conn, conn->inStart + 5 + msgLength); needInput = false; } diff --git a/src/interfaces/libpq/fe-trace.c b/src/interfaces/libpq/fe-trace.c index 3527b9f0f5d..bff7d919d57 100644 --- a/src/interfaces/libpq/fe-trace.c +++ b/src/interfaces/libpq/fe-trace.c @@ -280,6 +280,14 @@ pqTraceOutput_CommandComplete(FILE *f, const char *message, int *cursor) pqTraceOutputString(f, message, cursor, false); } +static void +pqTraceOutput_CopyData(FILE *f, const char *message, int *cursor, int length, + bool suppress) +{ + fprintf(f, "CopyData\t"); + pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, suppress); +} + static void pqTraceOutput_DataRow(FILE *f, const char *message, int *cursor) { @@ -472,10 +480,58 @@ pqTraceOutput_Query(FILE *f, const char *message, int *cursor) } static void -pqTraceOutput_Authentication(FILE *f, const char *message, int *cursor) +pqTraceOutput_Authentication(FILE *f, const char *message, int *cursor, + int length, bool suppress) { - fprintf(f, "Authentication\t"); - pqTraceOutputInt32(f, message, cursor, false); + int authType = 0; + + memcpy(&authType, message + *cursor, 4); + authType = (int) pg_ntoh32(authType); + *cursor += 4; + switch (authType) + { + case AUTH_REQ_OK: + fprintf(f, "AuthenticationOk"); + break; + /* AUTH_REQ_KRB4 not supported */ + /* AUTH_REQ_KRB5 not supported */ + case AUTH_REQ_PASSWORD: + fprintf(f, "AuthenticationCleartextPassword"); + break; + /* AUTH_REQ_CRYPT not supported */ + case AUTH_REQ_MD5: + fprintf(f, "AuthenticationMD5Password"); + break; + case AUTH_REQ_GSS: + fprintf(f, "AuthenticationGSS"); + break; + case AUTH_REQ_GSS_CONT: + fprintf(f, "AuthenticationGSSContinue\t"); + pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, + suppress); + break; + case AUTH_REQ_SSPI: + fprintf(f, "AuthenticationSSPI"); + break; + case AUTH_REQ_SASL: + fprintf(f, "AuthenticationSASL\t"); + while (message[*cursor] != '\0') + pqTraceOutputString(f, message, cursor, false); + pqTraceOutputString(f, message, cursor, false); + break; + case AUTH_REQ_SASL_CONT: + fprintf(f, "AuthenticationSASLContinue\t"); + pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, + suppress); + break; + case AUTH_REQ_SASL_FIN: + fprintf(f, "AuthenticationSASLFinal\t"); + pqTraceOutputNchar(f, length - *cursor + 1, message, cursor, + suppress); + break; + default: + fprintf(f, "Unknown authentication message %d", authType); + } } static void @@ -625,7 +681,8 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) pqTraceOutput_CommandComplete(conn->Pfdebug, message, &logCursor); break; case PqMsg_CopyData: - /* Drop COPY data to reduce the overhead of logging. */ + pqTraceOutput_CopyData(conn->Pfdebug, message, &logCursor, + length, regress); break; case PqMsg_Describe: /* Describe(F) and DataRow(B) use the same identifier. */ @@ -714,7 +771,8 @@ pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer) pqTraceOutput_Query(conn->Pfdebug, message, &logCursor); break; case PqMsg_AuthenticationRequest: - pqTraceOutput_Authentication(conn->Pfdebug, message, &logCursor); + pqTraceOutput_Authentication(conn->Pfdebug, message, &logCursor, + length, regress); break; case PqMsg_PortalSuspended: fprintf(conn->Pfdebug, "PortalSuspended"); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index d97b595c97f..8ed1b28fcc0 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -753,6 +753,7 @@ extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid, */ extern int pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn); extern int pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn); +extern void pqParseDone(PGconn *conn, int newInStart); extern int pqGetc(char *result, PGconn *conn); extern int pqPutc(char c, PGconn *conn); extern int pqGets(PQExpBuffer buf, PGconn *conn);