PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pgpa_output.c File Reference
#include "postgres.h"
#include "pgpa_output.h"
#include "pgpa_scan.h"
#include "nodes/parsenodes.h"
#include "parser/parsetree.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
Include dependency graph for pgpa_output.c:

Go to the source code of this file.

Data Structures

struct  pgpa_output_context
 

Typedefs

typedef struct pgpa_output_context pgpa_output_context
 

Functions

static void pgpa_output_unrolled_join (pgpa_output_context *context, pgpa_unrolled_join *join)
 
static void pgpa_output_join_member (pgpa_output_context *context, pgpa_join_member *member)
 
static void pgpa_output_scan_strategy (pgpa_output_context *context, pgpa_scan_strategy strategy, List *scans)
 
static void pgpa_output_relation_name (pgpa_output_context *context, Oid relid)
 
static void pgpa_output_query_feature (pgpa_output_context *context, pgpa_qf_type type, List *query_features)
 
static void pgpa_output_simple_strategy (pgpa_output_context *context, char *strategy, List *relid_sets)
 
static void pgpa_output_no_gather (pgpa_output_context *context, Bitmapset *relids)
 
static void pgpa_output_relations (pgpa_output_context *context, StringInfo buf, Bitmapset *relids)
 
static charpgpa_cstring_join_strategy (pgpa_join_strategy strategy)
 
static charpgpa_cstring_scan_strategy (pgpa_scan_strategy strategy)
 
static charpgpa_cstring_query_feature_type (pgpa_qf_type type)
 
static void pgpa_maybe_linebreak (StringInfo buf, int wrap_column)
 
void pgpa_output_advice (StringInfo buf, pgpa_plan_walker_context *walker, pgpa_identifier *rt_identifiers)
 

Typedef Documentation

◆ pgpa_output_context

Function Documentation

◆ pgpa_cstring_join_strategy()

static char * pgpa_cstring_join_strategy ( pgpa_join_strategy  strategy)
static

Definition at line 435 of file pgpa_output.c.

436{
437 switch (strategy)
438 {
440 return "MERGE_JOIN_PLAIN";
442 return "MERGE_JOIN_MATERIALIZE";
444 return "NESTED_LOOP_PLAIN";
446 return "NESTED_LOOP_MATERIALIZE";
448 return "NESTED_LOOP_MEMOIZE";
449 case JSTRAT_HASH_JOIN:
450 return "HASH_JOIN";
451 }
452
454 return NULL;
455}
#define pg_unreachable()
Definition c.h:361
@ JSTRAT_MERGE_JOIN_PLAIN
Definition pgpa_join.h:29
@ JSTRAT_NESTED_LOOP_MATERIALIZE
Definition pgpa_join.h:32
@ JSTRAT_NESTED_LOOP_MEMOIZE
Definition pgpa_join.h:33
@ JSTRAT_HASH_JOIN
Definition pgpa_join.h:34
@ JSTRAT_NESTED_LOOP_PLAIN
Definition pgpa_join.h:31
@ JSTRAT_MERGE_JOIN_MATERIALIZE
Definition pgpa_join.h:30
static int fb(int x)

References fb(), JSTRAT_HASH_JOIN, JSTRAT_MERGE_JOIN_MATERIALIZE, JSTRAT_MERGE_JOIN_PLAIN, JSTRAT_NESTED_LOOP_MATERIALIZE, JSTRAT_NESTED_LOOP_MEMOIZE, JSTRAT_NESTED_LOOP_PLAIN, and pg_unreachable.

Referenced by pgpa_output_advice().

◆ pgpa_cstring_query_feature_type()

static char * pgpa_cstring_query_feature_type ( pgpa_qf_type  type)
static

Definition at line 491 of file pgpa_output.c.

492{
493 switch (type)
494 {
495 case PGPAQF_GATHER:
496 return "GATHER";
498 return "GATHER_MERGE";
500 return "SEMIJOIN_NON_UNIQUE";
502 return "SEMIJOIN_UNIQUE";
503 }
504
505
507 return NULL;
508}
@ PGPAQF_GATHER
Definition pgpa_walker.h:63
@ PGPAQF_GATHER_MERGE
Definition pgpa_walker.h:64
@ PGPAQF_SEMIJOIN_UNIQUE
Definition pgpa_walker.h:66
@ PGPAQF_SEMIJOIN_NON_UNIQUE
Definition pgpa_walker.h:65
const char * type

