createplan.c 29.8 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * createplan.c--
4
 *	  Routines to create the desired plan for processing a query
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.31 1998/09/01 03:23:35 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14
#include <string.h>
M
Marc G. Fournier 已提交
15 16 17
#include <sys/types.h>

#include "postgres.h"
18

M
Marc G. Fournier 已提交
19 20 21
#include <utils/syscache.h>
#include <catalog/pg_index.h>

22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#include "nodes/execnodes.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
#include "nodes/primnodes.h"
#include "nodes/nodeFuncs.h"

#include "nodes/makefuncs.h"

#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/builtins.h"

#include "optimizer/clauseinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/tlist.h"
#include "optimizer/planner.h"
#include "optimizer/xfunc.h"
#include "optimizer/internal.h"


43
#define TEMP_SORT		1
44 45
#define TEMP_MATERIAL	2

46 47 48
static List *switch_outer(List *clauses);
static Scan *create_scan_node(Path *best_path, List *tlist);
static Join *create_join_node(JoinPath *best_path, List *tlist);
49 50
static SeqScan *
create_seqscan_node(Path *best_path, List *tlist,
51
					List *scan_clauses);
52 53
static IndexScan *
create_indexscan_node(IndexPath *best_path, List *tlist,
54
					  List *scan_clauses);
55 56
static NestLoop *
create_nestloop_node(JoinPath *best_path, List *tlist,
57 58
					 List *clauses, Plan *outer_node, List *outer_tlist,
					 Plan *inner_node, List *inner_tlist);
59 60
static MergeJoin *
create_mergejoin_node(MergePath *best_path, List *tlist,
61 62
					  List *clauses, Plan *outer_node, List *outer_tlist,
					  Plan *inner_node, List *inner_tlist);
63 64
static HashJoin *
create_hashjoin_node(HashPath *best_path, List *tlist,
65 66 67
					 List *clauses, Plan *outer_node, List *outer_tlist,
					 Plan *inner_node, List *inner_tlist);
static Node *fix_indxqual_references(Node *clause, Path *index_path);
68 69
static Temp *
make_temp(List *tlist, List *keys, Oid *operators,
70
		  Plan *plan_node, int temptype);
71 72
static IndexScan *
make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
B
Bruce Momjian 已提交
73
			   List *indxid, List *indxqual, Cost cost);
74 75
static NestLoop *
make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
76
			  Plan *righttree);
77 78
static HashJoin *
make_hashjoin(List *tlist, List *qpqual,
79 80
			  List *hashclauses, Plan *lefttree, Plan *righttree);
static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
81
static MergeJoin *
82
make_mergejoin(List *tlist, List *qpqual,
83 84
			   List *mergeclauses, Oid opcode, Oid *rightorder,
			   Oid *leftorder, Plan *righttree, Plan *lefttree);
85 86
static Material *
make_material(List *tlist, Oid tempid, Plan *lefttree,
87 88 89
			  int keycount);

/*
90
 * create_plan--
91 92 93 94 95 96 97 98 99 100
 *	  Creates the access plan for a query by tracing backwards through the
 *	  desired chain of pathnodes, starting at the node 'best-path'.  For
 *	  every pathnode found:
 *	  (1) Create a corresponding plan node containing appropriate id,
 *		  target list, and qualification information.
 *	  (2) Modify ALL clauses so that attributes are referenced using
 *		  relative values.
 *	  (3) Target lists are not modified, but will be in another routine.
 *
 *	  best-path is the best access path
101
 *
102
 *	  Returns the optimal(?) access plan.
103
 */
104
Plan *
105
create_plan(Path *best_path)
106
{
107 108
	List	   *tlist;
	Plan	   *plan_node = (Plan *) NULL;
B
Bruce Momjian 已提交
109
	RelOptInfo		   *parent_rel;
110 111 112 113
	int			size;
	int			width;
	int			pages;
	int			tuples;
114 115 116 117 118 119 120 121 122

	parent_rel = best_path->parent;
	tlist = get_actual_tlist(parent_rel->targetlist);
	size = parent_rel->size;
	width = parent_rel->width;
	pages = parent_rel->pages;
	tuples = parent_rel->tuples;

	switch (best_path->pathtype)
123
	{
124 125 126 127 128 129 130 131 132 133 134 135
		case T_IndexScan:
		case T_SeqScan:
			plan_node = (Plan *) create_scan_node(best_path, tlist);
			break;
		case T_HashJoin:
		case T_MergeJoin:
		case T_NestLoop:
			plan_node = (Plan *) create_join_node((JoinPath *) best_path, tlist);
			break;
		default:
			/* do nothing */
			break;
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
	}

	plan_node->plan_size = size;
	plan_node->plan_width = width;
	if (pages == 0)
		pages = 1;
	plan_node->plan_tupperpage = tuples / pages;

#if 0							/* fix xfunc */
	/* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
	if (XfuncMode != XFUNC_OFF)
	{
		set_qpqual((Plan) plan_node,
				   lisp_qsort(get_qpqual((Plan) plan_node),
							  xfunc_clause_compare));
		if (XfuncMode != XFUNC_NOR)
			/* sort the disjuncts within each clause by cost -- JMH 3/4/92 */
			xfunc_disjunct_sort(plan_node->qpqual);
154 155
	}
