]> granicus.if.org Git - postgresql/commitdiff
Rename ResolveNew() to ReplaceVarsFromTargetList(), and tweak its API.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 8 Nov 2012 21:52:49 +0000 (16:52 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 8 Nov 2012 21:52:49 +0000 (16:52 -0500)
This function currently lacks the option to throw error if the provided
targetlist doesn't have any matching entry for a Var to be replaced.
Two of the four existing call sites would be better off with an error,
as would the usage in the pending auto-updatable-views patch, so it seems
past time to extend the API to support that.  To do so, replace the "event"
parameter (historically of type CmdType, though it was declared plain int)
with a special-purpose enum type.

It's unclear whether this function might be called by third-party code.
Since many C compilers wouldn't warn about a call site continuing to use
the old calling convention, rename the function to forcibly break any
such code that hasn't been updated.  The old name was none too well chosen
anyhow.

src/backend/optimizer/path/allpaths.c
src/backend/rewrite/rewriteHandler.c
src/backend/rewrite/rewriteManip.c
src/include/rewrite/rewriteManip.h

index 458dae0489c029bd743c75c82f8e5102067e89bf..3a5efa2114e44a7bff0062ad301840c745c447f8 100644 (file)
@@ -1835,10 +1835,10 @@ subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual)
                 * This step also ensures that when we are pushing into a setop tree,
                 * each component query gets its own copy of the qual.
                 */
-               qual = ResolveNew(qual, rti, 0, rte,
-                                                 subquery->targetList,
-                                                 CMD_SELECT, 0,
-                                                 &subquery->hasSubLinks);
+               qual = ReplaceVarsFromTargetList(qual, rti, 0, rte,
+                                                                                subquery->targetList,
+                                                                                REPLACEVARS_REPORT_ERROR, 0,
+                                                                                &subquery->hasSubLinks);
 
                /*
                 * Now attach the qual to the proper place: normally WHERE, but if the
index 8f75948d0dd399e21fab2053064cfd43d7b38c43..b785c269a034c521b09d7d27c76537fe127d253c 100644 (file)
@@ -502,25 +502,27 @@ rewriteRuleAction(Query *parsetree,
        AddQual(sub_action, parsetree->jointree->quals);
 
        /*
-        * Rewrite new.attribute w/ right hand side of target-list entry for
+        * Rewrite new.attribute with right hand side of target-list entry for
         * appropriate field name in insert/update.
         *
-        * KLUGE ALERT: since ResolveNew returns a mutated copy, we can't just
-        * apply it to sub_action; we have to remember to update the sublink
-        * inside rule_action, too.
+        * KLUGE ALERT: since ReplaceVarsFromTargetList returns a mutated copy, we
+        * can't just apply it to sub_action; we have to remember to update the
+        * sublink inside rule_action, too.
         */
        if ((event == CMD_INSERT || event == CMD_UPDATE) &&
                sub_action->commandType != CMD_UTILITY)
        {
-               sub_action = (Query *) ResolveNew((Node *) sub_action,
-                                                                                 new_varno,
-                                                                                 0,
-                                                                                 rt_fetch(new_varno,
-                                                                                                  sub_action->rtable),
-                                                                                 parsetree->targetList,
-                                                                                 event,
-                                                                                 current_varno,
-                                                                                 NULL);
+               sub_action = (Query *)
+                       ReplaceVarsFromTargetList((Node *) sub_action,
+                                                                         new_varno,
+                                                                         0,
+                                                                         rt_fetch(new_varno, sub_action->rtable),
+                                                                         parsetree->targetList,
+                                                                         (event == CMD_UPDATE) ?
+                                                                         REPLACEVARS_CHANGE_VARNO :
+                                                                         REPLACEVARS_SUBSTITUTE_NULL,
+                                                                         current_varno,
+                                                                         NULL);
                if (sub_action_ptr)
                        *sub_action_ptr = sub_action;
                else
@@ -543,15 +545,15 @@ rewriteRuleAction(Query *parsetree,
                                   errmsg("cannot have RETURNING lists in multiple rules")));
                *returning_flag = true;
                rule_action->returningList = (List *)
-                       ResolveNew((Node *) parsetree->returningList,
-                                          parsetree->resultRelation,
-                                          0,
-                                          rt_fetch(parsetree->resultRelation,
-                                                               parsetree->rtable),
-                                          rule_action->returningList,
-                                          CMD_SELECT,
-                                          0,
-                                          &rule_action->hasSubLinks);
+                       ReplaceVarsFromTargetList((Node *) parsetree->returningList,
+                                                                         parsetree->resultRelation,
+                                                                         0,
+                                                                         rt_fetch(parsetree->resultRelation,
+                                                                                          parsetree->rtable),
+                                                                         rule_action->returningList,
+                                                                         REPLACEVARS_REPORT_ERROR,
+                                                                         0,
+                                                                         &rule_action->hasSubLinks);
 
                /*
                 * There could have been some SubLinks in parsetree's returningList,
@@ -1703,14 +1705,17 @@ CopyAndAddInvertedQual(Query *parsetree,
        ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
        /* Fix references to NEW */
        if (event == CMD_INSERT || event == CMD_UPDATE)
-               new_qual = ResolveNew(new_qual,
-                                                         PRS2_NEW_VARNO,
-                                                         0,
-                                                         rt_fetch(rt_index, parsetree->rtable),
-                                                         parsetree->targetList,
-                                                         event,
-                                                         rt_index,
-                                                         &parsetree->hasSubLinks);
+               new_qual = ReplaceVarsFromTargetList(new_qual,
+                                                                                        PRS2_NEW_VARNO,
+                                                                                        0,
+                                                                                        rt_fetch(rt_index,
+                                                                                                         parsetree->rtable),
+                                                                                        parsetree->targetList,
+                                                                                        (event == CMD_UPDATE) ?
+                                                                                        REPLACEVARS_CHANGE_VARNO :
+                                                                                        REPLACEVARS_SUBSTITUTE_NULL,
+                                                                                        rt_index,
+                                                                                        &parsetree->hasSubLinks);
        /* And attach the fixed qual */
        AddInvertedQual(parsetree, new_qual);
 
index ef04c342a295f8f3912c4a714a43ced9b04c96e6..bea00e48e58a260a60dc5c7b3c87abdf0e228659 100644 (file)
@@ -1323,12 +1323,16 @@ map_variable_attnos(Node *node,
 
 
 /*
- * ResolveNew - replace Vars with corresponding items from a targetlist
+ * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
  *
  * Vars matching target_varno and sublevels_up are replaced by the
  * entry with matching resno from targetlist, if there is one.
- * If not, we either change the unmatched Var's varno to update_varno
- * (when event == CMD_UPDATE) or replace it with a constant NULL.
+ *
+ * If there is no matching resno for such a Var, the action depends on the
+ * nomatch_option:
+ *     REPLACEVARS_REPORT_ERROR: throw an error
+ *     REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
+ *     REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
  *
  * The caller must also provide target_rte, the RTE describing the target
  * relation.  This is needed to handle whole-row Vars referencing the target.
@@ -1341,15 +1345,15 @@ typedef struct
 {
        RangeTblEntry *target_rte;
        List       *targetlist;
-       int                     event;
-       int                     update_varno;
-} ResolveNew_context;
+       ReplaceVarsNoMatchOption nomatch_option;
+       int                     nomatch_varno;
+} ReplaceVarsFromTargetList_context;
 
 static Node *
-ResolveNew_callback(Var *var,
-                                       replace_rte_variables_context *context)
+ReplaceVarsFromTargetList_callback(Var *var,
+                                                                  replace_rte_variables_context *context)
 {
-       ResolveNew_context *rcon = (ResolveNew_context *) context->callback_arg;
+       ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
        TargetEntry *tle;
 
        if (var->varattno == InvalidAttrNumber)
@@ -1388,29 +1392,37 @@ ResolveNew_callback(Var *var,
 
        if (tle == NULL || tle->resjunk)
        {
-               /* Failed to find column in insert/update tlist */
-               if (rcon->event == CMD_UPDATE)
-               {
-                       /* For update, just change unmatched var's varno */
-                       var = (Var *) copyObject(var);
-                       var->varno = rcon->update_varno;
-                       var->varnoold = rcon->update_varno;
-                       return (Node *) var;
-               }
-               else
+               /* Failed to find column in targetlist */
+               switch (rcon->nomatch_option)
                {
-                       /* Otherwise replace unmatched var with a null */
-                       /* need coerce_to_domain in case of NOT NULL domain constraint */
-                       return coerce_to_domain((Node *) makeNullConst(var->vartype,
-                                                                                                                  var->vartypmod,
-                                                                                                                  var->varcollid),
-                                                                       InvalidOid, -1,
-                                                                       var->vartype,
-                                                                       COERCE_IMPLICIT_CAST,
-                                                                       -1,
-                                                                       false,
-                                                                       false);
+                       case REPLACEVARS_REPORT_ERROR:
+                               /* fall through, throw error below */
+                               break;
+
+                       case REPLACEVARS_CHANGE_VARNO:
+                               var = (Var *) copyObject(var);
+                               var->varno = rcon->nomatch_varno;
+                               var->varnoold = rcon->nomatch_varno;
+                               return (Node *) var;
+
+                       case REPLACEVARS_SUBSTITUTE_NULL:
+                               /*
+                                * If Var is of domain type, we should add a CoerceToDomain
+                                * node, in case there is a NOT NULL domain constraint.
+                                */
+                               return coerce_to_domain((Node *) makeNullConst(var->vartype,
+                                                                                                                          var->vartypmod,
+                                                                                                                          var->varcollid),
+                                                                               InvalidOid, -1,
+                                                                               var->vartype,
+                                                                               COERCE_IMPLICIT_CAST,
+                                                                               -1,
+                                                                               false,
+                                                                               false);
                }
+               elog(ERROR, "could not find replacement targetlist entry for attno %d",
+                        var->varattno);
+               return NULL;                    /* keep compiler quiet */
        }
        else
        {
@@ -1426,20 +1438,23 @@ ResolveNew_callback(Var *var,
 }
 
 Node *
-ResolveNew(Node *node, int target_varno, int sublevels_up,
-                  RangeTblEntry *target_rte,
-                  List *targetlist, int event, int update_varno,
-                  bool *outer_hasSubLinks)
+ReplaceVarsFromTargetList(Node *node,
+                                                 int target_varno, int sublevels_up,
+                                                 RangeTblEntry *target_rte,
+                                                 List *targetlist,
+                                                 ReplaceVarsNoMatchOption nomatch_option,
+                                                 int nomatch_varno,
+                                                 bool *outer_hasSubLinks)
 {
-       ResolveNew_context context;
+       ReplaceVarsFromTargetList_context context;
 
        context.target_rte = target_rte;
        context.targetlist = targetlist;
-       context.event = event;
-       context.update_varno = update_varno;
+       context.nomatch_option = nomatch_option;
+       context.nomatch_varno = nomatch_varno;
 
        return replace_rte_variables(node, target_varno, sublevels_up,
-                                                                ResolveNew_callback,
+                                                                ReplaceVarsFromTargetList_callback,
                                                                 (void *) &context,
                                                                 outer_hasSubLinks);
 }
index e13331dcb5e41c8d872f9a65344fedcdfc966318..1a96c556c9f1354281a422b35ffc23a067860bcd 100644 (file)
@@ -31,6 +31,13 @@ struct replace_rte_variables_context
        bool            inserted_sublink;               /* have we inserted a SubLink? */
 };
 
+typedef enum ReplaceVarsNoMatchOption
+{
+       REPLACEVARS_REPORT_ERROR,       /* throw error if no match */
+       REPLACEVARS_CHANGE_VARNO,       /* change the Var's varno, nothing else */
+       REPLACEVARS_SUBSTITUTE_NULL     /* replace with a NULL Const */
+} ReplaceVarsNoMatchOption;
+
 
 extern void OffsetVarNodes(Node *node, int offset, int sublevels_up);
 extern void ChangeVarNodes(Node *node, int old_varno, int new_varno,
@@ -69,9 +76,12 @@ extern Node *map_variable_attnos(Node *node,
                                        const AttrNumber *attno_map, int map_length,
                                        bool *found_whole_row);
 
-extern Node *ResolveNew(Node *node, int target_varno, int sublevels_up,
-                  RangeTblEntry *target_rte,
-                  List *targetlist, int event, int update_varno,
-                  bool *outer_hasSubLinks);
+extern Node *ReplaceVarsFromTargetList(Node *node,
+                                                 int target_varno, int sublevels_up,
+                                                 RangeTblEntry *target_rte,
+                                                 List *targetlist,
+                                                 ReplaceVarsNoMatchOption nomatch_option,
+                                                 int nomatch_varno,
+                                                 bool *outer_hasSubLinks);
 
 #endif   /* REWRITEMANIP_H */