const char **rt_identifiers;
StringInfo buf;
List *unrolled_joins[NUM_PGPA_JOIN_STRATEGY];
- List *scans[NUM_PGPA_CLUMP_JOIN_STRATEGY];
+ List *scans[NUM_PGPA_SCAN_STRATEGY];
List *query_features[NUM_PGPA_QF_TYPES];
int wrap_column;
} pgpa_output_context;
static void pgpa_output_relations(pgpa_output_context *context, StringInfo buf,
Bitmapset *relids);
-static char *pgpa_cstring_join_clump_strategy(pgpa_join_clump_strategy strategy);
static char *pgpa_cstring_join_strategy(pgpa_join_strategy strategy);
+static char *pgpa_cstring_scan_strategy(pgpa_scan_strategy strategy);
static void pgpa_maybe_linebreak(StringInfo buf, int wrap_column);
* types as well as join types, and the question of how to handle that
* deserves more thought.
*/
- for (int c = 0; c < NUM_PGPA_CLUMP_JOIN_STRATEGY; ++c)
+ for (int c = 0; c < NUM_PGPA_SCAN_STRATEGY; ++c)
{
- char *cstrategy = pgpa_cstring_join_clump_strategy(c);
+ char *cstrategy = pgpa_cstring_scan_strategy(c);
bool first = true;
if (context.scans[c] == NIL)
}
}
-/*
- * Get a C string that corresponds to the specified join clump strategy.
- */
-static char *
-pgpa_cstring_join_clump_strategy(pgpa_join_clump_strategy strategy)
-{
- switch (strategy)
- {
- case JSTRAT_CLUMP_DEGENERATE:
- return "DEGENERATE";
- case JSTRAT_CLUMP_FOREIGN:
- return "FOREIGN";
- case JSTRAT_CLUMP_PARTITIONWISE:
- return "PARTITIONWISE";
- }
-
- Assert(false);
-}
-
/*
* Get a C string that corresponds to the specified join strategy.
*/
Assert(false);
}
+/*
+ * Get a C string that corresponds to the specified scan strategy.
+ */
+static char *
+pgpa_cstring_scan_strategy(pgpa_scan_strategy strategy)
+{
+ switch (strategy)
+ {
+ case JSTRAT_CLUMP_DEGENERATE:
+ return "DEGENERATE";
+ case JSTRAT_CLUMP_FOREIGN:
+ return "FOREIGN";
+ case JSTRAT_CLUMP_PARTITIONWISE:
+ return "PARTITIONWISE";
+ }
+
+ Assert(false);
+}
+
/*
* Insert a line break into the StringInfoData, if needed.
*
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pgpa_scan.h
+ * analysis of scans in Plan trees
+ *
+ * Note that our definition of "scan" is extremely broad. It includes
+ * (1) single plan nodes that scan multiple RTIs, such as a degenerate
+ * Result node that replaces what would otherwise have been a join, and
+ * (2) Append and MergeAppend nodes implementing a partitionwise scan
+ * or a partitionwise join.
+ *
+ * Copyright (c) 2016-2025, PostgreSQL Global Development Group
+ *
+ * contrib/pg_plan_advice/pgpa_scan.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PGPA_SCAN_H
+#define PGPA_SCAN_H
+
+#include "nodes/plannodes.h"
+
+/*
+ * Certain types of plan nodes can join any number of input relations in
+ * a single step; we call these "clumped joins".
+ *
+ * For our purposes, the important thing about a clumped join is that we
+ * can't meaningfully speak about the order in which tables are joined
+ * within a single clump. For example, if the optimizer chooses a
+ * partitionwise join on tables A and B, we can't say whether A was joined
+ * to B or whether B was joined to A; instead, each pair of child tables
+ * has its own join order. Likewise, if a foreign data wrapper pushes a
+ * join to the remote side, we don't know the join order.
+ *
+ * JSTRAT_CLUMP_DEGENERATE refers to the case where several relations are
+ * all proven empty and replaced with a single Result node. Here again, while
+ * the Result node may be joined to other things and we can speak about its
+ * place within the larger join order, we can't speak about a join ordering
+ * within the Result node itself.
+ */
+typedef enum
+{
+ JSTRAT_CLUMP_DEGENERATE = 0,
+ JSTRAT_CLUMP_FOREIGN,
+ JSTRAT_CLUMP_PARTITIONWISE
+ /* update NUM_PGPA_CLUMP_JOIN_STRATEGY if you add anything here */
+} pgpa_scan_strategy;
+
+#define NUM_PGPA_SCAN_STRATEGY ((int) JSTRAT_CLUMP_PARTITIONWISE + 1)
+
+/*
+ * All of the details we need regarding a scan.
+ */
+typedef struct pgpa_scan
+{
+ Plan *plan;
+ pgpa_scan_strategy strategy;
+ Bitmapset *relids;
+} pgpa_scan;
+
+extern pgpa_scan *pgpa_build_scan(PlannedStmt *pstmt, Plan *plan,
+ ElidedNode *elided_node);
+
+#endif