#endif
156

157
	return plan_node;
158 159
}

160
/*
161
 * create_scan_node--
162 163 164 165 166
 *	 Create a scan path for the parent relation of 'best-path'.
 *
 *	 tlist is the targetlist for the base relation scanned by 'best-path'
 *
 *	 Returns the scan node.
167
 */
168
static Scan *
169
create_scan_node(Path *best_path, List *tlist)
170 171
{

172 173
	Scan	   *node = NULL;
	List	   *scan_clauses;
174 175 176 177 178 179 180 181 182 183 184 185 186 187

	/*
	 * Extract the relevant clauses from the parent relation and replace
	 * the operator OIDs with the corresponding regproc ids.
	 *
	 * now that local predicate clauses are copied into paths in
	 * find_rel_paths() and then (possibly) pulled up in
	 * xfunc_trypullup(), we get the relevant clauses from the path
	 * itself, not its parent relation.   --- JMH, 6/15/92
	 */
	scan_clauses = fix_opids(get_actual_clauses(best_path->locclauseinfo));

	switch (best_path->pathtype)
	{
188 189 190 191 192 193 194 195 196 197 198
		case T_SeqScan:
			node = (Scan *) create_seqscan_node(best_path, tlist, scan_clauses);
			break;

		case T_IndexScan:
			node = (Scan *) create_indexscan_node((IndexPath *) best_path,
												  tlist,
												  scan_clauses);
			break;

		default:
199
			elog(ERROR, "create_scan_node: unknown node type",
200 201
				 best_path->pathtype);
			break;
202 203 204
	}

	return node;
205 206
}

207
/*
208
 * create_join_node --
209 210 211 212 213 214 215
 *	  Create a join path for 'best-path' and(recursively) paths for its
 *	  inner and outer paths.
 *
 *	  'tlist' is the targetlist for the join relation corresponding to
 *		'best-path'
 *
 *	  Returns the join node.
216
 */
217
static Join *
218
create_join_node(JoinPath *best_path, List *tlist)
219
{
220 221 222 223 224 225
	Plan	   *outer_node;
	List	   *outer_tlist;
	Plan	   *inner_node;
	List	   *inner_tlist;
	List	   *clauses;
	Join	   *retval = NULL;
226 227 228 229 230 231 232 233 234 235 236

	outer_node = create_plan((Path *) best_path->outerjoinpath);
	outer_tlist = outer_node->targetlist;

	inner_node = create_plan((Path *) best_path->innerjoinpath);
	inner_tlist = inner_node->targetlist;

	clauses = get_actual_clauses(best_path->pathclauseinfo);

	switch (best_path->path.pathtype)
	{
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
		case T_MergeJoin:
			retval = (Join *) create_mergejoin_node((MergePath *) best_path,
													tlist,
													clauses,
													outer_node,
													outer_tlist,
													inner_node,
													inner_tlist);
			break;
		case T_HashJoin:
			retval = (Join *) create_hashjoin_node((HashPath *) best_path,
												   tlist,
												   clauses,
												   outer_node,
												   outer_tlist,
												   inner_node,
												   inner_tlist);
			break;
		case T_NestLoop:
			retval = (Join *) create_nestloop_node((JoinPath *) best_path,
												   tlist,
												   clauses,
												   outer_node,
												   outer_tlist,
												   inner_node,
												   inner_tlist);
			break;
		default:
			/* do nothing */
266
			elog(ERROR, "create_join_node: unknown node type",
267
				 best_path->path.pathtype);
268
	}
269 270

#if 0
271 272 273

	/*
	 * * Expensive function pullups may have pulled local predicates *
274 275
	 * into this path node.  Put them in the qpqual of the plan node. * --
	 * JMH, 6/15/92
276 277 278 279 280 281
	 */
	if (get_locclauseinfo(best_path) != NIL)
		set_qpqual((Plan) retval,
				   nconc(get_qpqual((Plan) retval),
						 fix_opids(get_actual_clauses
								   (get_locclauseinfo(best_path)))));
282 283
#endif

284
	return retval;
285 286 287 288
}

/*****************************************************************************
 *
289
 *	BASE-RELATION SCAN METHODS
290 291 292
 *
 *****************************************************************************/

293 294

/*
295
 * create_seqscan_node--
296 297
 *	 Returns a seqscan node for the base relation scanned by 'best-path'
 *	 with restriction clauses 'scan-clauses' and targetlist 'tlist'.
298 299
 */
