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