From 5526e413c15d8719e89e23ec587ad1dba4e544c5 Mon Sep 17 00:00:00 2001 From: Andreas Karlsson Date: Tue, 23 Dec 2025 17:10:27 +0100 Subject: [PATCH] PG-2116 Truncate query strings at multi-byte character boundaries Make sure we never create broken encodings in query strings by making the truncation of query strings multi-byte aware. An alternative would be to change the rule for truncation to be based on number of characters, as the documentation claims it is, but I do not think that would be significantly better. Either works just fine so we just pick one. Based on bug report from Ivan Vyazmitinov: https://github.com/percona/pg_stat_monitor/issues/599 --- pg_stat_monitor.c | 2 +- t/015_settings_pgsm_query_max_len.pl | 8 ++++++++ t/expected/015_settings_pgsm_query_max_len.out | 13 +++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index 5ef4e38..024fbb7 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -1983,7 +1983,7 @@ pgsm_store(pgsmEntry *entry) /* New query, truncate length if necessary. */ if (query_len > pgsm_query_max_len) - query_len = pgsm_query_max_len; + query_len = pg_mbcliplen(query, query_len, pgsm_query_max_len); /* Save the query text in raw dsa area */ query_dsa_area = get_dsa_area_for_query_text(); diff --git a/t/015_settings_pgsm_query_max_len.pl b/t/015_settings_pgsm_query_max_len.pl index 310d28f..1b8211d 100644 --- a/t/015_settings_pgsm_query_max_len.pl +++ b/t/015_settings_pgsm_query_max_len.pl @@ -47,6 +47,14 @@ $node->restart(); ok($cmdret == 0, "Reset PGSM EXTENSION"); PGSM::append_to_file($stdout); +($cmdret, $stdout, $stderr) = $node->psql('postgres', "SELECT length('åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå');", extra_params => ['-a', '-Pformat=aligned','-Ptuples_only=off']); +ok($cmdret == 0, "Run truncated multi-byte query string"); +PGSM::append_to_file($stdout); + +($cmdret, $stdout, $stderr) = $node->psql('postgres', "SELECT length(query), query FROM pg_stat_monitor ORDER BY query;", extra_params => ['-a', '-Pformat=aligned','-Ptuples_only=off']); +ok($cmdret == 0, "Print truncated multi-byte query string"); +PGSM::append_to_file($stdout); + ($cmdret, $stdout, $stderr) = $node->psql('postgres', "SELECT name, setting, unit, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, pending_restart FROM pg_settings WHERE name='pg_stat_monitor.pgsm_query_max_len';", extra_params => ['-a', '-Pformat=aligned','-Ptuples_only=off']); ok($cmdret == 0, "Print PGSM EXTENSION Settings"); PGSM::append_to_file($stdout); diff --git a/t/expected/015_settings_pgsm_query_max_len.out b/t/expected/015_settings_pgsm_query_max_len.out index bc1f4aa..e514bb6 100644 --- a/t/expected/015_settings_pgsm_query_max_len.out +++ b/t/expected/015_settings_pgsm_query_max_len.out @@ -17,6 +17,19 @@ SELECT pg_stat_monitor_reset(); (1 row) +SELECT length('åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå'); + length +-------- + 512 +(1 row) + +SELECT length(query), query FROM pg_stat_monitor ORDER BY query; + length | query +--------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 519 | SELECT length('åååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååå + 30 | SELECT pg_stat_monitor_reset() +(2 rows) + SELECT name, setting, unit, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, pending_restart FROM pg_settings WHERE name='pg_stat_monitor.pgsm_query_max_len'; name | setting | unit | context | vartype | source | min_val | max_val | enumvals | boot_val | reset_val | pending_restart ------------------------------------+---------+------+------------+---------+--------------------+---------+------------+----------+----------+-----------+-----------------