static SeqScan *
300
create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
301
{
302 303 304
	SeqScan    *scan_node = (SeqScan *) NULL;
	Index		scan_relid = -1;
	List	   *temp;
305 306 307

	temp = best_path->parent->relids;
	if (temp == NULL)
308
		elog(ERROR, "scanrelid is empty");
309 310 311 312 313 314 315 316 317 318
	else
		scan_relid = (Index) lfirsti(temp);		/* ??? who takes care of
												 * lnext? - ay */
	scan_node = make_seqscan(tlist,
							 scan_clauses,
							 scan_relid,
							 (Plan *) NULL);

	scan_node->plan.cost = best_path->path_cost;

319
	return scan_node;
320 321
}

322
/*
323
 * create_indexscan_node--
324 325
 *	  Returns a indexscan node for the base relation scanned by 'best-path'
 *	  with restriction clauses 'scan-clauses' and targetlist 'tlist'.
326 327
 */
static IndexScan *
328 329 330
create_indexscan_node(IndexPath *best_path,
					  List *tlist,
					  List *scan_clauses)
331
{
332 333 334 335 336

	/*
	 * Extract the(first if conjunct, only if disjunct) clause from the
	 * clauseinfo list.
	 */
337 338 339 340 341 342 343 344
	Expr	   *index_clause = (Expr *) NULL;
	List	   *indxqual = NIL;
	List	   *qpqual = NIL;
	List	   *fixed_indxqual = NIL;
	List	   *ixid;
	IndexScan  *scan_node = (IndexScan *) NULL;
	bool		lossy = FALSE;
	HeapTuple	indexTuple;
345
	Form_pg_index index;
346 347 348 349 350 351 352 353 354 355 356 357 358 359

	/*
	 * If an 'or' clause is to be used with this index, the indxqual field
	 * will contain a list of the 'or' clause arguments, e.g., the
	 * clause(OR a b c) will generate: ((a) (b) (c)).  Otherwise, the
	 * indxqual will simply contain one conjunctive qualification: ((a)).
	 */
	if (best_path->indexqual != NULL)
		/* added call to fix_opids, JMH 6/23/92 */
		index_clause = (Expr *)
			lfirst(fix_opids(get_actual_clauses(best_path->indexqual)));

	if (or_clause((Node *) index_clause))
	{
360
		List	   *temp = NIL;
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377

		foreach(temp, index_clause->args)
			indxqual = lappend(indxqual, lcons(lfirst(temp), NIL));
	}
	else
	{
		indxqual = lcons(get_actual_clauses(best_path->indexqual),
						 NIL);
	}

	/* check and see if any indices are lossy */
	foreach(ixid, best_path->indexid)
	{
		indexTuple = SearchSysCacheTuple(INDEXRELID,
										 ObjectIdGetDatum(lfirsti(ixid)),
										 0, 0, 0);
		if (!HeapTupleIsValid(indexTuple))
378
			elog(ERROR, "create_plan: index %d not found",
379
				 lfirsti(ixid));
380
		index = (Form_pg_index) GETSTRUCT(indexTuple);
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
		if (index->indislossy)
			lossy = TRUE;
	}


	/*
	 * The qpqual field contains all restrictions not automatically
	 * handled by the index.  Note that for non-lossy indices, the
	 * predicates in the indxqual are handled by the index, while for
	 * lossy indices the indxqual predicates need to be double-checked
	 * after the index fetches the best-guess tuples.
	 */
	if (or_clause((Node *) index_clause))
	{
		qpqual = set_difference(scan_clauses,
								lcons(index_clause, NIL));

		if (lossy)
			qpqual = nconc(qpqual,
						   lcons((List *) copyObject(index_clause), NIL));
	}
	else
	{
		qpqual = set_difference(scan_clauses, lfirst(indxqual));
		if (lossy)
			qpqual = nconc(qpqual,
						   (List *) copyObject(lfirst(indxqual)));
	}

	fixed_indxqual =
		(List *) fix_indxqual_references((Node *) indxqual, (Path *) best_path);

	scan_node =
		make_indexscan(tlist,
					   qpqual,
					   lfirsti(best_path->path.parent->relids),
					   best_path->indexid,
B
Bruce Momjian 已提交
418 419
					   fixed_indxqual,
					   best_path->path.path_cost);
420

421
	return scan_node;
422 423 424 425
}

/*****************************************************************************
 *
426
 *	JOIN METHODS
427 428 429 430
 *
 *****************************************************************************/

static NestLoop *
431 432 433 434 435 436 437
create_nestloop_node(JoinPath *best_path,
					 List *tlist,
					 List *clauses,
					 Plan *outer_node,
					 List *outer_tlist,
					 Plan *inner_node,
					 List *inner_tlist)