References fb(), pg_unreachable, PGPAQF_GATHER, PGPAQF_GATHER_MERGE, PGPAQF_SEMIJOIN_NON_UNIQUE, PGPAQF_SEMIJOIN_UNIQUE, and type.

Referenced by pgpa_output_query_feature().

◆ pgpa_cstring_scan_strategy()

static char * pgpa_cstring_scan_strategy ( pgpa_scan_strategy  strategy)
static

Definition at line 461 of file pgpa_output.c.

462{
463 switch (strategy)
464 {
466 return "ORDINARY_SCAN";
467 case PGPA_SCAN_SEQ:
468 return "SEQ_SCAN";
470 return "BITMAP_HEAP_SCAN";
472 return "FOREIGN_JOIN";
473 case PGPA_SCAN_INDEX:
474 return "INDEX_SCAN";
476 return "INDEX_ONLY_SCAN";
478 return "PARTITIONWISE";
479 case PGPA_SCAN_TID:
480 return "TID_SCAN";
481 }
482
484 return NULL;
485}
@ PGPA_SCAN_SEQ
Definition pgpa_scan.h:58
@ PGPA_SCAN_INDEX
Definition pgpa_scan.h:61
@ PGPA_SCAN_INDEX_ONLY
Definition pgpa_scan.h:62
@ PGPA_SCAN_BITMAP_HEAP
Definition pgpa_scan.h:59
@ PGPA_SCAN_FOREIGN
Definition pgpa_scan.h:60
@ PGPA_SCAN_TID
Definition pgpa_scan.h:64
@ PGPA_SCAN_PARTITIONWISE
Definition pgpa_scan.h:63
@ PGPA_SCAN_ORDINARY
Definition pgpa_scan.h:57

References fb(), pg_unreachable, PGPA_SCAN_BITMAP_HEAP, PGPA_SCAN_FOREIGN, PGPA_SCAN_INDEX, PGPA_SCAN_INDEX_ONLY, PGPA_SCAN_ORDINARY, PGPA_SCAN_PARTITIONWISE, PGPA_SCAN_SEQ, and PGPA_SCAN_TID.

Referenced by pgpa_output_scan_strategy().

◆ pgpa_maybe_linebreak()

static void pgpa_maybe_linebreak ( StringInfo  buf,
int  wrap_column 
)
static

Definition at line 524 of file pgpa_output.c.

525{
526 char *trailing_nl;
527 int line_start;
528 int save_cursor;
529
530 /* If line wrapping is disabled, exit quickly. */
531 if (wrap_column <= 0)
532 return;
533
534 /*
535 * Set line_start to the byte offset within buf->data of the first
536 * character of the current line, where the current line means the last
537 * one in the buffer. Note that line_start could be the offset of the
538 * trailing '\0' if the last character in the buffer is a line break.
539 */
540 trailing_nl = strrchr(buf->data, '\n');
541 if (trailing_nl == NULL)
542 line_start = 0;
543 else
544 line_start = (trailing_nl - buf->data) + 1;
545
546 /*
547 * Remember that the current end of the buffer is a potential location to
548 * insert a line break on a future call to this function.
549 */
550 save_cursor = buf->cursor;
551 buf->cursor = buf->len;
552
553 /* If we haven't passed the wrap column, we don't need a newline. */
554 if (buf->len - line_start <= wrap_column)
555 return;
556
557 /*
558 * It only makes sense to insert a newline at a position later than the
559 * beginning of the current line.
560 */
561 if (save_cursor <= line_start)
562 return;
563
564 /* Insert a newline at the previous cursor location. */
566 memmove(&buf->data[save_cursor] + 1, &buf->data[save_cursor],
567 buf->len - save_cursor);
568 ++buf->cursor;
569 buf->data[++buf->len] = '\0';
570 buf->data[save_cursor] = '\n';
571}
static char buf[DEFAULT_XLOG_SEG_SIZE]
void enlargeStringInfo(StringInfo str, int needed)
Definition stringinfo.c:337

References buf, enlargeStringInfo(), and fb().

Referenced by pgpa_output_advice(), pgpa_output_query_feature(), pgpa_output_relations(), pgpa_output_scan_strategy(), pgpa_output_simple_strategy(), and pgpa_output_unrolled_join().

