]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/path/tidpath.c
Reimplement the linked list data structure used throughout the backend.
[postgresql] / src / backend / optimizer / path / tidpath.c
1 /*-------------------------------------------------------------------------
2  *
3  * tidpath.c
4  *        Routines to determine which tids are usable for scanning a
5  *        given relation, and create TidPaths accordingly.
6  *
7  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        $PostgreSQL: pgsql/src/backend/optimizer/path/tidpath.c,v 1.19 2004/05/26 04:41:22 neilc Exp $
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include <math.h>
19
20 #include "catalog/pg_operator.h"
21 #include "optimizer/clauses.h"
22 #include "optimizer/cost.h"
23 #include "optimizer/pathnode.h"
24 #include "optimizer/paths.h"
25 #include "parser/parse_coerce.h"
26 #include "utils/lsyscache.h"
27
28 static List *TidqualFromRestrictinfo(Relids relids, List *restrictinfo);
29 static bool isEvaluable(int varno, Node *node);
30 static Node *TidequalClause(int varno, OpExpr *node);
31 static List *TidqualFromExpr(int varno, Expr *expr);
32
33 static bool
34 isEvaluable(int varno, Node *node)
35 {
36         ListCell   *l;
37         FuncExpr   *expr;
38
39         if (IsA(node, Const))
40                 return true;
41         if (IsA(node, Param))
42                 return true;
43         if (IsA(node, Var))
44         {
45                 Var                *var = (Var *) node;
46
47                 if (var->varno == varno)
48                         return false;
49                 return true;
50         }
51         if (!is_funcclause(node))
52                 return false;
53         expr = (FuncExpr *) node;
54         foreach(l, expr->args)
55         {
56                 if (!isEvaluable(varno, lfirst(l)))
57                         return false;
58         }
59
60         return true;
61 }
62
63 /*
64  *      The 2nd parameter should be an opclause
65  *      Extract the right node if the opclause is CTID= ....
66  *        or    the left  node if the opclause is ....=CTID
67  */
68 static Node *
69 TidequalClause(int varno, OpExpr *node)
70 {
71         Node       *rnode = NULL,
72                            *arg1,
73                            *arg2,
74                            *arg;
75         Var                *var;
76         Const      *aconst;
77         Param      *param;
78         FuncExpr   *expr;
79
80         if (node->opno != TIDEqualOperator)
81                 return rnode;
82         if (length(node->args) != 2)
83                 return rnode;
84         arg1 = linitial(node->args);
85         arg2 = lsecond(node->args);
86
87         arg = NULL;
88         if (IsA(arg1, Var))
89         {
90                 var = (Var *) arg1;
91                 if (var->varno == varno &&
92                         var->varattno == SelfItemPointerAttributeNumber &&
93                         var->vartype == TIDOID)
94                         arg = arg2;
95                 else if (var->varnoold == varno &&
96                                  var->varoattno == SelfItemPointerAttributeNumber &&
97                                  var->vartype == TIDOID)
98                         arg = arg2;
99         }
100         if ((!arg) && IsA(arg2, Var))
101         {
102                 var = (Var *) arg2;
103                 if (var->varno == varno &&
104                         var->varattno == SelfItemPointerAttributeNumber &&
105                         var->vartype == TIDOID)
106                         arg = arg1;
107         }
108         if (!arg)
109                 return rnode;
110         switch (nodeTag(arg))
111         {
112                 case T_Const:
113                         aconst = (Const *) arg;
114                         if (aconst->consttype != TIDOID)
115                                 return rnode;
116                         if (aconst->constbyval)
117                                 return rnode;
118                         rnode = arg;
119                         break;
120                 case T_Param:
121                         param = (Param *) arg;
122                         if (param->paramtype != TIDOID)
123                                 return rnode;
124                         rnode = arg;
125                         break;
126                 case T_Var:
127                         var = (Var *) arg;
128                         if (var->varno == varno ||
129                                 var->vartype != TIDOID)
130                                 return rnode;
131                         rnode = arg;
132                         break;
133                 case T_FuncExpr:
134                         expr = (FuncExpr *) arg;
135                         if (expr->funcresulttype != TIDOID)
136                                 return rnode;
137                         if (isEvaluable(varno, (Node *) expr))
138                                 rnode = arg;
139                         break;
140                 default:
141                         break;
142         }
143         return rnode;
144 }
145
146 /*
147  *      Extract the list of CTID values from a specified expr node.
148  *      When the expr node is an or_clause,we try to extract CTID
149  *      values from all member nodes. However we would discard them
150  *      all if we couldn't extract CTID values from a member node.
151  *      When the expr node is an and_clause,we return the list of
152  *      CTID values if we could extract the CTID values from a member
153  *      node.
154  */
155 static List *
156 TidqualFromExpr(int varno, Expr *expr)
157 {
158         List       *rlst = NIL,
159                            *frtn;
160         ListCell   *l;
161         Node       *node = (Node *) expr,
162                            *rnode;
163
164         if (is_opclause(node))
165         {
166                 rnode = TidequalClause(varno, (OpExpr *) expr);
167                 if (rnode)
168                         rlst = lcons(rnode, rlst);
169         }
170         else if (and_clause(node))
171         {
172                 foreach(l, ((BoolExpr *) expr)->args)
173                 {
174                         node = (Node *) lfirst(l);
175                         rlst = TidqualFromExpr(varno, (Expr *) node);
176                         if (rlst)
177                                 break;
178                 }
179         }
180         else if (or_clause(node))
181         {
182                 foreach(l, ((BoolExpr *) expr)->args)
183                 {
184                         node = (Node *) lfirst(l);
185                         frtn = TidqualFromExpr(varno, (Expr *) node);
186                         if (frtn)
187                                 rlst = nconc(rlst, frtn);
188                         else
189                         {
190                                 if (rlst)
191                                         freeList(rlst);
192                                 rlst = NIL;
193                                 break;
194                         }
195                 }
196         }
197         return rlst;
198 }
199
200 static List *
201 TidqualFromRestrictinfo(Relids relids, List *restrictinfo)
202 {
203         ListCell   *l;
204         List       *rlst = NIL;
205         int                     varno;
206         Node       *node;
207         Expr       *expr;
208
209         if (bms_membership(relids) != BMS_SINGLETON)
210                 return NIL;
211         varno = bms_singleton_member(relids);
212         foreach(l, restrictinfo)
213         {
214                 node = (Node *) lfirst(l);
215                 if (!IsA(node, RestrictInfo))
216                         continue;
217                 expr = ((RestrictInfo *) node)->clause;
218                 rlst = TidqualFromExpr(varno, expr);
219                 if (rlst)
220                         break;
221         }
222         return rlst;
223 }
224
225 /*
226  * create_tidscan_paths
227  *        Creates paths corresponding to tid direct scans of the given rel.
228  *        Candidate paths are added to the rel's pathlist (using add_path).
229  */
230 void
231 create_tidscan_paths(Query *root, RelOptInfo *rel)
232 {
233         List       *tideval = TidqualFromRestrictinfo(rel->relids,
234                                                                                                   rel->baserestrictinfo);
235
236         if (tideval)
237                 add_path(rel, (Path *) create_tidscan_path(root, rel, tideval));
238 }