438
{
439
	NestLoop   *join_node = (NestLoop *) NULL;
440

441 442
	if (IsA(inner_node, IndexScan))
	{
443

444 445 446 447 448 449 450 451 452 453
		/*
		 * An index is being used to reduce the number of tuples scanned
		 * in the inner relation. There will never be more than one index
		 * used in the inner scan path, so we need only consider the first
		 * set of qualifications in indxqual.
		 *
		 * But there may be more than one clauses in this "first set" in the
		 * case of multi-column indices. - vadim 03/18/97
		 */

454 455 456
		List	   *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual);
		List	   *inner_qual;
		bool		found = false;
457 458 459 460 461 462 463 464 465

		foreach(inner_qual, inner_indxqual)
		{
			if (!qual_clause_p((Node *) lfirst(inner_qual)))
			{
				found = true;
				break;
			}
		}
466

467 468 469 470 471 472 473 474 475 476 477 478 479
		/*
		 * If we have in fact found a join index qualification, remove
		 * these index clauses from the nestloop's join clauses and reset
		 * the inner(index) scan's qualification so that the var nodes
		 * refer to the proper outer join relation attributes.
		 *
		 * XXX Re-moving index clauses doesn't work properly: 1.
		 * fix_indxqual_references may change varattno-s in
		 * inner_indxqual; 2. clauses may be commuted I havn't time to fix
		 * it at the moment.   - vadim 04/24/97
		 */
		if (found)
		{
480
			List	   *new_inner_qual = NIL;
481 482 483 484 485 486 487 488 489

			clauses = set_difference(clauses, inner_indxqual);	/* XXX */
			new_inner_qual =
				index_outerjoin_references(inner_indxqual,
										   outer_node->targetlist,
									   ((Scan *) inner_node)->scanrelid);
			((IndexScan *) inner_node)->indxqual =
				lcons(new_inner_qual, NIL);
		}
490
	}
491
	else if (IsA_Join(inner_node))
492
	{
493 494 495 496 497
		inner_node = (Plan *) make_temp(inner_tlist,
										NIL,
										NULL,
										inner_node,
										TEMP_MATERIAL);
498
	}
499 500 501 502 503 504 505 506 507 508

	join_node = make_nestloop(tlist,
							  join_references(clauses,
											  outer_tlist,
											  inner_tlist),
							  outer_node,
							  inner_node);

	join_node->join.cost = best_path->path.path_cost;

509
	return join_node;
510 511 512
}

static MergeJoin *
513 514 515 516 517 518 519
create_mergejoin_node(MergePath *best_path,
					  List *tlist,
					  List *clauses,
					  Plan *outer_node,
					  List *outer_tlist,
					  Plan *inner_node,
					  List *inner_tlist)
520
{
521 522 523 524 525 526
	List	   *qpqual,
			   *mergeclauses;
	RegProcedure opcode;
	Oid		   *outer_order,
			   *inner_order;
	MergeJoin  *join_node;
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564


	/*
	 * Separate the mergeclauses from the other join qualification clauses
	 * and set those clauses to contain references to lower attributes.
	 */
	qpqual = join_references(set_difference(clauses,
											best_path->path_mergeclauses),
							 outer_tlist,
							 inner_tlist);

	/*
	 * Now set the references in the mergeclauses and rearrange them so
	 * that the outer variable is always on the left.
	 */
	mergeclauses = switch_outer(join_references(best_path->path_mergeclauses,
												outer_tlist,
												inner_tlist));

	opcode =
		get_opcode((best_path->jpath.path.p_ordering.ord.merge)->join_operator);

	outer_order = (Oid *) palloc(sizeof(Oid) * 2);
	outer_order[0] =
		(best_path->jpath.path.p_ordering.ord.merge)->left_operator;
	outer_order[1] = 0;

	inner_order = (Oid *) palloc(sizeof(Oid) * 2);
	inner_order[0] =
		(best_path->jpath.path.p_ordering.ord.merge)->right_operator;
	inner_order[1] = 0;

	/*
	 * Create explicit sort paths for the outer and inner join paths if
	 * necessary.  The sort cost was already accounted for in the path.
	 */
	if (best_path->outersortkeys)
	{
565
		Temp	   *sorted_outer_node = make_temp(outer_tlist,
566
												best_path->outersortkeys,
567 568 569
												  outer_order,
												  outer_node,
												  TEMP_SORT);
570 571 572 573 574 575 576

		sorted_outer_node->plan.cost = outer_node->cost;
		outer_node = (Plan *) sorted_outer_node;
	}

	if (best_path->innersortkeys)
	{
577
		Temp	   *sorted_inner_node = make_temp(inner_tlist,
578
												best_path->innersortkeys,
579 580 581
												  inner_order,
												  inner_node,
												  TEMP_SORT);
582 583 584 585 586

		sorted_inner_node->plan.cost = outer_node->cost;
		inner_node = (Plan *) sorted_inner_node;
	}

587
	join_node = make_mergejoin(tlist,
588 589 590 591 592 593 594 595 596 597
							   qpqual,
							   mergeclauses,
							   opcode,
							   inner_order,
							   outer_order,
							   inner_node,
							   outer_node);

	join_node->join.cost = best_path->jpath.path.path_cost;

598
	return join_node;
599 600
}

