1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
/*-------------------------------------------------------------------------
*
* restrictinfo.c
* RestrictInfo node manipulation routines.
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.15 2002/11/24 21:52:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/clauses.h"
#include "optimizer/paths.h"
#include "optimizer/restrictinfo.h"
/*
* restriction_is_or_clause
*
* Returns t iff the restrictinfo node contains an 'or' clause.
*/
bool
restriction_is_or_clause(RestrictInfo *restrictinfo)
{
if (restrictinfo != NULL &&
or_clause((Node *) restrictinfo->clause))
return true;
else
return false;
}
/*
* get_actual_clauses
*
* Returns a list containing the bare clauses from 'restrictinfo_list'.
*/
List *
get_actual_clauses(List *restrictinfo_list)
{
List *result = NIL;
List *temp;
foreach(temp, restrictinfo_list)
{
RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
result = lappend(result, clause->clause);
}
return result;
}
/*
* get_actual_join_clauses
*
* Extract clauses from 'restrictinfo_list', separating those that
* syntactically match the join level from those that were pushed down.
*/
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);
if (clause->ispusheddown)
*otherquals = lappend(*otherquals, clause->clause);
else
*joinquals = lappend(*joinquals, clause->clause);
}
}
/*
* 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.
*
* 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);
/* eliminate duplicates */
if (member(rinfo, result))
continue;
/* check for redundant merge clauses */
if (rinfo->mergejoinoperator != InvalidOid)
{
bool redundant = false;
List *olditem;
cache_mergeclause_pathkeys(root, rinfo);
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)
continue;
}
/* otherwise, add it to result list */
result = lappend(result, rinfo);
}
return result;
}
|