From 02545297084f0326528013d6f6ceba710e5d49dd Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 27 Jun 2025 10:00:34 -0400 Subject: [PATCH] add some line wrapping logic --- contrib/pg_plan_advice/pg_plan_advice.c | 2 +- contrib/pg_plan_advice/pgpa_output.c | 101 +++++++++++++++++++++--- 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/contrib/pg_plan_advice/pg_plan_advice.c b/contrib/pg_plan_advice/pg_plan_advice.c index 6925ac4963..4017008d5b 100644 --- a/contrib/pg_plan_advice/pg_plan_advice.c +++ b/contrib/pg_plan_advice/pg_plan_advice.c @@ -71,5 +71,5 @@ pgpa_check_plan(PlannedStmt *pstmt) initStringInfo(&buf); pgpa_output_advice(&buf, &context, rt_identifiers); - elog(LOG, "advice:%s", buf.data); + elog(LOG, "advice:\n%s", buf.data); } diff --git a/contrib/pg_plan_advice/pgpa_output.c b/contrib/pg_plan_advice/pgpa_output.c index 9c04405b55..a3d9e0feb4 100644 --- a/contrib/pg_plan_advice/pgpa_output.c +++ b/contrib/pg_plan_advice/pgpa_output.c @@ -20,6 +20,8 @@ static void pgpa_debug_out_join_member(StringInfo buf, static char *pgpa_cstring_join_clump_strategy(pgpa_join_clump_strategy strategy); static char *pgpa_cstring_join_strategy(pgpa_join_strategy strategy); +static void pgpa_maybe_linebreak(StringInfo buf, int wrap_column); + void pgpa_output_advice(StringInfo buf, pgpa_plan_walker_context *context, const char **rt_identifiers) @@ -30,15 +32,17 @@ pgpa_output_advice(StringInfo buf, pgpa_plan_walker_context *context, { pgpa_unrolled_join *ujoin = lfirst(lc); - appendStringInfoChar(buf, ' '); - pgpa_debug_out_unrolled_join(buf, ujoin, rt_identifiers); + if (buf->len > 0) + appendStringInfoChar(buf, '\n'); + pgpa_debug_out_unrolled_join(buf, ujoin, rt_identifiers, true); } foreach(lc, context->clumped_joins) { pgpa_clumped_join *cjoin = lfirst(lc); - appendStringInfoChar(buf, ' '); + if (buf->len > 0) + appendStringInfoChar(buf, '\n'); pgpa_debug_out_clumped_join(buf, cjoin, rt_identifiers); } @@ -46,7 +50,8 @@ pgpa_output_advice(StringInfo buf, pgpa_plan_walker_context *context, { pgpa_gathered_join *gathered_join = lfirst(lc); - appendStringInfoChar(buf, ' '); + if (buf->len > 0) + appendStringInfoChar(buf, '\n'); pgpa_debug_out_gathered_join(buf, gathered_join, rt_identifiers); } } @@ -74,16 +79,22 @@ pgpa_debug_out_clumped_join(StringInfo buf, pgpa_clumped_join *clump, appendStringInfoString(buf, identifier); } else + { + pgpa_maybe_linebreak(buf, 79); appendStringInfo(buf, " %s", identifier); + } } appendStringInfoChar(buf, ')'); } void pgpa_debug_out_unrolled_join(StringInfo buf, pgpa_unrolled_join *join, - const char **rt_identifiers) + const char **rt_identifiers, bool toplevel) { - appendStringInfoChar(buf, '('); + if (toplevel) + appendStringInfo(buf, "JOIN_ORDER("); + else + appendStringInfoChar(buf, '('); pgpa_debug_out_join_member(buf, &join->outer, rt_identifiers); @@ -91,12 +102,19 @@ pgpa_debug_out_unrolled_join(StringInfo buf, pgpa_unrolled_join *join, { char *cstrategy; + pgpa_maybe_linebreak(buf, 79); cstrategy = pgpa_cstring_join_strategy(join->strategy[k]); - appendStringInfo(buf, " %s ", cstrategy); + appendStringInfo(buf, " %s", cstrategy); + + pgpa_maybe_linebreak(buf, 79); + appendStringInfoChar(buf, ' '); pgpa_debug_out_join_member(buf, &join->inner[k], rt_identifiers); } - appendStringInfoChar(buf, ')'); + if (toplevel) + appendStringInfo(buf, ")\n"); + else + appendStringInfoChar(buf, ')'); } void @@ -124,7 +142,10 @@ pgpa_debug_out_gathered_join(StringInfo buf, pgpa_gathered_join *gathered_join, appendStringInfoString(buf, identifier); } else + { + pgpa_maybe_linebreak(buf, 79); appendStringInfo(buf, " %s", identifier); + } } appendStringInfoChar(buf, ')'); } @@ -138,7 +159,7 @@ pgpa_debug_out_join_member(StringInfo buf, pgpa_join_member *member, rt_identifiers); else if (member->unrolled_join != NULL) pgpa_debug_out_unrolled_join(buf, member->unrolled_join, - rt_identifiers); + rt_identifiers, false); else { if (rt_identifiers[member->rti - 1] == NULL) @@ -190,3 +211,65 @@ pgpa_cstring_join_strategy(pgpa_join_strategy strategy) Assert(false); } + +/* + * Insert a line break into the StringInfoData, if needed. + * + * If wrap_column is zero or negative, this does nothing. Otherwise, we + * consider inserting a newline. We only insert a newline if the length of + * the last line in the buffer exceeds wrap_column, and not if we'd be + * inserting a newline at or before the beginning of the current line. + * + * The position at which the newline is inserted is simply wherever the + * buffer ended the last time this function was called. In other words, + * the caller is expected to call this function every time we reach a good + * place for a line break. + */ +static void +pgpa_maybe_linebreak(StringInfo buf, int wrap_column) +{ + char *trailing_nl; + int line_start; + int save_cursor; + + /* If line wrapping is disabled, exit quickly. */ + if (wrap_column <= 0) + return; + + /* + * Set line_start to the byte offset within buf->data of the first + * character of the current line, where the current line means the last + * one in the buffer. Note that line_start could be the offset of the + * trailing '\0' if the last character in the buffer is a line break. + */ + trailing_nl = strrchr(buf->data, '\n'); + if (trailing_nl == NULL) + line_start = 0; + else + line_start = (trailing_nl - buf->data) + 1; + + /* + * Remember that the current end of the buffer is a potential location + * to insert a line break on a future call to this function. + */ + save_cursor = buf->cursor; + buf->cursor = buf->len; + + /* If we haven't passed the wrap column, we don't need a newline. */ + if (buf->len - line_start <= wrap_column) + return; + + /* + * It only makes sense to insert a newline at a position later than the + * beginning of the current line. + */ + if (buf->cursor <= line_start) + return; + + /* Insert a newline at the previous cursor location. */ + enlargeStringInfo(buf, 1); + memmove(&buf->data[save_cursor] + 1, &buf->data[save_cursor], + buf->len - save_cursor); + buf->len++; + buf->data[save_cursor] = '\n'; +} -- 2.39.5