601 602 603 604 605 606 607
/*
 * create_hashjoin_node--						XXX HASH
 *
 *	  Returns a new hashjoin node.
 *
 *	  XXX hash join ops are totally bogus -- how the hell do we choose
 *		these??  at runtime?  what about a hash index?
608 609
 */
static HashJoin *
610 611 612 613 614 615 616
create_hashjoin_node(HashPath *best_path,
					 List *tlist,
					 List *clauses,
					 Plan *outer_node,
					 List *outer_tlist,
					 Plan *inner_node,
					 List *inner_tlist)
617
{
618 619 620 621 622
	List	   *qpqual;
	List	   *hashclauses;
	HashJoin   *join_node;
	Hash	   *hash_node;
	Var		   *innerhashkey;
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652

	/*
	 * Separate the hashclauses from the other join qualification clauses
	 * and set those clauses to contain references to lower attributes.
	 */
	qpqual =
		join_references(set_difference(clauses,
									   best_path->path_hashclauses),
						outer_tlist,
						inner_tlist);

	/*
	 * Now set the references in the hashclauses and rearrange them so
	 * that the outer variable is always on the left.
	 */
	hashclauses =
		switch_outer(join_references(best_path->path_hashclauses,
									 outer_tlist,
									 inner_tlist));

	innerhashkey = get_rightop(lfirst(hashclauses));

	hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
	join_node = make_hashjoin(tlist,
							  qpqual,
							  hashclauses,
							  outer_node,
							  (Plan *) hash_node);
	join_node->join.cost = best_path->jpath.path.path_cost;

653
	return join_node;
654 655 656 657 658
}


/*****************************************************************************
 *
659
 *	SUPPORTING ROUTINES
660 661 662
 *
 *****************************************************************************/

663
static Node *
664
fix_indxqual_references(Node *clause, Path *index_path)
665
{
666
	Node	   *newclause;
667 668 669 670 671

	if (IsA(clause, Var))
	{
		if (lfirsti(index_path->parent->relids) == ((Var *) clause)->varno)
		{
672 673 674
			int			pos = 0;
			int			varatt = ((Var *) clause)->varattno;
			int		   *indexkeys = ((IndexPath *) index_path)->indexkeys;
675 676 677 678 679 680 681 682 683 684 685 686

			if (indexkeys)
			{
				while (indexkeys[pos] != 0)
				{
					if (varatt == indexkeys[pos])
						break;
					pos++;
				}
			}
			newclause = copyObject((Node *) clause);
			((Var *) newclause)->varattno = pos + 1;
687
			return newclause;
688 689
		}
		else
690
			return clause;
691
	}
692
	else if (IsA(clause, Const))
693
		return clause;
694 695 696
	else if (IsA(clause, Param))
	{
		/* Function parameter used as index scan arg.  DZ - 27-8-1996 */
697
		return clause;
698 699 700 701 702
	}
	else if (is_opclause(clause) &&
			 is_funcclause((Node *) get_leftop((Expr *) clause)) &&
	((Func *) ((Expr *) get_leftop((Expr *) clause))->oper)->funcisindex)
	{
703
		Var		   *newvar =
704 705 706
		makeVar((Index) lfirsti(index_path->parent->relids),
				1,				/* func indices have one key */
				((Func *) ((Expr *) clause)->oper)->functype,
707
				-1,
708
				0,
709 710 711 712 713 714 715
				(Index) lfirsti(index_path->parent->relids),
				0);

		return
			((Node *) make_opclause((Oper *) ((Expr *) clause)->oper,
									newvar,
									get_rightop((Expr *) clause)));
716 717

	}
718 719
	else if (IsA(clause, Expr))
	{
720 721 722 723
		Expr	   *expr = (Expr *) clause;
		List	   *new_subclauses = NIL;
		Node	   *subclause = NULL;
		List	   *i = NIL;
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745

		foreach(i, expr->args)
		{
			subclause = lfirst(i);
			if (subclause)
				new_subclauses =
					lappend(new_subclauses,
							fix_indxqual_references(subclause,
													index_path));

		}

		/*
		 * XXX new_subclauses should be a list of the form: ( (var var)
		 * (var const) ...) ?
		 */
		if (new_subclauses)
		{
			return (Node *)
				make_clause(expr->opType, expr->oper, new_subclauses);
		}
		else
746
			return clause;
747 748 749
	}
	else
	{
750 751 752 753
		List	   *oldclauses = (List *) clause;
		List	   *new_subclauses = NIL;
		Node	   *subclause = NULL;
		List	   *i = NIL;
754 755 756 757 758 759 760 761 762 763 764

		foreach(i, oldclauses)
		{
			subclause = lfirst(i);
			if (subclause)
				new_subclauses =
					lappend(new_subclauses,
							fix_indxqual_references(subclause,
													index_path));

		}
765

766 767 768 769 770 771 772
		/*
		 * XXX new_subclauses should be a list of the form: ( (var var)
		 * (var const) ...) ?
		 */
		if (new_subclauses)
			return (Node *) new_subclauses;
		else
773
			return clause;
774 775 776 777
	}
}


