88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.25 2004/01/05 23:39:54 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.26 2004/02/27 21:48:04 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
1515#include "postgres.h"
1616
1717#include "optimizer/clauses.h"
18+ #include "optimizer/cost.h"
1819#include "optimizer/paths.h"
1920#include "optimizer/restrictinfo.h"
2021#include "optimizer/var.h"
@@ -27,7 +28,7 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause,
2728static Expr * make_sub_restrictinfos (Expr * clause ,
2829bool is_pushed_down ,
2930bool valid_everywhere );
30- static bool join_clause_is_redundant (Query * root ,
31+ static RestrictInfo * join_clause_is_redundant (Query * root ,
3132RestrictInfo * rinfo ,
3233List * reference_list ,
3334JoinType jointype );
@@ -317,17 +318,42 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
317318{
318319List * result = NIL ;
319320List * item ;
321+ QualCost cost ;
322+
323+ /*
324+ * If there are any redundant clauses, we want to eliminate the ones
325+ * that are more expensive in favor of the ones that are less so.
326+ * Run cost_qual_eval() to ensure the eval_cost fields are set up.
327+ */
328+ cost_qual_eval (& cost ,restrictinfo_list );
329+
330+ /*
331+ * We don't have enough knowledge yet to be able to estimate the number
332+ * of times a clause might be evaluated, so it's hard to weight the
333+ * startup and per-tuple costs appropriately. For now just weight 'em
334+ * the same.
335+ */
336+ #define CLAUSECOST (r ) ((r)->eval_cost.startup + (r)->eval_cost.per_tuple)
320337
321338foreach (item ,restrictinfo_list )
322339{
323340RestrictInfo * rinfo = (RestrictInfo * )lfirst (item );
341+ RestrictInfo * prevrinfo ;
324342
325- /* drop it if redundant with any prior clause */
326- if (join_clause_is_redundant (root ,rinfo ,result ,jointype ))
327- continue ;
328-
329- /* otherwise, add it to result list */
330- result = lappend (result ,rinfo );
343+ /* is it redundant with any prior clause? */
344+ prevrinfo = join_clause_is_redundant (root ,rinfo ,result ,jointype );
345+ if (prevrinfo == NULL )
346+ {
347+ /* no, so add it to result list */
348+ result = lappend (result ,rinfo );
349+ }
350+ else if (CLAUSECOST (rinfo )< CLAUSECOST (prevrinfo ))
351+ {
352+ /* keep this one, drop the previous one */
353+ result = lremove (prevrinfo ,result );
354+ result = lappend (result ,rinfo );
355+ }
356+ /* else, drop this one */
331357}
332358
333359return result ;
@@ -361,7 +387,7 @@ select_nonredundant_join_clauses(Query *root,
361387RestrictInfo * rinfo = (RestrictInfo * )lfirst (item );
362388
363389/* drop it if redundant with any reference clause */
364- if (join_clause_is_redundant (root ,rinfo ,reference_list ,jointype ))
390+ if (join_clause_is_redundant (root ,rinfo ,reference_list ,jointype )!= NULL )
365391continue ;
366392
367393/* otherwise, add it to result list */
@@ -373,7 +399,8 @@ select_nonredundant_join_clauses(Query *root,
373399
374400/*
375401 * join_clause_is_redundant
376- *Returns true if rinfo is redundant with any clause in reference_list.
402+ *If rinfo is redundant with any clause in reference_list,
403+ *return one such clause; otherwise return NULL.
377404 *
378405 * This is the guts of both remove_redundant_join_clauses and
379406 * select_nonredundant_join_clauses. See the docs above for motivation.
@@ -398,49 +425,53 @@ select_nonredundant_join_clauses(Query *root,
398425 * then they're not really redundant, because one constrains the
399426 * joined rows after addition of null fill rows, and the other doesn't.
400427 */
401- static bool
428+ static RestrictInfo *
402429join_clause_is_redundant (Query * root ,
403430RestrictInfo * rinfo ,
404431List * reference_list ,
405432JoinType jointype )
406433{
434+ List * refitem ;
435+
407436/* always consider exact duplicates redundant */
408- /* XXX would it be sufficient to use ptrMember here? */
409- if (member (rinfo ,reference_list ))
410- return true;
437+ foreach (refitem ,reference_list )
438+ {
439+ RestrictInfo * refrinfo = (RestrictInfo * )lfirst (refitem );
440+
441+ if (equal (rinfo ,refrinfo ))
442+ return refrinfo ;
443+ }
411444
412445/* check for redundant merge clauses */
413446if (rinfo -> mergejoinoperator != InvalidOid )
414447{
415- bool redundant = false;
416- List * refitem ;
417-
418448/* do the cheap test first: is it a "var = const" clause? */
419449if (bms_is_empty (rinfo -> left_relids )||
420450bms_is_empty (rinfo -> right_relids ))
421- return false ;/* var = const, so not redundant */
451+ return NULL ;/* var = const, so not redundant */
422452
423453cache_mergeclause_pathkeys (root ,rinfo );
424454
425455foreach (refitem ,reference_list )
426456{
427457RestrictInfo * refrinfo = (RestrictInfo * )lfirst (refitem );
428458
429- if (refrinfo -> mergejoinoperator != InvalidOid &&
430- rinfo -> left_pathkey == refrinfo -> left_pathkey &&
431- rinfo -> right_pathkey == refrinfo -> right_pathkey &&
432- (rinfo -> is_pushed_down == refrinfo -> is_pushed_down ||
433- !IS_OUTER_JOIN (jointype )))
459+ if (refrinfo -> mergejoinoperator != InvalidOid )
434460{
435- redundant = true;
436- break ;
461+ cache_mergeclause_pathkeys (root ,refrinfo );
462+
463+ if (rinfo -> left_pathkey == refrinfo -> left_pathkey &&
464+ rinfo -> right_pathkey == refrinfo -> right_pathkey &&
465+ (rinfo -> is_pushed_down == refrinfo -> is_pushed_down ||
466+ !IS_OUTER_JOIN (jointype )))
467+ {
468+ /* Yup, it's redundant */
469+ return refrinfo ;
470+ }
437471}
438472}
439-
440- if (redundant )
441- return true;/* var = var, so redundant */
442473}
443474
444475/* otherwise, not redundant */
445- return false ;
476+ return NULL ;
446477}