* 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)
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
/* 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;
}
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;
}
}
$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).
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(
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
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();