]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/plan/planner.c
Break parser functions into smaller files, group together.
[postgresql] / src / backend / optimizer / plan / planner.c
1 /*-------------------------------------------------------------------------
2  *
3  * planner.c--
4  *        The query optimizer external interface.
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.11 1997/11/25 21:59:59 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <sys/types.h>
15
16 #include "postgres.h"
17
18 #include "nodes/pg_list.h"
19 #include "nodes/plannodes.h"
20 #include "nodes/parsenodes.h"
21 #include "nodes/relation.h"
22 #include "parser/parse_expr.h"
23
24 #include "utils/elog.h"
25 #include "utils/lsyscache.h"
26 #include "access/heapam.h"
27
28 #include "optimizer/internal.h"
29 #include "optimizer/planner.h"
30 #include "optimizer/plancat.h"
31 #include "optimizer/prep.h"
32 #include "optimizer/planmain.h"
33 #include "optimizer/paths.h"
34 #include "optimizer/cost.h"
35
36 /* DATA STRUCTURE CREATION/MANIPULATION ROUTINES */
37 #include "nodes/relation.h"
38 #include "optimizer/clauseinfo.h"
39 #include "optimizer/joininfo.h"
40 #include "optimizer/keys.h"
41 #include "optimizer/ordering.h"
42 #include "optimizer/pathnode.h"
43 #include "optimizer/clauses.h"
44 #include "optimizer/tlist.h"
45 #include "optimizer/var.h"
46
47 #include "executor/executor.h"
48
49 static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode);
50 static Plan *init_query_planner(Query *parse);
51 static Existential *make_existential(Plan *left, Plan *right);
52
53 /*****************************************************************************
54  *
55  *         Query optimizer entry point
56  *
57  *****************************************************************************/
58
59
60 /*
61  * planner--
62  *        Main query optimizer routine.
63  *
64  *        Invokes the planner on union queries if there are any left,
65  *        recursing if necessary to get them all, then processes normal plans.
66  *
67  * Returns a query plan.
68  *
69  */
70 Plan       *
71 planner(Query *parse)
72 {
73         List       *tlist = parse->targetList;
74         List       *rangetable = parse->rtable;
75         char       *uniqueflag = parse->uniqueFlag;
76         List       *sortclause = parse->sortClause;
77         Plan       *special_plans = (Plan *) NULL;
78
79         Plan       *result_plan = (Plan *) NULL;
80
81         int                     rt_index;
82
83         /*
84          * plan inheritance
85          */
86         rt_index = first_matching_rt_entry(rangetable, INHERITS_FLAG);
87         if (rt_index != -1)
88         {
89                 special_plans = (Plan *) plan_union_queries((Index) rt_index,
90                                                                                                         parse,
91                                                                                                         INHERITS_FLAG);
92         }
93
94         if (special_plans)
95                 result_plan = special_plans;
96         else
97                 result_plan = init_query_planner(parse);                /* regular plans */
98
99         /*
100          * For now, before we hand back the plan, check to see if there is a
101          * user-specified sort that needs to be done.  Eventually, this will
102          * be moved into the guts of the planner s.t. user specified sorts
103          * will be considered as part of the planning process. Since we can
104          * only make use of user-specified sorts in special cases, we can do
105          * the optimization step later.
106          */
107
108         if (uniqueflag)
109         {
110                 Plan       *sortplan = make_sortplan(tlist, sortclause, result_plan);
111
112                 return ((Plan *) make_unique(tlist, sortplan, uniqueflag));
113         }
114         else
115         {
116                 if (sortclause)
117                         return (make_sortplan(tlist, sortclause, result_plan));
118                 else
119                         return ((Plan *) result_plan);
120         }
121
122 }
123
124 /*
125  * make_sortplan--
126  *        Returns a sortplan which is basically a SORT node attached to the
127  *        top of the plan returned from the planner.  It also adds the
128  *         cost of sorting into the plan.
129  *
130  * sortkeys: ( resdom1 resdom2 resdom3 ...)
131  * sortops:  (sortop1 sortop2 sortop3 ...)
132  */
133 static Plan *
134 make_sortplan(List *tlist, List *sortcls, Plan *plannode)
135 {
136         Plan       *sortplan = (Plan *) NULL;
137         List       *temp_tlist = NIL;
138         List       *i = NIL;
139         Resdom     *resnode = (Resdom *) NULL;
140         Resdom     *resdom = (Resdom *) NULL;
141         int                     keyno = 1;
142
143         /*
144          * First make a copy of the tlist so that we don't corrupt the the
145          * original .
146          */
147
148         temp_tlist = new_unsorted_tlist(tlist);
149
150         foreach(i, sortcls)
151         {
152                 SortClause *sortcl = (SortClause *) lfirst(i);
153
154                 resnode = sortcl->resdom;
155                 resdom = tlist_resdom(temp_tlist, resnode);
156
157                 /*
158                  * Order the resdom keys and replace the operator OID for each key
159                  * with the regproc OID.
160                  */
161                 resdom->reskey = keyno;
162                 resdom->reskeyop = get_opcode(sortcl->opoid);
163                 keyno += 1;
164         }
165
166         sortplan = (Plan *) make_sort(temp_tlist,
167                                                                   _TEMP_RELATION_ID_,
168                                                                   (Plan *) plannode,
169                                                                   length(sortcls));
170
171         /*
172          * XXX Assuming that an internal sort has no. cost. This is wrong, but
173          * given that at this point, we don't know the no. of tuples returned,
174          * etc, we can't do better than to add a constant cost. This will be
175          * fixed once we move the sort further into the planner, but for now
176          * ... functionality....
177          */
178
179         sortplan->cost = plannode->cost;
180
181         return (sortplan);
182 }
183
184
185 /*
186  * init-query-planner--
187  *        Deals with all non-union preprocessing, including existential
188  *        qualifications and CNFifying the qualifications.
189  *
190  * Returns a query plan.
191  * MODIFIES: tlist,qual
192  *
193  */
194 static Plan *
195 init_query_planner(Query *root)
196 {
197         List       *primary_qual;
198         List       *existential_qual;
199         Existential *exist_plan;
200         List       *tlist = root->targetList;
201
202         tlist = preprocess_targetlist(tlist,
203                                                                   root->commandType,
204                                                                   root->resultRelation,
205                                                                   root->rtable);
206
207         primary_qual =
208                 preprocess_qualification((Expr *) root->qual,
209                                                                  tlist,
210                                                                  &existential_qual);
211
212         if (existential_qual == NULL)
213         {
214                 return (query_planner(root,
215                                                           root->commandType,
216                                                           tlist,
217                                                           primary_qual));
218         }
219         else
220         {
221                 int                     temp = root->commandType;
222                 Plan       *existential_plan;
223
224                 root->commandType = CMD_SELECT;
225                 existential_plan = query_planner(root,
226                                                                                  temp,
227                                                                                  NIL,
228                                                                                  existential_qual);
229
230                 exist_plan = make_existential(existential_plan,
231                                                                           query_planner(root,
232                                                                                                         root->commandType,
233                                                                                                         tlist,
234                                                                                                         primary_qual));
235                 return ((Plan *) exist_plan);
236         }
237 }
238
239 /*
240  * make_existential--
241  *        Instantiates an existential plan node and fills in
242  *        the left and right subtree slots.
243  */
244 static Existential *
245 make_existential(Plan *left, Plan *right)
246 {
247         Existential *node = makeNode(Existential);
248
249         node->lefttree = left;
250         node->righttree = left;
251         return (node);
252 }
253
254 /*
255  * pg_checkretval() -- check return value of a list of sql parse
256  *                                              trees.
257  *
258  * The return value of a sql function is the value returned by
259  * the final query in the function.  We do some ad-hoc define-time
260  * type checking here to be sure that the user is returning the
261  * type he claims.
262  */
263 void
264 pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
265 {
266         Query      *parse;
267         List       *tlist;
268         List       *rt;
269         int                     cmd;
270         Type            typ;
271         Resdom     *resnode;
272         Relation        reln;
273         Oid                     relid;
274         Oid                     tletype;
275         int                     relnatts;
276         int                     i;
277
278         /* find the final query */
279         parse = queryTreeList->qtrees[queryTreeList->len - 1];
280
281         /*
282          * test 1:      if the last query is a utility invocation, then there had
283          * better not be a return value declared.
284          */
285         if (parse->commandType == CMD_UTILITY)
286         {
287                 if (rettype == InvalidOid)
288                         return;
289                 else
290                         elog(WARN, "return type mismatch in function decl: final query is a catalog utility");
291         }
292
293         /* okay, it's an ordinary query */
294         tlist = parse->targetList;
295         rt = parse->rtable;
296         cmd = parse->commandType;
297
298         /*
299          * test 2:      if the function is declared to return no value, then the
300          * final query had better not be a retrieve.
301          */
302         if (rettype == InvalidOid)
303         {
304                 if (cmd == CMD_SELECT)
305                         elog(WARN,
306                                  "function declared with no return type, but final query is a retrieve");
307                 else
308                         return;
309         }
310
311         /* by here, the function is declared to return some type */
312         if ((typ = typeidType(rettype)) == NULL)
313                 elog(WARN, "can't find return type %d for function\n", rettype);
314
315         /*
316          * test 3:      if the function is declared to return a value, then the
317          * final query had better be a retrieve.
318          */
319         if (cmd != CMD_SELECT)
320                 elog(WARN, "function declared to return type %s, but final query is not a retrieve", typeTypeName(typ));
321
322         /*
323          * test 4:      for base type returns, the target list should have exactly
324          * one entry, and its type should agree with what the user declared.
325          */
326
327         if (typeTypeRelid(typ) == InvalidOid)
328         {
329                 if (exec_tlist_length(tlist) > 1)
330                         elog(WARN, "function declared to return %s returns multiple values in final retrieve", typeTypeName(typ));
331
332                 resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
333                 if (resnode->restype != rettype)
334                         elog(WARN, "return type mismatch in function: declared to return %s, returns %s", typeTypeName(typ), typeidTypeName(resnode->restype));
335
336                 /* by here, base return types match */
337                 return;
338         }
339
340         /*
341          * If the target list is of length 1, and the type of the varnode in
342          * the target list is the same as the declared return type, this is
343          * okay.  This can happen, for example, where the body of the function
344          * is 'retrieve (x = func2())', where func2 has the same return type
345          * as the function that's calling it.
346          */
347         if (exec_tlist_length(tlist) == 1)
348         {
349                 resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
350                 if (resnode->restype == rettype)
351                         return;
352         }
353
354         /*
355          * By here, the procedure returns a (set of) tuples.  This part of the
356          * typechecking is a hack.      We look up the relation that is the
357          * declared return type, and be sure that attributes 1 .. n in the
358          * target list match the declared types.
359          */
360         reln = heap_open(typeTypeRelid(typ));
361
362         if (!RelationIsValid(reln))
363                 elog(WARN, "cannot open relation relid %d", typeTypeRelid(typ));
364
365         relid = reln->rd_id;
366         relnatts = reln->rd_rel->relnatts;
367
368         if (exec_tlist_length(tlist) != relnatts)
369                 elog(WARN, "function declared to return type %s does not retrieve (%s.*)", typeTypeName(typ), typeTypeName(typ));
370
371         /* expect attributes 1 .. n in order */
372         for (i = 1; i <= relnatts; i++)
373         {
374                 TargetEntry *tle = lfirst(tlist);
375                 Node       *thenode = tle->expr;
376
377                 tlist = lnext(tlist);
378                 tletype = exprType(thenode);
379
380 #if 0                                                   /* fix me */
381                 /* this is tedious */
382                 if (IsA(thenode, Var))
383                         tletype = (Oid) ((Var *) thenode)->vartype;
384                 else if (IsA(thenode, Const))
385                         tletype = (Oid) ((Const *) thenode)->consttype;
386                 else if (IsA(thenode, Param))
387                         tletype = (Oid) ((Param *) thenode)->paramtype;
388                 else if (IsA(thenode, Expr))
389                         tletype = Expr;
390
391                 else if (IsA(thenode, LispList))
392                 {
393                         thenode = lfirst(thenode);
394                         if (IsA(thenode, Oper))
395                                 tletype = (Oid) get_opresulttype((Oper *) thenode);
396                         else if (IsA(thenode, Func))
397                                 tletype = (Oid) get_functype((Func *) thenode);
398                         else
399                                 elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
400                 }
401                 else
402                         elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
403 #endif
404                 /* reach right in there, why don't you? */
405                 if (tletype != reln->rd_att->attrs[i - 1]->atttypid)
406                         elog(WARN, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
407         }
408
409         heap_close(reln);
410
411         /* success */
412         return;
413 }