◆ pgpa_output_advice()

void pgpa_output_advice ( StringInfo  buf,
pgpa_plan_walker_context walker,
pgpa_identifier rt_identifiers 
)

Definition at line 78 of file pgpa_output.c.

80{
81 Index rtable_length = list_length(walker->pstmt->rtable);
82 ListCell *lc;
83 pgpa_output_context context;
84
85 /* Basic initialization. */
86 memset(&context, 0, sizeof(pgpa_output_context));
87 context.buf = buf;
88
89 /*
90 * Convert identifiers to string form. Note that the loop variable here is
91 * not an RTI, because RTIs are 1-based. Some RTIs will have no
92 * identifier, either because the reloptkind is RTE_JOIN or because that
93 * portion of the query didn't make it into the final plan.
94 */
95 context.rid_strings = palloc0_array(const char *, rtable_length);
96 for (int i = 0; i < rtable_length; ++i)
97 if (rt_identifiers[i].alias_name != NULL)
99
100 /*
101 * If the user chooses to use EXPLAIN (PLAN_ADVICE) in an 80-column window
102 * from a psql client with default settings, psql will add one space to
103 * the left of the output and EXPLAIN will add two more to the left of the
104 * advice. Thus, lines of more than 77 characters will wrap. We set the
105 * wrap limit to 76 here so that the output won't reach all the way to the
106 * very last column of the terminal.
107 *
108 * Of course, this is fairly arbitrary set of assumptions, and one could
109 * well make an argument for a different wrap limit, or for a configurable
110 * one.
111 */
112 context.wrap_column = 76;
113
114 /*
115 * Each piece of JOIN_ORDER() advice fully describes the join order for a
116 * a single unrolled join. Merging is not permitted, because that would
117 * change the meaning, e.g. SEQ_SCAN(a b c d) means simply that sequential
118 * scans should be used for all of those relations, and is thus equivalent
119 * to SEQ_SCAN(a b) SEQ_SCAN(c d), but JOIN_ORDER(a b c d) means that "a"
120 * is the driving table which is then joined to "b" then "c" then "d",
121 * which is totally different from JOIN_ORDER(a b) and JOIN_ORDER(c d).
122 */
123 foreach(lc, walker->toplevel_unrolled_joins)
124 {
126
127 if (buf->len > 0)
129 appendStringInfo(context.buf, "JOIN_ORDER(");
131 appendStringInfoChar(context.buf, ')');
132 pgpa_maybe_linebreak(context.buf, context.wrap_column);
133 }
134
135 /* Emit join strategy advice. */
136 for (int s = 0; s < NUM_PGPA_JOIN_STRATEGY; ++s)
137 {
138 char *strategy = pgpa_cstring_join_strategy(s);
139
141 strategy,
142 walker->join_strategies[s]);
143 }
144
145 /*
146 * Emit scan strategy advice (but not for ordinary scans, which are
147 * definitionally uninteresting).
148 */
149 for (int c = 0; c < NUM_PGPA_SCAN_STRATEGY; ++c)
150 if (c != PGPA_SCAN_ORDINARY)
151 pgpa_output_scan_strategy(&context, c, walker->scans[c]);
152
153 /* Emit query feature advice. */
154 for (int t = 0; t < NUM_PGPA_QF_TYPES; ++t)
155 pgpa_output_query_feature(&context, t, walker->query_features[t]);
156
157 /* Emit NO_GATHER advice. */
158 pgpa_output_no_gather(&context, walker->no_gather_scans);
159}
unsigned int Index
Definition c.h:682
#define palloc0_array(type, count)
Definition fe_memutils.h:77
int i
Definition isn.c:77
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
const char * pgpa_identifier_string(const pgpa_identifier *rid)
#define NUM_PGPA_JOIN_STRATEGY
Definition pgpa_join.h:38
static void pgpa_output_simple_strategy(pgpa_output_context *context, char *strategy, List *relid_sets)
static char * pgpa_cstring_join_strategy(pgpa_join_strategy strategy)
static void pgpa_output_no_gather(pgpa_output_context *context, Bitmapset *relids)
static void pgpa_maybe_linebreak(StringInfo buf, int wrap_column)
static void pgpa_output_unrolled_join(pgpa_output_context *context, pgpa_unrolled_join *join)
static void pgpa_output_scan_strategy(pgpa_output_context *context, pgpa_scan_strategy strategy, List *scans)
static void pgpa_output_query_feature(pgpa_output_context *context, pgpa_qf_type type, List *query_features)
#define NUM_PGPA_SCAN_STRATEGY
Definition pgpa_scan.h:68
#define NUM_PGPA_QF_TYPES
Definition pgpa_walker.h:70
char * c
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
const char ** rid_strings
Definition pgpa_output.c:36

