aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteManip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/rewrite/rewriteManip.c')
-rw-r--r--src/backend/rewrite/rewriteManip.c112
1 files changed, 77 insertions, 35 deletions
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 5210b99fd7e..45b60715966 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.81 2003/11/29 19:51:55 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.82 2004/05/10 22:44:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -850,6 +850,10 @@ AddInvertedQual(Query *parsetree, Node *qual)
* If not, we either change the unmatched Var's varno to update_varno
* (when event == CMD_UPDATE) or replace it with a constant NULL.
*
+ * The caller must also provide target_rte, the RTE describing the target
+ * relation. This is needed to handle whole-row Vars referencing the target.
+ * We expand such Vars into RowExpr constructs.
+ *
* Note: the business with inserted_sublink is needed to update hasSubLinks
* in subqueries when the replacement adds a subquery inside a subquery.
* Messy, isn't it? We do not need to do similar pushups for hasAggs,
@@ -861,6 +865,7 @@ typedef struct
{
int target_varno;
int sublevels_up;
+ RangeTblEntry *target_rte;
List *targetlist;
int event;
int update_varno;
@@ -868,6 +873,45 @@ typedef struct
} ResolveNew_context;
static Node *
+resolve_one_var(Var *var, ResolveNew_context *context)
+{
+ TargetEntry *tle;
+
+ tle = get_tle_by_resno(context->targetlist, var->varattno);
+
+ if (tle == NULL)
+ {
+ /* Failed to find column in insert/update tlist */
+ if (context->event == CMD_UPDATE)
+ {
+ /* For update, just change unmatched var's varno */
+ var = (Var *) copyObject(var);
+ var->varno = context->update_varno;
+ var->varnoold = context->update_varno;
+ return (Node *) var;
+ }
+ else
+ {
+ /* Otherwise replace unmatched var with a null */
+ return (Node *) makeNullConst(var->vartype);
+ }
+ }
+ else
+ {
+ /* Make a copy of the tlist item to return */
+ Node *n = copyObject(tle->expr);
+
+ /* Adjust varlevelsup if tlist item is from higher query */
+ if (var->varlevelsup > 0)
+ IncrementVarSublevelsUp(n, var->varlevelsup, 0);
+ /* Report it if we are adding a sublink to query */
+ if (!context->inserted_sublink)
+ context->inserted_sublink = checkExprHasSubLink(n);
+ return n;
+ }
+}
+
+static Node *
ResolveNew_mutator(Node *node, ResolveNew_context *context)
{
if (node == NULL)
@@ -881,45 +925,41 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
if (this_varno == context->target_varno &&
this_varlevelsup == context->sublevels_up)
{
- TargetEntry *tle;
-
- /* band-aid: don't do the wrong thing with a whole-tuple Var */
if (var->varattno == InvalidAttrNumber)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot handle whole-row reference")));
-
- tle = get_tle_by_resno(context->targetlist, var->varattno);
-
- if (tle == NULL)
{
- if (context->event == CMD_UPDATE)
+ /* Must expand whole-tuple reference into RowExpr */
+ RangeTblEntry *rte = context->target_rte;
+ RowExpr *rowexpr;
+ List *fields = NIL;
+ AttrNumber nfields = length(rte->eref->colnames);
+ AttrNumber nf;
+
+ for (nf = 1; nf <= nfields; nf++)
{
- /* For update, just change unmatched var's varno */
- var = (Var *) copyObject(node);
- var->varno = context->update_varno;
- var->varnoold = context->update_varno;
- return (Node *) var;
+ Oid vartype;
+ int32 vartypmod;
+ Var *newvar;
+
+ get_rte_attribute_type(rte, nf, &vartype, &vartypmod);
+ newvar = makeVar(this_varno,
+ nf,
+ vartype,
+ vartypmod,
+ this_varlevelsup);
+ fields = lappend(fields,
+ resolve_one_var(newvar, context));
}
- else
- {
- /* Otherwise replace unmatched var with a null */
- return (Node *) makeNullConst(var->vartype);
- }
- }
- else
- {
- /* Make a copy of the tlist item to return */
- Node *n = copyObject(tle->expr);
-
- /* Adjust varlevelsup if tlist item is from higher query */
- if (this_varlevelsup > 0)
- IncrementVarSublevelsUp(n, this_varlevelsup, 0);
- /* Report it if we are adding a sublink to query */
- if (!context->inserted_sublink)
- context->inserted_sublink = checkExprHasSubLink(n);
- return n;
+
+ rowexpr = makeNode(RowExpr);
+ rowexpr->args = fields;
+ rowexpr->row_typeid = var->vartype;
+ rowexpr->row_format = COERCE_IMPLICIT_CAST;
+
+ return (Node *) rowexpr;
}
+
+ /* Normal case for scalar variable */
+ return resolve_one_var(var, context);
}
/* otherwise fall through to copy the var normally */
}
@@ -948,12 +988,14 @@ ResolveNew_mutator(Node *node, ResolveNew_context *context)
Node *
ResolveNew(Node *node, int target_varno, int sublevels_up,
+ RangeTblEntry *target_rte,
List *targetlist, int event, int update_varno)
{
ResolveNew_context context;
context.target_varno = target_varno;
context.sublevels_up = sublevels_up;
+ context.target_rte = target_rte;
context.targetlist = targetlist;
context.event = event;
context.update_varno = update_varno;