1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* restrictinfo.c
|
1999-02-03 21:15:53 +01:00
|
|
|
* RestrictInfo node manipulation routines.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-06-20 22:29:54 +02:00
|
|
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2003-01-24 04:58:44 +01:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.16 2003/01/24 03:58:43 tgl Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "optimizer/clauses.h"
|
2002-11-24 22:52:15 +01:00
|
|
|
#include "optimizer/paths.h"
|
1999-02-03 21:15:53 +01:00
|
|
|
#include "optimizer/restrictinfo.h"
|
2003-01-24 04:58:44 +01:00
|
|
|
#include "optimizer/var.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2002-11-24 22:52:15 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1999-07-25 01:21:14 +02:00
|
|
|
* restriction_is_or_clause
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
1999-07-25 01:21:14 +02:00
|
|
|
* Returns t iff the restrictinfo node contains an 'or' clause.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
bool
|
1999-07-25 01:21:14 +02:00
|
|
|
restriction_is_or_clause(RestrictInfo *restrictinfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-02-03 21:15:53 +01:00
|
|
|
if (restrictinfo != NULL &&
|
|
|
|
or_clause((Node *) restrictinfo->clause))
|
1998-09-01 05:29:17 +02:00
|
|
|
return true;
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
1998-09-01 05:29:17 +02:00
|
|
|
return false;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1999-02-14 00:22:53 +01:00
|
|
|
* get_actual_clauses
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2002-11-24 22:52:15 +01:00
|
|
|
* Returns a list containing the bare clauses from 'restrictinfo_list'.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1998-02-26 05:46:47 +01:00
|
|
|
List *
|
1999-02-03 21:15:53 +01:00
|
|
|
get_actual_clauses(List *restrictinfo_list)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
List *result = NIL;
|
|
|
|
List *temp;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-02-03 21:15:53 +01:00
|
|
|
foreach(temp, restrictinfo_list)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1999-07-26 01:07:26 +02:00
|
|
|
RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-07-26 01:07:26 +02:00
|
|
|
result = lappend(result, clause->clause);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1998-09-01 05:29:17 +02:00
|
|
|
return result;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2000-09-12 23:07:18 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* get_actual_join_clauses
|
|
|
|
*
|
|
|
|
* Extract clauses from 'restrictinfo_list', separating those that
|
2000-09-29 20:21:41 +02:00
|
|
|
* syntactically match the join level from those that were pushed down.
|
2000-09-12 23:07:18 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
get_actual_join_clauses(List *restrictinfo_list,
|
|
|
|
List **joinquals, List **otherquals)
|
|
|
|
{
|
|
|
|
List *temp;
|
|
|
|
|
|
|
|
*joinquals = NIL;
|
|
|
|
*otherquals = NIL;
|
|
|
|
|
|
|
|
foreach(temp, restrictinfo_list)
|
|
|
|
{
|
|
|
|
RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
|
|
|
|
|
2000-09-29 20:21:41 +02:00
|
|
|
if (clause->ispusheddown)
|
2000-09-12 23:07:18 +02:00
|
|
|
*otherquals = lappend(*otherquals, clause->clause);
|
2000-09-29 20:21:41 +02:00
|
|
|
else
|
|
|
|
*joinquals = lappend(*joinquals, clause->clause);
|
2000-09-12 23:07:18 +02:00
|
|
|
}
|
|
|
|
}
|
2002-11-24 22:52:15 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* remove_redundant_join_clauses
|
|
|
|
*
|
|
|
|
* Given a list of RestrictInfo clauses that are to be applied in a join,
|
|
|
|
* remove any duplicate or redundant clauses.
|
|
|
|
*
|
|
|
|
* We must eliminate duplicates when forming the restrictlist for a joinrel,
|
|
|
|
* since we will see many of the same clauses arriving from both input
|
|
|
|
* relations. Also, if a clause is a mergejoinable clause, it's possible that
|
|
|
|
* it is redundant with previous clauses (see optimizer/README for
|
|
|
|
* discussion). We detect that case and omit the redundant clause from the
|
|
|
|
* result list.
|
|
|
|
*
|
|
|
|
* We can detect redundant mergejoinable clauses very cheaply by using their
|
|
|
|
* left and right pathkeys, which uniquely identify the sets of equijoined
|
|
|
|
* variables in question. All the members of a pathkey set that are in the
|
|
|
|
* left relation have already been forced to be equal; likewise for those in
|
|
|
|
* the right relation. So, we need to have only one clause that checks
|
|
|
|
* equality between any set member on the left and any member on the right;
|
|
|
|
* by transitivity, all the rest are then equal.
|
|
|
|
*
|
2003-01-24 04:58:44 +01:00
|
|
|
* However, clauses that are of the form "var expr = const expr" cannot be
|
|
|
|
* eliminated as redundant. This is because when there are const expressions
|
|
|
|
* in a pathkey set, generate_implied_equalities() suppresses "var = var"
|
|
|
|
* clauses in favor of "var = const" clauses. We cannot afford to drop any
|
|
|
|
* of the latter, even though they might seem redundant by the pathkey
|
|
|
|
* membership test.
|
|
|
|
*
|
2002-11-24 22:52:15 +01:00
|
|
|
* Weird special case: if we have two clauses that seem redundant
|
|
|
|
* except one is pushed down into an outer join and the other isn't,
|
|
|
|
* then they're not really redundant, because one constrains the
|
|
|
|
* joined rows after addition of null fill rows, and the other doesn't.
|
|
|
|
*
|
|
|
|
* The result is a fresh List, but it points to the same member nodes
|
|
|
|
* as were in the input.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
|
|
|
|
JoinType jointype)
|
|
|
|
{
|
|
|
|
List *result = NIL;
|
|
|
|
List *item;
|
|
|
|
|
|
|
|
foreach(item, restrictinfo_list)
|
|
|
|
{
|
|
|
|
RestrictInfo *rinfo = (RestrictInfo *) lfirst(item);
|
|
|
|
|
2003-01-24 04:58:44 +01:00
|
|
|
/* always eliminate duplicates */
|
2002-11-24 22:52:15 +01:00
|
|
|
if (member(rinfo, result))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* check for redundant merge clauses */
|
|
|
|
if (rinfo->mergejoinoperator != InvalidOid)
|
|
|
|
{
|
|
|
|
bool redundant = false;
|
|
|
|
List *olditem;
|
|
|
|
|
|
|
|
cache_mergeclause_pathkeys(root, rinfo);
|
|
|
|
|
2003-01-24 04:58:44 +01:00
|
|
|
/* do the cheap tests first */
|
2002-11-24 22:52:15 +01:00
|
|
|
foreach(olditem, result)
|
|
|
|
{
|
|
|
|
RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
|
|
|
|
|
|
|
|
if (oldrinfo->mergejoinoperator != InvalidOid &&
|
|
|
|
rinfo->left_pathkey == oldrinfo->left_pathkey &&
|
|
|
|
rinfo->right_pathkey == oldrinfo->right_pathkey &&
|
|
|
|
(rinfo->ispusheddown == oldrinfo->ispusheddown ||
|
|
|
|
!IS_OUTER_JOIN(jointype)))
|
|
|
|
{
|
|
|
|
redundant = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (redundant)
|
2003-01-24 04:58:44 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* It looks redundant, now check for "var = const" case.
|
|
|
|
* If left_relids/right_relids are set, then there are
|
|
|
|
* definitely vars on both sides; else we must check the
|
|
|
|
* hard way.
|
|
|
|
*/
|
|
|
|
if (rinfo->left_relids)
|
|
|
|
continue; /* var = var, so redundant */
|
|
|
|
if (contain_var_clause(get_leftop(rinfo->clause)) &&
|
|
|
|
contain_var_clause(get_rightop(rinfo->clause)))
|
|
|
|
continue; /* var = var, so redundant */
|
|
|
|
/* else var = const, not redundant */
|
|
|
|
}
|
2002-11-24 22:52:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* otherwise, add it to result list */
|
|
|
|
result = lappend(result, rinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|