public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v3 3/3] Fix sizing of tape read buffers.
15+ messages / 4 participants
[nested] [flat]
* [PATCH v3 3/3] Fix sizing of tape read buffers.
@ 2021-01-22 20:59 Heikki Linnakangas <[email protected]>
0 siblings, 0 replies; 15+ messages in thread
From: Heikki Linnakangas @ 2021-01-22 20:59 UTC (permalink / raw)
---
src/backend/utils/sort/tuplesort.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 14104643e78..aff2f201f52 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -2658,7 +2658,7 @@ merge_read_buffer_size(int64 avail_mem, int nInputTapes, int nInputRuns,
* we derive the input buffer size from the amount of memory available,
* and M and N.
*/
- return (avail_mem - TAPE_BUFFER_OVERHEAD * nOutputTapes) / nInputTapes;
+ return Max((avail_mem - TAPE_BUFFER_OVERHEAD * nOutputTapes) / nInputTapes, 0);
}
/*
--
2.29.2
--------------631E0A48DCAEA386819DFCEC--
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
@ 2026-02-05 10:22 Álvaro Herrera <[email protected]>
2026-02-05 11:53 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
0 siblings, 2 replies; 15+ messages in thread
From: Álvaro Herrera @ 2026-02-05 10:22 UTC (permalink / raw)
To: Jim Jones <[email protected]>; +Cc: Fujii Masao <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Kirill Reshke <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On 2026-Feb-05, Jim Jones wrote:
> On 05/02/2026 03:17, Fujii Masao wrote:
> > At least I'm not for now. So please feel free to work on the patch if
> > you'd like!
>
> If nobody is planning to work on this, I can take a look at it next week.
That'd be swell.
My only comment at this point is that the proposed GUC name is not
great. I think it should be something like log_statement_max_length, or
something like that. Reading just the thread subject, people would
imagine this is about the size of the log file.
Another point is that the current patch does strlen() twice on each
query. It might be better to do away with need_truncate_query_log() and
have a single routine that both determines whether the truncation is
needed and returns the truncated query if it is. If it returns NULL
then caller assumes it's not needed.
--
Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
@ 2026-02-05 11:53 ` Jim Jones <[email protected]>
1 sibling, 0 replies; 15+ messages in thread
From: Jim Jones @ 2026-02-05 11:53 UTC (permalink / raw)
To: Álvaro Herrera <[email protected]>; +Cc: Fujii Masao <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Kirill Reshke <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On 05/02/2026 11:22, Álvaro Herrera wrote:
> My only comment at this point is that the proposed GUC name is not
> great. I think it should be something like log_statement_max_length, or
> something like that. Reading just the thread subject, people would
> imagine this is about the size of the log file.
+1 for log_statement_max_length
>
> Another point is that the current patch does strlen() twice on each
> query. It might be better to do away with need_truncate_query_log() and
> have a single routine that both determines whether the truncation is
> needed and returns the truncated query if it is. If it returns NULL
> then caller assumes it's not needed.
I'll take a look at this.
Another thing that we could adjust is the default/disable value: I
personally find 0 to disable the feature a bit confusing. 0 might be
interpreted as "log 0 bytes", and the user ends up with the full
statement logged. What about -1?
Best, Jim
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
@ 2026-02-06 07:50 ` Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
1 sibling, 1 reply; 15+ messages in thread
From: Jim Jones @ 2026-02-06 07:50 UTC (permalink / raw)
To: Álvaro Herrera <[email protected]>; +Cc: Fujii Masao <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Kirill Reshke <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On 05/02/2026 11:22, Álvaro Herrera wrote:
> My only comment at this point is that the proposed GUC name is not
> great. I think it should be something like log_statement_max_length, or
> something like that. Reading just the thread subject, people would
> imagine this is about the size of the log file.
Done. GUC changed to log_statement_max_length.
> Another point is that the current patch does strlen() twice on each
> query. It might be better to do away with need_truncate_query_log() and
> have a single routine that both determines whether the truncation is
> needed and returns the truncated query if it is. If it returns NULL
> then caller assumes it's not needed.
Done. Now truncate_query_log() returns a palloc'd truncated copy of the
statement if truncation is needed, and NULL otherwise.
== issue with issue with empty STATEMENT ==
This issue was mentioned by Fujii upthread. It is now fixed:
postgres=# SET log_statement TO 'all';
SET
postgres=# SET log_statement_max_length TO 3;
SET
postgres=# SELECT 1/0;
ERROR: division by zero
Log entries:
2026-02-05 17:54:47.521 CET [570568] LOG: statement: SEL
2026-02-05 17:54:47.521 CET [570568] ERROR: division by zero
2026-02-05 17:54:47.521 CET [570568] STATEMENT: SELECT 1/0;
== default value ==
To be consistent with other parameters, such as
log_parameter_max_length, the default (disabled) value is now -1.
== tests ==
Added new tests for -1 and multi-byte characters.
Best, Jim
Attachments:
[text/x-patch] v7-0001-Add-log_statement_max_length-GUC-to-limit-logged-.patch (10.7K, ../../[email protected]/2-v7-0001-Add-log_statement_max_length-GUC-to-limit-logged-.patch)
download | inline diff:
From d12a565220d1827079c033507919ac5229004ce7 Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Thu, 5 Feb 2026 18:00:13 +0100
Subject: [PATCH v7] Add log_statement_max_length GUC to limit logged statement
size
When log_statement is enabled, queries can be arbitrarily long and may
consume significant disk space in server logs. This patch introduces a
new GUC, log_statement_max_length, which limits the maximum byte length
of logged statements.
A value greater than zero truncates each logged statement to the given
number of bytes. The default is -1, which disables truncation and logs
full statements. If specified without units, the value is interpreted
as bytes.
---
doc/src/sgml/config.sgml | 18 ++++++++++
src/backend/tcop/postgres.c | 11 ++++--
src/backend/utils/error/elog.c | 34 +++++++++++++++++++
src/backend/utils/misc/guc_parameters.dat | 10 ++++++
src/backend/utils/misc/guc_tables.c | 1 +
src/backend/utils/misc/postgresql.conf.sample | 2 ++
src/bin/pg_ctl/t/004_logrotate.pl | 24 +++++++++++++
src/include/utils/elog.h | 2 ++
src/include/utils/guc.h | 1 +
9 files changed, 101 insertions(+), 2 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 5560b95ee6..d9d708d7b9 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -8235,6 +8235,24 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
</listitem>
</varlistentry>
+ <varlistentry id="guc-log-statement-max-length" xreflabel="log_statement_max_length">
+ <term><varname>log_statement_max_length</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>log_statement_max_length</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ If greater than zero, each statement logged by <xref linkend="guc-log-statement"/>
+ is truncated to at most this many bytes.
+ <literal>-1</literal> (the default) disables truncation.
+ If this value is specified without units, it is taken as bytes.
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</sect2>
<sect2 id="runtime-config-logging-csvlog">
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 02e9aaa6bc..14265ecd08 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -72,6 +72,7 @@
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
+#include "utils/elog.h"
#include "utils/guc_hooks.h"
#include "utils/injection_point.h"
#include "utils/lsyscache.h"
@@ -1023,11 +1024,15 @@ exec_simple_query(const char *query_string)
bool was_logged = false;
bool use_implicit_block;
char msec_str[32];
+ char *truncated_query = NULL;
+ const char *query_log;
/*
* Report query to various monitoring facilities.
*/
debug_query_string = query_string;
+ truncated_query = truncate_query_log(query_string);
+ query_log = truncated_query ? truncated_query : query_string;
pgstat_report_activity(STATE_RUNNING, query_string);
@@ -1072,7 +1077,7 @@ exec_simple_query(const char *query_string)
if (check_log_statement(parsetree_list))
{
ereport(LOG,
- (errmsg("statement: %s", query_string),
+ (errmsg("statement: %s", query_log),
errhidestmt(true),
errdetail_execute(parsetree_list)));
was_logged = true;
@@ -1370,7 +1375,7 @@ exec_simple_query(const char *query_string)
case 2:
ereport(LOG,
(errmsg("duration: %s ms statement: %s",
- msec_str, query_string),
+ msec_str, query_log),
errhidestmt(true),
errdetail_execute(parsetree_list)));
break;
@@ -1381,6 +1386,8 @@ exec_simple_query(const char *query_string)
TRACE_POSTGRESQL_QUERY_DONE(query_string);
+ if (truncated_query)
+ pfree(truncated_query);
debug_query_string = NULL;
}
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index e6a4ef9905..ffabbfbceb 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -3805,6 +3805,40 @@ write_stderr(const char *fmt,...)
va_end(ap);
}
+/*
+ * truncate_query_log - truncate query string if needed for logging
+ *
+ * Returns a palloc'd truncated copy if truncation is needed,
+ * or NULL if no truncation is required.
+ */
+char *
+truncate_query_log(const char *query)
+{
+ size_t query_len;
+ size_t truncated_len;
+ char *truncated_query;
+
+ /* Check if truncation is disabled (-1) or no query string provided */
+ if (!query || log_statement_max_length < 0)
+ return NULL;
+
+ query_len = strlen(query);
+
+ /*
+ * No need to allocate a truncated copy if the query is shorter
+ * than log_statement_max_length.
+ */
+ if (query_len <= (size_t) log_statement_max_length)
+ return NULL;
+
+ /* Truncate at multibyte character boundary */
+ truncated_len = pg_mbcliplen(query, query_len, log_statement_max_length);
+ truncated_query = (char *) palloc(truncated_len + 1);
+ memcpy(truncated_query, query, truncated_len);
+ truncated_query[truncated_len] = '\0';
+
+ return truncated_query;
+}
/*
* Write errors to stderr (or by equal means when stderr is
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index f0260e6e41..4864dbbbb2 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -1777,6 +1777,16 @@
options => 'log_statement_options',
},
+{ name => 'log_statement_max_length', type => 'int', context => 'PGC_SUSET', group => 'LOGGING_WHAT',
+ short_desc => 'Sets the maximum length in bytes of logged statements.',
+ long_desc => '-1 means no truncation.',
+ flags => 'GUC_UNIT_BYTE',
+ variable => 'log_statement_max_length',
+ boot_val => '-1',
+ min => '-1',
+ max => 'INT_MAX / 2',
+},
+
{ name => 'log_statement_sample_rate', type => 'real', context => 'PGC_SUSET', group => 'LOGGING_WHEN',
short_desc => 'Fraction of statements exceeding "log_min_duration_sample" to be logged.',
long_desc => 'Use a value between 0.0 (never log) and 1.0 (always log).',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 13c569d879..dbcb25e130 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -544,6 +544,7 @@ int log_min_duration_statement = -1;
int log_parameter_max_length = -1;
int log_parameter_max_length_on_error = 0;
int log_temp_files = -1;
+int log_statement_max_length = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index c4f92fcdac..3cc4399026 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -642,6 +642,8 @@
# bind-parameter values to N bytes;
# -1 means print in full, 0 disables
#log_statement = 'none' # none, ddl, mod, all
+#log_statement_max_length = -1 # max length of logged statements
+ # -1 disables truncation
#log_replication_commands = off
#log_temp_files = -1 # log temporary files equal or larger
# than the specified size in kilobytes;
diff --git a/src/bin/pg_ctl/t/004_logrotate.pl b/src/bin/pg_ctl/t/004_logrotate.pl
index 7b19f86467..dd1aa21f4c 100644
--- a/src/bin/pg_ctl/t/004_logrotate.pl
+++ b/src/bin/pg_ctl/t/004_logrotate.pl
@@ -135,6 +135,30 @@ check_log_pattern('stderr', $new_current_logfiles, 'syntax error', $node);
check_log_pattern('csvlog', $new_current_logfiles, 'syntax error', $node);
check_log_pattern('jsonlog', $new_current_logfiles, 'syntax error', $node);
+# Verify truncation works with ASCII
+$node->append_conf('postgresql.conf', "log_statement = 'all'\nlog_statement_max_length = 20\n");
+$node->reload();
+$node->psql('postgres', "SELECT '123456789ABCDEF'");
+check_log_pattern('stderr', $new_current_logfiles, "SELECT '123456789ABC", $node);
+check_log_pattern('csvlog', $new_current_logfiles, "SELECT '123456789ABC", $node);
+check_log_pattern('jsonlog', $new_current_logfiles, "SELECT '123456789ABC", $node);
+
+# Verify -1 disables truncation (logs full query)
+$node->append_conf('postgresql.conf', "log_statement_max_length = -1\n");
+$node->reload();
+$node->psql('postgres', "SELECT '123456789ABCDEF'");
+check_log_pattern('stderr', $new_current_logfiles, "SELECT '123456789ABCDEF'", $node);
+check_log_pattern('csvlog', $new_current_logfiles, "SELECT '123456789ABCDEF'", $node);
+check_log_pattern('jsonlog', $new_current_logfiles, "SELECT '123456789ABCDEF'", $node);
+
+# Verify multibyte character handling (must not produce invalid UTF-8)
+$node->append_conf('postgresql.conf', "log_statement_max_length = 12\n");
+$node->reload();
+$node->psql('postgres', "SELECT '🐘test'");
+check_log_pattern('stderr', $new_current_logfiles, "SELECT '", $node);
+check_log_pattern('csvlog', $new_current_logfiles, "SELECT '", $node);
+check_log_pattern('jsonlog', $new_current_logfiles, "SELECT '", $node);
+
$node->stop();
done_testing();
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index a12b379e09..aabee73aa4 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -494,6 +494,7 @@ extern PGDLLIMPORT int Log_destination;
extern PGDLLIMPORT char *Log_destination_string;
extern PGDLLIMPORT bool syslog_sequence_numbers;
extern PGDLLIMPORT bool syslog_split_messages;
+extern PGDLLIMPORT int log_statement_max_length;
/* Log destination bitmap */
#define LOG_DESTINATION_STDERR 1
@@ -508,6 +509,7 @@ extern void log_status_format(StringInfo buf, const char *format,
extern void DebugFileOpen(void);
extern char *unpack_sql_state(int sql_state);
extern bool in_error_recursion_trouble(void);
+extern char *truncate_query_log(const char *query);
/* Common functions shared across destinations */
extern void reset_formatted_start_time(void);
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index bf39878c43..8043d8fa45 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -300,6 +300,7 @@ extern PGDLLIMPORT int client_min_messages;
extern PGDLLIMPORT int log_min_duration_sample;
extern PGDLLIMPORT int log_min_duration_statement;
extern PGDLLIMPORT int log_temp_files;
+extern PGDLLIMPORT int log_statement_max_length;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
--
2.43.0
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
@ 2026-07-02 15:49 ` Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
0 siblings, 1 reply; 15+ messages in thread
From: Fujii Masao @ 2026-07-02 15:49 UTC (permalink / raw)
To: Jim Jones <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On Fri, May 15, 2026 at 7:48 PM Jim Jones <[email protected]> wrote:
>
> rebase due to recent changes in src/test/modules/test_misc/meson.build
I reviewed the patch again and made a few additional changes. The updated
patch is attached. Barring any objections, I'm thinking to commit it.
If greater than zero, each statement logged by
- <xref linkend="guc-log-statement"/> or
- <xref linkend="guc-log-min-duration-statement"/> is truncated to
- at most this many bytes.
+ <xref linkend="guc-log-statement"/>,
+ <xref linkend="guc-log-min-duration-statement"/>,
+ <xref linkend="guc-log-min-duration-sample"/>, or
+ <xref linkend="guc-log-transaction-sample-rate"/>
+ is truncated to at most this many bytes.
Since this parameter also affects statements logged by
log_min_duration_sample and log_transaction_sample_rate, I added
those parameters to the description.
+ This setting does not affect statements logged because of
+ <xref linkend="guc-log-min-error-statement"/>.
I also clarified that this parameter does not affect statements logged
by log_min_error_statement.
+static char *
+truncate_query_log(const char *query)
Since truncate_query_log() is only used in postgres.c, I moved it
from elog.c and made it a static function.
-ok( $node->log_contains(
- qr/statement: SELECT '123456789ABC(?!D)/, $log_offset),
+ok($node->log_contains(qr/statement: SELECT '123456789ABC$/m, $log_offset),
I tightened the test to verify that the truncated statement ends exactly
at the 20th byte.
-# character (the 🐘 emoji is 4 bytes; with limit=12 it must be kept whole
-# and the following 't' must not appear).
-note "Multibyte truncation respects character boundaries";
+# character when the byte limit falls in the middle of it.
+SKIP:
Using an emoji directly in the test seems fragile and the behavior
may depend on the test platform. To make the test more robust, I changed
it to construct the multibyte character with pack() and run the test
only when the server encoding is UTF-8.
Regards,
--
Fujii Masao
Attachments:
[application/octet-stream] v14-0001-Add-log_statement_max_length-GUC-to-limit-logged.patch (17.5K, ../../CAHGQGwHJHCi=4zEyMc4GJWPC9-oQZHj+9kncxS2442V9PXGgoQ@mail.gmail.com/2-v14-0001-Add-log_statement_max_length-GUC-to-limit-logged.patch)
download | inline diff:
From 7d348771607551f57c7806ef6f32bfda27050bdc Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Fri, 15 May 2026 12:44:45 +0200
Subject: [PATCH v14] Add log_statement_max_length GUC to limit logged
statement size
Queries logged by log_statement or log_min_duration_statement can be
arbitrarily long and may consume significant disk space in server logs.
This patch introduces a new GUC, log_statement_max_length, which limits
the maximum byte length of those logged statements.
A value greater than zero truncates each logged statement to the given
number of bytes, respecting multibyte character boundaries to avoid
producing invalid output. The default is -1, which logs statements in
full. If specified without units, the value is interpreted as bytes.
---
doc/src/sgml/config.sgml | 25 +++
src/backend/tcop/postgres.c | 171 ++++++++++++++----
src/backend/utils/misc/guc_parameters.dat | 10 +
src/backend/utils/misc/guc_tables.c | 1 +
src/backend/utils/misc/postgresql.conf.sample | 3 +
src/include/utils/guc.h | 1 +
src/test/modules/test_misc/meson.build | 1 +
.../t/014_log_statement_max_length.pl | 115 ++++++++++++
8 files changed, 289 insertions(+), 38 deletions(-)
create mode 100644 src/test/modules/test_misc/t/014_log_statement_max_length.pl
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 6e9626fcf38..9172a4c5c95 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -8512,6 +8512,31 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
</listitem>
</varlistentry>
+ <varlistentry id="guc-log-statement-max-length" xreflabel="log_statement_max_length">
+ <term><varname>log_statement_max_length</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>log_statement_max_length</varname> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ If greater than zero, each statement logged by
+ <xref linkend="guc-log-statement"/>,
+ <xref linkend="guc-log-min-duration-statement"/>,
+ <xref linkend="guc-log-min-duration-sample"/>, or
+ <xref linkend="guc-log-transaction-sample-rate"/>
+ is truncated to at most this many bytes.
+ A value of zero causes statements to be logged with an empty body.
+ <literal>-1</literal> (the default) logs statements in full.
+ If this value is specified without units, it is taken as bytes.
+ This setting does not affect statements logged because of
+ <xref linkend="guc-log-min-error-statement"/>.
+ Only superusers and users with the appropriate <literal>SET</literal>
+ privilege can change this setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-log-replication-commands" xreflabel="log_replication_commands">
<term><varname>log_replication_commands</varname> (<type>boolean</type>)
<indexterm>
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index dbef734a93f..ce18df820cd 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -183,6 +183,7 @@ static int SocketBackend(StringInfo inBuf);
static int ReadCommand(StringInfo inBuf);
static void forbidden_in_wal_sender(char firstchar);
static bool check_log_statement(List *stmt_list);
+static char *truncate_query_log(const char *query);
static int errdetail_execute(List *raw_parsetree_list);
static int errdetail_params(ParamListInfo params);
static void bind_param_error_callback(void *arg);
@@ -1084,11 +1085,20 @@ exec_simple_query(const char *query_string)
/* Log immediately if dictated by log_statement */
if (check_log_statement(parsetree_list))
{
+ char *truncated_stmt = NULL;
+
+ if (log_statement_max_length >= 0)
+ truncated_stmt = truncate_query_log(query_string);
+
ereport(LOG,
- (errmsg("statement: %s", query_string),
+ (errmsg("statement: %s",
+ (truncated_stmt != NULL) ? truncated_stmt : query_string),
errhidestmt(true),
errdetail_execute(parsetree_list)));
was_logged = true;
+
+ if (truncated_stmt != NULL)
+ pfree(truncated_stmt);
}
/*
@@ -1381,12 +1391,23 @@ exec_simple_query(const char *query_string)
errhidestmt(true)));
break;
case 2:
- ereport(LOG,
- (errmsg("duration: %s ms statement: %s",
- msec_str, query_string),
- errhidestmt(true),
- errdetail_execute(parsetree_list)));
- break;
+ {
+ char *truncated_stmt = NULL;
+
+ if (log_statement_max_length >= 0)
+ truncated_stmt = truncate_query_log(query_string);
+
+ ereport(LOG,
+ (errmsg("duration: %s ms statement: %s",
+ msec_str,
+ (truncated_stmt != NULL) ? truncated_stmt : query_string),
+ errhidestmt(true),
+ errdetail_execute(parsetree_list)));
+
+ if (truncated_stmt != NULL)
+ pfree(truncated_stmt);
+ break;
+ }
}
if (save_log_statement_stats)
@@ -1616,13 +1637,23 @@ exec_parse_message(const char *query_string, /* string to execute */
errhidestmt(true)));
break;
case 2:
- ereport(LOG,
- (errmsg("duration: %s ms parse %s: %s",
- msec_str,
- *stmt_name ? stmt_name : "<unnamed>",
- query_string),
- errhidestmt(true)));
- break;
+ {
+ char *truncated_stmt = NULL;
+
+ if (log_statement_max_length >= 0)
+ truncated_stmt = truncate_query_log(query_string);
+
+ ereport(LOG,
+ (errmsg("duration: %s ms parse %s: %s",
+ msec_str,
+ *stmt_name ? stmt_name : "<unnamed>",
+ (truncated_stmt != NULL) ? truncated_stmt : query_string),
+ errhidestmt(true)));
+
+ if (truncated_stmt != NULL)
+ pfree(truncated_stmt);
+ break;
+ }
}
if (save_log_statement_stats)
@@ -2093,16 +2124,26 @@ exec_bind_message(StringInfo input_message)
errhidestmt(true)));
break;
case 2:
- ereport(LOG,
- (errmsg("duration: %s ms bind %s%s%s: %s",
- msec_str,
- *stmt_name ? stmt_name : "<unnamed>",
- *portal_name ? "/" : "",
- *portal_name ? portal_name : "",
- psrc->query_string),
- errhidestmt(true),
- errdetail_params(params)));
- break;
+ {
+ char *truncated_stmt = NULL;
+
+ if (log_statement_max_length >= 0)
+ truncated_stmt = truncate_query_log(psrc->query_string);
+
+ ereport(LOG,
+ (errmsg("duration: %s ms bind %s%s%s: %s",
+ msec_str,
+ *stmt_name ? stmt_name : "<unnamed>",
+ *portal_name ? "/" : "",
+ *portal_name ? portal_name : "",
+ (truncated_stmt != NULL) ? truncated_stmt : psrc->query_string),
+ errhidestmt(true),
+ errdetail_params(params)));
+
+ if (truncated_stmt != NULL)
+ pfree(truncated_stmt);
+ break;
+ }
}
if (save_log_statement_stats)
@@ -2241,6 +2282,11 @@ exec_execute_message(const char *portal_name, long max_rows)
/* Log immediately if dictated by log_statement */
if (check_log_statement(portal->stmts))
{
+ char *truncated_source = NULL;
+
+ if (log_statement_max_length >= 0)
+ truncated_source = truncate_query_log(sourceText);
+
ereport(LOG,
(errmsg("%s %s%s%s: %s",
execute_is_fetch ?
@@ -2249,10 +2295,13 @@ exec_execute_message(const char *portal_name, long max_rows)
prepStmtName,
*portal_name ? "/" : "",
*portal_name ? portal_name : "",
- sourceText),
+ (truncated_source != NULL) ? truncated_source : sourceText),
errhidestmt(true),
errdetail_params(portalParams)));
was_logged = true;
+
+ if (truncated_source != NULL)
+ pfree(truncated_source);
}
/*
@@ -2364,19 +2413,29 @@ exec_execute_message(const char *portal_name, long max_rows)
errhidestmt(true)));
break;
case 2:
- ereport(LOG,
- (errmsg("duration: %s ms %s %s%s%s: %s",
- msec_str,
- execute_is_fetch ?
- _("execute fetch from") :
- _("execute"),
- prepStmtName,
- *portal_name ? "/" : "",
- *portal_name ? portal_name : "",
- sourceText),
- errhidestmt(true),
- errdetail_params(portalParams)));
- break;
+ {
+ char *truncated_source = NULL;
+
+ if (log_statement_max_length >= 0)
+ truncated_source = truncate_query_log(sourceText);
+
+ ereport(LOG,
+ (errmsg("duration: %s ms %s %s%s%s: %s",
+ msec_str,
+ execute_is_fetch ?
+ _("execute fetch from") :
+ _("execute"),
+ prepStmtName,
+ *portal_name ? "/" : "",
+ *portal_name ? portal_name : "",
+ (truncated_source != NULL) ? truncated_source : sourceText),
+ errhidestmt(true),
+ errdetail_params(portalParams)));
+
+ if (truncated_source != NULL)
+ pfree(truncated_source);
+ break;
+ }
}
if (save_log_statement_stats)
@@ -2490,6 +2549,42 @@ check_log_duration(char *msec_str, bool was_logged)
return 0;
}
+/*
+ * truncate_query_log
+ * Truncate query string if needed for logging
+ *
+ * Returns a palloc'd truncated copy if truncation is needed,
+ * or NULL if no truncation is required.
+ */
+static char *
+truncate_query_log(const char *query)
+{
+ size_t query_len;
+ size_t truncated_len;
+ char *truncated_query;
+
+ /* Truncation is disabled when the limit is negative */
+ if (!query || log_statement_max_length < 0)
+ return NULL;
+
+ query_len = strlen(query);
+
+ /*
+ * No need to allocate a truncated copy if the query is shorter than
+ * log_statement_max_length.
+ */
+ if (query_len <= (size_t) log_statement_max_length)
+ return NULL;
+
+ /* Truncate at a multibyte character boundary */
+ truncated_len = pg_mbcliplen(query, query_len, log_statement_max_length);
+ truncated_query = (char *) palloc(truncated_len + 1);
+ memcpy(truncated_query, query, truncated_len);
+ truncated_query[truncated_len] = '\0';
+
+ return truncated_query;
+}
+
/*
* errdetail_execute
*
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index 3c1e6b31bf8..c9118e71988 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -1868,6 +1868,16 @@
options => 'log_statement_options',
},
+{ name => 'log_statement_max_length', type => 'int', context => 'PGC_SUSET', group => 'LOGGING_WHAT',
+ short_desc => 'Sets the maximum length in bytes of logged statements.',
+ long_desc => '-1 means log statement in full; 0 means log an empty statement body.',
+ flags => 'GUC_UNIT_BYTE',
+ variable => 'log_statement_max_length',
+ boot_val => '-1',
+ min => '-1',
+ max => 'INT_MAX / 2',
+},
+
{ name => 'log_statement_sample_rate', type => 'real', context => 'PGC_SUSET', group => 'LOGGING_WHEN',
short_desc => 'Fraction of statements exceeding "log_min_duration_sample" to be logged.',
long_desc => 'Use a value between 0.0 (never log) and 1.0 (always log).',
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 290ccbc543e..90aa374b3ec 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -571,6 +571,7 @@ int log_min_duration_statement = -1;
int log_parameter_max_length = -1;
int log_parameter_max_length_on_error = 0;
int log_temp_files = -1;
+int log_statement_max_length = -1;
double log_statement_sample_rate = 1.0;
double log_xact_sample_rate = 0;
char *backtrace_functions;
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 86f2e16eba0..d7942f50a70 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -675,6 +675,9 @@
# bind-parameter values to N bytes;
# -1 means print in full, 0 disables
#log_statement = 'none' # none, ddl, mod, all
+#log_statement_max_length = -1 # max bytes of logged statements;
+ # -1 means log statement in full,
+ # 0 means log an empty body
#log_replication_commands = off
#log_temp_files = -1 # log temporary files equal or larger
# than the specified size in kilobytes;
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index dc406d6651a..8057d7870ad 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -300,6 +300,7 @@ extern PGDLLIMPORT int client_min_messages;
extern PGDLLIMPORT int log_min_duration_sample;
extern PGDLLIMPORT int log_min_duration_statement;
extern PGDLLIMPORT int log_temp_files;
+extern PGDLLIMPORT int log_statement_max_length;
extern PGDLLIMPORT double log_statement_sample_rate;
extern PGDLLIMPORT double log_xact_sample_rate;
extern PGDLLIMPORT char *backtrace_functions;
diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build
index 969e90b396d..ee290698b31 100644
--- a/src/test/modules/test_misc/meson.build
+++ b/src/test/modules/test_misc/meson.build
@@ -22,6 +22,7 @@ tests += {
't/011_lock_stats.pl',
't/012_ddlutils.pl',
't/013_temp_obj_multisession.pl',
+ 't/014_log_statement_max_length.pl',
],
# The injection points are cluster-wide, so disable installcheck
'runningcheck': false,
diff --git a/src/test/modules/test_misc/t/014_log_statement_max_length.pl b/src/test/modules/test_misc/t/014_log_statement_max_length.pl
new file mode 100644
index 00000000000..6cd45f2ee83
--- /dev/null
+++ b/src/test/modules/test_misc/t/014_log_statement_max_length.pl
@@ -0,0 +1,115 @@
+# Copyright (c) 2026, PostgreSQL Global Development Group
+
+# Test log_statement_max_length GUC: verifies that logged statement text is
+# truncated at the specified byte limit, respecting multibyte boundaries, for
+# both log_statement and log_min_duration_statement logging.
+
+use strict;
+use warnings FATAL => 'all';
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init();
+$node->start;
+
+# Verify ASCII truncation. With log_statement_max_length = 20,
+# a 24-byte query should end at the 20th byte ('C').
+note "ASCII truncation via log_statement";
+my $log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO 20;
+ SELECT '123456789ABCDEF';");
+ok($node->log_contains(qr/statement: SELECT '123456789ABC$/m, $log_offset),
+ "ASCII query truncated at 20 bytes");
+
+# Verify -1 logs statement in full (closing quote must be present).
+note "-1 logs statement in full";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO -1;
+ SELECT '123456789ABCDEF';");
+ok( $node->log_contains(qr/statement: SELECT '123456789ABCDEF'/, $log_offset),
+ "-1 logs full query");
+
+# Verify multibyte character handling: truncation must not split a multibyte
+# character when the byte limit falls in the middle of it.
+SKIP:
+{
+ skip "UTF8 database encoding required for multibyte truncation test", 1
+ unless $node->safe_psql('postgres', 'SHOW server_encoding') eq 'UTF8';
+
+ note "Multibyte truncation respects character boundaries";
+ my $mbchar = pack("C*", 0xC4, 0x80); # U+0100 in UTF-8
+ my $mbquery = "SELECT 'AA${mbchar}Z';";
+ $log_offset = -s $node->logfile;
+ $node->psql(
+ 'postgres', "
+ SET client_encoding TO 'UTF8';
+ SET log_statement_max_length TO 11;
+ $mbquery");
+ ok($node->log_contains(qr/statement: SELECT 'AA$/m, $log_offset),
+ "multibyte truncation at character boundary");
+}
+
+# Verify 0 logs an empty statement body.
+note "Zero length truncation";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO 0;
+ SELECT '123456789ABCDEF';");
+ok($node->log_contains(qr/LOG:\s+statement:\s*$/m, $log_offset),
+ "0 logs an empty statement body");
+
+# Verify truncation via the extended query protocol (execute message).
+# With log_statement_max_length = 20, a 24-byte query should end
+# at the 20th byte ('C').
+note "Extended query protocol (execute) truncation";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO 20;
+ SELECT '123456789ABCDEF' \\bind \\g");
+ok( $node->log_contains(
+ qr/execute <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ "extended protocol execute truncated at 20 bytes");
+
+# Verify extended protocol also respects -1 (no truncation; closing quote
+# present).
+note "Extended query protocol with -1 (no truncation)";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO -1;
+ SELECT '123456789ABCDEF' \\bind \\g");
+ok( $node->log_contains(
+ qr/execute <unnamed>: SELECT '123456789ABCDEF'/, $log_offset),
+ "extended protocol -1 logs full query");
+
+# Verify truncation applies to the parse/bind/execute duration log entries
+# emitted by log_min_duration_statement. log_statement must be 'none' to
+# ensure the duration entries include the statement text.
+note "Duration logging via log_min_duration_statement";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement TO 'none';
+ SET log_min_duration_statement TO 0;
+ SET log_statement_max_length TO 20;
+ SELECT '123456789ABCDEF' \\bind \\g");
+ok( $node->log_contains(
+ qr/parse <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ "parse duration entry truncated");
+ok( $node->log_contains(
+ qr/bind <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ "bind duration entry truncated");
+ok( $node->log_contains(
+ qr/execute <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ "execute duration entry truncated");
+
+$node->stop;
+done_testing();
--
2.53.0
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
@ 2026-07-02 18:47 ` Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
0 siblings, 1 reply; 15+ messages in thread
From: Jim Jones @ 2026-07-02 18:47 UTC (permalink / raw)
To: Fujii Masao <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
Hi Fujii
On 02/07/2026 17:49, Fujii Masao wrote:
> I reviewed the patch again and made a few additional changes. The updated
> patch is attached. Barring any objections, I'm thinking to commit it.
The changes seem reasonable to me.
Thanks for taking care of it!
Best, Jim
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
@ 2026-07-03 00:56 ` Fujii Masao <[email protected]>
2026-07-03 04:24 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 07:34 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
0 siblings, 2 replies; 15+ messages in thread
From: Fujii Masao @ 2026-07-03 00:56 UTC (permalink / raw)
To: Jim Jones <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On Fri, Jul 3, 2026 at 3:47 AM Jim Jones <[email protected]> wrote:
>
> Hi Fujii
>
> On 02/07/2026 17:49, Fujii Masao wrote:
> > I reviewed the patch again and made a few additional changes. The updated
> > patch is attached. Barring any objections, I'm thinking to commit it.
>
>
> The changes seem reasonable to me.
> Thanks for taking care of it!
Thanks for the review! I've pushed the patch.
While working on it, I found a few possible follow-up improvements.
(1)
When log_statement is enabled, executing a prepared statement logs the
prepared query in a DETAIL message. For example:
=# SET log_statement_max_length TO 10;
=# PREPARE test AS SELECT * FROM pgbench_accounts WHERE aid = $1;
LOG: statement: PREPARE te
=# EXECUTE test(1);
LOG: statement: EXECUTE te
DETAIL: prepare: PREPARE test AS SELECT * FROM pgbench_accounts
WHERE aid = $1;
Should log_statement_max_length also apply to such query string in the
DETAIL message?
(2)
When a bind parameter is truncated by
log_parameter_max_length, an ellipsis (...) is appended:
=# SET log_parameter_max_length TO 5;
=# SELECT $1::text \bind 'abcdefghijk' \g
LOG: execute <unnamed>: SELECT $1::text
DETAIL: Parameters: $1 = 'abcde...'
Would it make sense for log_statement_max_length to append an
ellipsis as well, so that users can easily tell when a statement has
been truncated?
(3)
+ query_len = strlen(query);
truncate_query_log() uses strlen() only to determine whether the
query exceeds log_statement_max_length. Since the query can be very
large, would it be better to use
strnlen(query, log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN)
instead, to avoid scanning the entire string?
Regards,
--
Fujii Masao
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
@ 2026-07-03 04:24 ` Fujii Masao <[email protected]>
2026-07-03 15:06 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
1 sibling, 1 reply; 15+ messages in thread
From: Fujii Masao @ 2026-07-03 04:24 UTC (permalink / raw)
To: Jim Jones <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On Fri, Jul 3, 2026 at 9:56 AM Fujii Masao <[email protected]> wrote:
> Thanks for the review! I've pushed the patch.
The buildfarm member prion reported the failure [1].
It looks like the failure occurs because prion runs with
log_error_verbosity = verbose, which inserts the SQLSTATE between
"LOG:" and the message text. The log_statement_max_length = 0 test
expected "statement:" to appear immediately after "LOG:", so it failed
even though the server correctly logged an empty statement body.
The attached patch fixes the test.
Regards,
[1] https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=prion&dt=2026-07-03%2002%3A23%3A06
--
Fujii Masao
Attachments:
[application/octet-stream] v1-0001-Fix-log_statement_max_length-test-with-verbose-lo.patch (1015B, ../../CAHGQGwFiQKwvLVG+U0WWNo2kgkQ88FVGhYH_MBZu9Y0SJ8BjDw@mail.gmail.com/2-v1-0001-Fix-log_statement_max_length-test-with-verbose-lo.patch)
download | inline diff:
From ea14e198cc867ae53a0b535b71bb7afd4f734c56 Mon Sep 17 00:00:00 2001
From: Fujii Masao <[email protected]>
Date: Fri, 3 Jul 2026 13:13:00 +0900
Subject: [PATCH v1] Fix log_statement_max_length test with verbose logs
---
src/test/modules/test_misc/t/014_log_statement_max_length.pl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/modules/test_misc/t/014_log_statement_max_length.pl b/src/test/modules/test_misc/t/014_log_statement_max_length.pl
index 6cd45f2ee83..b1ce6068f5d 100644
--- a/src/test/modules/test_misc/t/014_log_statement_max_length.pl
+++ b/src/test/modules/test_misc/t/014_log_statement_max_length.pl
@@ -62,7 +62,7 @@ $node->psql(
'postgres', "
SET log_statement_max_length TO 0;
SELECT '123456789ABCDEF';");
-ok($node->log_contains(qr/LOG:\s+statement:\s*$/m, $log_offset),
+ok($node->log_contains(qr/statement:\s*$/m, $log_offset),
"0 logs an empty statement body");
# Verify truncation via the extended query protocol (execute message).
--
2.53.0
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 04:24 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
@ 2026-07-03 15:06 ` Fujii Masao <[email protected]>
0 siblings, 0 replies; 15+ messages in thread
From: Fujii Masao @ 2026-07-03 15:06 UTC (permalink / raw)
To: Jim Jones <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On Fri, Jul 3, 2026 at 1:24 PM Fujii Masao <[email protected]> wrote:
>
> On Fri, Jul 3, 2026 at 9:56 AM Fujii Masao <[email protected]> wrote:
> > Thanks for the review! I've pushed the patch.
>
> The buildfarm member prion reported the failure [1].
>
> It looks like the failure occurs because prion runs with
> log_error_verbosity = verbose, which inserts the SQLSTATE between
> "LOG:" and the message text. The log_statement_max_length = 0 test
> expected "statement:" to appear immediately after "LOG:", so it failed
> even though the server correctly logged an empty statement body.
>
> The attached patch fixes the test.
I've pushed the patch, and confirmed that prion is green again.
Regards,
--
Fujii Masao
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
@ 2026-07-03 07:34 ` Jim Jones <[email protected]>
2026-07-03 15:46 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
1 sibling, 1 reply; 15+ messages in thread
From: Jim Jones @ 2026-07-03 07:34 UTC (permalink / raw)
To: Fujii Masao <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On 03/07/2026 02:56, Fujii Masao wrote:
> Thanks for the review! I've pushed the patch.
Awesome. Thanks!
> While working on it, I found a few possible follow-up improvements.
>
> (1)
> When log_statement is enabled, executing a prepared statement logs the
> prepared query in a DETAIL message. For example:
>
> =# SET log_statement_max_length TO 10;
> =# PREPARE test AS SELECT * FROM pgbench_accounts WHERE aid = $1;
> LOG: statement: PREPARE te
> =# EXECUTE test(1);
> LOG: statement: EXECUTE te
> DETAIL: prepare: PREPARE test AS SELECT * FROM pgbench_accounts
> WHERE aid = $1;
>
> Should log_statement_max_length also apply to such query string in the
> DETAIL message?
>
> (2)
> When a bind parameter is truncated by
> log_parameter_max_length, an ellipsis (...) is appended:
>
> =# SET log_parameter_max_length TO 5;
> =# SELECT $1::text \bind 'abcdefghijk' \g
> LOG: execute <unnamed>: SELECT $1::text
> DETAIL: Parameters: $1 = 'abcde...'
>
> Would it make sense for log_statement_max_length to append an
> ellipsis as well, so that users can easily tell when a statement has
> been truncated?
+1
Nice additions -- the feature gap is obvious, IMHO.
Are you planning to work on it? I'm drowning in work right now and can
only jump on it next week.
> (3)
> + query_len = strlen(query);
>
> truncate_query_log() uses strlen() only to determine whether the
> query exceeds log_statement_max_length. Since the query can be very
> large, would it be better to use
>
> strnlen(query, log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN)
>
> instead, to avoid scanning the entire string?
I'm not so sure about this one. At this point, isn't "query" already \0
terminated? I'm also wondering if it could affect pg_mbcliplen() down
the road, since strnlen() can return a different value
(log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN) on large queries --
not tested yet.
Thanks!
Best, Jim
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 07:34 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
@ 2026-07-03 15:46 ` Fujii Masao <[email protected]>
2026-07-04 11:01 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-08 17:02 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
0 siblings, 2 replies; 15+ messages in thread
From: Fujii Masao @ 2026-07-03 15:46 UTC (permalink / raw)
To: Jim Jones <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On Fri, Jul 3, 2026 at 4:34 PM Jim Jones <[email protected]> wrote:
> +1
> Nice additions -- the feature gap is obvious, IMHO.
>
> Are you planning to work on it? I'm drowning in work right now and can
> only jump on it next week.
I don't have plans to work on those at the moment, so please feel free
to take them on if you have time!
> I'm not so sure about this one. At this point, isn't "query" already \0
> terminated? I'm also wondering if it could affect pg_mbcliplen() down
> the road, since strnlen() can return a different value
> (log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN) on large queries --
> not tested yet.
Yes, "query" should already be NUL-terminated here. The reason for
using strnlen() is not to handle an unterminated string, but to avoid
scanning the entire query when it's very large and we only need to
know whether it exceeds log_statement_max_length.
I think it's fine to pass the bounded length to pg_mbcliplen().
It only needs enough input to find a multibyte-safe clipping point at
or before log_statement_max_length, i.e., it doesn't need the full
query length. The extra MAX_MULTIBYTE_CHAR_LEN bytes provide enough
lookahead to handle a multibyte character boundary correctly.
- query_len = strlen(query);
+ query_len = strnlen(query,
+ (size_t) log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN);
Regards,
--
Fujii Masao
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 07:34 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 15:46 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
@ 2026-07-04 11:01 ` Jim Jones <[email protected]>
1 sibling, 0 replies; 15+ messages in thread
From: Jim Jones @ 2026-07-04 11:01 UTC (permalink / raw)
To: Fujii Masao <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On 03/07/2026 17:46, Fujii Masao wrote:
> On Fri, Jul 3, 2026 at 4:34 PM Jim Jones <[email protected]> wrote:
>> +1
>> Nice additions -- the feature gap is obvious, IMHO.
>>
>> Are you planning to work on it? I'm drowning in work right now and can
>> only jump on it next week.
> I don't have plans to work on those at the moment, so please feel free
> to take them on if you have time!
>
>
>> I'm not so sure about this one. At this point, isn't "query" already \0
>> terminated? I'm also wondering if it could affect pg_mbcliplen() down
>> the road, since strnlen() can return a different value
>> (log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN) on large queries --
>> not tested yet.
> Yes, "query" should already be NUL-terminated here. The reason for
> using strnlen() is not to handle an unterminated string, but to avoid
> scanning the entire query when it's very large and we only need to
> know whether it exceeds log_statement_max_length.
>
> I think it's fine to pass the bounded length to pg_mbcliplen().
> It only needs enough input to find a multibyte-safe clipping point at
> or before log_statement_max_length, i.e., it doesn't need the full
> query length. The extra MAX_MULTIBYTE_CHAR_LEN bytes provide enough
> lookahead to handle a multibyte character boundary correctly.
>
> - query_len = strlen(query);
> + query_len = strnlen(query,
> + (size_t) log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN);
All right, thanks for the explanation.
I'll give it a try next week.
Have a nice weekend!
Best, Jim
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 07:34 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 15:46 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
@ 2026-07-08 17:02 ` Jim Jones <[email protected]>
2026-07-09 04:03 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
1 sibling, 1 reply; 15+ messages in thread
From: Jim Jones @ 2026-07-08 17:02 UTC (permalink / raw)
To: Fujii Masao <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
Hi Fujii
On 03.07.26 17:46, Fujii Masao wrote:
> On Fri, Jul 3, 2026 at 4:34 PM Jim Jones <[email protected]> wrote:
>> +1
>> Nice additions -- the feature gap is obvious, IMHO.
>>
>> Are you planning to work on it? I'm drowning in work right now and can
>> only jump on it next week.
>
> I don't have plans to work on those at the moment, so please feel free
> to take them on if you have time!
>
>
>> I'm not so sure about this one. At this point, isn't "query" already \0
>> terminated? I'm also wondering if it could affect pg_mbcliplen() down
>> the road, since strnlen() can return a different value
>> (log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN) on large queries --
>> not tested yet.
>
> Yes, "query" should already be NUL-terminated here. The reason for
> using strnlen() is not to handle an unterminated string, but to avoid
> scanning the entire query when it's very large and we only need to
> know whether it exceeds log_statement_max_length.
>
> I think it's fine to pass the bounded length to pg_mbcliplen().
> It only needs enough input to find a multibyte-safe clipping point at
> or before log_statement_max_length, i.e., it doesn't need the full
> query length. The extra MAX_MULTIBYTE_CHAR_LEN bytes provide enough
> lookahead to handle a multibyte character boundary correctly.
>
> - query_len = strlen(query);
> + query_len = strnlen(query,
> + (size_t) log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN);
Attached 0001 addressing the points you made:
* appending ellipsis to the query to indicate truncation (docs and tests
also updated accordingly). A side effect of this change is that setting
the parameter to 0 logs an ellipsis, which is not zero in length, but is
arguably correct, as it indicates that the whole query has been
truncated - just noting.
* use of strnlen to avoid scanning the whole query.
* truncation of prepared statements in DETAIL.
While working on this I noticed some redundant checks to call
truncate_query_log(), e.g. in exec_execute_message():
if (log_statement_max_length >= 0)
truncated_source = truncate_query_log(sourceText);
truncate_query_log() already returns NULL when query logging is disabled
or when no truncation is needed:
/* Truncation is disabled when the limit is negative */
if (!query || log_statement_max_length < 0)
return NULL;
So I'd argue that we don't need any checks in the caller.
- char *truncated_source = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_source = truncate_query_log(sourceText);
+ char *truncated_source = truncate_query_log(sourceText);
0002 attached does this.
Thoughts?
BTW, should I open a new CF entry for this?
Best, Jim
Attachments:
[text/x-patch] v1-0001-Improve-log_statement_max_length-truncation.patch (7.0K, ../../[email protected]/2-v1-0001-Improve-log_statement_max_length-truncation.patch)
download | inline diff:
From a47ccafc334e8b508f117afdfc5ce3266e0ed8fa Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Wed, 8 Jul 2026 18:29:09 +0200
Subject: [PATCH v1 1/2] Improve log_statement_max_length truncation
Apply log_statement_max_length consistently when logging prepared
statements. Previously, the prepared query emitted in the DETAIL
message for EXECUTE was not truncated, even though the corresponding
statement logged by log_statement was.
Also append an ellipsis to truncated statements, so it is immediately
apparent when a statement has been truncated.
This also avoid scanning the entire query string when determining
if truncation is needed by using strnlen() instead of strlen() in
truncate_query_log().
Author: Jim Jones <[email protected]>
Co-authored-by: Fujii Masao <[email protected]>
---
doc/src/sgml/config.sgml | 4 +-
src/backend/tcop/postgres.c | 16 +++++---
.../t/014_log_statement_max_length.pl | 37 +++++++++++++++----
3 files changed, 42 insertions(+), 15 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 9172a4c5c95..f4782261e17 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -8525,7 +8525,9 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
<xref linkend="guc-log-min-duration-statement"/>,
<xref linkend="guc-log-min-duration-sample"/>, or
<xref linkend="guc-log-transaction-sample-rate"/>
- is truncated to at most this many bytes.
+ is truncated to at most this many bytes. When a statement is
+ truncated, an ellipsis (<literal>...</literal>) is appended to
+ indicate that truncation has occurred.
A value of zero causes statements to be logged with an empty body.
<literal>-1</literal> (the default) logs statements in full.
If this value is specified without units, it is taken as bytes.
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index ce18df820cd..b0947fd7298 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -2553,8 +2553,9 @@ check_log_duration(char *msec_str, bool was_logged)
* truncate_query_log
* Truncate query string if needed for logging
*
- * Returns a palloc'd truncated copy if truncation is needed,
- * or NULL if no truncation is required.
+ * Returns a palloc'd copy of the query truncated for logging, with an
+ * ellipsis appended if truncation occurs, or NULL if no truncation is
+ * required.
*/
static char *
truncate_query_log(const char *query)
@@ -2567,7 +2568,7 @@ truncate_query_log(const char *query)
if (!query || log_statement_max_length < 0)
return NULL;
- query_len = strlen(query);
+ query_len = strnlen(query, (size_t) log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN);
/*
* No need to allocate a truncated copy if the query is shorter than
@@ -2578,9 +2579,10 @@ truncate_query_log(const char *query)
/* Truncate at a multibyte character boundary */
truncated_len = pg_mbcliplen(query, query_len, log_statement_max_length);
- truncated_query = (char *) palloc(truncated_len + 1);
+ truncated_query = (char *) palloc(truncated_len + 4);
memcpy(truncated_query, query, truncated_len);
- truncated_query[truncated_len] = '\0';
+ memcpy(truncated_query + truncated_len, "...", 3);
+ truncated_query[truncated_len + 3] = '\0';
return truncated_query;
}
@@ -2608,7 +2610,9 @@ errdetail_execute(List *raw_parsetree_list)
pstmt = FetchPreparedStatement(stmt->name, false);
if (pstmt)
{
- errdetail("prepare: %s", pstmt->plansource->query_string);
+ char *truncated_stmt = truncate_query_log(pstmt->plansource->query_string);
+
+ errdetail("prepare: %s", truncated_stmt ? truncated_stmt : pstmt->plansource->query_string);
return 0;
}
}
diff --git a/src/test/modules/test_misc/t/014_log_statement_max_length.pl b/src/test/modules/test_misc/t/014_log_statement_max_length.pl
index b1ce6068f5d..1239eff4a93 100644
--- a/src/test/modules/test_misc/t/014_log_statement_max_length.pl
+++ b/src/test/modules/test_misc/t/014_log_statement_max_length.pl
@@ -22,7 +22,7 @@ $node->psql(
'postgres', "
SET log_statement_max_length TO 20;
SELECT '123456789ABCDEF';");
-ok($node->log_contains(qr/statement: SELECT '123456789ABC$/m, $log_offset),
+ok($node->log_contains(qr/statement: SELECT '123456789ABC...$/m, $log_offset),
"ASCII query truncated at 20 bytes");
# Verify -1 logs statement in full (closing quote must be present).
@@ -51,7 +51,7 @@ SKIP:
SET client_encoding TO 'UTF8';
SET log_statement_max_length TO 11;
$mbquery");
- ok($node->log_contains(qr/statement: SELECT 'AA$/m, $log_offset),
+ ok($node->log_contains(qr/statement: SELECT 'AA...$/m, $log_offset),
"multibyte truncation at character boundary");
}
@@ -62,8 +62,8 @@ $node->psql(
'postgres', "
SET log_statement_max_length TO 0;
SELECT '123456789ABCDEF';");
-ok($node->log_contains(qr/statement:\s*$/m, $log_offset),
- "0 logs an empty statement body");
+ok($node->log_contains(qr/statement: ...\s*$/m, $log_offset),
+ "0 logs statement body with ellipsis");
# Verify truncation via the extended query protocol (execute message).
# With log_statement_max_length = 20, a 24-byte query should end
@@ -75,7 +75,7 @@ $node->psql(
SET log_statement_max_length TO 20;
SELECT '123456789ABCDEF' \\bind \\g");
ok( $node->log_contains(
- qr/execute <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ qr/execute <unnamed>: SELECT '123456789ABC...$/m, $log_offset),
"extended protocol execute truncated at 20 bytes");
# Verify extended protocol also respects -1 (no truncation; closing quote
@@ -102,14 +102,35 @@ $node->psql(
SET log_statement_max_length TO 20;
SELECT '123456789ABCDEF' \\bind \\g");
ok( $node->log_contains(
- qr/parse <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ qr/parse <unnamed>: SELECT '123456789ABC...$/m, $log_offset),
"parse duration entry truncated");
ok( $node->log_contains(
- qr/bind <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ qr/bind <unnamed>: SELECT '123456789ABC...$/m, $log_offset),
"bind duration entry truncated");
ok( $node->log_contains(
- qr/execute <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ qr/execute <unnamed>: SELECT '123456789ABC...$/m, $log_offset),
"execute duration entry truncated");
+note "Truncate prepared statement query in DETAIL";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO 12;
+ PREPARE stmt AS SELECT * FROM pg_hba_file_rules WHERE address = \$1;
+ EXECUTE stmt('127.0.0.1');");
+ok( $node->log_contains(
+ qr/prepare: PREPARE stmt...$/m, $log_offset),
+ "Truncate prepared statement query in DETAIL");
+
+note "Truncate prepared statement query in DETAIL (0 length)";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO 0;
+ PREPARE stmt AS SELECT * FROM pg_hba_file_rules WHERE address = \$1;
+ EXECUTE stmt('127.0.0.1');");
+ok( $node->log_contains(
+ qr/prepare: ...$/m, $log_offset),
+ "Truncate prepared statement query in DETAIL (0 length)");
$node->stop;
done_testing();
--
2.25.1
[text/x-patch] v1-0002-Simplify-callers-of-truncate_query_log.patch (3.2K, ../../[email protected]/3-v1-0002-Simplify-callers-of-truncate_query_log.patch)
download | inline diff:
From 7110f93844d22f92ee664c2e5ba2d959ce7180bf Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Wed, 8 Jul 2026 18:31:27 +0200
Subject: [PATCH v1 2/2] Simplify callers of truncate_query_log()
truncate_query_log() already returns NULL when query logging is disabled
or when no truncation is needed. Callers therefore do not need to check
log_statement_max_length before invoking it.
Remove the redundant checks and rely on truncate_query_log() to decide
whether a truncated copy should be returned. This is purely a code
cleanup with no behavioral change.
Author: Jim Jones <[email protected]>
---
src/backend/tcop/postgres.c | 30 ++++++------------------------
1 file changed, 6 insertions(+), 24 deletions(-)
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index b0947fd7298..61d28728ce1 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1085,10 +1085,7 @@ exec_simple_query(const char *query_string)
/* Log immediately if dictated by log_statement */
if (check_log_statement(parsetree_list))
{
- char *truncated_stmt = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_stmt = truncate_query_log(query_string);
+ char *truncated_stmt = truncate_query_log(query_string);
ereport(LOG,
(errmsg("statement: %s",
@@ -1392,10 +1389,7 @@ exec_simple_query(const char *query_string)
break;
case 2:
{
- char *truncated_stmt = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_stmt = truncate_query_log(query_string);
+ char *truncated_stmt = truncate_query_log(query_string);
ereport(LOG,
(errmsg("duration: %s ms statement: %s",
@@ -1638,10 +1632,7 @@ exec_parse_message(const char *query_string, /* string to execute */
break;
case 2:
{
- char *truncated_stmt = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_stmt = truncate_query_log(query_string);
+ char *truncated_stmt = truncate_query_log(query_string);
ereport(LOG,
(errmsg("duration: %s ms parse %s: %s",
@@ -2125,10 +2116,7 @@ exec_bind_message(StringInfo input_message)
break;
case 2:
{
- char *truncated_stmt = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_stmt = truncate_query_log(psrc->query_string);
+ char *truncated_stmt = truncate_query_log(psrc->query_string);
ereport(LOG,
(errmsg("duration: %s ms bind %s%s%s: %s",
@@ -2282,10 +2270,7 @@ exec_execute_message(const char *portal_name, long max_rows)
/* Log immediately if dictated by log_statement */
if (check_log_statement(portal->stmts))
{
- char *truncated_source = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_source = truncate_query_log(sourceText);
+ char *truncated_source = truncate_query_log(sourceText);
ereport(LOG,
(errmsg("%s %s%s%s: %s",
@@ -2414,10 +2399,7 @@ exec_execute_message(const char *portal_name, long max_rows)
break;
case 2:
{
- char *truncated_source = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_source = truncate_query_log(sourceText);
+ char *truncated_source = truncate_query_log(sourceText);
ereport(LOG,
(errmsg("duration: %s ms %s %s%s%s: %s",
--
2.25.1
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 07:34 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 15:46 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-08 17:02 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
@ 2026-07-09 04:03 ` Fujii Masao <[email protected]>
2026-07-09 07:41 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
0 siblings, 1 reply; 15+ messages in thread
From: Fujii Masao @ 2026-07-09 04:03 UTC (permalink / raw)
To: Jim Jones <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
On Thu, Jul 9, 2026 at 2:02 AM Jim Jones <[email protected]> wrote:
> Attached 0001 addressing the points you made:
Thanks for the patch!
- errdetail("prepare: %s", pstmt->plansource->query_string);
+ char *truncated_stmt = truncate_query_log(pstmt->plansource->query_string);
+
+ errdetail("prepare: %s", truncated_stmt ? truncated_stmt :
pstmt->plansource->query_string);
Shouldn't truncated_stmt be freed with pfree() (when non-NULL)
immediately after errdetail()?
- is truncated to at most this many bytes.
+ is truncated to at most this many bytes. When a statement is
+ truncated, an ellipsis (<literal>...</literal>) is appended to
+ indicate that truncation has occurred.
Since an ellipsis is appended, the logged output can exceed the configured
limit by three bytes. Wouldn't it be clearer to say something like
"has its statement text truncated to at most this many bytes"?
That makes it clear the limit applies to the statement text, not the entire
logged message.
-ok($node->log_contains(qr/statement: SELECT '123456789ABC$/m, $log_offset),
+ok($node->log_contains(qr/statement: SELECT '123456789ABC...$/m, $log_offset),
Shouldn't the dots be escaped? As written, "..." matches any three characters.
I think it should be "\.\.\.".
# a 24-byte query should end at the 20th byte ('C').
Since an ellipsis is now appended, isn't it better to replace this
with "a 24-byte query should be clipped at the 20th byte ('C')
and followed by an ellipsis."?
# With log_statement_max_length = 20, a 24-byte query should end
# at the 20th byte ('C').
Similarly, isn't it better to replace this with
"With log_statement_max_length = 20, a 24-byte query should be clipped
at the 20th byte ('C'). and followed by an ellipsis."?
> * appending ellipsis to the query to indicate truncation (docs and tests
> also updated accordingly). A side effect of this change is that setting
> the parameter to 0 logs an ellipsis, which is not zero in length, but is
> arguably correct, as it indicates that the whole query has been
> truncated - just noting.
So, should we update the docs and comments accordingly? For example:
--------------------------------------------
- A value of zero causes statements to be logged with an empty body.
+ A value of zero causes statements to be logged as only an ellipsis.
<literal>-1</literal> (the default) logs statements in full.
If this value is specified without units, it is taken as bytes.
{ name => 'log_statement_max_length', type => 'int', context =>
'PGC_SUSET', group => 'LOGGING_WHAT',
- short_desc => 'Sets the maximum length in bytes of logged statements.',
- long_desc => '-1 means log statement in full; 0 means log an empty
statement body.',
+ short_desc => 'Sets the maximum length in bytes of logged statement text.',
+ long_desc => '-1 means log statement in full; 0 means log only an ellipsis.',
- #log_statement_max_length = -1 # max bytes of logged statements;
+ #log_statement_max_length = -1 # max bytes of logged statement text;
# -1 means log statement in full,
- # 0 means log an empty body
+ # 0 means log only an ellipsis
-# Verify 0 logs an empty statement body.
+# Verify 0 logs only an ellipsis.
note "Zero length truncation";
ok($node->log_contains(qr/statement: \.\.\.\s*$/m, $log_offset),
- "0 logs statement body with ellipsis");
+ "0 logs only an ellipsis");
--------------------------------------------
> 0002 attached does this.
+1 to this patch!
> BTW, should I open a new CF entry for this?
Yes, I think that's a good idea so these follow-up patches don't get forgotten.
Regards,
--
Fujii Masao
^ permalink raw reply [nested|flat] 15+ messages in thread
* Re: Truncate logs by max_log_size
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 07:34 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 15:46 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-08 17:02 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-09 04:03 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
@ 2026-07-09 07:41 ` Jim Jones <[email protected]>
0 siblings, 0 replies; 15+ messages in thread
From: Jim Jones @ 2026-07-09 07:41 UTC (permalink / raw)
To: Fujii Masao <[email protected]>; +Cc: Maxym Kharchenko <[email protected]>; Kirill Reshke <[email protected]>; Álvaro Herrera <[email protected]>; Fujii Masao <[email protected]>; Kirill Gavrilov <[email protected]>; Andrey M. Borodin <[email protected]>; Euler Taveira <[email protected]>; [email protected]
Thanks for the thorough review!
On 09/07/2026 06:03, Fujii Masao wrote:
> - errdetail("prepare: %s", pstmt->plansource->query_string);
> + char *truncated_stmt = truncate_query_log(pstmt->plansource->query_string);
> +
> + errdetail("prepare: %s", truncated_stmt ? truncated_stmt :
> pstmt->plansource->query_string);
>
> Shouldn't truncated_stmt be freed with pfree() (when non-NULL)
> immediately after errdetail()?
Yes, I missed that one.
Fixed.
> - is truncated to at most this many bytes.
> + is truncated to at most this many bytes. When a statement is
> + truncated, an ellipsis (<literal>...</literal>) is appended to
> + indicate that truncation has occurred.
>
> Since an ellipsis is appended, the logged output can exceed the configured
> limit by three bytes. Wouldn't it be clearer to say something like
> "has its statement text truncated to at most this many bytes"?
> That makes it clear the limit applies to the statement text, not the entire
> logged message.
Agreed.
I added your suggestion.
> -ok($node->log_contains(qr/statement: SELECT '123456789ABC$/m, $log_offset),
> +ok($node->log_contains(qr/statement: SELECT '123456789ABC...$/m, $log_offset),
>
> Shouldn't the dots be escaped? As written, "..." matches any three characters.
> I think it should be "\.\.\.".
At first I also thought so, as in this context ... could mean any three
arbitrary characters, but the tests results showed a different picture,
so I thought it was not necessary. Anyway, I escaped them now in v2.
> # a 24-byte query should end at the 20th byte ('C').
>
> Since an ellipsis is now appended, isn't it better to replace this
> with "a 24-byte query should be clipped at the 20th byte ('C')
> and followed by an ellipsis."?
>
>
> # With log_statement_max_length = 20, a 24-byte query should end
> # at the 20th byte ('C').
>
> Similarly, isn't it better to replace this with
> "With log_statement_max_length = 20, a 24-byte query should be clipped
> at the 20th byte ('C'). and followed by an ellipsis."?
>> * appending ellipsis to the query to indicate truncation (docs and tests
>> also updated accordingly). A side effect of this change is that setting
>> the parameter to 0 logs an ellipsis, which is not zero in length, but is
>> arguably correct, as it indicates that the whole query has been
>> truncated - just noting.
> So, should we update the docs and comments accordingly? For example:
>
> --------------------------------------------
> - A value of zero causes statements to be logged with an empty body.
> + A value of zero causes statements to be logged as only an ellipsis.
> <literal>-1</literal> (the default) logs statements in full.
> If this value is specified without units, it is taken as bytes.
>
> { name => 'log_statement_max_length', type => 'int', context =>
> 'PGC_SUSET', group => 'LOGGING_WHAT',
> - short_desc => 'Sets the maximum length in bytes of logged statements.',
> - long_desc => '-1 means log statement in full; 0 means log an empty
> statement body.',
> + short_desc => 'Sets the maximum length in bytes of logged statement text.',
> + long_desc => '-1 means log statement in full; 0 means log only an ellipsis.',
>
> - #log_statement_max_length = -1 # max bytes of logged statements;
> + #log_statement_max_length = -1 # max bytes of logged statement text;
> # -1 means log statement in full,
> - # 0 means log an empty body
> + # 0 means log only an ellipsis
>
> -# Verify 0 logs an empty statement body.
> +# Verify 0 logs only an ellipsis.
> note "Zero length truncation";
>
> ok($node->log_contains(qr/statement: \.\.\.\s*$/m, $log_offset),
> - "0 logs statement body with ellipsis");
> + "0 logs only an ellipsis");
> --------------------------------------------
Comments and docs updated.
>> BTW, should I open a new CF entry for this?
> Yes, I think that's a good idea so these follow-up patches don't get forgotten.
Done: https://commitfest.postgresql.org/patch/6998/
Best, Jim
Attachments:
[text/x-patch] v2-0001-Improve-log_statement_max_length-truncation.patch (9.1K, ../../[email protected]/2-v2-0001-Improve-log_statement_max_length-truncation.patch)
download | inline diff:
From 39072fa5bff8e23d4c56604d45635f835a0c78ad Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Thu, 9 Jul 2026 09:25:32 +0200
Subject: [PATCH v2 1/2] Improve log_statement_max_length truncation
Apply log_statement_max_length consistently when logging prepared
statements. Previously, the prepared query emitted in the DETAIL
message for EXECUTE was not truncated, even though the corresponding
statement logged by log_statement was.
Also append an ellipsis to truncated statements, so it is immediately
apparent when a statement has been truncated.
This also avoid scanning the entire query string when determining
if truncation is needed by using strnlen() instead of strlen() in
truncate_query_log().
Author: Jim Jones <[email protected]>
Co-authored-by: Fujii Masao <[email protected]>
---
doc/src/sgml/config.sgml | 6 ++-
src/backend/tcop/postgres.c | 20 +++++---
src/backend/utils/misc/postgresql.conf.sample | 4 +-
.../t/014_log_statement_max_length.pl | 46 ++++++++++++++-----
4 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index c67130c620e..0848c18d329 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -8539,8 +8539,10 @@ log_line_prefix = '%m [%p] %q%u@%d/%a '
<xref linkend="guc-log-min-duration-statement"/>,
<xref linkend="guc-log-min-duration-sample"/>, or
<xref linkend="guc-log-transaction-sample-rate"/>
- is truncated to at most this many bytes.
- A value of zero causes statements to be logged with an empty body.
+ has its statement text truncated to at most this many bytes.
+ When a statement is truncated, an ellipsis (<literal>...</literal>)
+ is appended to indicate that truncation has occurred.
+ A value of zero causes statements to be logged as only an ellipsis.
<literal>-1</literal> (the default) logs statements in full.
If this value is specified without units, it is taken as bytes.
This setting does not affect statements logged because of
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index ce18df820cd..019e4ab42fe 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -2553,8 +2553,9 @@ check_log_duration(char *msec_str, bool was_logged)
* truncate_query_log
* Truncate query string if needed for logging
*
- * Returns a palloc'd truncated copy if truncation is needed,
- * or NULL if no truncation is required.
+ * Returns a palloc'd copy of the query truncated for logging, with an
+ * ellipsis appended if truncation occurs, or NULL if no truncation is
+ * required.
*/
static char *
truncate_query_log(const char *query)
@@ -2567,7 +2568,7 @@ truncate_query_log(const char *query)
if (!query || log_statement_max_length < 0)
return NULL;
- query_len = strlen(query);
+ query_len = strnlen(query, (size_t) log_statement_max_length + MAX_MULTIBYTE_CHAR_LEN);
/*
* No need to allocate a truncated copy if the query is shorter than
@@ -2578,9 +2579,10 @@ truncate_query_log(const char *query)
/* Truncate at a multibyte character boundary */
truncated_len = pg_mbcliplen(query, query_len, log_statement_max_length);
- truncated_query = (char *) palloc(truncated_len + 1);
+ truncated_query = (char *) palloc(truncated_len + 4);
memcpy(truncated_query, query, truncated_len);
- truncated_query[truncated_len] = '\0';
+ memcpy(truncated_query + truncated_len, "...", 3);
+ truncated_query[truncated_len + 3] = '\0';
return truncated_query;
}
@@ -2608,7 +2610,13 @@ errdetail_execute(List *raw_parsetree_list)
pstmt = FetchPreparedStatement(stmt->name, false);
if (pstmt)
{
- errdetail("prepare: %s", pstmt->plansource->query_string);
+ char *truncated_stmt = truncate_query_log(pstmt->plansource->query_string);
+
+ errdetail("prepare: %s", truncated_stmt ? truncated_stmt : pstmt->plansource->query_string);
+
+ if (truncated_stmt != NULL)
+ pfree(truncated_stmt);
+
return 0;
}
}
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 47e1221f3c3..7958653077b 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -676,9 +676,9 @@
# bind-parameter values to N bytes;
# -1 means print in full, 0 disables
#log_statement = 'none' # none, ddl, mod, all
-#log_statement_max_length = -1 # max bytes of logged statements;
+#log_statement_max_length = -1 # max bytes of logged statement text;
# -1 means log statement in full,
- # 0 means log an empty body
+ # 0 means log only an ellipsis
#log_replication_commands = off
#log_temp_files = -1 # log temporary files equal or larger
# than the specified size in kilobytes;
diff --git a/src/test/modules/test_misc/t/014_log_statement_max_length.pl b/src/test/modules/test_misc/t/014_log_statement_max_length.pl
index b1ce6068f5d..b879566ef54 100644
--- a/src/test/modules/test_misc/t/014_log_statement_max_length.pl
+++ b/src/test/modules/test_misc/t/014_log_statement_max_length.pl
@@ -15,14 +15,15 @@ $node->init();
$node->start;
# Verify ASCII truncation. With log_statement_max_length = 20,
-# a 24-byte query should end at the 20th byte ('C').
+# a 24-byte query should be clipped at the 20th byte ('C') and
+# followed by an ellipsis.
note "ASCII truncation via log_statement";
my $log_offset = -s $node->logfile;
$node->psql(
'postgres', "
SET log_statement_max_length TO 20;
SELECT '123456789ABCDEF';");
-ok($node->log_contains(qr/statement: SELECT '123456789ABC$/m, $log_offset),
+ok($node->log_contains(qr/statement: SELECT '123456789ABC\.\.\.$/m, $log_offset),
"ASCII query truncated at 20 bytes");
# Verify -1 logs statement in full (closing quote must be present).
@@ -51,23 +52,23 @@ SKIP:
SET client_encoding TO 'UTF8';
SET log_statement_max_length TO 11;
$mbquery");
- ok($node->log_contains(qr/statement: SELECT 'AA$/m, $log_offset),
+ ok($node->log_contains(qr/statement: SELECT 'AA\.\.\.$/m, $log_offset),
"multibyte truncation at character boundary");
}
-# Verify 0 logs an empty statement body.
+# Verify 0 logs only an ellipsis.
note "Zero length truncation";
$log_offset = -s $node->logfile;
$node->psql(
'postgres', "
SET log_statement_max_length TO 0;
SELECT '123456789ABCDEF';");
-ok($node->log_contains(qr/statement:\s*$/m, $log_offset),
- "0 logs an empty statement body");
+ok($node->log_contains(qr/statement: \.\.\.\s*$/m, $log_offset),
+ "0 logs statement body with only an ellipsis");
# Verify truncation via the extended query protocol (execute message).
-# With log_statement_max_length = 20, a 24-byte query should end
-# at the 20th byte ('C').
+# With log_statement_max_length = 20, a 24-byte query should be clipped
+# at the 20th byte ('C') and followed by an ellipsis.
note "Extended query protocol (execute) truncation";
$log_offset = -s $node->logfile;
$node->psql(
@@ -75,7 +76,7 @@ $node->psql(
SET log_statement_max_length TO 20;
SELECT '123456789ABCDEF' \\bind \\g");
ok( $node->log_contains(
- qr/execute <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ qr/execute <unnamed>: SELECT '123456789ABC\.\.\.$/m, $log_offset),
"extended protocol execute truncated at 20 bytes");
# Verify extended protocol also respects -1 (no truncation; closing quote
@@ -102,14 +103,35 @@ $node->psql(
SET log_statement_max_length TO 20;
SELECT '123456789ABCDEF' \\bind \\g");
ok( $node->log_contains(
- qr/parse <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ qr/parse <unnamed>: SELECT '123456789ABC\.\.\.$/m, $log_offset),
"parse duration entry truncated");
ok( $node->log_contains(
- qr/bind <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ qr/bind <unnamed>: SELECT '123456789ABC\.\.\.$/m, $log_offset),
"bind duration entry truncated");
ok( $node->log_contains(
- qr/execute <unnamed>: SELECT '123456789ABC$/m, $log_offset),
+ qr/execute <unnamed>: SELECT '123456789ABC\.\.\.$/m, $log_offset),
"execute duration entry truncated");
+note "Truncate prepared statement query in DETAIL";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO 12;
+ PREPARE stmt AS SELECT * FROM pg_hba_file_rules WHERE address = \$1;
+ EXECUTE stmt('127.0.0.1');");
+ok( $node->log_contains(
+ qr/prepare: PREPARE stmt\.\.\.$/m, $log_offset),
+ "Truncate prepared statement query in DETAIL");
+
+note "Truncate prepared statement query in DETAIL (0 length)";
+$log_offset = -s $node->logfile;
+$node->psql(
+ 'postgres', "
+ SET log_statement_max_length TO 0;
+ PREPARE stmt AS SELECT * FROM pg_hba_file_rules WHERE address = \$1;
+ EXECUTE stmt('127.0.0.1');");
+ok( $node->log_contains(
+ qr/prepare: \.\.\.$/m, $log_offset),
+ "0 logs the prepared statement body with only an ellipsis");
$node->stop;
done_testing();
--
2.55.0
[text/x-patch] v2-0002-Simplify-callers-of-truncate_query_log.patch (3.2K, ../../[email protected]/3-v2-0002-Simplify-callers-of-truncate_query_log.patch)
download | inline diff:
From 4c1fb8acd321dea4830b96d1518b1ffd4474b164 Mon Sep 17 00:00:00 2001
From: Jim Jones <[email protected]>
Date: Wed, 8 Jul 2026 18:31:27 +0200
Subject: [PATCH v2 2/2] Simplify callers of truncate_query_log()
truncate_query_log() already returns NULL when query logging is disabled
or when no truncation is needed. Callers therefore do not need to check
log_statement_max_length before invoking it.
Remove the redundant checks and rely on truncate_query_log() to decide
whether a truncated copy should be returned. This is purely a code
cleanup with no behavioral change.
Author: Jim Jones <[email protected]>
---
src/backend/tcop/postgres.c | 30 ++++++------------------------
1 file changed, 6 insertions(+), 24 deletions(-)
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 019e4ab42fe..b966cb242b7 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1085,10 +1085,7 @@ exec_simple_query(const char *query_string)
/* Log immediately if dictated by log_statement */
if (check_log_statement(parsetree_list))
{
- char *truncated_stmt = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_stmt = truncate_query_log(query_string);
+ char *truncated_stmt = truncate_query_log(query_string);
ereport(LOG,
(errmsg("statement: %s",
@@ -1392,10 +1389,7 @@ exec_simple_query(const char *query_string)
break;
case 2:
{
- char *truncated_stmt = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_stmt = truncate_query_log(query_string);
+ char *truncated_stmt = truncate_query_log(query_string);
ereport(LOG,
(errmsg("duration: %s ms statement: %s",
@@ -1638,10 +1632,7 @@ exec_parse_message(const char *query_string, /* string to execute */
break;
case 2:
{
- char *truncated_stmt = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_stmt = truncate_query_log(query_string);
+ char *truncated_stmt = truncate_query_log(query_string);
ereport(LOG,
(errmsg("duration: %s ms parse %s: %s",
@@ -2125,10 +2116,7 @@ exec_bind_message(StringInfo input_message)
break;
case 2:
{
- char *truncated_stmt = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_stmt = truncate_query_log(psrc->query_string);
+ char *truncated_stmt = truncate_query_log(psrc->query_string);
ereport(LOG,
(errmsg("duration: %s ms bind %s%s%s: %s",
@@ -2282,10 +2270,7 @@ exec_execute_message(const char *portal_name, long max_rows)
/* Log immediately if dictated by log_statement */
if (check_log_statement(portal->stmts))
{
- char *truncated_source = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_source = truncate_query_log(sourceText);
+ char *truncated_source = truncate_query_log(sourceText);
ereport(LOG,
(errmsg("%s %s%s%s: %s",
@@ -2414,10 +2399,7 @@ exec_execute_message(const char *portal_name, long max_rows)
break;
case 2:
{
- char *truncated_source = NULL;
-
- if (log_statement_max_length >= 0)
- truncated_source = truncate_query_log(sourceText);
+ char *truncated_source = truncate_query_log(sourceText);
ereport(LOG,
(errmsg("duration: %s ms %s %s%s%s: %s",
--
2.55.0
^ permalink raw reply [nested|flat] 15+ messages in thread
end of thread, other threads:[~2026-07-09 07:41 UTC | newest]
Thread overview: 15+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-01-22 20:59 [PATCH v3 3/3] Fix sizing of tape read buffers. Heikki Linnakangas <[email protected]>
2026-02-05 10:22 Re: Truncate logs by max_log_size Álvaro Herrera <[email protected]>
2026-02-05 11:53 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-02-06 07:50 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-02 15:49 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-02 18:47 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 00:56 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 04:24 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 15:06 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-03 07:34 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-03 15:46 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-04 11:01 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-08 17:02 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
2026-07-09 04:03 ` Re: Truncate logs by max_log_size Fujii Masao <[email protected]>
2026-07-09 07:41 ` Re: Truncate logs by max_log_size Jim Jones <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox