99 *
1010 *
1111 * IDENTIFICATION
12- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.71 2001/03/22 03:59:37 momjian Exp $
12+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.72 2001/10/30 19:58:58 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
@@ -33,7 +33,8 @@ typedef struct
3333typedef struct
3434{
3535Index subvarno ;
36- List * subplanTargetList ;
36+ List * subplan_targetlist ;
37+ bool tlist_has_non_vars ;
3738}replace_vars_with_subplan_refs_context ;
3839
3940static void fix_expr_references (Plan * plan ,Node * node );
@@ -43,7 +44,8 @@ static Node *join_references_mutator(Node *node,
4344join_references_context * context );
4445static Node * replace_vars_with_subplan_refs (Node * node ,
4546Index subvarno ,
46- List * subplanTargetList );
47+ List * subplan_targetlist ,
48+ bool tlist_has_non_vars );
4749static Node * replace_vars_with_subplan_refs_mutator (Node * node ,
4850replace_vars_with_subplan_refs_context * context );
4951static bool fix_opids_walker (Node * node ,void * context );
@@ -278,75 +280,62 @@ set_join_references(Join *join)
278280 * qual expressions with elements of the subplan's tlist (which was
279281 * generated by flatten_tlist() from these selfsame expressions, so it
280282 * should have all the required variables). There is an important exception,
281- * however: a GROUP BY expression that is also an output expression will
282- * have been pushed into the subplan tlist unflattened. We want to detect
283- * this case and reference the subplan output directly. Therefore, check
284- * for equality of the whole tlist expression to any subplan element before
285- * we resort to picking the expression apart for individual Vars.
283+ * however: GROUP BY and ORDER BY expressions will have been pushed into the
284+ * subplan tlist unflattened. If these values are also needed in the output
285+ * then we want to reference the subplan tlist element rather than recomputing
286+ * the expression.
286287 */
287288static void
288289set_uppernode_references (Plan * plan ,Index subvarno )
289290{
290291Plan * subplan = plan -> lefttree ;
291- List * subplanTargetList ,
292- * outputTargetList ,
292+ List * subplan_targetlist ,
293+ * output_targetlist ,
293294* l ;
295+ bool tlist_has_non_vars ;
294296
295297if (subplan != NULL )
296- subplanTargetList = subplan -> targetlist ;
298+ subplan_targetlist = subplan -> targetlist ;
297299else
298- subplanTargetList = NIL ;
300+ subplan_targetlist = NIL ;
299301
300- outputTargetList = NIL ;
301- foreach (l ,plan -> targetlist )
302+ /*
303+ * Detect whether subplan tlist has any non-Vars (typically it won't
304+ * because it's been flattened). This allows us to save comparisons
305+ * in common cases.
306+ */
307+ tlist_has_non_vars = false;
308+ foreach (l ,subplan_targetlist )
302309{
303310TargetEntry * tle = (TargetEntry * )lfirst (l );
304- TargetEntry * subplantle ;
305- Node * newexpr ;
306-
307- subplantle = tlistentry_member (tle -> expr ,subplanTargetList );
308- if (subplantle )
309- {
310- /* Found a matching subplan output expression */
311- Resdom * resdom = subplantle -> resdom ;
312- Var * newvar ;
313311
314- newvar = makeVar (subvarno ,
315- resdom -> resno ,
316- resdom -> restype ,
317- resdom -> restypmod ,
318- 0 );
319- /* If we're just copying a simple Var, copy up original info */
320- if (subplantle -> expr && IsA (subplantle -> expr ,Var ))
321- {
322- Var * subvar = (Var * )subplantle -> expr ;
323-
324- newvar -> varnoold = subvar -> varnoold ;
325- newvar -> varoattno = subvar -> varoattno ;
326- }
327- else
328- {
329- newvar -> varnoold = 0 ;
330- newvar -> varoattno = 0 ;
331- }
332- newexpr = (Node * )newvar ;
333- }
334- else
312+ if (tle -> expr && !IsA (tle -> expr ,Var ))
335313{
336- /* No matching expression, so replace individual Vars */
337- newexpr = replace_vars_with_subplan_refs (tle -> expr ,
338- subvarno ,
339- subplanTargetList );
314+ tlist_has_non_vars = true;
315+ break ;
340316}
341- outputTargetList = lappend (outputTargetList ,
342- makeTargetEntry (tle -> resdom ,newexpr ));
343317}
344- plan -> targetlist = outputTargetList ;
318+
319+ output_targetlist = NIL ;
320+ foreach (l ,plan -> targetlist )
321+ {
322+ TargetEntry * tle = (TargetEntry * )lfirst (l );
323+ Node * newexpr ;
324+
325+ newexpr = replace_vars_with_subplan_refs (tle -> expr ,
326+ subvarno ,
327+ subplan_targetlist ,
328+ tlist_has_non_vars );
329+ output_targetlist = lappend (output_targetlist ,
330+ makeTargetEntry (tle -> resdom ,newexpr ));
331+ }
332+ plan -> targetlist = output_targetlist ;
345333
346334plan -> qual = (List * )
347335replace_vars_with_subplan_refs ((Node * )plan -> qual ,
348336subvarno ,
349- subplanTargetList );
337+ subplan_targetlist ,
338+ tlist_has_non_vars );
350339}
351340
352341/*
@@ -439,9 +428,16 @@ join_references_mutator(Node *node,
439428 * --- so this routine should only be applied to nodes whose subplans'
440429 * targetlists were generated via flatten_tlist() or some such method.
441430 *
442- * 'node': the tree to be fixed (a targetlist or qual list)
431+ * If tlist_has_non_vars is true, then we try to match whole subexpressions
432+ * against elements of the subplan tlist, so that we can avoid recomputing
433+ * expressions that were already computed by the subplan. (This is relatively
434+ * expensive, so we don't want to try it in the common case where the
435+ * subplan tlist is just a flattened list of Vars.)
436+ *
437+ * 'node': the tree to be fixed (a target item or qual)
443438 * 'subvarno': varno to be assigned to all Vars
444- * 'subplanTargetList': target list for subplan
439+ * 'subplan_targetlist': target list for subplan
440+ * 'tlist_has_non_vars': true if subplan_targetlist contains non-Var exprs
445441 *
446442 * The resulting tree is a copy of the original in which all Var nodes have
447443 * varno = subvarno, varattno = resno of corresponding subplan target.
@@ -450,12 +446,14 @@ join_references_mutator(Node *node,
450446static Node *
451447replace_vars_with_subplan_refs (Node * node ,
452448Index subvarno ,
453- List * subplanTargetList )
449+ List * subplan_targetlist ,
450+ bool tlist_has_non_vars )
454451{
455452replace_vars_with_subplan_refs_context context ;
456453
457454context .subvarno = subvarno ;
458- context .subplanTargetList = subplanTargetList ;
455+ context .subplan_targetlist = subplan_targetlist ;
456+ context .tlist_has_non_vars = tlist_has_non_vars ;
459457return replace_vars_with_subplan_refs_mutator (node ,& context );
460458}
461459
@@ -468,17 +466,38 @@ replace_vars_with_subplan_refs_mutator(Node *node,
468466if (IsA (node ,Var ))
469467{
470468Var * var = (Var * )node ;
471- Var * newvar = (Var * )copyObject (var );
472469Resdom * resdom ;
470+ Var * newvar ;
473471
474- resdom = tlist_member ((Node * )var ,context -> subplanTargetList );
472+ resdom = tlist_member ((Node * )var ,context -> subplan_targetlist );
475473if (!resdom )
476474elog (ERROR ,"replace_vars_with_subplan_refs: variable not in subplan target list" );
477-
475+ newvar = ( Var * ) copyObject ( var );
478476newvar -> varno = context -> subvarno ;
479477newvar -> varattno = resdom -> resno ;
480478return (Node * )newvar ;
481479}
480+ /* Try matching more complex expressions too, if tlist has any */
481+ if (context -> tlist_has_non_vars )
482+ {
483+ Resdom * resdom ;
484+
485+ resdom = tlist_member (node ,context -> subplan_targetlist );
486+ if (resdom )
487+ {
488+ /* Found a matching subplan output expression */
489+ Var * newvar ;
490+
491+ newvar = makeVar (context -> subvarno ,
492+ resdom -> resno ,
493+ resdom -> restype ,
494+ resdom -> restypmod ,
495+ 0 );
496+ newvar -> varnoold = 0 ;/* wasn't ever a plain Var */
497+ newvar -> varoattno = 0 ;
498+ return (Node * )newvar ;
499+ }
500+ }
482501return expression_tree_mutator (node ,
483502replace_vars_with_subplan_refs_mutator ,
484503 (void * )context );