remove old file
authorRobert Haas <rhaas@postgresql.org>
Thu, 3 Jul 2025 19:00:55 +0000 (15:00 -0400)
committerRobert Haas <rhaas@postgresql.org>
Thu, 3 Jul 2025 19:00:55 +0000 (15:00 -0400)
contrib/pg_plan_advice/create_advice.c [deleted file]

diff --git a/contrib/pg_plan_advice/create_advice.c b/contrib/pg_plan_advice/create_advice.c
deleted file mode 100644 (file)
index bb44d09..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * create_advice.c
- *       generate advice from a finished plan that can be fed back into
- *       future planning cycles if desired
- *
- * Copyright (c) 2016-2024, PostgreSQL Global Development Group
- *
- *       contrib/pg_plan_advice/pg_plan_advice.c
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "commands/explain.h"
-#include "parser/parsetree.h"
-#include "pg_plan_advice.h"
-#include "utils/builtins.h"
-#include "utils/lsyscache.h"
-
-typedef enum
-{
-       JOIN_NONE,
-       JOIN_FOREIGN,
-       JOIN_MERGEJOIN_PLAIN,
-       JOIN_MERGEJOIN_MATERIALIZE,
-       JOIN_NESTLOOP_PLAIN,
-       JOIN_NESTLOOP_MATERIALIZE,
-       JOIN_NESTLOOP_MEMOIZE,
-       JOIN_HASHJOIN,
-       JOIN_PARTITIONWISE
-} join_strategy;
-
-typedef struct
-{
-       PlannedStmt *stmt;
-       int                     rtable_length;
-       SubPlanRTInfo **rtable_subplans;
-       char      **rtable_names;
-       Plan      **rtable_scans;
-       bool       *rtable_drivingjoin;
-       join_strategy *rtable_joinstrat;
-       List       *all_join_orders;
-} advice_context;
-
-typedef struct
-{
-       bool            inner_side;
-       join_strategy   jstrat;
-       Node       *join_order;
-} join_traversal;
-
-static void scan_plan_tree(advice_context *context, Plan *plan,
-                                                  join_traversal *jtraversal);
-static void scan_plan_tree_list(advice_context *context, List *list);
-
-static void
-init_advice_context(advice_context *context, PlannedStmt *stmt)
-{
-       int                     rtable_length = list_length(stmt->rtable);
-
-       context->stmt = stmt;
-       context->rtable_length = list_length(stmt->rtable);
-       context->rtable_subplans = palloc0_array(SubPlanRTInfo *, rtable_length);
-       context->rtable_names = palloc0_array(char *, rtable_length);
-       context->rtable_scans = palloc0_array(Plan *, rtable_length);
-       context->rtable_drivingjoin = palloc0_array(bool, rtable_length);
-       context->rtable_joinstrat = palloc0_array(join_strategy, rtable_length);
-       context->all_join_orders = NIL;
-}
-
-static void
-generate_relation_identifiers(advice_context *context)
-{
-       PlannedStmt *stmt = context->stmt;
-       Index           rti;
-       Index      *topparent;
-
-       topparent = CreateParentRelationMap(stmt->rtable, stmt->appendRelations);
-
-       /* Main loop over the entire flattened range table. */
-       for (rti = 1; rti <= context->rtable_length; ++rti)
-       {
-               const char *result;
-
-               result = MakeRelationIdentifier(stmt->rtable,
-                                                                               topparent,
-                                                                               stmt->subrtinfos,
-                                                                               rti);
-
-               /* Save the name we just generated. */
-               context->rtable_names[rti - 1] = unconstify(char *, result);
-       }
-}
-
-static void
-scan_plan_tree(advice_context *context, Plan *plan, join_traversal *jtraversal)
-{
-       Node       *join_order = NULL;
-       Index           rti;
-
-       if (IsA(plan, NestLoop) || IsA(plan, HashJoin) || IsA(plan, MergeJoin))
-       {
-               join_traversal  outer_join_traversal;
-               join_traversal  inner_join_traversal;
-
-               /*
-                * The outermost table in a set of joins needs no join strategy advice;
-                * in the case of a bushy join, the outermost table of each clump
-                * needs join strategy advice to indicate how the clump as a whole
-                * should be joined.
-                */
-               outer_join_traversal.inner_side = false;
-               outer_join_traversal.jstrat = JOIN_NONE;
-               outer_join_traversal.join_order = NULL;
-               if (jtraversal != NULL)
-                       outer_join_traversal.jstrat = jtraversal->jstrat;
-               else
-                       outer_join_traversal.jstrat = JOIN_NONE;
-               outer_join_traversal.join_order = NULL;
-               scan_plan_tree(context, plan->lefttree, &outer_join_traversal);
-
-               /*
-                * Any table on the inner side of a join needs join strategy advice.
-                */
-               inner_join_traversal.inner_side = true;
-               inner_join_traversal.join_order = NULL;
-               if (IsA(plan, MergeJoin))
-               {
-                       if (IsA(plan->righttree, Material))
-                               inner_join_traversal.jstrat = JOIN_MERGEJOIN_MATERIALIZE;
-                       else
-                               inner_join_traversal.jstrat = JOIN_MERGEJOIN_PLAIN;
-               }
-               else if (IsA(plan, NestLoop))
-               {
-                       if (IsA(plan->righttree, Material))
-                               inner_join_traversal.jstrat = JOIN_NESTLOOP_MATERIALIZE;
-                       else if (IsA(plan->righttree, Memoize))
-                               inner_join_traversal.jstrat = JOIN_NESTLOOP_MEMOIZE;
-                       else
-                               inner_join_traversal.jstrat = JOIN_NESTLOOP_PLAIN;
-               }
-               else if (IsA(plan, HashJoin))
-                       inner_join_traversal.jstrat = JOIN_HASHJOIN;
-               else
-                       elog(ERROR, "unknown node type: %d", nodeTag(plan));
-               scan_plan_tree(context, plan->righttree, &inner_join_traversal);
-
-               /*
-                * We assume that left-deep (or outer-deep) join trees are the norm;
-                * hence JOIN(JOIN(A,B),C) is represented as (A B C), whereas
-                * JOIN(A,JOIN(B,C)) is represnted as (A (B C)).
-                */
-               if (IsA(outer_join_traversal.join_order, List))
-                       join_order = (Node *)
-                               lappend((List *) outer_join_traversal.join_order,
-                                               inner_join_traversal.join_order);
-               else
-                       join_order = (Node *)
-                               list_make2(outer_join_traversal.join_order,
-                                                  inner_join_traversal.join_order);
-       }
-       else if (jtraversal != NULL && !jtraversal->inner_side &&
-                        IsA(plan, Sort))
-       {
-               Assert(plan->lefttree != NULL && plan->righttree == NULL);
-               scan_plan_tree(context, plan->lefttree, jtraversal);
-       }
-       else if (jtraversal != NULL && jtraversal->inner_side &&
-                        (IsA(plan, Material) || IsA(plan, Memoize) || IsA(plan, Hash) ||
-                         IsA(plan, Sort)))
-       {
-               Assert(plan->lefttree != NULL && plan->righttree == NULL);
-               scan_plan_tree(context, plan->lefttree, jtraversal);
-       }
-       else
-       {
-               if (plan->lefttree != NULL)
-                       scan_plan_tree(context, plan->lefttree, NULL);
-               if (plan->righttree != NULL)
-                       scan_plan_tree(context, plan->righttree, NULL);
-
-               if (jtraversal != NULL)
-                       join_order = (Node *) plan;
-       }
-
-       if (join_order != NULL)
-       {
-               if (jtraversal == NULL)
-                       context->all_join_orders = lappend(context->all_join_orders,
-                                                                                          join_order);
-               else
-               {
-                       Assert(jtraversal->join_order == NULL);
-                       jtraversal->join_order = join_order;
-               }
-       }
-
-       /* recurse into any special children */
-       switch (nodeTag(plan))
-       {
-               case T_Append:
-                       scan_plan_tree_list(context, ((Append *) plan)->appendplans);
-                       break;
-               case T_MergeAppend:
-                       scan_plan_tree_list(context, ((MergeAppend *) plan)->mergeplans);
-                       break;
-               case T_BitmapAnd:
-                       scan_plan_tree_list(context, ((BitmapAnd *) plan)->bitmapplans);
-                       break;
-               case T_BitmapOr:
-                       scan_plan_tree_list(context, ((BitmapOr *) plan)->bitmapplans);
-                       break;
-               case T_SubqueryScan:
-                       scan_plan_tree(context, ((SubqueryScan *) plan)->subplan, NULL);
-                       break;
-               case T_CustomScan:
-                       scan_plan_tree_list(context, ((CustomScan *) plan)->custom_plans);
-                       break;
-               default:
-                       break;
-       }
-
-       rti = GetScannedRTI(context->stmt, plan);
-       if (rti != 0)
-       {
-               if (context->rtable_scans[rti - 1] != NULL)
-                       elog(ERROR, "rti %d is duplicated", rti);
-               context->rtable_scans[rti - 1] = plan;
-               if (jtraversal != NULL)
-               {
-                       context->rtable_drivingjoin[rti - 1] = !jtraversal->inner_side;
-                       context->rtable_joinstrat[rti - 1] = jtraversal->jstrat;
-               }
-       }
-}
-
-static void
-scan_plan_tree_list(advice_context *context, List *list)
-{
-       ListCell   *lc;
-
-       foreach(lc, list)
-       {
-               scan_plan_tree(context, lfirst(lc), NULL);
-       }
-}
-
-static void
-join_method_dump(StringInfo result, advice_context *context)
-{
-       Index           rti;
-
-       for (rti = 1; rti <= context->rtable_length; ++rti)
-       {
-               char       *name = context->rtable_names[rti - 1];
-               bool            drivingjoin = context->rtable_drivingjoin[rti - 1];
-               join_strategy jstrat = context->rtable_joinstrat[rti - 1];
-               char       *jstrat_name = NULL;
-
-               switch (jstrat)
-               {
-                       case JOIN_NONE:
-                               break;
-                       case JOIN_FOREIGN:
-                               jstrat_name = drivingjoin ? "BUSHY_FOREIGN_JOIN" : "FOREIGN_JOIN";
-                               break;
-                       case JOIN_MERGEJOIN_PLAIN:
-                               jstrat_name = drivingjoin ? "BUSHY_MERGE_JOIN" : "MERGE_JOIN";
-                               break;
-                       case JOIN_MERGEJOIN_MATERIALIZE:
-                               jstrat_name = drivingjoin ? "BUSHY_MERGE_JOIN_MATERIALIZE" : "MERGE_JOIN_MATERIALIZE";
-                               break;
-                       case JOIN_NESTLOOP_PLAIN:
-                               jstrat_name = drivingjoin ? "BUSHY_NESTED_LOOP" : "NESTED_LOOP";
-                               break;
-                       case JOIN_NESTLOOP_MATERIALIZE:
-                               jstrat_name = drivingjoin ? "BUSHY_NESTED_LOOP_MATERIALIZE" : "NESTED_LOOP_MATERIALIZE";
-                               break;
-                       case JOIN_NESTLOOP_MEMOIZE:
-                               jstrat_name = drivingjoin ? "BUSHY_NESTED_LOOP_MEMOIZE" : "NESTED_LOOP_MEMOIZE";
-                               break;
-                       case JOIN_HASHJOIN:
-                               jstrat_name = drivingjoin ? "BUSHY_HASH_JOIN" : "HASH_JOIN";
-                               break;
-                       case JOIN_PARTITIONWISE:
-                               jstrat_name = drivingjoin ? "BUSHY_PARTITIONWISE" : "PARTITIONWISE";
-                               break;
-               }
-
-               if (name == NULL)
-                       name = "???";
-               if (jstrat_name != NULL)
-                       appendStringInfo(result, "%s(%s)\n", jstrat_name, name);
-       }
-}
-
-static void
-scan_method_dump(StringInfo result, advice_context *context)
-{
-       Index           rti;
-
-       for (rti = 1; rti <= context->rtable_length; ++rti)
-       {
-               char       *name = context->rtable_names[rti - 1];
-               Plan       *plan = context->rtable_scans[rti - 1];
-               char       *scan_name = NULL;
-               Oid                     index_oid = InvalidOid;
-
-               /*
-                * Convert the node tag of the scan to a string. We can ignore scan
-                * types for which there is no alternative, e.g. SubqueryScan,
-                * FunctionScan, ValuesScan.
-                */
-               if (plan != NULL)
-               {
-                       switch (nodeTag(plan))
-                       {
-                               case T_SeqScan:
-                                       scan_name = "SEQ_SCAN";
-                                       break;
-                               case T_IndexScan:
-                                       scan_name = "INDEX_SCAN";
-                                       index_oid = ((IndexScan *) plan)->indexid;
-                                       break;
-                               case T_IndexOnlyScan:
-                                       scan_name = "INDEX_ONLY_SCAN";
-                                       index_oid = ((IndexOnlyScan *) plan)->indexid;
-                                       break;
-                               case T_BitmapHeapScan:
-                                       scan_name = "BITMAP_HEAP_SCAN";
-                                       break;
-                               case T_TidScan:
-                                       scan_name = "TID_SCAN";
-                                       break;
-                               case T_TidRangeScan:
-                                       scan_name = "TID_RANGE_SCAN";
-                                       break;
-                               case T_CustomScan:
-                                       scan_name = "CUSTOM_SCAN";
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-
-               if (name == NULL)
-                       name = "???";
-               if (OidIsValid(index_oid))
-               {
-                       char       *indnsp;
-                       char       *indrel;
-
-                       indnsp = get_namespace_name_or_temp(get_rel_namespace(index_oid));
-                       indrel = get_rel_name(index_oid);
-                       appendStringInfo(result, "%s(%s, %s.%s)\n", scan_name, name,
-                                                        quote_identifier(indnsp), quote_identifier(indrel));
-               }
-               else if (scan_name != NULL)
-                       appendStringInfo(result, "%s(%s)\n", scan_name, name);
-       }
-}
-
-static void
-join_order_dump_recursive(StringInfo result, advice_context *context, Node *n)
-{
-       if (IsA(n, List))
-       {
-               ListCell   *lc;
-               bool            first = true;
-
-               appendStringInfoString(result, "(");
-               foreach(lc, (List *) n)
-               {
-                       if (first)
-                               first = false;
-                       else
-                               appendStringInfoString(result, " ");
-                       join_order_dump_recursive(result, context, (Node *) lfirst(lc));
-               }
-               appendStringInfoString(result, ")");
-       }
-       else
-       {
-               Index           rti = GetScannedRTI(context->stmt, (Plan *) n);
-
-               if (rti != 0)
-                       appendStringInfoString(result, context->rtable_names[rti - 1]);
-               else
-                       appendStringInfo(result, "?[rti=%d,nodetag=%d]", (int) rti,
-                                                        (int) nodeTag(n));
-       }
-}
-
-static void
-join_order_dump(StringInfo result, advice_context *context)
-{
-       ListCell   *lc;
-
-       foreach(lc, context->all_join_orders)
-       {
-               List       *l = lfirst_node(List, lc);
-               ListCell   *lc2;
-               bool            first = true;
-
-               appendStringInfoString(result, "JOIN_ORDER(");
-               foreach(lc2, l)
-               {
-                       if (first)
-                               first = false;
-                       else
-                               appendStringInfoString(result, " ");
-                       join_order_dump_recursive(result, context, (Node *) lfirst(lc2));
-               }
-               appendStringInfoString(result, ")\n");
-       }
-}
-
-/*
- * Generate advice from a PlannedStmt, and append it to the buffer provided.
- *
- * Returns false if the PlannedStmt has no plan tree, otherwise true.
- */
-bool
-append_advice_from_plan(StringInfo buf, PlannedStmt *stmt)
-{
-       advice_context context;
-       ListCell   *lc;
-
-       /* If this is a utility statement, there's no useful work to be done. */
-       if (stmt->planTree == NULL)
-               return false;
-
-       /* Initialization steps. */
-       init_advice_context(&context, stmt);
-       generate_relation_identifiers(&context);
-
-       /* First, scan the main plan tree. */
-       scan_plan_tree(&context, stmt->planTree, NULL);
-
-       /*
-        * Now, scan the list of InitPlans and SubPlans, which, confusingly,
-        * are collectively known as subplans. Some subplans may have been elided
-        * during planning, so skip any NULL entries in the array.
-        */
-       foreach(lc, stmt->subplans)
-       {
-               Plan       *plan = lfirst(lc);
-
-               if (plan != NULL)
-                       scan_plan_tree(&context, plan, NULL);
-       }
-
-       /* Finally, append advice to the output buffer. */
-       join_order_dump(buf, &context);
-       join_method_dump(buf, &context);
-       scan_method_dump(buf, &context);
-
-       return true;
-}