References appendStringInfo(), appendStringInfoChar(), pgpa_output_context::buf, buf, fb(), i, lfirst, list_length(), NUM_PGPA_JOIN_STRATEGY, NUM_PGPA_QF_TYPES, NUM_PGPA_SCAN_STRATEGY, palloc0_array, pgpa_cstring_join_strategy(), pgpa_identifier_string(), pgpa_maybe_linebreak(), pgpa_output_no_gather(), pgpa_output_query_feature(), pgpa_output_scan_strategy(), pgpa_output_simple_strategy(), pgpa_output_unrolled_join(), PGPA_SCAN_ORDINARY, pgpa_output_context::rid_strings, and pgpa_output_context::wrap_column.

Referenced by pgpa_planner_shutdown().

◆ pgpa_output_join_member()

static void pgpa_output_join_member ( pgpa_output_context context,
pgpa_join_member member 
)
static

Definition at line 185 of file pgpa_output.c.

187{
188 if (member->unrolled_join != NULL)
189 {
190 appendStringInfoChar(context->buf, '(');
192 appendStringInfoChar(context->buf, ')');
193 }
194 else
195 {
196 pgpa_scan *scan = member->scan;
197
198 Assert(scan != NULL);
199 if (bms_membership(scan->relids) == BMS_SINGLETON)
200 pgpa_output_relations(context, context->buf, scan->relids);
201 else
202 {
203 appendStringInfoChar(context->buf, '{');
204 pgpa_output_relations(context, context->buf, scan->relids);
205 appendStringInfoChar(context->buf, '}');
206 }
207 }
208}
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:765
@ BMS_SINGLETON
Definition bitmapset.h:72
#define Assert(condition)
Definition c.h:927
static void pgpa_output_relations(pgpa_output_context *context, StringInfo buf, Bitmapset *relids)
struct pgpa_scan * scan
Definition pgpa_join.h:60
pgpa_unrolled_join * unrolled_join
Definition pgpa_join.h:61
Bitmapset * relids
Definition pgpa_scan.h:77

References appendStringInfoChar(), Assert, bms_membership(), BMS_SINGLETON, pgpa_output_context::buf, fb(), pgpa_output_relations(), pgpa_output_unrolled_join(), pgpa_scan::relids, pgpa_join_member::scan, and pgpa_join_member::unrolled_join.

Referenced by pgpa_output_unrolled_join().

◆ pgpa_output_no_gather()

static void pgpa_output_no_gather ( pgpa_output_context context,
Bitmapset relids 
)
static

Definition at line 387 of file pgpa_output.c.

388{
389 if (relids == NULL)
390 return;
391 if (context->buf->len > 0)
392 appendStringInfoChar(context->buf, '\n');
393 appendStringInfoString(context->buf, "NO_GATHER(");
394 pgpa_output_relations(context, context->buf, relids);
395 appendStringInfoChar(context->buf, ')');
396}
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230

References appendStringInfoChar(), appendStringInfoString(), pgpa_output_context::buf, fb(), StringInfoData::len, and pgpa_output_relations().

Referenced by pgpa_output_advice().

◆ pgpa_output_query_feature()

static void pgpa_output_query_feature ( pgpa_output_context context,
pgpa_qf_type  type,
List query_features 
)
static

Definition at line 295 of file pgpa_output.c.