778
/*
779
 * switch_outer--
780 781 782 783 784 785 786
 *	  Given a list of merge clauses, rearranges the elements within the
 *	  clauses so the outer join variable is on the left and the inner is on
 *	  the right.
 *
 *	  Returns the rearranged list ?
 *
 *	  XXX Shouldn't the operator be commuted?!
787
 */
788
static List *
789
switch_outer(List *clauses)
790
{
791 792 793 794 795
	List	   *t_list = NIL;
	Expr	   *temp = NULL;
	List	   *i = NIL;
	Expr	   *clause;
	Node	   *op;
796 797

	foreach(i, clauses)
V
Vadim B. Mikheev 已提交
798
	{
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
		clause = lfirst(i);
		op = (Node *) get_rightop(clause);
		if (IsA(op, ArrayRef))
			op = ((ArrayRef *) op)->refexpr;
		Assert(IsA(op, Var));
		if (var_is_outer((Var *) op))
		{
			temp = make_clause(clause->opType, clause->oper,
							   lcons(get_rightop(clause),
									 lcons(get_leftop(clause),
										   NIL)));
			t_list = lappend(t_list, temp);
		}
		else
			t_list = lappend(t_list, clause);
	}
815
	return t_list;
816 817
}

818
/*
819
 * set-temp-tlist-operators--
820 821 822 823 824 825 826 827 828 829 830
 *	  Sets the key and keyop fields of resdom nodes in a target list.
 *
 *	  'tlist' is the target list
 *	  'pathkeys' is a list of N keys in the form((key1) (key2)...(keyn)),
 *				corresponding to vars in the target list that are to
 *				be sorted or hashed
 *	  'operators' is the corresponding list of N sort or hash operators
 *	  'keyno' is the first key number
 *	  XXX - keyno ? doesn't exist - jeff
 *
 *	  Returns the modified target list.
831
 */
832
static List *
833
set_temp_tlist_operators(List *tlist, List *pathkeys, Oid *operators)
834
{
835 836 837 838
	Node	   *keys = NULL;
	int			keyno = 1;
	Resdom	   *resdom = (Resdom *) NULL;
	List	   *i = NIL;
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857

	foreach(i, pathkeys)
	{
		keys = lfirst((List *) lfirst(i));
		resdom = tlist_member((Var *) keys, tlist);
		if (resdom)
		{

			/*
			 * Order the resdom keys and replace the operator OID for each
			 * key with the regproc OID.
			 *
			 * XXX Note that the optimizer only generates merge joins with 1
			 * operator (see create_mergejoin_node)  - ay 2/95
			 */
			resdom->reskey = keyno;
			resdom->reskeyop = get_opcode(operators[0]);
		}
		keyno += 1;
858
	}
859
	return tlist;
860 861 862 863 864 865 866
}

/*****************************************************************************
 *
 *
 *****************************************************************************/

867
/*
868
 * make_temp--
869 870 871 872 873 874 875 876 877 878
 *	  Create plan nodes to sort or materialize relations into temporaries. The
 *	  result returned for a sort will look like (SEQSCAN(SORT(plan-node)))
 *	  or (SEQSCAN(MATERIAL(plan-node)))
 *
 *	  'tlist' is the target list of the scan to be sorted or hashed
 *	  'keys' is the list of keys which the sort or hash will be done on
 *	  'operators' is the operators with which the sort or hash is to be done
 *		(a list of operator OIDs)
 *	  'plan-node' is the node which yields tuples for the sort
 *	  'temptype' indicates which operation(sort or hash) to perform
879
 */
880
static Temp *
881 882 883 884
make_temp(List *tlist,
		  List *keys,
		  Oid *operators,
		  Plan *plan_node,
885
		  int temptype)
886
{
887 888
	List	   *temp_tlist;
	Temp	   *retval = NULL;
889 890 891 892 893 894 895

	/* Create a new target list for the temporary, with keys set. */
	temp_tlist = set_temp_tlist_operators(new_unsorted_tlist(tlist),
										  keys,
										  operators);
	switch (temptype)
	{
896 897 898 899 900
		case TEMP_SORT:
			retval = (Temp *) make_seqscan(tlist,
										   NIL,
										   _TEMP_RELATION_ID_,
										   (Plan *) make_sort(temp_tlist,
901
													  _TEMP_RELATION_ID_,
902
															  plan_node,
903
														  length(keys)));
904
			break;
905

906 907 908 909
		case TEMP_MATERIAL:
			retval = (Temp *) make_seqscan(tlist,
										   NIL,
										   _TEMP_RELATION_ID_,
910 911 912 913
									   (Plan *) make_material(temp_tlist,
													  _TEMP_RELATION_ID_,
															  plan_node,
														  length(keys)));
914
			break;
915

916
		default:
917
			elog(ERROR, "make_temp: unknown temp type %d", temptype);
918 919

	}
920
	return retval;
921 922 923
}


