From: Peter Eisentraut Date: Mon, 9 Sep 2019 16:56:50 +0000 (+0200) Subject: Send stats columns as numeric instead of bigint X-Git-Tag: pgbouncer_1_12_0~34 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2bc1747aaebdd96197e63662a8e50958c958af61;p=pgbouncer Send stats columns as numeric instead of bigint Internally, most statistiscs are kept as uint64_t. Sending those with a row descriptor that claims they are bigint can lead to problems if uint64_t values can overflow the signed 64-bit integer range. Then a client library that wants to convert the value to its locally appropriate signed 64-bit integer type would run into errors. based on patch by @stanhu fixes #360 #401 --- diff --git a/include/system.h b/include/system.h index e476337..6022119 100644 --- a/include/system.h +++ b/include/system.h @@ -45,14 +45,6 @@ #define UNIX_PATH_MAX 128 /* actual sizeof() will be applied later anyway */ #endif -/* - * PostgreSQL type OIDs for resultsets. - */ - -#define INT8OID 20 -#define INT4OID 23 -#define TEXTOID 25 - /* * libc compat functions. */ diff --git a/src/pktbuf.c b/src/pktbuf.c index b61870b..722f8b4 100644 --- a/src/pktbuf.c +++ b/src/pktbuf.c @@ -22,6 +22,16 @@ #include "bouncer.h" + +/* + * PostgreSQL type OIDs for result sets + */ +#define INT8OID 20 +#define INT4OID 23 +#define TEXTOID 25 +#define NUMERICOID 1700 + + void pktbuf_free(PktBuf *buf) { if (!buf || buf->fixed_buf) @@ -341,6 +351,7 @@ void pktbuf_write_generic(PktBuf *buf, int type, const char *pktdesc, ...) * 'i' - int4 * 'q' - int8 * 's' - string + * 'N' - uint64_t to numeric * 'T' - usec_t to date */ void pktbuf_write_RowDescription(PktBuf *buf, const char *tupdesc, ...) @@ -372,13 +383,16 @@ void pktbuf_write_RowDescription(PktBuf *buf, const char *tupdesc, ...) } else if (tupdesc[i] == 'q') { pktbuf_put_uint32(buf, INT8OID); pktbuf_put_uint16(buf, 8); + } else if (tupdesc[i] == 'N') { + pktbuf_put_uint32(buf, NUMERICOID); + pktbuf_put_uint16(buf, -1); } else if (tupdesc[i] == 'T') { pktbuf_put_uint32(buf, TEXTOID); pktbuf_put_uint16(buf, -1); } else { fatal("bad tupdesc"); } - pktbuf_put_uint32(buf, 0); + pktbuf_put_uint32(buf, -1); pktbuf_put_uint16(buf, 0); } va_end(ap); @@ -394,6 +408,7 @@ void pktbuf_write_RowDescription(PktBuf *buf, const char *tupdesc, ...) * 'i' - int4 * 'q' - int8 * 's' - string + * 'N' - uint64_t to numeric * 'T' - usec_t to date */ void pktbuf_write_DataRow(PktBuf *buf, const char *tupdesc, ...) @@ -411,7 +426,7 @@ void pktbuf_write_DataRow(PktBuf *buf, const char *tupdesc, ...) if (tupdesc[i] == 'i') { snprintf(tmp, sizeof(tmp), "%d", va_arg(ap, int)); val = tmp; - } else if (tupdesc[i] == 'q') { + } else if (tupdesc[i] == 'q' || tupdesc[i] == 'N') { snprintf(tmp, sizeof(tmp), "%" PRIu64, va_arg(ap, uint64_t)); val = tmp; } else if (tupdesc[i] == 's') { diff --git a/src/stats.c b/src/stats.c index a9a9de8..a02252c 100644 --- a/src/stats.c +++ b/src/stats.c @@ -77,7 +77,7 @@ static void write_stats(PktBuf *buf, PgStats *stat, PgStats *old, char *dbname) { PgStats avg; calc_average(&avg, stat, old); - pktbuf_write_DataRow(buf, "sqqqqqqqqqqqqqq", dbname, + pktbuf_write_DataRow(buf, "sNNNNNNNNNNNNNN", dbname, stat->xact_count, stat->query_count, stat->client_bytes, stat->server_bytes, stat->xact_time, stat->query_time, @@ -108,7 +108,7 @@ bool admin_database_stats(PgSocket *client, struct StatList *pool_list) return true; } - pktbuf_write_RowDescription(buf, "sqqqqqqqqqqqqqq", "database", + pktbuf_write_RowDescription(buf, "sNNNNNNNNNNNNNN", "database", "total_xact_count", "total_query_count", "total_received", "total_sent", "total_xact_time", "total_query_time", @@ -152,7 +152,7 @@ static void write_stats_totals(PktBuf *buf, PgStats *stat, PgStats *old, char *d { PgStats avg; calc_average(&avg, stat, old); - pktbuf_write_DataRow(buf, "sqqqqqqq", dbname, + pktbuf_write_DataRow(buf, "sNNNNNNN", dbname, stat->xact_count, stat->query_count, stat->client_bytes, stat->server_bytes, stat->xact_time, stat->query_time, @@ -179,7 +179,7 @@ bool admin_database_stats_totals(PgSocket *client, struct StatList *pool_list) return true; } - pktbuf_write_RowDescription(buf, "sqqqqqqq", "database", + pktbuf_write_RowDescription(buf, "sNNNNNNN", "database", "xact_count", "query_count", "bytes_received", "bytes_sent", "xact_time", "query_time", @@ -219,7 +219,7 @@ static void write_stats_averages(PktBuf *buf, PgStats *stat, PgStats *old, char { PgStats avg; calc_average(&avg, stat, old); - pktbuf_write_DataRow(buf, "sqqqqqqq", dbname, + pktbuf_write_DataRow(buf, "sNNNNNNN", dbname, avg.xact_count, avg.query_count, avg.client_bytes, avg.server_bytes, avg.xact_time, avg.query_time, @@ -246,7 +246,7 @@ bool admin_database_stats_averages(PgSocket *client, struct StatList *pool_list) return true; } - pktbuf_write_RowDescription(buf, "sqqqqqqq", "database", + pktbuf_write_RowDescription(buf, "sNNNNNNN", "database", "xact_count", "query_count", "bytes_received", "bytes_sent", "xact_time", "query_time", @@ -307,10 +307,10 @@ bool show_stat_totals(PgSocket *client, struct StatList *pool_list) calc_average(&avg, &st_total, &old_total); - pktbuf_write_RowDescription(buf, "sq", "name", "value"); + pktbuf_write_RowDescription(buf, "sN", "name", "value"); -#define WTOTAL(name) pktbuf_write_DataRow(buf, "sq", "total_" #name, st_total.name) -#define WAVG(name) pktbuf_write_DataRow(buf, "sq", "avg_" #name, avg.name) +#define WTOTAL(name) pktbuf_write_DataRow(buf, "sN", "total_" #name, st_total.name) +#define WAVG(name) pktbuf_write_DataRow(buf, "sN", "avg_" #name, avg.name) WTOTAL(xact_count); WTOTAL(query_count);