From 3b8515aaea164174d18ef2450b19478de8e64298 Mon Sep 17 00:00:00 2001 From: csteam Date: Tue, 16 Jul 2019 16:19:49 -0700 Subject: [PATCH v1 2/3] Execution-time scan col extraction and comparison with plan-time cols Extract the columns needed to scan directly before scanning from the ScanState and compare this set of columns with those extracted at plan-time. In regress, there are two main queries where there is a difference in the columns extracted at plan time vs execution time. They are both due to the fact that UPDATE/DELETE on partition tables adds the contents of the returningList to the PathTargets in the RelOptInfos. This manifests as a difference in the column sets. --- src/backend/executor/execScan.c | 63 ++++++++++++++++++++++++++++++ src/backend/executor/nodeSeqscan.c | 24 ++++++++++++ src/include/executor/executor.h | 4 ++ 3 files changed, 91 insertions(+) diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index c0e4a5376c..89146693a3 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -20,6 +20,7 @@ #include "executor/executor.h" #include "miscadmin.h" +#include "nodes/nodeFuncs.h" #include "utils/memutils.h" @@ -300,3 +301,65 @@ ExecScanReScan(ScanState *node) } } } + +typedef struct neededColumnContext +{ + Bitmapset **mask; + int n; +} neededColumnContext; + +static bool +neededColumnContextWalker(Node *node, neededColumnContext *c) +{ + if (node == NULL) + return false; + + if (IsA(node, Var)) + { + Var *var = (Var *)node; + + if (var->varattno >= 0) + { + Assert(var->varattno <= c->n); + *(c->mask) = bms_add_member(*(c->mask), var->varattno); + } + + return false; + } + return expression_tree_walker(node, neededColumnContextWalker, (void * )c); +} + +/* + * n specifies the number of allowed entries in mask: we use + * it for bounds-checking in the walker above. + */ +void +PopulateNeededColumnsForNode(Node *expr, int n, Bitmapset **scanCols) +{ + neededColumnContext c; + + c.mask = scanCols; + c.n = n; + + neededColumnContextWalker(expr, &c); +} + +Bitmapset * +PopulateNeededColumnsForScan(ScanState *scanstate, int ncol) +{ + Bitmapset *result = NULL; + Plan *plan = scanstate->ps.plan; + + PopulateNeededColumnsForNode((Node *) plan->targetlist, ncol, &result); + PopulateNeededColumnsForNode((Node *) plan->qual, ncol, &result); + + if (IsA(plan, IndexScan)) + { + PopulateNeededColumnsForNode((Node *) ((IndexScan *) plan)->indexqualorig, ncol, &result); + PopulateNeededColumnsForNode((Node *) ((IndexScan *) plan)->indexorderbyorig, ncol, &result); + } + else if (IsA(plan, BitmapHeapScan)) + PopulateNeededColumnsForNode((Node *) ((BitmapHeapScan *) plan)->bitmapqualorig, ncol, &result); + + return result; +} diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 436b43f8ca..c4b6a35554 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -64,6 +64,30 @@ SeqNext(SeqScanState *node) if (scandesc == NULL) { + /* + * Print used cols extracted during planning as well as + * used cols extracted now from the ScanState + */ + int plan_col_num; + Bitmapset *execution_cols = NULL; + Scan *planNode = (Scan *)node->ss.ps.plan; + int ncols = node->ss.ss_currentRelation->rd_att->natts; + int rti = planNode->scanrelid; + RangeTblEntry *rangeTblEntry = list_nth(estate->es_plannedstmt->rtable, rti - 1); + + Bitmapset *plan_cols = rangeTblEntry->scanCols; +#ifdef USE_ASSERT_CHECKING + while ((plan_col_num = bms_next_member(plan_cols, ncols)) >= 0) + Assert(plan_col_num <= ncols); +#endif + execution_cols = PopulateNeededColumnsForScan(&node->ss, ncols); + + if (bms_is_empty(bms_difference(plan_cols, execution_cols)) == false) + elog(NOTICE, "table: %s.\n exec-time cols: %s\n plan-time cols: %s", + RelationGetRelationName(node->ss.ss_currentRelation), + bmsToString(execution_cols), + bmsToString(plan_cols)); + /* * We reach here if the scan is not parallel, or if we're serially * executing a scan that was planned to be parallel. diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 1fb28b4596..310fa2c1bb 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -596,5 +596,9 @@ extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd); extern void CheckSubscriptionRelkind(char relkind, const char *nspname, const char *relname); +extern void +PopulateNeededColumnsForNode(Node *expr, int n, Bitmapset **scanCols); +extern Bitmapset * +PopulateNeededColumnsForScan(ScanState *scanstate, int ncol); #endif /* EXECUTOR_H */ -- 2.22.0