1 /*-------------------------------------------------------------------------
4 * Routines to create the desired plan for processing a query.
5 * Planning is complete, we just need to convert the selected
8 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.118 2002/09/04 20:31:21 momjian Exp $
15 *-------------------------------------------------------------------------
20 #include "nodes/makefuncs.h"
21 #include "nodes/nodeFuncs.h"
22 #include "optimizer/clauses.h"
23 #include "optimizer/cost.h"
24 #include "optimizer/paths.h"
25 #include "optimizer/planmain.h"
26 #include "optimizer/restrictinfo.h"
27 #include "optimizer/tlist.h"
28 #include "optimizer/var.h"
29 #include "parser/parse_expr.h"
30 #include "utils/lsyscache.h"
31 #include "utils/syscache.h"
34 static Scan *create_scan_plan(Query *root, Path *best_path);
35 static Join *create_join_plan(Query *root, JoinPath *best_path);
36 static Append *create_append_plan(Query *root, AppendPath *best_path);
37 static SeqScan *create_seqscan_plan(Path *best_path, List *tlist,
39 static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
40 List *tlist, List *scan_clauses);
41 static TidScan *create_tidscan_plan(TidPath *best_path, List *tlist,
43 static SubqueryScan *create_subqueryscan_plan(Path *best_path,
44 List *tlist, List *scan_clauses);
45 static FunctionScan *create_functionscan_plan(Path *best_path,
46 List *tlist, List *scan_clauses);
47 static NestLoop *create_nestloop_plan(Query *root,
48 NestPath *best_path, List *tlist,
49 List *joinclauses, List *otherclauses,
50 Plan *outer_plan, List *outer_tlist,
51 Plan *inner_plan, List *inner_tlist);
52 static MergeJoin *create_mergejoin_plan(Query *root,
53 MergePath *best_path, List *tlist,
54 List *joinclauses, List *otherclauses,
55 Plan *outer_plan, List *outer_tlist,
56 Plan *inner_plan, List *inner_tlist);
57 static HashJoin *create_hashjoin_plan(Query *root,
58 HashPath *best_path, List *tlist,
59 List *joinclauses, List *otherclauses,
60 Plan *outer_plan, List *outer_tlist,
61 Plan *inner_plan, List *inner_tlist);
62 static void fix_indxqual_references(List *indexquals, IndexPath *index_path,
63 List **fixed_indexquals,
64 List **recheck_indexquals);
65 static void fix_indxqual_sublist(List *indexqual, int baserelid,
67 List **fixed_quals, List **recheck_quals);
68 static Node *fix_indxqual_operand(Node *node, int baserelid,
71 static List *switch_outer(List *clauses);
72 static void copy_path_costsize(Plan *dest, Path *src);
73 static void copy_plan_costsize(Plan *dest, Plan *src);
74 static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
75 static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
76 List *indxid, List *indxqual,
78 ScanDirection indexscandir);
79 static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
81 static FunctionScan *make_functionscan(List *qptlist, List *qpqual,
83 static NestLoop *make_nestloop(List *tlist,
84 List *joinclauses, List *otherclauses,
85 Plan *lefttree, Plan *righttree,
87 static HashJoin *make_hashjoin(List *tlist,
88 List *joinclauses, List *otherclauses,
90 Plan *lefttree, Plan *righttree,
92 static Hash *make_hash(List *tlist, Node *hashkey, Plan *lefttree);
93 static MergeJoin *make_mergejoin(List *tlist,
94 List *joinclauses, List *otherclauses,
96 Plan *lefttree, Plan *righttree,
101 * Creates the access plan for a query by tracing backwards through the
102 * desired chain of pathnodes, starting at the node 'best_path'. For
103 * every pathnode found:
104 * (1) Create a corresponding plan node containing appropriate id,
105 * target list, and qualification information.
106 * (2) Modify qual clauses of join nodes so that subplan attributes are
107 * referenced using relative values.
108 * (3) Target lists are not modified, but will be in setrefs.c.
110 * best_path is the best access path
112 * Returns a Plan tree.
115 create_plan(Query *root, Path *best_path)
119 switch (best_path->pathtype)
126 plan = (Plan *) create_scan_plan(root, best_path);
131 plan = (Plan *) create_join_plan(root,
132 (JoinPath *) best_path);
135 plan = (Plan *) create_append_plan(root,
136 (AppendPath *) best_path);
139 elog(ERROR, "create_plan: unknown pathtype %d",
140 best_path->pathtype);
141 plan = NULL; /* keep compiler quiet */
145 #ifdef NOT_USED /* fix xfunc */
146 /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
147 if (XfuncMode != XFUNC_OFF)
149 set_qpqual((Plan) plan,
150 lisp_qsort(get_qpqual((Plan) plan),
151 xfunc_clause_compare));
152 if (XfuncMode != XFUNC_NOR)
153 /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */
154 xfunc_disjunct_sort(plan->qpqual);
163 * Create a scan plan for the parent relation of 'best_path'.
165 * Returns a Plan node.
168 create_scan_plan(Query *root, Path *best_path)
171 List *tlist = best_path->parent->targetlist;
175 * Extract the relevant restriction clauses from the parent relation;
176 * the executor must apply all these restrictions during the scan.
178 scan_clauses = get_actual_clauses(best_path->parent->baserestrictinfo);
180 switch (best_path->pathtype)
183 plan = (Scan *) create_seqscan_plan(best_path,
189 plan = (Scan *) create_indexscan_plan(root,
190 (IndexPath *) best_path,
196 plan = (Scan *) create_tidscan_plan((TidPath *) best_path,
202 plan = (Scan *) create_subqueryscan_plan(best_path,
208 plan = (Scan *) create_functionscan_plan(best_path,
214 elog(ERROR, "create_scan_plan: unknown node type: %d",
215 best_path->pathtype);
216 plan = NULL; /* keep compiler quiet */
225 * Create a join plan for 'best_path' and (recursively) plans for its
226 * inner and outer paths.
228 * Returns a Plan node.
231 create_join_plan(Query *root, JoinPath *best_path)
233 List *join_tlist = best_path->path.parent->targetlist;
242 outer_plan = create_plan(root, best_path->outerjoinpath);
243 outer_tlist = outer_plan->targetlist;
245 inner_plan = create_plan(root, best_path->innerjoinpath);
246 inner_tlist = inner_plan->targetlist;
248 if (IS_OUTER_JOIN(best_path->jointype))
250 get_actual_join_clauses(best_path->joinrestrictinfo,
251 &joinclauses, &otherclauses);
255 /* We can treat all clauses alike for an inner join */
256 joinclauses = get_actual_clauses(best_path->joinrestrictinfo);
260 switch (best_path->path.pathtype)
263 plan = (Join *) create_mergejoin_plan(root,
264 (MergePath *) best_path,
274 plan = (Join *) create_hashjoin_plan(root,
275 (HashPath *) best_path,
285 plan = (Join *) create_nestloop_plan(root,
286 (NestPath *) best_path,
296 elog(ERROR, "create_join_plan: unknown node type: %d",
297 best_path->path.pathtype);
298 plan = NULL; /* keep compiler quiet */
305 * * Expensive function pullups may have pulled local predicates *
306 * into this path node. Put them in the qpqual of the plan node. *
309 if (get_loc_restrictinfo(best_path) != NIL)
310 set_qpqual((Plan) plan,
311 nconc(get_qpqual((Plan) plan),
312 get_actual_clauses(get_loc_restrictinfo(best_path))));
320 * Create an Append plan for 'best_path' and (recursively) plans
323 * Returns a Plan node.
326 create_append_plan(Query *root, AppendPath *best_path)
329 List *tlist = best_path->path.parent->targetlist;
330 List *subplans = NIL;
333 foreach(subpaths, best_path->subpaths)
335 Path *subpath = (Path *) lfirst(subpaths);
337 subplans = lappend(subplans, create_plan(root, subpath));
340 plan = make_append(subplans, false, tlist);
346 /*****************************************************************************
348 * BASE-RELATION SCAN METHODS
350 *****************************************************************************/
354 * create_seqscan_plan
355 * Returns a seqscan plan for the base relation scanned by 'best_path'
356 * with restriction clauses 'scan_clauses' and targetlist 'tlist'.
359 create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
364 /* there should be exactly one base rel involved... */
365 Assert(length(best_path->parent->relids) == 1);
366 Assert(best_path->parent->rtekind == RTE_RELATION);
368 scan_relid = (Index) lfirsti(best_path->parent->relids);
370 scan_plan = make_seqscan(tlist,
374 copy_path_costsize(&scan_plan->plan, best_path);
380 * create_indexscan_plan
381 * Returns a indexscan plan for the base relation scanned by 'best_path'
382 * with restriction clauses 'scan_clauses' and targetlist 'tlist'.
384 * The indexqual of the path contains a sublist of implicitly-ANDed qual
385 * conditions for each scan of the index(es); if there is more than one
386 * scan then the retrieved tuple sets are ORed together. The indexqual
387 * and indexinfo lists must have the same length, ie, the number of scans
388 * that will occur. Note it is possible for a qual condition sublist
389 * to be empty --- then no index restrictions will be applied during that
393 create_indexscan_plan(Query *root,
394 IndexPath *best_path,
398 List *indxqual = best_path->indexqual;
401 Expr *indxqual_or_expr = NULL;
402 List *fixed_indxqual;
403 List *recheck_indxqual;
406 IndexScan *scan_plan;
408 /* there should be exactly one base rel involved... */
409 Assert(length(best_path->path.parent->relids) == 1);
410 Assert(best_path->path.parent->rtekind == RTE_RELATION);
412 baserelid = lfirsti(best_path->path.parent->relids);
415 * Build list of index OIDs.
418 foreach(ixinfo, best_path->indexinfo)
420 IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
422 indexids = lappendi(indexids, index->indexoid);
426 * The qpqual list must contain all restrictions not automatically
427 * handled by the index. Normally the predicates in the indxqual are
428 * checked fully by the index, but if the index is "lossy" for a
429 * particular operator (as signaled by the amopreqcheck flag in
430 * pg_amop), then we need to double-check that predicate in qpqual,
431 * because the index may return more tuples than match the predicate.
433 * Since the indexquals were generated from the restriction clauses given
434 * by scan_clauses, there will normally be some duplications between
435 * the lists. We get rid of the duplicates, then add back if lossy.
437 if (length(indxqual) > 1)
440 * Build an expression representation of the indexqual, expanding
441 * the implicit OR and AND semantics of the first- and
442 * second-level lists.
444 List *orclauses = NIL;
447 foreach(orclause, indxqual)
449 orclauses = lappend(orclauses,
450 make_ands_explicit(lfirst(orclause)));
452 indxqual_or_expr = make_orclause(orclauses);
454 qpqual = set_difference(scan_clauses, makeList1(indxqual_or_expr));
456 else if (indxqual != NIL)
459 * Here, we can simply treat the first sublist as an independent
460 * set of qual expressions, since there is no top-level OR
463 qpqual = set_difference(scan_clauses, lfirst(indxqual));
466 qpqual = scan_clauses;
469 * The executor needs a copy with the indexkey on the left of each
470 * clause and with index attr numbers substituted for table ones. This
471 * pass also looks for "lossy" operators.
473 fix_indxqual_references(indxqual, best_path,
474 &fixed_indxqual, &recheck_indxqual);
477 * If there were any "lossy" operators, need to add back the
478 * appropriate qual clauses to the qpqual. When there is just one
479 * indexscan being performed (ie, we have simple AND semantics), we
480 * can just add the lossy clauses themselves to qpqual. If we have
481 * OR-of-ANDs, we'd better add the entire original indexqual to make
482 * sure that the semantics are correct.
484 if (recheck_indxqual != NIL)
486 if (indxqual_or_expr)
488 /* Better do a deep copy of the original scanclauses */
489 qpqual = lappend(qpqual, copyObject(indxqual_or_expr));
493 /* Subroutine already copied quals, so just append to list */
494 Assert(length(recheck_indxqual) == 1);
495 qpqual = nconc(qpqual, (List *) lfirst(recheck_indxqual));
499 /* Finally ready to build the plan node */
500 scan_plan = make_indexscan(tlist,
506 best_path->indexscandir);
508 copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
509 /* use the indexscan-specific rows estimate, not the parent rel's */
510 scan_plan->scan.plan.plan_rows = best_path->rows;
516 * create_tidscan_plan
517 * Returns a tidscan plan for the base relation scanned by 'best_path'
518 * with restriction clauses 'scan_clauses' and targetlist 'tlist'.
521 create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses)
526 /* there should be exactly one base rel involved... */
527 Assert(length(best_path->path.parent->relids) == 1);
528 Assert(best_path->path.parent->rtekind == RTE_RELATION);
530 scan_relid = (Index) lfirsti(best_path->path.parent->relids);
532 scan_plan = make_tidscan(tlist,
537 if (best_path->unjoined_relids)
538 scan_plan->needRescan = true;
540 copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
546 * create_subqueryscan_plan
547 * Returns a subqueryscan plan for the base relation scanned by 'best_path'
548 * with restriction clauses 'scan_clauses' and targetlist 'tlist'.
550 static SubqueryScan *
551 create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses)
553 SubqueryScan *scan_plan;
556 /* there should be exactly one base rel involved... */
557 Assert(length(best_path->parent->relids) == 1);
558 /* and it must be a subquery */
559 Assert(best_path->parent->rtekind == RTE_SUBQUERY);
561 scan_relid = (Index) lfirsti(best_path->parent->relids);
563 scan_plan = make_subqueryscan(tlist,
566 best_path->parent->subplan);
572 * create_functionscan_plan
573 * Returns a functionscan plan for the base relation scanned by 'best_path'
574 * with restriction clauses 'scan_clauses' and targetlist 'tlist'.
576 static FunctionScan *
577 create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses)
579 FunctionScan *scan_plan;
582 /* there should be exactly one base rel involved... */
583 Assert(length(best_path->parent->relids) == 1);
584 /* and it must be a function */
585 Assert(best_path->parent->rtekind == RTE_FUNCTION);
587 scan_relid = (Index) lfirsti(best_path->parent->relids);
589 scan_plan = make_functionscan(tlist, scan_clauses, scan_relid);
591 copy_path_costsize(&scan_plan->scan.plan, best_path);
596 /*****************************************************************************
600 * A general note about join_references() processing in these routines:
601 * once we have changed a Var node to refer to a subplan output rather than
602 * the original relation, it is no longer equal() to an unmodified Var node
603 * for the same var. So, we cannot easily compare reference-adjusted qual
604 * clauses to clauses that have not been adjusted. Fortunately, that
605 * doesn't seem to be necessary; all the decisions are made before we do
606 * the reference adjustments.
608 * A cleaner solution would be to not call join_references() here at all,
609 * but leave it for setrefs.c to do at the end of plan tree construction.
610 * But that would make switch_outer() much more complicated, and some care
611 * would be needed to get setrefs.c to do the right thing with nestloop
612 * inner indexscan quals. So, we do subplan reference adjustment here for
613 * quals of join nodes (and *only* for quals of join nodes).
615 *****************************************************************************/
618 create_nestloop_plan(Query *root,
630 if (IsA(inner_plan, IndexScan))
633 * An index is being used to reduce the number of tuples scanned
634 * in the inner relation. If there are join clauses being used
635 * with the index, we must update their outer-rel var nodes to
636 * refer to the outer side of the join.
638 * We can also remove those join clauses from the list of clauses
639 * that have to be checked as qpquals at the join node, but only
640 * if there's just one indexscan in the inner path (otherwise,
641 * several different sets of clauses are being ORed together).
643 * Note: if the index is lossy, the same clauses may also be getting
644 * checked as qpquals in the indexscan. We can still remove them
645 * from the nestloop's qpquals, but we gotta update the outer-rel
646 * vars in the indexscan's qpquals too.
648 * Note: we can safely do set_difference() against my clauses and
649 * join_references() because the innerscan is a primitive plan,
650 * and therefore has not itself done join_references renumbering
651 * of the vars in its quals.
653 IndexScan *innerscan = (IndexScan *) inner_plan;
654 List *indxqualorig = innerscan->indxqualorig;
656 /* No work needed if indxqual refers only to its own relation... */
657 if (NumRelids((Node *) indxqualorig) > 1)
659 Index innerrel = innerscan->scan.scanrelid;
662 * Remove redundant tests from my clauses, if possible. Note
663 * we must compare against indxqualorig not the "fixed"
664 * indxqual (which has index attnos instead of relation
665 * attnos, and may have been commuted as well).
667 if (length(indxqualorig) == 1) /* single indexscan? */
668 joinclauses = set_difference(joinclauses,
669 lfirst(indxqualorig));
671 /* only refs to outer vars get changed in the inner indexqual */
672 innerscan->indxqualorig = join_references(indxqualorig,
677 innerscan->indxqual = join_references(innerscan->indxqual,
682 /* fix the inner qpqual too, if it has join clauses */
683 if (NumRelids((Node *) inner_plan->qual) > 1)
684 inner_plan->qual = join_references(inner_plan->qual,
691 else if (IsA(inner_plan, TidScan))
693 TidScan *innerscan = (TidScan *) inner_plan;
695 innerscan->tideval = join_references(innerscan->tideval,
699 innerscan->scan.scanrelid);
701 else if (IsA_Join(inner_plan))
704 * Materialize the inner join for speed reasons.
706 * XXX It is probably *not* always fastest to materialize an inner
707 * join --- how can we estimate whether this is a good thing to
710 inner_plan = (Plan *) make_material(inner_tlist,
715 * Set quals to contain INNER/OUTER var references.
717 joinclauses = join_references(joinclauses,
722 otherclauses = join_references(otherclauses,
728 join_plan = make_nestloop(tlist,
733 best_path->jointype);
735 copy_path_costsize(&join_plan->join.plan, &best_path->path);
741 create_mergejoin_plan(Query *root,
742 MergePath *best_path,
752 MergeJoin *join_plan;
754 mergeclauses = get_actual_clauses(best_path->path_mergeclauses);
757 * Remove the mergeclauses from the list of join qual clauses, leaving
758 * the list of quals that must be checked as qpquals. Set those
759 * clauses to contain INNER/OUTER var references.
761 joinclauses = join_references(set_difference(joinclauses, mergeclauses),
768 * Fix the additional qpquals too.
770 otherclauses = join_references(otherclauses,
777 * Now set the references in the mergeclauses and rearrange them so
778 * that the outer variable is always on the left.
780 mergeclauses = switch_outer(join_references(mergeclauses,
787 * Create explicit sort nodes for the outer and inner join paths if
788 * necessary. The sort cost was already accounted for in the path.
790 if (best_path->outersortkeys)
791 outer_plan = (Plan *)
792 make_sort_from_pathkeys(root,
795 best_path->outersortkeys);
797 if (best_path->innersortkeys)
798 inner_plan = (Plan *)
799 make_sort_from_pathkeys(root,
802 best_path->innersortkeys);
805 * The executor requires the inner side of a mergejoin to support
806 * "mark" and "restore" operations. Not all plan types do, so we must
807 * be careful not to generate an invalid plan. If necessary, an
808 * invalid inner plan can be handled by inserting a Materialize node.
810 * Since the inner side must be ordered, and only Sorts and IndexScans
811 * can create order to begin with, you might think there's no problem
812 * --- but you'd be wrong. Nestloop and merge joins can *preserve*
813 * the order of their inputs, so they can be selected as the input of
814 * a mergejoin, and that won't work in the present executor.
816 * Doing this here is a bit of a kluge since the cost of the Materialize
817 * wasn't taken into account in our earlier decisions. But
818 * Materialize is hard to estimate a cost for, and the above
819 * consideration shows that this is a rare case anyway, so this seems
820 * an acceptable way to proceed.
822 * This check must agree with ExecMarkPos/ExecRestrPos in
823 * executor/execAmi.c!
825 switch (nodeTag(inner_plan))
832 /* OK, these inner plans support mark/restore */
836 /* Ooops, need to materialize the inner plan */
837 inner_plan = (Plan *) make_material(inner_tlist,
843 * Now we can build the mergejoin node.
845 join_plan = make_mergejoin(tlist,
851 best_path->jpath.jointype);
853 copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path);
859 create_hashjoin_plan(Query *root,
875 * NOTE: there will always be exactly one hashclause in the list
876 * best_path->path_hashclauses (cf. hash_inner_and_outer()). We
877 * represent it as a list anyway, for convenience with routines that
878 * want to work on lists of clauses.
880 hashclauses = get_actual_clauses(best_path->path_hashclauses);
883 * Remove the hashclauses from the list of join qual clauses, leaving
884 * the list of quals that must be checked as qpquals. Set those
885 * clauses to contain INNER/OUTER var references.
887 joinclauses = join_references(set_difference(joinclauses, hashclauses),
894 * Fix the additional qpquals too.
896 otherclauses = join_references(otherclauses,
903 * Now set the references in the hashclauses and rearrange them so
904 * that the outer variable is always on the left.
906 hashclauses = switch_outer(join_references(hashclauses,
912 /* Now the righthand op of the sole hashclause is the inner hash key. */
913 innerhashkey = (Node *) get_rightop(lfirst(hashclauses));
916 * Build the hash node and hash join node.
918 hash_plan = make_hash(inner_tlist, innerhashkey, inner_plan);
919 join_plan = make_hashjoin(tlist,
925 best_path->jpath.jointype);
927 copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path);
933 /*****************************************************************************
935 * SUPPORTING ROUTINES
937 *****************************************************************************/
940 * fix_indxqual_references
941 * Adjust indexqual clauses to the form the executor's indexqual
942 * machinery needs, and check for recheckable (lossy) index conditions.
944 * We have four tasks here:
945 * * Index keys must be represented by Var nodes with varattno set to the
946 * index's attribute number, not the attribute number in the original rel.
947 * * indxpath.c may have selected an index that is binary-compatible with
948 * the actual expression operator, but not exactly the same datatype.
949 * We must replace the expression's operator with the binary-compatible
950 * equivalent operator that the index will recognize.
951 * * If the index key is on the right, commute the clause to put it on the
952 * left. (Someday the executor might not need this, but for now it does.)
953 * * If the indexable operator is marked 'amopreqcheck' in pg_amop, then
954 * the index is "lossy" for this operator: it may return more tuples than
955 * actually satisfy the operator condition. For each such operator, we
956 * must add (the original form of) the indexqual clause to the "qpquals"
957 * of the indexscan node, where the operator will be re-evaluated to
960 * This code used to be entirely bogus for multi-index scans. Now it keeps
961 * track of which index applies to each subgroup of index qual clauses...
963 * Both the input list and the output lists have the form of lists of sublists
964 * of qual clauses --- the top-level list has one entry for each indexscan
965 * to be performed. The semantics are OR-of-ANDs.
967 * fixed_indexquals receives a modified copy of the indexqual list --- the
968 * original is not changed. Note also that the copy shares no substructure
969 * with the original; this is needed in case there is a subplan in it (we need
970 * two separate copies of the subplan tree, or things will go awry).
972 * recheck_indexquals similarly receives a full copy of whichever clauses
976 fix_indxqual_references(List *indexquals, IndexPath *index_path,
977 List **fixed_indexquals, List **recheck_indexquals)
979 List *fixed_quals = NIL;
980 List *recheck_quals = NIL;
981 int baserelid = lfirsti(index_path->path.parent->relids);
982 List *ixinfo = index_path->indexinfo;
985 foreach(i, indexquals)
987 List *indexqual = lfirst(i);
988 IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
992 fix_indxqual_sublist(indexqual, baserelid, index,
993 &fixed_qual, &recheck_qual);
994 fixed_quals = lappend(fixed_quals, fixed_qual);
995 if (recheck_qual != NIL)
996 recheck_quals = lappend(recheck_quals, recheck_qual);
998 ixinfo = lnext(ixinfo);
1001 *fixed_indexquals = fixed_quals;
1002 *recheck_indexquals = recheck_quals;
1006 * Fix the sublist of indexquals to be used in a particular scan.
1008 * For each qual clause, commute if needed to put the indexkey operand on the
1009 * left, and then fix its varattno. (We do not need to change the other side
1010 * of the clause.) Also change the operator if necessary, and check for
1011 * lossy index behavior.
1013 * Returns two lists: the list of fixed indexquals, and the list (usually
1014 * empty) of original clauses that must be rechecked as qpquals because
1015 * the index is lossy for this operator type.
1018 fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
1019 List **fixed_quals, List **recheck_quals)
1021 List *fixed_qual = NIL;
1022 List *recheck_qual = NIL;
1025 foreach(i, indexqual)
1027 Expr *clause = (Expr *) lfirst(i);
1033 if (!is_opclause((Node *) clause) || length(clause->args) != 2)
1034 elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
1037 * Make a copy that will become the fixed clause.
1039 * We used to try to do a shallow copy here, but that fails if there
1040 * is a subplan in the arguments of the opclause. So just do a
1043 newclause = (Expr *) copyObject((Node *) clause);
1046 * Check to see if the indexkey is on the right; if so, commute
1047 * the clause. The indexkey should be the side that refers to
1048 * (only) the base relation.
1050 leftvarnos = pull_varnos((Node *) lfirst(newclause->args));
1051 if (length(leftvarnos) != 1 || lfirsti(leftvarnos) != baserelid)
1052 CommuteClause(newclause);
1053 freeList(leftvarnos);
1056 * Now, determine which index attribute this is, change the
1057 * indexkey operand as needed, and get the index opclass.
1059 lfirst(newclause->args) = fix_indxqual_operand(lfirst(newclause->args),
1065 * Substitute the appropriate operator if the expression operator
1066 * is merely binary-compatible with the index. This shouldn't
1067 * fail, since indxpath.c found it before...
1069 newopno = indexable_operator(newclause, opclass, true);
1070 if (newopno == InvalidOid)
1071 elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
1072 ((Oper *) newclause->oper)->opno = newopno;
1074 fixed_qual = lappend(fixed_qual, newclause);
1077 * Finally, check to see if index is lossy for this operator. If
1078 * so, add (a copy of) original form of clause to recheck list.
1080 if (op_requires_recheck(newopno, opclass))
1081 recheck_qual = lappend(recheck_qual,
1082 copyObject((Node *) clause));
1085 *fixed_quals = fixed_qual;
1086 *recheck_quals = recheck_qual;
1090 fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index,
1094 * Remove any binary-compatible relabeling of the indexkey
1096 if (IsA(node, RelabelType))
1097 node = ((RelabelType *) node)->arg;
1100 * We represent index keys by Var nodes having the varno of the base
1101 * table but varattno equal to the index's attribute number (index
1102 * column position). This is a bit hokey ... would be cleaner to use
1103 * a special-purpose node type that could not be mistaken for a
1104 * regular Var. But it will do for now.
1108 /* If it's a var, find which index key position it occupies */
1109 Assert(index->indproc == InvalidOid);
1111 if (((Var *) node)->varno == baserelid)
1113 int varatt = ((Var *) node)->varattno;
1116 for (pos = 0; pos < index->nkeys; pos++)
1118 if (index->indexkeys[pos] == varatt)
1120 Node *newnode = copyObject(node);
1122 ((Var *) newnode)->varattno = pos + 1;
1123 /* return the correct opclass, too */
1124 *opclass = index->classlist[pos];
1131 * Oops, this Var isn't an indexkey!
1133 elog(ERROR, "fix_indxqual_operand: var is not index attribute");
1137 * Else, it must be a func expression matching a functional index.
1138 * Since we currently only support single-column functional indexes,
1139 * the returned varattno must be 1.
1141 Assert(index->indproc != InvalidOid);
1142 Assert(is_funcclause(node)); /* not a very thorough check, but easy */
1144 /* classlist[0] is the only class of a functional index */
1145 *opclass = index->classlist[0];
1147 return (Node *) makeVar(baserelid, 1, exprType(node), -1, 0);
1152 * Given a list of merge or hash joinclauses, rearrange the elements within
1153 * the clauses so the outer join variable is on the left and the inner is
1154 * on the right. The original list is not touched; a modified list
1158 switch_outer(List *clauses)
1165 Expr *clause = (Expr *) lfirst(i);
1168 Assert(is_opclause((Node *) clause));
1169 op = get_rightop(clause);
1170 Assert(op && IsA(op, Var));
1171 if (var_is_outer(op))
1174 * Duplicate just enough of the structure to allow commuting
1175 * the clause without changing the original list. Could use
1176 * copyObject, but a complete deep copy is overkill.
1180 temp = make_clause(clause->opType, clause->oper,
1181 listCopy(clause->args));
1182 /* Commute it --- note this modifies the temp node in-place. */
1183 CommuteClause(temp);
1184 t_list = lappend(t_list, temp);
1187 t_list = lappend(t_list, clause);
1193 * Copy cost and size info from a Path node to the Plan node created from it.
1194 * The executor won't use this info, but it's needed by EXPLAIN.
1197 copy_path_costsize(Plan *dest, Path *src)
1201 dest->startup_cost = src->startup_cost;
1202 dest->total_cost = src->total_cost;
1203 dest->plan_rows = src->parent->rows;
1204 dest->plan_width = src->parent->width;
1208 dest->startup_cost = 0;
1209 dest->total_cost = 0;
1210 dest->plan_rows = 0;
1211 dest->plan_width = 0;
1216 * Copy cost and size info from a lower plan node to an inserted node.
1217 * This is not critical, since the decisions have already been made,
1218 * but it helps produce more reasonable-looking EXPLAIN output.
1219 * (Some callers alter the info after copying it.)
1222 copy_plan_costsize(Plan *dest, Plan *src)
1226 dest->startup_cost = src->startup_cost;
1227 dest->total_cost = src->total_cost;
1228 dest->plan_rows = src->plan_rows;
1229 dest->plan_width = src->plan_width;
1233 dest->startup_cost = 0;
1234 dest->total_cost = 0;
1235 dest->plan_rows = 0;
1236 dest->plan_width = 0;
1241 /*****************************************************************************
1243 * PLAN NODE BUILDING ROUTINES
1245 * Some of these are exported because they are called to build plan nodes
1246 * in contexts where we're not deriving the plan node from a path node.
1248 *****************************************************************************/
1251 make_seqscan(List *qptlist,
1255 SeqScan *node = makeNode(SeqScan);
1256 Plan *plan = &node->plan;
1258 /* cost should be inserted by caller */
1259 plan->state = (EState *) NULL;
1260 plan->targetlist = qptlist;
1261 plan->qual = qpqual;
1262 plan->lefttree = NULL;
1263 plan->righttree = NULL;
1264 node->scanrelid = scanrelid;
1265 node->scanstate = (CommonScanState *) NULL;
1271 make_indexscan(List *qptlist,
1277 ScanDirection indexscandir)
1279 IndexScan *node = makeNode(IndexScan);
1280 Plan *plan = &node->scan.plan;
1282 /* cost should be inserted by caller */
1283 plan->state = (EState *) NULL;
1284 plan->targetlist = qptlist;
1285 plan->qual = qpqual;
1286 plan->lefttree = NULL;
1287 plan->righttree = NULL;
1288 node->scan.scanrelid = scanrelid;
1289 node->indxid = indxid;
1290 node->indxqual = indxqual;
1291 node->indxqualorig = indxqualorig;
1292 node->indxorderdir = indexscandir;
1293 node->scan.scanstate = (CommonScanState *) NULL;
1299 make_tidscan(List *qptlist,
1304 TidScan *node = makeNode(TidScan);
1305 Plan *plan = &node->scan.plan;
1307 /* cost should be inserted by caller */
1308 plan->state = (EState *) NULL;
1309 plan->targetlist = qptlist;
1310 plan->qual = qpqual;
1311 plan->lefttree = NULL;
1312 plan->righttree = NULL;
1313 node->scan.scanrelid = scanrelid;
1314 node->tideval = copyObject(tideval); /* XXX do we really need a
1316 node->needRescan = false;
1317 node->scan.scanstate = (CommonScanState *) NULL;
1323 make_subqueryscan(List *qptlist,
1328 SubqueryScan *node = makeNode(SubqueryScan);
1329 Plan *plan = &node->scan.plan;
1331 copy_plan_costsize(plan, subplan);
1332 plan->state = (EState *) NULL;
1333 plan->targetlist = qptlist;
1334 plan->qual = qpqual;
1335 plan->lefttree = NULL;
1336 plan->righttree = NULL;
1337 node->scan.scanrelid = scanrelid;
1338 node->subplan = subplan;
1339 node->scan.scanstate = (CommonScanState *) NULL;
1344 static FunctionScan *
1345 make_functionscan(List *qptlist,
1349 FunctionScan *node = makeNode(FunctionScan);
1350 Plan *plan = &node->scan.plan;
1352 /* cost should be inserted by caller */
1353 plan->state = (EState *) NULL;
1354 plan->targetlist = qptlist;
1355 plan->qual = qpqual;
1356 plan->lefttree = NULL;
1357 plan->righttree = NULL;
1358 node->scan.scanrelid = scanrelid;
1359 node->scan.scanstate = (CommonScanState *) NULL;
1365 make_append(List *appendplans, bool isTarget, List *tlist)
1367 Append *node = makeNode(Append);
1368 Plan *plan = &node->plan;
1371 /* compute costs from subplan costs */
1372 plan->startup_cost = 0;
1373 plan->total_cost = 0;
1374 plan->plan_rows = 0;
1375 plan->plan_width = 0;
1376 foreach(subnode, appendplans)
1378 Plan *subplan = (Plan *) lfirst(subnode);
1380 if (subnode == appendplans) /* first node? */
1381 plan->startup_cost = subplan->startup_cost;
1382 plan->total_cost += subplan->total_cost;
1383 plan->plan_rows += subplan->plan_rows;
1384 if (plan->plan_width < subplan->plan_width)
1385 plan->plan_width = subplan->plan_width;
1387 plan->state = (EState *) NULL;
1388 plan->targetlist = tlist;
1390 plan->lefttree = NULL;
1391 plan->righttree = NULL;
1392 node->appendplans = appendplans;
1393 node->isTarget = isTarget;
1399 make_nestloop(List *tlist,
1406 NestLoop *node = makeNode(NestLoop);
1407 Plan *plan = &node->join.plan;
1409 /* cost should be inserted by caller */
1410 plan->state = (EState *) NULL;
1411 plan->targetlist = tlist;
1412 plan->qual = otherclauses;
1413 plan->lefttree = lefttree;
1414 plan->righttree = righttree;
1415 node->join.jointype = jointype;
1416 node->join.joinqual = joinclauses;
1422 make_hashjoin(List *tlist,
1430 HashJoin *node = makeNode(HashJoin);
1431 Plan *plan = &node->join.plan;
1433 /* cost should be inserted by caller */
1434 plan->state = (EState *) NULL;
1435 plan->targetlist = tlist;
1436 plan->qual = otherclauses;
1437 plan->lefttree = lefttree;
1438 plan->righttree = righttree;
1439 node->hashclauses = hashclauses;
1440 node->join.jointype = jointype;
1441 node->join.joinqual = joinclauses;
1447 make_hash(List *tlist, Node *hashkey, Plan *lefttree)
1449 Hash *node = makeNode(Hash);
1450 Plan *plan = &node->plan;
1452 copy_plan_costsize(plan, lefttree);
1455 * For plausibility, make startup & total costs equal total cost of
1456 * input plan; this only affects EXPLAIN display not decisions.
1458 plan->startup_cost = plan->total_cost;
1459 plan->state = (EState *) NULL;
1460 plan->targetlist = tlist;
1462 plan->lefttree = lefttree;
1463 plan->righttree = NULL;
1464 node->hashkey = hashkey;
1470 make_mergejoin(List *tlist,
1478 MergeJoin *node = makeNode(MergeJoin);
1479 Plan *plan = &node->join.plan;
1481 /* cost should be inserted by caller */
1482 plan->state = (EState *) NULL;
1483 plan->targetlist = tlist;
1484 plan->qual = otherclauses;
1485 plan->lefttree = lefttree;
1486 plan->righttree = righttree;
1487 node->mergeclauses = mergeclauses;
1488 node->join.jointype = jointype;
1489 node->join.joinqual = joinclauses;
1495 * To use make_sort directly, you must already have marked the tlist
1496 * with reskey and reskeyop information. The keys had better be
1497 * non-redundant, too (ie, there had better be tlist items marked with
1498 * each key number from 1 to keycount), or the executor will get confused!
1501 make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
1503 Sort *node = makeNode(Sort);
1504 Plan *plan = &node->plan;
1505 Path sort_path; /* dummy for result of cost_sort */
1507 copy_plan_costsize(plan, lefttree); /* only care about copying size */
1508 cost_sort(&sort_path, root, NIL,
1509 lefttree->plan_rows, lefttree->plan_width);
1510 plan->startup_cost = sort_path.startup_cost + lefttree->total_cost;
1511 plan->total_cost = sort_path.total_cost + lefttree->total_cost;
1512 plan->state = (EState *) NULL;
1513 plan->targetlist = tlist;
1515 plan->lefttree = lefttree;
1516 plan->righttree = NULL;
1517 node->keycount = keycount;
1523 * make_sort_from_pathkeys
1524 * Create sort plan to sort according to given pathkeys
1526 * 'tlist' is the target list of the input plan
1527 * 'lefttree' is the node which yields input tuples
1528 * 'pathkeys' is the list of pathkeys by which the result is to be sorted
1530 * We must convert the pathkey information into reskey and reskeyop fields
1531 * of resdom nodes in the sort plan's target list.
1534 make_sort_from_pathkeys(Query *root, List *tlist,
1535 Plan *lefttree, List *pathkeys)
1539 int numsortkeys = 0;
1541 /* Create a new target list for the sort, with sort keys set. */
1542 sort_tlist = new_unsorted_tlist(tlist);
1544 foreach(i, pathkeys)
1546 List *keysublist = (List *) lfirst(i);
1547 PathKeyItem *pathkey = NULL;
1548 Resdom *resdom = NULL;
1552 * We can sort by any one of the sort key items listed in this
1553 * sublist. For now, we take the first one that corresponds to an
1554 * available Var in the sort_tlist.
1556 * XXX if we have a choice, is there any way of figuring out which
1557 * might be cheapest to execute? (For example, int4lt is likely
1558 * much cheaper to execute than numericlt, but both might appear
1559 * in the same pathkey sublist...) Not clear that we ever will
1560 * have a choice in practice, so it may not matter.
1562 foreach(j, keysublist)
1564 pathkey = lfirst(j);
1565 Assert(IsA(pathkey, PathKeyItem));
1566 resdom = tlist_member(pathkey->key, sort_tlist);
1571 elog(ERROR, "make_sort_from_pathkeys: cannot find tlist item to sort");
1574 * The resdom might be already marked as a sort key, if the
1575 * pathkeys contain duplicate entries. (This can happen in
1576 * scenarios where multiple mergejoinable clauses mention the same
1577 * var, for example.) In that case the current pathkey is
1578 * essentially a no-op, because only one value can be seen within
1579 * any subgroup where it would be consulted. We can ignore it.
1581 if (resdom->reskey == 0)
1583 /* OK, mark it as a sort key and set the sort operator */
1584 resdom->reskey = ++numsortkeys;
1585 resdom->reskeyop = pathkey->sortop;
1589 Assert(numsortkeys > 0);
1591 return make_sort(root, sort_tlist, lefttree, numsortkeys);
1595 make_material(List *tlist, Plan *lefttree)
1597 Material *node = makeNode(Material);
1598 Plan *plan = &node->plan;
1600 copy_plan_costsize(plan, lefttree);
1603 * For plausibility, make startup & total costs equal total cost of
1604 * input plan; this only affects EXPLAIN display not decisions.
1606 * XXX shouldn't we charge some additional cost for materialization?
1608 plan->startup_cost = plan->total_cost;
1609 plan->state = (EState *) NULL;
1610 plan->targetlist = tlist;
1612 plan->lefttree = lefttree;
1613 plan->righttree = NULL;
1619 make_agg(List *tlist, List *qual, Plan *lefttree)
1621 Agg *node = makeNode(Agg);
1622 Plan *plan = &node->plan;
1624 copy_plan_costsize(plan, lefttree);
1627 * Charge one cpu_operator_cost per aggregate function per input
1630 plan->total_cost += cpu_operator_cost * plan->plan_rows *
1631 (length(pull_agg_clause((Node *) tlist)) +
1632 length(pull_agg_clause((Node *) qual)));
1635 * We will produce a single output tuple if the input is not a Group,
1636 * and a tuple per group otherwise. For now, estimate the number of
1637 * groups as 10% of the number of tuples --- bogus, but how to do
1638 * better? (Note we assume the input Group node is in "tuplePerGroup"
1639 * mode, so it didn't reduce its row count already.)
1641 if (IsA(lefttree, Group))
1643 plan->plan_rows *= 0.1;
1644 if (plan->plan_rows < 1)
1645 plan->plan_rows = 1;
1649 plan->plan_rows = 1;
1650 plan->startup_cost = plan->total_cost;
1653 plan->state = (EState *) NULL;
1655 plan->targetlist = tlist;
1656 plan->lefttree = lefttree;
1657 plan->righttree = (Plan *) NULL;
1663 make_group(List *tlist,
1666 AttrNumber *grpColIdx,
1669 Group *node = makeNode(Group);
1670 Plan *plan = &node->plan;
1672 copy_plan_costsize(plan, lefttree);
1675 * Charge one cpu_operator_cost per comparison per input tuple. We
1676 * assume all columns get compared at most of the tuples.
1678 plan->total_cost += cpu_operator_cost * plan->plan_rows * ngrp;
1681 * If tuplePerGroup (which is named exactly backwards) is true, we
1682 * will return all the input tuples, so the input node's row count is
1683 * OK. Otherwise, we'll return only one tuple from each group. For
1684 * now, estimate the number of groups as 10% of the number of tuples
1685 * --- bogus, but how to do better?
1689 plan->plan_rows *= 0.1;
1690 if (plan->plan_rows < 1)
1691 plan->plan_rows = 1;
1694 plan->state = (EState *) NULL;
1696 plan->targetlist = tlist;
1697 plan->lefttree = lefttree;
1698 plan->righttree = (Plan *) NULL;
1699 node->tuplePerGroup = tuplePerGroup;
1700 node->numCols = ngrp;
1701 node->grpColIdx = grpColIdx;
1707 * distinctList is a list of SortClauses, identifying the targetlist items
1708 * that should be considered by the Unique filter.
1712 make_unique(List *tlist, Plan *lefttree, List *distinctList)
1714 Unique *node = makeNode(Unique);
1715 Plan *plan = &node->plan;
1716 int numCols = length(distinctList);
1718 AttrNumber *uniqColIdx;
1721 copy_plan_costsize(plan, lefttree);
1724 * Charge one cpu_operator_cost per comparison per input tuple. We
1725 * assume all columns get compared at most of the tuples.
1727 plan->total_cost += cpu_operator_cost * plan->plan_rows * numCols;
1730 * As for Group, we make the unsupported assumption that there will be
1731 * 10% as many tuples out as in.
1733 plan->plan_rows *= 0.1;
1734 if (plan->plan_rows < 1)
1735 plan->plan_rows = 1;
1737 plan->state = (EState *) NULL;
1738 plan->targetlist = tlist;
1740 plan->lefttree = lefttree;
1741 plan->righttree = NULL;
1744 * convert SortClause list into array of attr indexes, as wanted by
1747 Assert(numCols > 0);
1748 uniqColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
1750 foreach(slitem, distinctList)
1752 SortClause *sortcl = (SortClause *) lfirst(slitem);
1753 TargetEntry *tle = get_sortgroupclause_tle(sortcl, tlist);
1755 uniqColIdx[keyno++] = tle->resdom->resno;
1758 node->numCols = numCols;
1759 node->uniqColIdx = uniqColIdx;
1765 * distinctList is a list of SortClauses, identifying the targetlist items
1766 * that should be considered by the SetOp filter.
1770 make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
1771 List *distinctList, AttrNumber flagColIdx)
1773 SetOp *node = makeNode(SetOp);
1774 Plan *plan = &node->plan;
1775 int numCols = length(distinctList);
1777 AttrNumber *dupColIdx;
1780 copy_plan_costsize(plan, lefttree);
1783 * Charge one cpu_operator_cost per comparison per input tuple. We
1784 * assume all columns get compared at most of the tuples.
1786 plan->total_cost += cpu_operator_cost * plan->plan_rows * numCols;
1789 * As for Group, we make the unsupported assumption that there will be
1790 * 10% as many tuples out as in.
1792 plan->plan_rows *= 0.1;
1793 if (plan->plan_rows < 1)
1794 plan->plan_rows = 1;
1796 plan->state = (EState *) NULL;
1797 plan->targetlist = tlist;
1799 plan->lefttree = lefttree;
1800 plan->righttree = NULL;
1803 * convert SortClause list into array of attr indexes, as wanted by
1806 Assert(numCols > 0);
1807 dupColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
1809 foreach(slitem, distinctList)
1811 SortClause *sortcl = (SortClause *) lfirst(slitem);
1812 TargetEntry *tle = get_sortgroupclause_tle(sortcl, tlist);
1814 dupColIdx[keyno++] = tle->resdom->resno;
1818 node->numCols = numCols;
1819 node->dupColIdx = dupColIdx;
1820 node->flagColIdx = flagColIdx;
1826 make_limit(List *tlist, Plan *lefttree,
1827 Node *limitOffset, Node *limitCount)
1829 Limit *node = makeNode(Limit);
1830 Plan *plan = &node->plan;
1832 copy_plan_costsize(plan, lefttree);
1835 * If offset/count are constants, adjust the output rows count and
1836 * costs accordingly. This is only a cosmetic issue if we are at top
1837 * level, but if we are building a subquery then it's important to
1838 * report correct info to the outer planner.
1840 if (limitOffset && IsA(limitOffset, Const))
1842 Const *limito = (Const *) limitOffset;
1843 int32 offset = DatumGetInt32(limito->constvalue);
1845 if (!limito->constisnull && offset > 0)
1847 if (offset > plan->plan_rows)
1848 offset = (int32) plan->plan_rows;
1849 if (plan->plan_rows > 0)
1850 plan->startup_cost +=
1851 (plan->total_cost - plan->startup_cost)
1852 * ((double) offset) / plan->plan_rows;
1853 plan->plan_rows -= offset;
1854 if (plan->plan_rows < 1)
1855 plan->plan_rows = 1;
1858 if (limitCount && IsA(limitCount, Const))
1860 Const *limitc = (Const *) limitCount;
1861 int32 count = DatumGetInt32(limitc->constvalue);
1863 if (!limitc->constisnull && count >= 0)
1865 if (count > plan->plan_rows)
1866 count = (int32) plan->plan_rows;
1867 if (plan->plan_rows > 0)
1868 plan->total_cost = plan->startup_cost +
1869 (plan->total_cost - plan->startup_cost)
1870 * ((double) count) / plan->plan_rows;
1871 plan->plan_rows = count;
1872 if (plan->plan_rows < 1)
1873 plan->plan_rows = 1;
1877 plan->state = (EState *) NULL;
1878 plan->targetlist = tlist;
1880 plan->lefttree = lefttree;
1881 plan->righttree = NULL;
1883 node->limitOffset = limitOffset;
1884 node->limitCount = limitCount;
1890 make_result(List *tlist,
1891 Node *resconstantqual,
1894 Result *node = makeNode(Result);
1895 Plan *plan = &node->plan;
1898 tlist = generate_fjoin(tlist);
1901 copy_plan_costsize(plan, subplan);
1904 plan->startup_cost = 0;
1905 plan->total_cost = cpu_tuple_cost;
1906 plan->plan_rows = 1; /* wrong if we have a set-valued function? */
1907 plan->plan_width = 0; /* XXX try to be smarter? */
1910 plan->state = (EState *) NULL;
1911 plan->targetlist = tlist;
1913 plan->lefttree = subplan;
1914 plan->righttree = NULL;
1915 node->resconstantqual = resconstantqual;
1916 node->resstate = NULL;
1923 generate_fjoin(List *tlist)
1926 List newTlist = NIL;
1927 List fjoinList = NIL;
1931 * Break the target list into elements with Iter nodes, and those
1934 foreach(tlistP, tlist)
1938 tlistElem = lfirst(tlistP);
1939 if (IsA(lsecond(tlistElem), Iter))
1942 fjoinList = lappend(fjoinList, tlistElem);
1945 newTlist = lappend(newTlist, tlistElem);
1949 * if we have an Iter node then we need to flatten.
1956 DatumPtr results = (DatumPtr) palloc(nIters * sizeof(Datum));
1957 BoolPtr alwaysDone = (BoolPtr) palloc(nIters * sizeof(bool));
1959 inner = lfirst(fjoinList);
1960 fjoinList = lnext(fjoinList);
1961 fjoinNode = (Fjoin) MakeFjoin(false,
1966 tempList = lcons(fjoinNode, fjoinList);
1967 newTlist = lappend(newTlist, tempList);
1970 return tlist; /* do nothing for now - ay 10/94 */