297{
298 bool first = true;
299
300 if (query_features == NIL)
301 return;
302
303 if (context->buf->len > 0)
304 appendStringInfoChar(context->buf, '\n');
305 appendStringInfo(context->buf, "%s(",
307
308 foreach_ptr(pgpa_query_feature, qf, query_features)
309 {
310 if (first)
311 first = false;
312 else
313 {
314 pgpa_maybe_linebreak(context->buf, context->wrap_column);
315 appendStringInfoChar(context->buf, ' ');
316 }
317
318 if (bms_membership(qf->relids) == BMS_SINGLETON)
319 pgpa_output_relations(context, context->buf, qf->relids);
320 else
321 {
322 appendStringInfoChar(context->buf, '(');
323 pgpa_output_relations(context, context->buf, qf->relids);
324 appendStringInfoChar(context->buf, ')');
325 }
326 }
327
328 appendStringInfoChar(context->buf, ')');
329 pgpa_maybe_linebreak(context->buf, context->wrap_column);
330}
#define NIL
Definition pg_list.h:68
#define foreach_ptr(type, var, lst)
Definition pg_list.h:469
static char * pgpa_cstring_query_feature_type(pgpa_qf_type type)

References appendStringInfo(), appendStringInfoChar(), bms_membership(), BMS_SINGLETON, pgpa_output_context::buf, fb(), foreach_ptr, StringInfoData::len, NIL, pgpa_cstring_query_feature_type(), pgpa_maybe_linebreak(), pgpa_output_relations(), type, and pgpa_output_context::wrap_column.

Referenced by pgpa_output_advice().

◆ pgpa_output_relation_name()

static void pgpa_output_relation_name ( pgpa_output_context context,
Oid  relid 
)
static

Definition at line 278 of file pgpa_output.c.

279{
281 char *relnamespace = get_namespace_name_or_temp(nspoid);
282 char *relname = get_rel_name(relid);
283
284 appendStringInfoString(context->buf, quote_identifier(relnamespace));
285 appendStringInfoChar(context->buf, '.');
287}
char * get_rel_name(Oid relid)
Definition lsyscache.c:2146
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2170
char * get_namespace_name_or_temp(Oid nspid)
Definition lsyscache.c:3610
NameData relname
Definition pg_class.h:40
unsigned int Oid
const char * quote_identifier(const char *ident)

References appendStringInfoChar(), appendStringInfoString(), pgpa_output_context::buf, fb(), get_namespace_name_or_temp(), get_rel_name(), get_rel_namespace(), quote_identifier(), and relname.

Referenced by pgpa_output_scan_strategy().

◆ pgpa_output_relations()

static void pgpa_output_relations ( pgpa_output_context context,
StringInfo  buf,
Bitmapset relids 
)
static

Definition at line 405 of file pgpa_output.c.

407{
408 int rti = -1;
409 bool first = true;
410
411 while ((rti = bms_next_member(relids, rti)) >= 0)
412 {
413 const char *rid_string = context->rid_strings[rti - 1];
414
415 if (rid_string == NULL)
416 elog(ERROR, "no identifier for RTI %d", rti);
417
418 if (first)
419 {
420 first = false;
422 }
423 else
424 {
427 }
428 }
429}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226

References appendStringInfo(), appendStringInfoString(), bms_next_member(), buf, elog, ERROR, fb(), pgpa_maybe_linebreak(), pgpa_output_context::rid_strings, and pgpa_output_context::wrap_column.

Referenced by pgpa_output_join_member(), pgpa_output_no_gather(), pgpa_output_query_feature(), pgpa_output_scan_strategy(), and pgpa_output_simple_strategy().

◆ pgpa_output_scan_strategy()

static void pgpa_output_scan_strategy ( pgpa_output_context context,
pgpa_scan_strategy  strategy,
List scans 
)
static

Definition at line 216 of file pgpa_output.c.

219{
220 bool first = true;
221
222 if (scans == NIL)
223 return;
224
225 if (context->buf->len > 0)
226 appendStringInfoChar(context->buf, '\n');
227 appendStringInfo(context->buf, "%s(",
229
230 foreach_ptr(pgpa_scan, scan, scans)
231 {
232 Plan *plan = scan->plan;
233
234 if (first)
235 first = false;
236 else
237 {
238 pgpa_maybe_linebreak(context->buf, context->wrap_column);
239 appendStringInfoChar(context->buf, ' ');
240 }
241
242 /* Output the relation identifiers. */
243 if (bms_membership(scan->relids) == BMS_SINGLETON)
244 pgpa_output_relations(context, context->buf, scan->relids);
245 else
246 {
247 appendStringInfoChar(context->buf, '(');
248 pgpa_output_relations(context, context->buf, scan->relids);
249 appendStringInfoChar(context->buf, ')');
250 }
251
252 /* For index or index-only scans, output index information. */
253 if (strategy == PGPA_SCAN_INDEX)
254 {
256 pgpa_maybe_linebreak(context->buf, context->wrap_column);
257 appendStringInfoChar(context->buf, ' ');
258 pgpa_output_relation_name(context, ((IndexScan *) plan)->indexid);
259 }
260 else if (strategy == PGPA_SCAN_INDEX_ONLY)
261 {
263 pgpa_maybe_linebreak(context->buf, context->wrap_column);
264 appendStringInfoChar(context->buf, ' ');
266 ((IndexOnlyScan *) plan)->indexid);
267 }
268 }
269
270 appendStringInfoChar(context->buf, ')');
271 pgpa_maybe_linebreak(context->buf, context->wrap_column);
272}
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define plan(x)
Definition pg_regress.c:161
static void pgpa_output_relation_name(pgpa_output_context *context, Oid relid)
static char * pgpa_cstring_scan_strategy(pgpa_scan_strategy strategy)

References appendStringInfo(), appendStringInfoChar(), Assert, bms_membership(), BMS_SINGLETON, pgpa_output_context::buf, foreach_ptr, IsA, StringInfoData::len, NIL, pgpa_cstring_scan_strategy(), pgpa_maybe_linebreak(), pgpa_output_relation_name(), pgpa_output_relations(), PGPA_SCAN_INDEX, PGPA_SCAN_INDEX_ONLY, plan, and pgpa_output_context::wrap_column.

Referenced by pgpa_output_advice().

◆ pgpa_output_simple_strategy()

static void pgpa_output_simple_strategy ( pgpa_output_context context,
char strategy,
List relid_sets 
)
static

Definition at line 346 of file pgpa_output.c.

348{
349 bool first = true;
350
351 if (relid_sets == NIL)
352 return;
353
354 if (context->buf->len > 0)
355 appendStringInfoChar(context->buf, '\n');
356 appendStringInfo(context->buf, "%s(", strategy);
357
359 {
360 if (first)
361 first = false;
362 else
363 {
364 pgpa_maybe_linebreak(context->buf, context->wrap_column);
365 appendStringInfoChar(context->buf, ' ');
366 }
367
368 if (bms_membership(relids) == BMS_SINGLETON)
369 pgpa_output_relations(context, context->buf, relids);
370 else
371 {
372 appendStringInfoChar(context->buf, '(');
373 pgpa_output_relations(context, context->buf, relids);
374 appendStringInfoChar(context->buf, ')');
375 }
376 }
377
378 appendStringInfoChar(context->buf, ')');
379 pgpa_maybe_linebreak(context->buf, context->wrap_column);
380}
#define foreach_node(type, var, lst)
Definition pg_list.h:496

References appendStringInfo(), appendStringInfoChar(), bms_membership(), BMS_SINGLETON, pgpa_output_context::buf, fb(), foreach_node, StringInfoData::len, NIL, pgpa_maybe_linebreak(), pgpa_output_relations(), and pgpa_output_context::wrap_column.

Referenced by pgpa_output_advice().

◆ pgpa_output_unrolled_join()

static void pgpa_output_unrolled_join ( pgpa_output_context context,
pgpa_unrolled_join join 
)
static

Definition at line 166 of file pgpa_output.c.

168{
169 pgpa_output_join_member(context, &join->outer);
170
171 for (int k = 0; k < join->ninner; ++k)
172 {
173 pgpa_join_member *member = &join->inner[k];
174
175 pgpa_maybe_linebreak(context->buf, context->wrap_column);
176 appendStringInfoChar(context->buf, ' ');
177 pgpa_output_join_member(context, member);
178 }
179}
static void pgpa_output_join_member(pgpa_output_context *context, pgpa_join_member *member)
pgpa_join_member * inner
Definition pgpa_join.h:83
pgpa_join_member outer
Definition pgpa_join.h:74

References appendStringInfoChar(), pgpa_output_context::buf, pgpa_unrolled_join::inner, pgpa_unrolled_join::ninner, pgpa_unrolled_join::outer, pgpa_maybe_linebreak(), pgpa_output_join_member(), and pgpa_output_context::wrap_column.

Referenced by pgpa_output_advice(), and pgpa_output_join_member().