924
SeqScan    *
925 926
make_seqscan(List *qptlist,
			 List *qpqual,
927
			 Index scanrelid,
928
			 Plan *lefttree)
929
{
930 931
	SeqScan    *node = makeNode(SeqScan);
	Plan	   *plan = &node->plan;
932

933
	plan->cost = (lefttree ? lefttree->cost : 0);
934 935 936 937 938 939 940 941
	plan->state = (EState *) NULL;
	plan->targetlist = qptlist;
	plan->qual = qpqual;
	plan->lefttree = lefttree;
	plan->righttree = NULL;
	node->scanrelid = scanrelid;
	node->scanstate = (CommonScanState *) NULL;

942
	return node;
943 944 945
}

static IndexScan *
946 947
make_indexscan(List *qptlist,
			   List *qpqual,
948
			   Index scanrelid,
949
			   List *indxid,
B
Bruce Momjian 已提交
950
			   List *indxqual,
951
			   Cost cost)
952
{
953 954
	IndexScan  *node = makeNode(IndexScan);
	Plan	   *plan = &node->scan.plan;
955

B
Bruce Momjian 已提交
956
	plan->cost = cost;
957 958 959 960 961 962 963 964 965 966
	plan->state = (EState *) NULL;
	plan->targetlist = qptlist;
	plan->qual = qpqual;
	plan->lefttree = NULL;
	plan->righttree = NULL;
	node->scan.scanrelid = scanrelid;
	node->indxid = indxid;
	node->indxqual = indxqual;
	node->scan.scanstate = (CommonScanState *) NULL;

967
	return node;
968 969 970 971
}


static NestLoop *
972 973 974 975
make_nestloop(List *qptlist,
			  List *qpqual,
			  Plan *lefttree,
			  Plan *righttree)
976
{
977 978
	NestLoop   *node = makeNode(NestLoop);
	Plan	   *plan = &node->join;
979

980 981
	plan->cost = (lefttree ? lefttree->cost : 0) +
		(righttree ? righttree->cost : 0);
982 983 984 985 986 987 988
	plan->state = (EState *) NULL;
	plan->targetlist = qptlist;
	plan->qual = qpqual;
	plan->lefttree = lefttree;
	plan->righttree = righttree;
	node->nlstate = (NestLoopState *) NULL;

989
	return node;
990 991 992
}

static HashJoin *
993 994 995 996 997
make_hashjoin(List *tlist,
			  List *qpqual,
			  List *hashclauses,
			  Plan *lefttree,
			  Plan *righttree)
998
{
999 1000
	HashJoin   *node = makeNode(HashJoin);
	Plan	   *plan = &node->join;
1001

1002 1003
	plan->cost = (lefttree ? lefttree->cost : 0) +
		(righttree ? righttree->cost : 0);
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
	plan->cost = 0.0;
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = qpqual;
	plan->lefttree = lefttree;
	plan->righttree = righttree;
	node->hashclauses = hashclauses;
	node->hashjointable = NULL;
	node->hashjointablekey = 0;
	node->hashjointablesize = 0;
	node->hashdone = false;

1016
	return node;
1017 1018
}

1019
static Hash *
1020
make_hash(List *tlist, Var *hashkey, Plan *lefttree)
1021
{
1022 1023
	Hash	   *node = makeNode(Hash);
	Plan	   *plan = &node->plan;
1024

1025
	plan->cost = (lefttree ? lefttree->cost : 0);
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
	plan->cost = 0.0;
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = NULL;
	plan->lefttree = lefttree;
	plan->righttree = NULL;
	node->hashkey = hashkey;
	node->hashtable = NULL;
	node->hashtablekey = 0;
	node->hashtablesize = 0;

1037
	return node;
1038 1039 1040
}

static MergeJoin *
1041
make_mergejoin(List *tlist,
1042 1043
			   List *qpqual,
			   List *mergeclauses,
1044
			   Oid opcode,
1045 1046 1047 1048
			   Oid *rightorder,
			   Oid *leftorder,
			   Plan *righttree,
			   Plan *lefttree)
1049
{
1050 1051
	MergeJoin  *node = makeNode(MergeJoin);
	Plan	   *plan = &node->join;
1052

1053 1054
	plan->cost = (lefttree ? lefttree->cost : 0) +
		(righttree ? righttree->cost : 0);
1055 1056 1057 1058 1059 1060
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = qpqual;
	plan->lefttree = lefttree;
	plan->righttree = righttree;
	node->mergeclauses = mergeclauses;
1061
	node->mergejoinop = opcode;
1062 1063 1064
	node->mergerightorder = rightorder;
	node->mergeleftorder = leftorder;

1065
	return node;
1066 1067
}

1068
Sort *
1069
make_sort(List *tlist, Oid tempid, Plan *lefttree, int keycount)
1070
{
1071 1072
	Sort	   *node = makeNode(Sort);
	Plan	   *plan = &node->plan;
1073

1074
	plan->cost = (lefttree ? lefttree->cost : 0);
1075 1076 1077 1078 1079 1080 1081 1082
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = NIL;
	plan->lefttree = lefttree;
	plan->righttree = NULL;
	node->tempid = tempid;
	node->keycount = keycount;

1083
	return node;
1084 1085 1086
}

static Material *
1087
make_material(List *tlist,
1088
			  Oid tempid,
1089
			  Plan *lefttree,
1090
			  int keycount)
1091
{
1092 1093
	Material   *node = makeNode(Material);
	Plan	   *plan = &node->plan;
1094

1095
	plan->cost = (lefttree ? lefttree->cost : 0);
1096 1097 1098 1099 1100 1101 1102 1103
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = NIL;
	plan->lefttree = lefttree;
	plan->righttree = NULL;
	node->tempid = tempid;
	node->keycount = keycount;

1104
	return node;
1105 1106
}

1107
Agg *
1108
make_agg(List *tlist, Plan *lefttree)
1109
{
1110
	Agg		   *node = makeNode(Agg);
1111

1112
	node->plan.cost = (lefttree ? lefttree->cost : 0);
1113 1114 1115
	node->plan.state = (EState *) NULL;
	node->plan.qual = NULL;
	node->plan.targetlist = tlist;
B
Bruce Momjian 已提交
1116
	node->plan.lefttree = lefttree;
1117
	node->plan.righttree = (Plan *) NULL;
1118
	node->aggs = NIL;
1119

1120
	return node;
1121 1122
}

1123
Group *
1124
make_group(List *tlist,
1125 1126
		   bool tuplePerGroup,
		   int ngrp,
B
Bruce Momjian 已提交
1127
		   AttrNumber *grpColIdx,
1128
		   Sort *lefttree)
1129
{
1130
	Group	   *node = makeNode(Group);
1131

1132
	node->plan.cost = (lefttree ? lefttree->plan.cost : 0);
1133 1134 1135 1136 1137 1138 1139 1140 1141
	node->plan.state = (EState *) NULL;
	node->plan.qual = NULL;
	node->plan.targetlist = tlist;
	node->plan.lefttree = (Plan *) lefttree;
	node->plan.righttree = (Plan *) NULL;
	node->tuplePerGroup = tuplePerGroup;
	node->numCols = ngrp;
	node->grpColIdx = grpColIdx;

1142
	return node;
1143 1144 1145
}

/*
1146
 *	A unique node always has a SORT node in the lefttree.
1147
 *
1148 1149
 *	the uniqueAttr argument must be a null-terminated string,
 * either the name of the attribute to select unique on
1150 1151 1152
 * or "*"
 */

1153
Unique *
1154
make_unique(List *tlist, Plan *lefttree, char *uniqueAttr)
1155
{
1156 1157
	Unique	   *node = makeNode(Unique);
	Plan	   *plan = &node->plan;
1158

1159
	plan->cost = (lefttree ? lefttree->cost : 0);
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = NIL;
	plan->lefttree = lefttree;
	plan->righttree = NULL;
	node->tempid = _TEMP_RELATION_ID_;
	node->keycount = 0;
	if (strcmp(uniqueAttr, "*") == 0)
		node->uniqueAttr = NULL;
	else
		node->uniqueAttr = pstrdup(uniqueAttr);
1171
	return node;
1172 1173
}

1174
#ifdef NOT_USED
1175
List *
1176
generate_fjoin(List *tlist)
1177
{
1178 1179 1180 1181
	List		tlistP;
	List		newTlist = NIL;
	List		fjoinList = NIL;
	int			nIters = 0;
1182 1183 1184 1185 1186 1187 1188

	/*
	 * Break the target list into elements with Iter nodes, and those
	 * without them.
	 */
	foreach(tlistP, tlist)
	{
1189
		List		tlistElem;
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205

		tlistElem = lfirst(tlistP);
		if (IsA(lsecond(tlistElem), Iter))
		{
			nIters++;
			fjoinList = lappend(fjoinList, tlistElem);
		}
		else
			newTlist = lappend(newTlist, tlistElem);
	}

	/*
	 * if we have an Iter node then we need to flatten.
	 */
	if (nIters > 0)
	{
1206 1207 1208 1209 1210
		List	   *inner;
		List	   *tempList;
		Fjoin	   *fjoinNode;
		DatumPtr	results = (DatumPtr) palloc(nIters * sizeof(Datum));
		BoolPtr		alwaysDone = (BoolPtr) palloc(nIters * sizeof(bool));
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221

		inner = lfirst(fjoinList);
		fjoinList = lnext(fjoinList);
		fjoinNode = (Fjoin) MakeFjoin(false,
									  nIters,
									  inner,
									  results,
									  alwaysDone);
		tempList = lcons(fjoinNode, NIL);
		tempList = nconc(tempList, fjoinList);
		newTlist = lappend(newTlist, tempList);
1222
	}
1223 1224
	return newTlist;
	return tlist;				/* do nothing for now - ay 10/94 */
1225
}
1226

1227
#endif