mirror of https://github.com/sysown/proxysql
parent
1c559e96d8
commit
fe701d29aa
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file PgSQLErrorFields.h
|
||||
* @brief Parser for PostgreSQL ErrorResponse message fields.
|
||||
*
|
||||
* Extracted for unit testability. Scans ErrorResponse payload for
|
||||
* SQLSTATE ('C') and message ('M') fields.
|
||||
*
|
||||
* @see PostgreSQL Protocol: ErrorResponse message format
|
||||
*/
|
||||
|
||||
#ifndef PGSQL_ERROR_FIELDS_H
|
||||
#define PGSQL_ERROR_FIELDS_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* @brief Result of parsing a PostgreSQL ErrorResponse payload.
|
||||
*/
|
||||
struct PgSQLErrorResult {
|
||||
bool parsed; ///< True if payload was non-null and scanned.
|
||||
char sqlstate[6]; ///< 5-char SQLSTATE + null terminator (empty if not found).
|
||||
const char* message; ///< Pointer into payload at 'M' field value (null if not found).
|
||||
size_t message_len; ///< Length of message string.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Parse a PostgreSQL ErrorResponse payload to extract SQLSTATE and message.
|
||||
*
|
||||
* Scans the field-type/value pairs in the ErrorResponse payload.
|
||||
* Field format: type_byte + null_terminated_string, repeated, ending with '\0'.
|
||||
*
|
||||
* @param payload ErrorResponse message payload (after the 5-byte header).
|
||||
* @param len Length of the payload.
|
||||
* @return PgSQLErrorResult with parsed fields.
|
||||
*/
|
||||
PgSQLErrorResult pgsql_parse_error_response(const unsigned char* payload, size_t len);
|
||||
|
||||
#endif // PGSQL_ERROR_FIELDS_H
|
||||
@ -0,0 +1,37 @@
|
||||
#include "PgSQLErrorFields.h"
|
||||
#include <cstring>
|
||||
|
||||
PgSQLErrorResult pgsql_parse_error_response(const unsigned char* payload, size_t len) {
|
||||
PgSQLErrorResult result {};
|
||||
result.parsed = false;
|
||||
result.sqlstate[0] = '\0';
|
||||
result.message = nullptr;
|
||||
result.message_len = 0;
|
||||
|
||||
if (!payload || len == 0) return result;
|
||||
result.parsed = true;
|
||||
|
||||
size_t pos = 0;
|
||||
while (pos < len) {
|
||||
char field_type = static_cast<char>(payload[pos]);
|
||||
if (field_type == '\0') break; // end of fields
|
||||
pos++; // skip field type byte
|
||||
|
||||
// Find the null terminator for this field's value
|
||||
const char* value = reinterpret_cast<const char*>(payload + pos);
|
||||
size_t value_len = strnlen(value, len - pos);
|
||||
if (pos + value_len >= len) break; // truncated
|
||||
|
||||
if (field_type == 'C' && value_len <= 5) {
|
||||
memcpy(result.sqlstate, value, value_len);
|
||||
result.sqlstate[value_len] = '\0';
|
||||
} else if (field_type == 'M') {
|
||||
result.message = value;
|
||||
result.message_len = value_len;
|
||||
}
|
||||
|
||||
pos += value_len + 1; // skip value + null terminator
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Loading…
Reference in new issue