aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execUtils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/execUtils.c')
-rw-r--r--src/backend/executor/execUtils.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index e8c06c76056..876439835a3 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -56,6 +56,7 @@
#include "utils/typcache.h"
+static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc);
static void ShutdownExprContext(ExprContext *econtext, bool isCommit);
@@ -504,6 +505,85 @@ ExecAssignProjectionInfo(PlanState *planstate,
/* ----------------
+ * ExecConditionalAssignProjectionInfo
+ *
+ * as ExecAssignProjectionInfo, but store NULL rather than building projection
+ * info if no projection is required
+ * ----------------
+ */
+void
+ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc,
+ Index varno)
+{
+ if (tlist_matches_tupdesc(planstate,
+ planstate->plan->targetlist,
+ varno,
+ inputDesc))
+ planstate->ps_ProjInfo = NULL;
+ else
+ ExecAssignProjectionInfo(planstate, inputDesc);
+}
+
+static bool
+tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc)
+{
+ int numattrs = tupdesc->natts;
+ int attrno;
+ bool hasoid;
+ ListCell *tlist_item = list_head(tlist);
+
+ /* Check the tlist attributes */
+ for (attrno = 1; attrno <= numattrs; attrno++)
+ {
+ Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
+ Var *var;
+
+ if (tlist_item == NULL)
+ return false; /* tlist too short */
+ var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr;
+ if (!var || !IsA(var, Var))
+ return false; /* tlist item not a Var */
+ /* if these Asserts fail, planner messed up */
+ Assert(var->varno == varno);
+ Assert(var->varlevelsup == 0);
+ if (var->varattno != attrno)
+ return false; /* out of order */
+ if (att_tup->attisdropped)
+ return false; /* table contains dropped columns */
+
+ /*
+ * Note: usually the Var's type should match the tupdesc exactly, but
+ * in situations involving unions of columns that have different
+ * typmods, the Var may have come from above the union and hence have
+ * typmod -1. This is a legitimate situation since the Var still
+ * describes the column, just not as exactly as the tupdesc does. We
+ * could change the planner to prevent it, but it'd then insert
+ * projection steps just to convert from specific typmod to typmod -1,
+ * which is pretty silly.
+ */
+ if (var->vartype != att_tup->atttypid ||
+ (var->vartypmod != att_tup->atttypmod &&
+ var->vartypmod != -1))
+ return false; /* type mismatch */
+
+ tlist_item = lnext(tlist_item);
+ }
+
+ if (tlist_item)
+ return false; /* tlist too long */
+
+ /*
+ * If the plan context requires a particular hasoid setting, then that has
+ * to match, too.
+ */
+ if (ExecContextForcesOids(ps, &hasoid) &&
+ hasoid != tupdesc->tdhasoid)
+ return false;
+
+ return true;
+}
+
+/* ----------------
* ExecFreeExprContext
*
* A plan node's ExprContext should be freed explicitly during executor