]> granicus.if.org Git - postgresql/blob - src/backend/optimizer/plan/planner.c
Final cleanup.
[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.60 1999/07/16 04:59:19 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <sys/types.h>
15 #include <string.h>
16
17 #include "postgres.h"
18
19 #include "access/genam.h"
20 #include "access/heapam.h"
21 #include "catalog/pg_type.h"
22 #include "executor/executor.h"
23 #include "nodes/makefuncs.h"
24 #include "optimizer/clauses.h"
25 #include "optimizer/internal.h"
26 #include "optimizer/planmain.h"
27 #include "optimizer/planner.h"
28 #include "optimizer/prep.h"
29 #include "optimizer/subselect.h"
30 #include "optimizer/tlist.h"
31 #include "optimizer/var.h"
32 #include "parser/parse_expr.h"
33 #include "parser/parse_oper.h"
34 #include "utils/builtins.h"
35 #include "utils/lsyscache.h"
36 #include "utils/syscache.h"
37
38 static List *make_subplanTargetList(Query *parse, List *tlist,
39                                            AttrNumber **groupColIdx);
40 static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup,
41                            List *groupClause, AttrNumber *grpColIdx,
42                            Plan *subplan);
43 static bool need_sortplan(List *sortcls, Plan *plan);
44 static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode);
45
46 /*****************************************************************************
47  *
48  *         Query optimizer entry point
49  *
50  *****************************************************************************/
51 Plan *
52 planner(Query *parse)
53 {
54         Plan       *result_plan;
55
56         /* Initialize state for subselects */
57         PlannerQueryLevel = 1;
58         PlannerInitPlan = NULL;
59         PlannerParamVar = NULL;
60         PlannerPlanId = 0;
61
62         transformKeySetQuery(parse);
63         result_plan = union_planner(parse);
64
65         Assert(PlannerQueryLevel == 1);
66         if (PlannerPlanId > 0)
67         {
68                 result_plan->initPlan = PlannerInitPlan;
69                 (void) SS_finalize_plan(result_plan);
70         }
71         result_plan->nParamExec = length(PlannerParamVar);
72
73         return result_plan;
74 }
75
76 /*
77  * union_planner
78  *
79  *        Invokes the planner on union queries if there are any left,
80  *        recursing if necessary to get them all, then processes normal plans.
81  *
82  * Returns a query plan.
83  *
84  */
85 Plan *
86 union_planner(Query *parse)
87 {
88         List       *tlist = parse->targetList;
89         List       *rangetable = parse->rtable;
90         Plan       *result_plan = (Plan *) NULL;
91         AttrNumber *groupColIdx = NULL;
92         Index           rt_index;
93
94         if (parse->unionClause)
95         {
96                 result_plan = (Plan *) plan_union_queries(parse);
97                 /* XXX do we need to do this? bjm 12/19/97 */
98                 tlist = preprocess_targetlist(tlist,
99                                                                           parse->commandType,
100                                                                           parse->resultRelation,
101                                                                           parse->rtable);
102         }
103         else if ((rt_index = first_inherit_rt_entry(rangetable)) != -1)
104         {
105                 List       *sub_tlist;
106
107                 /*
108                  * Generate appropriate target list for subplan; may be different
109                  * from tlist if grouping or aggregation is needed.
110                  */
111                 sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx);
112
113                 /*
114                  * Recursively plan the subqueries needed for inheritance
115                  */
116                 result_plan = (Plan *) plan_inherit_queries(parse, sub_tlist,
117                                                                                                         rt_index);
118
119                 /*
120                  * Fix up outer target list.  NOTE: unlike the case for non-inherited
121                  * query, we pass the unfixed tlist to subplans, which do their own
122                  * fixing.  But we still want to fix the outer target list afterwards.
123                  * I *think* this is correct --- doing the fix before recursing is
124                  * definitely wrong, because preprocess_targetlist() will do the
125                  * wrong thing if invoked twice on the same list. Maybe that is a bug?
126                  * tgl 6/6/99
127                  */
128                 tlist = preprocess_targetlist(tlist,
129                                                                           parse->commandType,
130                                                                           parse->resultRelation,
131                                                                           parse->rtable);
132
133                 if (parse->rowMark != NULL)
134                         elog(ERROR, "SELECT FOR UPDATE is not supported for inherit queries");
135         }
136         else
137         {
138                 List       *sub_tlist;
139
140                 /* Preprocess targetlist in case we are inside an INSERT/UPDATE. */
141                 tlist = preprocess_targetlist(tlist,
142                                                                           parse->commandType,
143                                                                           parse->resultRelation,
144                                                                           parse->rtable);
145
146                 /*
147                  * Add row-mark targets for UPDATE (should this be done in
148                  * preprocess_targetlist?)
149                  */
150                 if (parse->rowMark != NULL)
151                 {
152                         List       *l;
153
154                         foreach(l, parse->rowMark)
155                         {
156                                 RowMark    *rowmark = (RowMark *) lfirst(l);
157                                 TargetEntry *ctid;
158                                 Resdom     *resdom;
159                                 Var                *var;
160                                 char       *resname;
161
162                                 if (!(rowmark->info & ROW_MARK_FOR_UPDATE))
163                                         continue;
164
165                                 resname = (char *) palloc(32);
166                                 sprintf(resname, "ctid%u", rowmark->rti);
167                                 resdom = makeResdom(length(tlist) + 1,
168                                                                         TIDOID,
169                                                                         -1,
170                                                                         resname,
171                                                                         0,
172                                                                         0,
173                                                                         true);
174
175                                 var = makeVar(rowmark->rti, -1, TIDOID,
176                                                           -1, 0, rowmark->rti, -1);
177
178                                 ctid = makeTargetEntry(resdom, (Node *) var);
179                                 tlist = lappend(tlist, ctid);
180                         }
181                 }
182
183                 /*
184                  * Generate appropriate target list for subplan; may be different
185                  * from tlist if grouping or aggregation is needed.
186                  */
187                 sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx);
188
189                 /* Generate the (sub) plan */
190                 result_plan = query_planner(parse,
191                                                                         parse->commandType,
192                                                                         sub_tlist,
193                                                                         (List *) parse->qual);
194         }
195
196         /* query_planner returns NULL if it thinks plan is bogus */
197         if (! result_plan)
198                 elog(ERROR, "union_planner: failed to create plan");
199
200         /*
201          * If we have a GROUP BY clause, insert a group node (with the
202          * appropriate sort node.)
203          */
204         if (parse->groupClause)
205         {
206                 bool            tuplePerGroup;
207                 List       *group_tlist;
208
209                 /*
210                  * Decide whether how many tuples per group the Group node needs
211                  * to return. (Needs only one tuple per group if no aggregate is
212                  * present. Otherwise, need every tuple from the group to do the
213                  * aggregation.)  Note tuplePerGroup is named backwards :-(
214                  */
215                 tuplePerGroup = parse->hasAggs;
216
217                 /*
218                  * If there are aggregates then the Group node should just return
219                  * the same (simplified) tlist as the subplan, which we indicate
220                  * to make_groupplan by passing NIL.  If there are no aggregates
221                  * then the Group node had better compute the final tlist.
222                  */
223                 group_tlist = parse->hasAggs ? NIL : tlist;
224
225                 result_plan = make_groupplan(group_tlist,
226                                                                          tuplePerGroup,
227                                                                          parse->groupClause,
228                                                                          groupColIdx,
229                                                                          result_plan);
230         }
231
232         /*
233          * If we have a HAVING clause, do the necessary things with it.
234          */
235         if (parse->havingQual)
236         {
237                 /* convert the havingQual to conjunctive normal form (cnf) */
238                 parse->havingQual = (Node *) cnfify((Expr *) parse->havingQual, true);
239
240                 if (parse->hasSubLinks)
241                 {
242                         /*
243                          * There may be a subselect in the havingQual, so we have to
244                          * process it using the same function as for a subselect in
245                          * 'where'
246                          */
247                         parse->havingQual = SS_process_sublinks(parse->havingQual);
248
249                         /*
250                          * Check for ungrouped variables passed to subplans. (Probably
251                          * this should be done for the targetlist as well???)
252                          */
253                         check_having_for_ungrouped_vars(parse->havingQual,
254                                                                                         parse->groupClause,
255                                                                                         parse->targetList);
256                 }
257
258                 /* Calculate the opfids from the opnos */
259                 parse->havingQual = (Node *) fix_opids((List *) parse->havingQual);
260         }
261
262         /*
263          * If aggregate is present, insert the agg node
264          */
265         if (parse->hasAggs)
266         {
267                 result_plan = (Plan *) make_agg(tlist, result_plan);
268
269                 /* HAVING clause, if any, becomes qual of the Agg node */
270                 result_plan->qual = (List *) parse->havingQual;
271
272                 /*
273                  * Update vars to refer to subplan result tuples, find Aggrefs,
274                  * make sure there is an Aggref in every HAVING clause.
275                  */
276                 if (!set_agg_tlist_references((Agg *) result_plan))
277                         elog(ERROR, "SELECT/HAVING requires aggregates to be valid");
278
279                 /*
280                  * Check that we actually found some aggregates, else executor
281                  * will die unpleasantly.  (This defends against possible bugs in
282                  * parser or rewrite that might cause hasAggs to be incorrectly
283                  * set 'true'. It's not easy to recover here, since we've already
284                  * made decisions assuming there will be an Agg node.)
285                  */
286                 if (((Agg *) result_plan)->aggs == NIL)
287                         elog(ERROR, "union_planner: query is marked hasAggs, but I don't see any");
288         }
289
290         /*
291          * For now, before we hand back the plan, check to see if there is a
292          * user-specified sort that needs to be done.  Eventually, this will
293          * be moved into the guts of the planner s.t. user specified sorts
294          * will be considered as part of the planning process. Since we can
295          * only make use of user-specified sorts in special cases, we can do
296          * the optimization step later.
297          */
298
299         if (parse->uniqueFlag)
300         {
301                 Plan       *sortplan = make_sortplan(tlist, parse->sortClause, result_plan);
302
303                 return ((Plan *) make_unique(tlist, sortplan, parse->uniqueFlag));
304         }
305         else
306         {
307                 if (parse->sortClause && need_sortplan(parse->sortClause, result_plan))
308                         return (make_sortplan(tlist, parse->sortClause, result_plan));
309                 else
310                         return ((Plan *) result_plan);
311         }
312
313 }
314
315 /*---------------
316  * make_subplanTargetList
317  *        Generate appropriate target lists when grouping is required.
318  *
319  * When union_planner inserts Aggregate and/or Group/Sort plan nodes above
320  * the result of query_planner, we typically need to pass a different
321  * target list to query_planner than the outer plan nodes should have.
322  * This routine generates the correct target list for the subplan, and
323  * if necessary modifies the target list for the inserted nodes as well.
324  *
325  * The initial target list passed from the parser already contains entries
326  * for all ORDER BY and GROUP BY expressions, but it will not have entries
327  * for variables used only in HAVING clauses; so we need to add those
328  * variables to the subplan target list.  Also, if we are doing either
329  * grouping or aggregation, we flatten all expressions except GROUP BY items
330  * into their component variables; the other expressions will be computed by
331  * the inserted nodes rather than by the subplan.  For example,
332  * given a query like
333  *              SELECT a+b,SUM(c+d) FROM table GROUP BY a+b;
334  * we want to pass this targetlist to the subplan:
335  *              a+b,c,d
336  * where the a+b target will be used by the Sort/Group steps, and the
337  * c and d targets will be needed to compute the aggregate results.
338  *
339  * 'parse' is the query being processed.
340  * 'tlist' is the query's target list.  CAUTION: list elements may be
341  * modified by this routine!
342  * 'groupColIdx' receives an array of column numbers for the GROUP BY
343  * expressions (if there are any) in the subplan's target list.
344  *
345  * The result is the targetlist to be passed to the subplan.  Also,
346  * the parent tlist is modified so that any nontrivial targetlist items that
347  * exactly match GROUP BY items are replaced by simple Var nodes referencing
348  * those outputs of the subplan.  This avoids redundant recalculations in
349  * cases like
350  *              SELECT a+1, ... GROUP BY a+1
351  * Note, however, that other varnodes in the parent's targetlist (and
352  * havingQual, if any) will still need to be updated to refer to outputs
353  * of the subplan.      This routine is quite large enough already, so we do
354  * that later.
355  *---------------
356  */
357 static List *
358 make_subplanTargetList(Query *parse,
359                                            List *tlist,
360                                            AttrNumber **groupColIdx)
361 {
362         List       *sub_tlist;
363         List       *prnt_tlist;
364         List       *sl,
365                            *gl;
366         List       *glc = NIL;
367         List       *extravars = NIL;
368         int                     numCols;
369         AttrNumber *grpColIdx = NULL;
370         int                     next_resno = 1;
371
372         *groupColIdx = NULL;
373
374         /*
375          * If we're not grouping or aggregating, nothing to do here;
376          * query_planner should receive the unmodified target list.
377          */
378         if (!parse->hasAggs && !parse->groupClause && !parse->havingQual)
379                 return tlist;
380
381         /*
382          * If grouping, make a working copy of groupClause list (which we use
383          * just to verify that we found all the groupClause items in tlist).
384          * Also allocate space to remember where the group columns are in the
385          * subplan tlist.
386          */
387         numCols = length(parse->groupClause);
388         if (numCols > 0)
389         {
390                 glc = listCopy(parse->groupClause);
391                 grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
392                 *groupColIdx = grpColIdx;
393         }
394
395         sub_tlist = new_unsorted_tlist(tlist);          /* make a modifiable copy */
396
397         /*
398          * Step 1: build grpColIdx by finding targetlist items that match
399          * GroupBy entries.  If there are aggregates, remove non-GroupBy items
400          * from sub_tlist, and reset its resnos accordingly.  When we leave an
401          * expression in the subplan tlist, modify the parent tlist to copy
402          * the value from the subplan output rather than re-evaluating it.
403          */
404         prnt_tlist = tlist;                     /* scans parent tlist in sync with sl */
405         foreach(sl, sub_tlist)
406         {
407                 TargetEntry *te = (TargetEntry *) lfirst(sl);
408                 TargetEntry *parentte = (TargetEntry *) lfirst(prnt_tlist);
409                 Resdom     *resdom = te->resdom;
410                 bool            keepInSubPlan = true;
411                 bool            foundGroupClause = false;
412                 int                     keyno = 0;
413
414                 foreach(gl, parse->groupClause)
415                 {
416                         GroupClause *grpcl = (GroupClause *) lfirst(gl);
417
418                         keyno++;                        /* sort key # for this GroupClause */
419                         if (grpcl->tleGroupref == resdom->resgroupref)
420                         {
421                                 /* Found a matching groupclause; record info for sorting */
422                                 foundGroupClause = true;
423                                 resdom->reskey = keyno;
424                                 resdom->reskeyop = get_opcode(grpcl->grpOpoid);
425                                 grpColIdx[keyno - 1] = next_resno;
426
427                                 /*
428                                  * Remove groupclause from our list of unmatched
429                                  * groupclauses. NB: this depends on having used a shallow
430                                  * listCopy() above.
431                                  */
432                                 glc = lremove((void *) grpcl, glc);
433                                 break;
434                         }
435                 }
436
437                 if (!foundGroupClause)
438                 {
439
440                         /*
441                          * Non-GroupBy entry: remove it from subplan if there are
442                          * aggregates in query - it will be evaluated by Aggregate
443                          * plan. But do not remove simple-Var entries; we'd just have
444                          * to add them back anyway, and we risk confusing
445                          * INSERT/UPDATE.
446                          */
447                         if (parse->hasAggs && !IsA(te->expr, Var))
448                                 keepInSubPlan = false;
449                 }
450
451                 if (keepInSubPlan)
452                 {
453                         /* Assign new sequential resnos to subplan tlist items */
454                         resdom->resno = next_resno++;
455                         if (!IsA(parentte->expr, Var))
456                         {
457
458                                 /*
459                                  * Since the item is being computed in the subplan, we can
460                                  * just make a Var node to reference it in the outer plan,
461                                  * rather than recomputing it there. Note we use varnoold
462                                  * = -1 as a flag to let replace_vars_with_subplan_refs
463                                  * know it needn't change this Var node. If it's only a
464                                  * Var anyway, we leave it alone for now;
465                                  * replace_vars_with_subplan_refs will fix it later.
466                                  */
467                                 parentte->expr = (Node *) makeVar(1, resdom->resno,
468                                                                                                   resdom->restype,
469                                                                                                   resdom->restypmod,
470                                                                                                   0, -1, resdom->resno);
471                         }
472                 }
473                 else
474                 {
475
476                         /*
477                          * Remove this tlist item from the subplan, but remember the
478                          * vars it needs.  The outer tlist item probably needs
479                          * changes, but that will happen later.
480                          */
481                         sub_tlist = lremove(te, sub_tlist);
482                         extravars = nconc(extravars, pull_var_clause(te->expr));
483                 }
484
485                 prnt_tlist = lnext(prnt_tlist);
486         }
487
488         /* We should have found all the GROUP BY clauses in the tlist. */
489         if (length(glc) != 0)
490                 elog(ERROR, "make_subplanTargetList: GROUP BY attribute not found in target list");
491
492         /*
493          * Add subplan targets for any variables needed by removed tlist
494          * entries that aren't otherwise mentioned in the subplan target list.
495          * We'll also need targets for any variables seen only in HAVING.
496          */
497         extravars = nconc(extravars, pull_var_clause(parse->havingQual));
498
499         foreach(gl, extravars)
500         {
501                 Var                *v = (Var *) lfirst(gl);
502
503                 if (tlist_member(v, sub_tlist) == NULL)
504                 {
505
506                         /*
507                          * Make sure sub_tlist element is a fresh object not shared
508                          * with any other structure; not sure if anything will break
509                          * if it is shared, but better to be safe...
510                          */
511                         sub_tlist = lappend(sub_tlist,
512                                                                 create_tl_element((Var *) copyObject(v),
513                                                                                                   next_resno));
514                         next_resno++;
515                 }
516         }
517
518         return sub_tlist;
519 }
520
521 static Plan *
522 make_groupplan(List *group_tlist,
523                            bool tuplePerGroup,
524                            List *groupClause,
525                            AttrNumber *grpColIdx,
526                            Plan *subplan)
527 {
528         List       *sort_tlist;
529         List       *sl;
530         Sort       *sortplan;
531         Group      *grpplan;
532         int                     numCols = length(groupClause);
533
534         /*
535          * Make the targetlist for the Sort node; it always just references
536          * each of the corresponding target items of the subplan.  We need to
537          * ensure that simple Vars in the subplan's target list are
538          * recognizable by replace_vars_with_subplan_refs when it's applied to
539          * the Sort/Group target list, so copy up their varnoold/varoattno.
540          */
541         sort_tlist = NIL;
542         foreach(sl, subplan->targetlist)
543         {
544                 TargetEntry *te = (TargetEntry *) lfirst(sl);
545                 Resdom     *resdom = te->resdom;
546                 Var                *newvar;
547
548                 if (IsA(te->expr, Var))
549                 {
550                         Var                *subvar = (Var *) te->expr;
551
552                         newvar = makeVar(1, resdom->resno,
553                                                          resdom->restype, resdom->restypmod,
554                                                          0, subvar->varnoold, subvar->varoattno);
555                 }
556                 else
557                 {
558                         newvar = makeVar(1, resdom->resno,
559                                                          resdom->restype, resdom->restypmod,
560                                                          0, -1, resdom->resno);
561                 }
562
563                 sort_tlist = lappend(sort_tlist,
564                                                    makeTargetEntry((Resdom *) copyObject(resdom),
565                                                                                    (Node *) newvar));
566         }
567
568         /*
569          * Make the Sort node
570          */
571         sortplan = make_sort(sort_tlist,
572                                                  _NONAME_RELATION_ID_,
573                                                  subplan,
574                                                  numCols);
575         sortplan->plan.cost = subplan->cost;            /* XXX assume no cost */
576
577         /*
578          * If the caller gave us a target list, use it after fixing the
579          * variables. If not, we need the same sort of "repeater" tlist as for
580          * the Sort node.
581          */
582         if (group_tlist)
583         {
584                 group_tlist = copyObject(group_tlist);  /* necessary?? */
585                 replace_tlist_with_subplan_refs(group_tlist,
586                                                                                 (Index) 0,
587                                                                                 subplan->targetlist);
588         }
589         else
590                 group_tlist = copyObject(sort_tlist);
591
592         /*
593          * Make the Group node
594          */
595         grpplan = make_group(group_tlist, tuplePerGroup, numCols,
596                                                  grpColIdx, sortplan);
597
598         return (Plan *) grpplan;
599 }
600
601 /*
602  * make_sortplan
603  *        Returns a sortplan which is basically a SORT node attached to the
604  *        top of the plan returned from the planner.  It also adds the
605  *         cost of sorting into the plan.
606  *
607  * sortkeys: ( resdom1 resdom2 resdom3 ...)
608  * sortops:  (sortop1 sortop2 sortop3 ...)
609  */
610 static Plan *
611 make_sortplan(List *tlist, List *sortcls, Plan *plannode)
612 {
613         Plan       *sortplan = (Plan *) NULL;
614         List       *temp_tlist = NIL;
615         List       *i = NIL;
616         Resdom     *resnode = (Resdom *) NULL;
617         Resdom     *resdom = (Resdom *) NULL;
618         int                     keyno = 1;
619
620         /*
621          * First make a copy of the tlist so that we don't corrupt the the
622          * original .
623          */
624
625         temp_tlist = new_unsorted_tlist(tlist);
626
627         foreach(i, sortcls)
628         {
629                 SortClause *sortcl = (SortClause *) lfirst(i);
630
631                 resnode = sortcl->resdom;
632                 resdom = tlist_resdom(temp_tlist, resnode);
633
634                 /*
635                  * Order the resdom keys and replace the operator OID for each key
636                  * with the regproc OID.
637                  */
638                 resdom->reskey = keyno;
639                 resdom->reskeyop = get_opcode(sortcl->opoid);
640                 keyno += 1;
641         }
642
643         sortplan = (Plan *) make_sort(temp_tlist,
644                                                                   _NONAME_RELATION_ID_,
645                                                                   (Plan *) plannode,
646                                                                   length(sortcls));
647
648         /*
649          * XXX Assuming that an internal sort has no. cost. This is wrong, but
650          * given that at this point, we don't know the no. of tuples returned,
651          * etc, we can't do better than to add a constant cost. This will be
652          * fixed once we move the sort further into the planner, but for now
653          * ... functionality....
654          */
655
656         sortplan->cost = plannode->cost;
657
658         return sortplan;
659 }
660
661 /*
662  * pg_checkretval() -- check return value of a list of sql parse
663  *                                              trees.
664  *
665  * The return value of a sql function is the value returned by
666  * the final query in the function.  We do some ad-hoc define-time
667  * type checking here to be sure that the user is returning the
668  * type he claims.
669  *
670  * XXX Why is this function in this module?
671  */
672 void
673 pg_checkretval(Oid rettype, List *queryTreeList)
674 {
675         Query      *parse;
676         List       *tlist;
677         List       *rt;
678         int                     cmd;
679         Type            typ;
680         Resdom     *resnode;
681         Relation        reln;
682         Oid                     relid;
683         Oid                     tletype;
684         int                     relnatts;
685         int                     i;
686
687         /* find the final query */
688         parse = (Query *) nth(length(queryTreeList) - 1, queryTreeList);
689
690         /*
691          * test 1:      if the last query is a utility invocation, then there had
692          * better not be a return value declared.
693          */
694         if (parse->commandType == CMD_UTILITY)
695         {
696                 if (rettype == InvalidOid)
697                         return;
698                 else
699                         elog(ERROR, "return type mismatch in function decl: final query is a catalog utility");
700         }
701
702         /* okay, it's an ordinary query */
703         tlist = parse->targetList;
704         rt = parse->rtable;
705         cmd = parse->commandType;
706
707         /*
708          * test 2:      if the function is declared to return no value, then the
709          * final query had better not be a retrieve.
710          */
711         if (rettype == InvalidOid)
712         {
713                 if (cmd == CMD_SELECT)
714                         elog(ERROR,
715                                  "function declared with no return type, but final query is a retrieve");
716                 else
717                         return;
718         }
719
720         /* by here, the function is declared to return some type */
721         if ((typ = typeidType(rettype)) == NULL)
722                 elog(ERROR, "can't find return type %u for function\n", rettype);
723
724         /*
725          * test 3:      if the function is declared to return a value, then the
726          * final query had better be a retrieve.
727          */
728         if (cmd != CMD_SELECT)
729                 elog(ERROR, "function declared to return type %s, but final query is not a retrieve", typeTypeName(typ));
730
731         /*
732          * test 4:      for base type returns, the target list should have exactly
733          * one entry, and its type should agree with what the user declared.
734          */
735
736         if (typeTypeRelid(typ) == InvalidOid)
737         {
738                 if (ExecTargetListLength(tlist) > 1)
739                         elog(ERROR, "function declared to return %s returns multiple values in final retrieve", typeTypeName(typ));
740
741                 resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
742                 if (resnode->restype != rettype)
743                         elog(ERROR, "return type mismatch in function: declared to return %s, returns %s", typeTypeName(typ), typeidTypeName(resnode->restype));
744
745                 /* by here, base return types match */
746                 return;
747         }
748
749         /*
750          * If the target list is of length 1, and the type of the varnode in
751          * the target list is the same as the declared return type, this is
752          * okay.  This can happen, for example, where the body of the function
753          * is 'retrieve (x = func2())', where func2 has the same return type
754          * as the function that's calling it.
755          */
756         if (ExecTargetListLength(tlist) == 1)
757         {
758                 resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
759                 if (resnode->restype == rettype)
760                         return;
761         }
762
763         /*
764          * By here, the procedure returns a (set of) tuples.  This part of the
765          * typechecking is a hack.      We look up the relation that is the
766          * declared return type, and be sure that attributes 1 .. n in the
767          * target list match the declared types.
768          */
769         reln = heap_open(typeTypeRelid(typ));
770
771         if (!RelationIsValid(reln))
772                 elog(ERROR, "cannot open relation relid %u", typeTypeRelid(typ));
773
774         relid = reln->rd_id;
775         relnatts = reln->rd_rel->relnatts;
776
777         if (ExecTargetListLength(tlist) != relnatts)
778                 elog(ERROR, "function declared to return type %s does not retrieve (%s.*)", typeTypeName(typ), typeTypeName(typ));
779
780         /* expect attributes 1 .. n in order */
781         for (i = 1; i <= relnatts; i++)
782         {
783                 TargetEntry *tle = lfirst(tlist);
784                 Node       *thenode = tle->expr;
785
786                 tlist = lnext(tlist);
787                 tletype = exprType(thenode);
788
789 #ifdef NOT_USED                                 /* fix me */
790                 /* this is tedious */
791                 if (IsA(thenode, Var))
792                         tletype = (Oid) ((Var *) thenode)->vartype;
793                 else if (IsA(thenode, Const))
794                         tletype = (Oid) ((Const *) thenode)->consttype;
795                 else if (IsA(thenode, Param))
796                         tletype = (Oid) ((Param *) thenode)->paramtype;
797                 else if (IsA(thenode, Expr))
798                         tletype = Expr;
799
800                 else if (IsA(thenode, LispList))
801                 {
802                         thenode = lfirst(thenode);
803                         if (IsA(thenode, Oper))
804                                 tletype = (Oid) get_opresulttype((Oper *) thenode);
805                         else if (IsA(thenode, Func))
806                                 tletype = (Oid) get_functype((Func *) thenode);
807                         else
808                                 elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
809                 }
810                 else
811                         elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
812 #endif
813                 /* reach right in there, why don't you? */
814                 if (tletype != reln->rd_att->attrs[i - 1]->atttypid)
815                         elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));
816         }
817
818         heap_close(reln);
819
820         /* success */
821         return;
822 }
823
824
825 /* ----------
826  * Support function for need_sortplan
827  * ----------
828  */
829 static TargetEntry *
830 get_matching_tle(Plan *plan, Resdom *resdom)
831 {
832         List       *i;
833         TargetEntry *tle;
834
835         foreach(i, plan->targetlist)
836         {
837                 tle = (TargetEntry *) lfirst(i);
838                 if (tle->resdom->resno == resdom->resno)
839                         return tle;
840         }
841         return NULL;
842 }
843
844
845 /* ----------
846  * Check if a user requested ORDER BY is already satisfied by
847  * the choosen index scan.
848  *
849  * Returns TRUE if sort is required, FALSE if can be omitted.
850  * ----------
851  */
852 static bool
853 need_sortplan(List *sortcls, Plan *plan)
854 {
855         Relation        indexRel;
856         IndexScan  *indexScan;
857         Oid                     indexId;
858         List       *i;
859         HeapTuple       htup;
860         Form_pg_index index_tup;
861         int                     key_no = 0;
862
863         /* ----------
864          * Must be an IndexScan
865          * ----------
866          */
867         if (nodeTag(plan) != T_IndexScan)
868                 return TRUE;
869
870         indexScan = (IndexScan *) plan;
871
872         /* ----------
873          * Should not have left- or righttree
874          * ----------
875          */
876         if (plan->lefttree != NULL)
877                 return TRUE;
878         if (plan->righttree != NULL)
879                 return TRUE;
880
881         /* ----------
882          * Must be a single index scan
883          * ----------
884          */
885         if (length(indexScan->indxid) != 1)
886                 return TRUE;
887
888         /* ----------
889          * Indices can only have up to 8 attributes. So an ORDER BY using
890          * more that 8 attributes could never be satisfied by an index.
891          * ----------
892          */
893         if (length(sortcls) > 8)
894                 return TRUE;
895
896         /* ----------
897          * The choosen Index must be a btree
898          * ----------
899          */
900         indexId = lfirsti(indexScan->indxid);
901
902         indexRel = index_open(indexId);
903         if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0)
904         {
905                 heap_close(indexRel);
906                 return TRUE;
907         }
908         heap_close(indexRel);
909
910         /* ----------
911          * Fetch the index tuple
912          * ----------
913          */
914         htup = SearchSysCacheTuple(INDEXRELID,
915                                                            ObjectIdGetDatum(indexId), 0, 0, 0);
916         if (!HeapTupleIsValid(htup))
917                 elog(ERROR, "cache lookup for index %u failed", indexId);
918         index_tup = (Form_pg_index) GETSTRUCT(htup);
919
920         /* ----------
921          * Check if all the sort clauses match the attributes in the index
922          * ----------
923          */
924         foreach(i, sortcls)
925         {
926                 SortClause *sortcl;
927                 Resdom     *resdom;
928                 TargetEntry *tle;
929                 Var                *var;
930
931                 sortcl = (SortClause *) lfirst(i);
932
933                 resdom = sortcl->resdom;
934                 tle = get_matching_tle(plan, resdom);
935                 if (tle == NULL)
936                 {
937                         /* ----------
938                          * Could this happen?
939                          * ----------
940                          */
941                         return TRUE;
942                 }
943                 if (nodeTag(tle->expr) != T_Var)
944                 {
945                         /* ----------
946                          * The target list expression isn't a var, so it
947                          * cannot be the indexed attribute
948                          * ----------
949                          */
950                         return TRUE;
951                 }
952                 var = (Var *) (tle->expr);
953
954                 if (var->varno != indexScan->scan.scanrelid)
955                 {
956                         /* ----------
957                          * This Var isn't from the scan relation. So it isn't
958                          * that of the index
959                          * ----------
960                          */
961                         return TRUE;
962                 }
963
964                 if (var->varattno != index_tup->indkey[key_no])
965                 {
966                         /* ----------
967                          * It isn't the indexed attribute.
968                          * ----------
969                          */
970                         return TRUE;
971                 }
972
973                 if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid)
974                 {
975                         /* ----------
976                          * Sort order isn't in ascending order.
977                          * ----------
978                          */
979                         return TRUE;
980                 }
981
982                 key_no++;
983         }
984
985         /* ----------
986          * Index matches ORDER BY - sort not required
987          * ----------
988          */
989         return FALSE;
990 }