createplan.c 30.0 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
B
Bruce Momjian 已提交
10
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.38 1999/02/08 04:29:17 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
#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"

34
#include "optimizer/restrictinfo.h"
35 36 37 38 39 40 41 42
#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
static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
50
					List *scan_clauses);
51
static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist,
52
					  List *scan_clauses);
53
static NestLoop *create_nestloop_node(JoinPath *best_path, List *tlist,
54 55
					 List *clauses, Plan *outer_node, List *outer_tlist,
					 Plan *inner_node, List *inner_tlist);
56
static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist,
57 58
					  List *clauses, Plan *outer_node, List *outer_tlist,
					  Plan *inner_node, List *inner_tlist);
59
static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist,
60 61 62
					 List *clauses, Plan *outer_node, List *outer_tlist,
					 Plan *inner_node, List *inner_tlist);
static Node *fix_indxqual_references(Node *clause, Path *index_path);
63
static Temp *make_temp(List *tlist, List *keys, Oid *operators,
64
		  Plan *plan_node, int temptype);
65
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
V
Vadim B. Mikheev 已提交
66
			   List *indxid, List *indxqual, List *indxqualorig, Cost cost);
67
static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
68
			  Plan *righttree);
69
static HashJoin *make_hashjoin(List *tlist, List *qpqual,
70 71
			  List *hashclauses, Plan *lefttree, Plan *righttree);
static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
72
static MergeJoin *make_mergejoin(List *tlist, List *qpqual,
73 74
			   List *mergeclauses, Oid opcode, Oid *rightorder,
			   Oid *leftorder, Plan *righttree, Plan *lefttree);
75
static Material *make_material(List *tlist, Oid tempid, Plan *lefttree,
76 77 78
			  int keycount);

/*
79
 * create_plan--
80 81 82 83 84 85 86 87 88 89
 *	  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
90
 *
91
 *	  Returns the optimal(?) access plan.
92
 */
93
Plan *
94
create_plan(Path *best_path)
95
{
96 97
	List	   *tlist;
	Plan	   *plan_node = (Plan *) NULL;
98
	RelOptInfo *parent_rel;
99 100 101 102
	int			size;
	int			width;
	int			pages;
	int			tuples;
103 104 105 106 107 108 109 110 111

	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)
112
	{
113 114 115 116 117 118 119 120 121 122 123 124
		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;
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	}

	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);
143 144
	}
#endif
145

146
	return plan_node;
147 148
}

149
/*
150
 * create_scan_node--
151 152 153 154 155
 *	 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.
156
 */
157
static Scan *
158
create_scan_node(Path *best_path, List *tlist)
159 160
{

161 162
	Scan	   *node = NULL;
	List	   *scan_clauses;
163 164 165 166 167 168 169 170 171 172

	/*
	 * 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
	 */
173
	scan_clauses = fix_opids(get_actual_clauses(best_path->loc_restrictinfo));
174 175 176

	switch (best_path->pathtype)
	{
177 178 179 180 181 182 183 184 185 186 187
		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:
188
			elog(ERROR, "create_scan_node: unknown node type",
189 190
				 best_path->pathtype);
			break;
191 192 193
	}

	return node;
194 195
}

196
/*
197
 * create_join_node --
198 199 200 201 202 203 204
 *	  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.
205
 */
206
static Join *
207
create_join_node(JoinPath *best_path, List *tlist)
208
{
209 210 211 212 213 214
	Plan	   *outer_node;
	List	   *outer_tlist;
	Plan	   *inner_node;
	List	   *inner_tlist;
	List	   *clauses;
	Join	   *retval = NULL;
215 216 217 218 219 220 221

	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;

222
	clauses = get_actual_clauses(best_path->pathinfo);
223 224 225

	switch (best_path->path.pathtype)
	{
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
		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 */
255
			elog(ERROR, "create_join_node: unknown node type",
256
				 best_path->path.pathtype);
257
	}
258 259

#if 0
260 261 262

	/*
	 * * Expensive function pullups may have pulled local predicates *
263 264
	 * into this path node.  Put them in the qpqual of the plan node. * --
	 * JMH, 6/15/92
265
	 */
266
	if (get_loc_restrictinfo(best_path) != NIL)
267 268 269
		set_qpqual((Plan) retval,
				   nconc(get_qpqual((Plan) retval),
						 fix_opids(get_actual_clauses
270
								   (get_loc_restrictinfo(best_path)))));
271 272
#endif

273
	return retval;
274 275 276 277
}

/*****************************************************************************
 *
278
 *	BASE-RELATION SCAN METHODS
279 280 281
 *
 *****************************************************************************/

282 283

/*
284
 * create_seqscan_node--
285 286
 *	 Returns a seqscan node for the base relation scanned by 'best-path'
 *	 with restriction clauses 'scan-clauses' and targetlist 'tlist'.
287 288
 */
static SeqScan *
289
create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
290
{
291 292 293
	SeqScan    *scan_node = (SeqScan *) NULL;
	Index		scan_relid = -1;
	List	   *temp;
294 295 296

	temp = best_path->parent->relids;
	if (temp == NULL)
297
		elog(ERROR, "scanrelid is empty");
298 299 300 301 302 303 304 305 306 307
	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;

308
	return scan_node;
309 310
}

311
/*
312
 * create_indexscan_node--
313 314
 *	  Returns a indexscan node for the base relation scanned by 'best-path'
 *	  with restriction clauses 'scan-clauses' and targetlist 'tlist'.
315 316
 */
static IndexScan *
317 318 319
create_indexscan_node(IndexPath *best_path,
					  List *tlist,
					  List *scan_clauses)
320
{
321 322 323

	/*
	 * Extract the(first if conjunct, only if disjunct) clause from the
B
Bruce Momjian 已提交
324
	 * restrictinfo list.
325
	 */
326 327 328 329 330 331 332 333
	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;
334
	Form_pg_index index;
335 336 337 338 339 340 341 342 343 344 345 346 347 348

	/*
	 * 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))
	{
349
		List	   *temp = NIL;
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366

		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))
367
			elog(ERROR, "create_plan: index %d not found",
368
				 lfirsti(ixid));
369
		index = (Form_pg_index) GETSTRUCT(indexTuple);
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
		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)));
	}

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

401
	scan_node = make_indexscan(tlist,
402 403 404
					   qpqual,
					   lfirsti(best_path->path.parent->relids),
					   best_path->indexid,
B
Bruce Momjian 已提交
405
					   fixed_indxqual,
V
Vadim B. Mikheev 已提交
406
					   indxqual,
B
Bruce Momjian 已提交
407
					   best_path->path.path_cost);
408

409
	return scan_node;
410 411 412 413
}

/*****************************************************************************
 *
414
 *	JOIN METHODS
415 416 417 418
 *
 *****************************************************************************/

static NestLoop *
419 420 421 422 423 424 425
create_nestloop_node(JoinPath *best_path,
					 List *tlist,
					 List *clauses,
					 Plan *outer_node,
					 List *outer_tlist,
					 Plan *inner_node,
					 List *inner_tlist)
426
{
427
	NestLoop   *join_node = (NestLoop *) NULL;
428

429 430
	if (IsA(inner_node, IndexScan))
	{
431

432 433 434 435 436 437
		/*
		 * 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.
		 *
T
Thomas G. Lockhart 已提交
438
		 * But there may be more than one clause in this "first set" in the
439 440 441
		 * case of multi-column indices. - vadim 03/18/97
		 */

442 443 444
		List	   *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual);
		List	   *inner_qual;
		bool		found = false;
445 446 447 448 449 450 451 452 453

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

455 456 457 458 459 460 461 462 463 464 465 466 467
		/*
		 * 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)
		{
468
			List	   *new_inner_qual = NIL;
469 470

			clauses = set_difference(clauses, inner_indxqual);	/* XXX */
471
			new_inner_qual = index_outerjoin_references(inner_indxqual,
472 473
										   outer_node->targetlist,
									   ((Scan *) inner_node)->scanrelid);
474
			((IndexScan *) inner_node)->indxqual = lcons(new_inner_qual, NIL);
475
		}
476
	}
477
	else if (IsA_Join(inner_node))
478
	{
479 480 481 482 483
		inner_node = (Plan *) make_temp(inner_tlist,
										NIL,
										NULL,
										inner_node,
										TEMP_MATERIAL);
484
	}
485 486 487 488 489 490 491 492 493 494

	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;

495
	return join_node;
496 497 498
}

static MergeJoin *
499 500 501 502 503 504 505
create_mergejoin_node(MergePath *best_path,
					  List *tlist,
					  List *clauses,
					  Plan *outer_node,
					  List *outer_tlist,
					  Plan *inner_node,
					  List *inner_tlist)
506
{
507 508 509 510 511 512
	List	   *qpqual,
			   *mergeclauses;
	RegProcedure opcode;
	Oid		   *outer_order,
			   *inner_order;
	MergeJoin  *join_node;
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531


	/*
	 * 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));

B
Bruce Momjian 已提交
532
	opcode = get_opcode((best_path->jpath.path.path_order.ord.merge)->join_operator);
533 534

	outer_order = (Oid *) palloc(sizeof(Oid) * 2);
B
Bruce Momjian 已提交
535
	outer_order[0] = (best_path->jpath.path.path_order.ord.merge)->left_operator;
536 537 538
	outer_order[1] = 0;

	inner_order = (Oid *) palloc(sizeof(Oid) * 2);
B
Bruce Momjian 已提交
539
	inner_order[0] = (best_path->jpath.path.path_order.ord.merge)->right_operator;
540 541 542 543 544 545 546 547
	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)
	{
548
		Temp	   *sorted_outer_node = make_temp(outer_tlist,
549
												best_path->outersortkeys,
550 551 552
												  outer_order,
												  outer_node,
												  TEMP_SORT);
553 554 555 556 557 558 559

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

	if (best_path->innersortkeys)
	{
560
		Temp	   *sorted_inner_node = make_temp(inner_tlist,
561
												best_path->innersortkeys,
562 563 564
												  inner_order,
												  inner_node,
												  TEMP_SORT);
565 566 567 568 569

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

570
	join_node = make_mergejoin(tlist,
571 572 573 574 575 576 577 578 579 580
							   qpqual,
							   mergeclauses,
							   opcode,
							   inner_order,
							   outer_order,
							   inner_node,
							   outer_node);

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

581
	return join_node;
582 583
}

584 585 586 587 588 589 590
/*
 * 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?
591 592
 */
static HashJoin *
593 594 595 596 597 598 599
create_hashjoin_node(HashPath *best_path,
					 List *tlist,
					 List *clauses,
					 Plan *outer_node,
					 List *outer_tlist,
					 Plan *inner_node,
					 List *inner_tlist)
600
{
601 602 603 604 605
	List	   *qpqual;
	List	   *hashclauses;
	HashJoin   *join_node;
	Hash	   *hash_node;
	Var		   *innerhashkey;
606 607 608 609 610

	/*
	 * Separate the hashclauses from the other join qualification clauses
	 * and set those clauses to contain references to lower attributes.
	 */
611
	qpqual = join_references(set_difference(clauses,
612 613 614 615 616 617 618 619
									   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.
	 */
620
	hashclauses = switch_outer(join_references(best_path->path_hashclauses,
621 622 623 624 625 626 627 628 629 630 631 632 633
									 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;

634
	return join_node;
635 636 637 638 639
}


/*****************************************************************************
 *
640
 *	SUPPORTING ROUTINES
641 642 643
 *
 *****************************************************************************/

644
static Node *
645
fix_indxqual_references(Node *clause, Path *index_path)
646
{
647
	Node	   *newclause;
648 649 650 651 652

	if (IsA(clause, Var))
	{
		if (lfirsti(index_path->parent->relids) == ((Var *) clause)->varno)
		{
653 654 655
			int			pos = 0;
			int			varatt = ((Var *) clause)->varattno;
			int		   *indexkeys = ((IndexPath *) index_path)->indexkeys;
656 657 658 659 660 661 662 663 664 665 666 667

			if (indexkeys)
			{
				while (indexkeys[pos] != 0)
				{
					if (varatt == indexkeys[pos])
						break;
					pos++;
				}
			}
			newclause = copyObject((Node *) clause);
			((Var *) newclause)->varattno = pos + 1;
668
			return newclause;
669 670
		}
		else
671
			return clause;
672
	}
673
	else if (IsA(clause, Const))
674
		return clause;
675 676 677
	else if (IsA(clause, Param))
	{
		/* Function parameter used as index scan arg.  DZ - 27-8-1996 */
678
		return clause;
679 680 681 682 683
	}
	else if (is_opclause(clause) &&
			 is_funcclause((Node *) get_leftop((Expr *) clause)) &&
	((Func *) ((Expr *) get_leftop((Expr *) clause))->oper)->funcisindex)
	{
684
		Var		   *newvar = makeVar((Index) lfirsti(index_path->parent->relids),
685 686
				1,				/* func indices have one key */
				((Func *) ((Expr *) clause)->oper)->functype,
687
				-1,
688
				0,
689 690 691
				(Index) lfirsti(index_path->parent->relids),
				0);

692
		return ((Node *) make_opclause((Oper *) ((Expr *) clause)->oper,
693 694
									newvar,
									get_rightop((Expr *) clause)));
695 696

	}
697 698
	else if (IsA(clause, Expr))
	{
699 700 701 702
		Expr	   *expr = (Expr *) clause;
		List	   *new_subclauses = NIL;
		Node	   *subclause = NULL;
		List	   *i = NIL;
703 704 705 706 707

		foreach(i, expr->args)
		{
			subclause = lfirst(i);
			if (subclause)
708
				new_subclauses = lappend(new_subclauses,
709 710 711 712 713 714 715 716 717 718 719 720
							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 *)
721
					make_clause(expr->opType, expr->oper, new_subclauses);
722 723
		}
		else
724
			return clause;
725
	}
T
Thomas G. Lockhart 已提交
726 727 728 729 730
	else if (IsA(clause, CaseExpr))
	{
		elog(NOTICE,"optimizer: fix_indxqual_references sees CaseExpr");
		return clause;
	}
731 732
	else
	{
733 734 735 736
		List	   *oldclauses = (List *) clause;
		List	   *new_subclauses = NIL;
		Node	   *subclause = NULL;
		List	   *i = NIL;
737 738 739 740 741

		foreach(i, oldclauses)
		{
			subclause = lfirst(i);
			if (subclause)
742
				new_subclauses = lappend(new_subclauses,
743 744 745 746
							fix_indxqual_references(subclause,
													index_path));

		}
747

748 749 750 751 752 753 754
		/*
		 * XXX new_subclauses should be a list of the form: ( (var var)
		 * (var const) ...) ?
		 */
		if (new_subclauses)
			return (Node *) new_subclauses;
		else
755
			return clause;
756 757 758 759
	}
}


760
/*
761
 * switch_outer--
762 763 764 765 766 767 768
 *	  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?!
769
 */
770
static List *
771
switch_outer(List *clauses)
772
{
773 774 775 776 777
	List	   *t_list = NIL;
	Expr	   *temp = NULL;
	List	   *i = NIL;
	Expr	   *clause;
	Node	   *op;
778 779

	foreach(i, clauses)
V
Vadim B. Mikheev 已提交
780
	{
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
		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);
	}
797
	return t_list;
798 799
}

800
/*
801
 * set-temp-tlist-operators--
802 803 804 805 806 807 808 809 810 811 812
 *	  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.
813
 */
814
static List *
815
set_temp_tlist_operators(List *tlist, List *pathkeys, Oid *operators)
816
{
817 818 819 820
	Node	   *keys = NULL;
	int			keyno = 1;
	Resdom	   *resdom = (Resdom *) NULL;
	List	   *i = NIL;
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839

	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;
840
	}
841
	return tlist;
842 843 844 845 846 847 848
}

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

849
/*
850
 * make_temp--
851 852 853 854 855 856 857 858 859 860
 *	  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
861
 */
862
static Temp *
863 864 865 866
make_temp(List *tlist,
		  List *keys,
		  Oid *operators,
		  Plan *plan_node,
867
		  int temptype)
868
{
869 870
	List	   *temp_tlist;
	Temp	   *retval = NULL;
871 872 873 874 875 876 877

	/* 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)
	{
878 879 880 881 882
		case TEMP_SORT:
			retval = (Temp *) make_seqscan(tlist,
										   NIL,
										   _TEMP_RELATION_ID_,
										   (Plan *) make_sort(temp_tlist,
883
													  _TEMP_RELATION_ID_,
884
															  plan_node,
885
														  length(keys)));
886
			break;
887

888 889 890 891
		case TEMP_MATERIAL:
			retval = (Temp *) make_seqscan(tlist,
										   NIL,
										   _TEMP_RELATION_ID_,
892 893 894 895
									   (Plan *) make_material(temp_tlist,
													  _TEMP_RELATION_ID_,
															  plan_node,
														  length(keys)));
896
			break;
897

898
		default:
899
			elog(ERROR, "make_temp: unknown temp type %d", temptype);
900 901

	}
902
	return retval;
903 904 905
}


906
SeqScan    *
907 908
make_seqscan(List *qptlist,
			 List *qpqual,
909
			 Index scanrelid,
910
			 Plan *lefttree)
911
{
912 913
	SeqScan    *node = makeNode(SeqScan);
	Plan	   *plan = &node->plan;
914

915
	plan->cost = (lefttree ? lefttree->cost : 0);
916 917 918 919 920 921 922 923
	plan->state = (EState *) NULL;
	plan->targetlist = qptlist;
	plan->qual = qpqual;
	plan->lefttree = lefttree;
	plan->righttree = NULL;
	node->scanrelid = scanrelid;
	node->scanstate = (CommonScanState *) NULL;

924
	return node;
925 926 927
}

static IndexScan *
928 929
make_indexscan(List *qptlist,
			   List *qpqual,
930
			   Index scanrelid,
931
			   List *indxid,
B
Bruce Momjian 已提交
932
			   List *indxqual,
V
Vadim B. Mikheev 已提交
933
			   List *indxqualorig,
934
			   Cost cost)
935
{
936 937
	IndexScan  *node = makeNode(IndexScan);
	Plan	   *plan = &node->scan.plan;
938

B
Bruce Momjian 已提交
939
	plan->cost = cost;
940 941 942 943 944 945 946 947
	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;
V
Vadim B. Mikheev 已提交
948
	node->indxqualorig = indxqualorig;
949 950
	node->scan.scanstate = (CommonScanState *) NULL;

951
	return node;
952 953 954 955
}


static NestLoop *
956 957 958 959
make_nestloop(List *qptlist,
			  List *qpqual,
			  Plan *lefttree,
			  Plan *righttree)
960
{
961 962
	NestLoop   *node = makeNode(NestLoop);
	Plan	   *plan = &node->join;
963

964 965
	plan->cost = (lefttree ? lefttree->cost : 0) +
		(righttree ? righttree->cost : 0);
966 967 968 969 970 971 972
	plan->state = (EState *) NULL;
	plan->targetlist = qptlist;
	plan->qual = qpqual;
	plan->lefttree = lefttree;
	plan->righttree = righttree;
	node->nlstate = (NestLoopState *) NULL;

973
	return node;
974 975 976
}

static HashJoin *
977 978 979 980 981
make_hashjoin(List *tlist,
			  List *qpqual,
			  List *hashclauses,
			  Plan *lefttree,
			  Plan *righttree)
982
{
983 984
	HashJoin   *node = makeNode(HashJoin);
	Plan	   *plan = &node->join;
985

986 987
	plan->cost = (lefttree ? lefttree->cost : 0) +
		(righttree ? righttree->cost : 0);
988 989 990 991 992 993 994 995 996 997 998 999
	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;

1000
	return node;
1001 1002
}

1003
static Hash *
1004
make_hash(List *tlist, Var *hashkey, Plan *lefttree)
1005
{
1006 1007
	Hash	   *node = makeNode(Hash);
	Plan	   *plan = &node->plan;
1008

1009
	plan->cost = (lefttree ? lefttree->cost : 0);
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
	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;

1021
	return node;
1022 1023 1024
}

static MergeJoin *
1025
make_mergejoin(List *tlist,
1026 1027
			   List *qpqual,
			   List *mergeclauses,
1028
			   Oid opcode,
1029 1030 1031 1032
			   Oid *rightorder,
			   Oid *leftorder,
			   Plan *righttree,
			   Plan *lefttree)
1033
{
1034 1035
	MergeJoin  *node = makeNode(MergeJoin);
	Plan	   *plan = &node->join;
1036

1037 1038
	plan->cost = (lefttree ? lefttree->cost : 0) +
		(righttree ? righttree->cost : 0);
1039 1040 1041 1042 1043 1044
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = qpqual;
	plan->lefttree = lefttree;
	plan->righttree = righttree;
	node->mergeclauses = mergeclauses;
1045
	node->mergejoinop = opcode;
1046 1047 1048
	node->mergerightorder = rightorder;
	node->mergeleftorder = leftorder;

1049
	return node;
1050 1051
}

1052
Sort *
1053
make_sort(List *tlist, Oid tempid, Plan *lefttree, int keycount)
1054
{
1055 1056
	Sort	   *node = makeNode(Sort);
	Plan	   *plan = &node->plan;
1057

1058
	plan->cost = (lefttree ? lefttree->cost : 0);
1059 1060 1061 1062 1063 1064 1065 1066
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = NIL;
	plan->lefttree = lefttree;
	plan->righttree = NULL;
	node->tempid = tempid;
	node->keycount = keycount;

1067
	return node;
1068 1069 1070
}

static Material *
1071
make_material(List *tlist,
1072
			  Oid tempid,
1073
			  Plan *lefttree,
1074
			  int keycount)
1075
{
1076 1077
	Material   *node = makeNode(Material);
	Plan	   *plan = &node->plan;
1078

1079
	plan->cost = (lefttree ? lefttree->cost : 0);
1080 1081 1082 1083 1084 1085 1086 1087
	plan->state = (EState *) NULL;
	plan->targetlist = tlist;
	plan->qual = NIL;
	plan->lefttree = lefttree;
	plan->righttree = NULL;
	node->tempid = tempid;
	node->keycount = keycount;

1088
	return node;
1089 1090
}

1091
Agg *
1092
make_agg(List *tlist, Plan *lefttree)
1093
{
1094
	Agg		   *node = makeNode(Agg);
1095

1096
	node->plan.cost = (lefttree ? lefttree->cost : 0);
1097 1098 1099
	node->plan.state = (EState *) NULL;
	node->plan.qual = NULL;
	node->plan.targetlist = tlist;
B
Bruce Momjian 已提交
1100
	node->plan.lefttree = lefttree;
1101
	node->plan.righttree = (Plan *) NULL;
1102
	node->aggs = NIL;
1103

1104
	return node;
1105 1106
}

1107
Group *
1108
make_group(List *tlist,
1109 1110
		   bool tuplePerGroup,
		   int ngrp,
B
Bruce Momjian 已提交
1111
		   AttrNumber *grpColIdx,
1112
		   Sort *lefttree)
1113
{
1114
	Group	   *node = makeNode(Group);
1115

1116
	node->plan.cost = (lefttree ? lefttree->plan.cost : 0);
1117 1118 1119 1120 1121 1122 1123 1124 1125
	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;

1126
	return node;
1127 1128 1129
}

/*
1130
 *	A unique node always has a SORT node in the lefttree.
1131
 *
1132 1133
 *	the uniqueAttr argument must be a null-terminated string,
 * either the name of the attribute to select unique on
1134 1135 1136
 * or "*"
 */

1137
Unique *
1138
make_unique(List *tlist, Plan *lefttree, char *uniqueAttr)
1139
{
1140 1141
	Unique	   *node = makeNode(Unique);
	Plan	   *plan = &node->plan;
1142

1143
	plan->cost = (lefttree ? lefttree->cost : 0);
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
	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);
1155
	return node;
1156 1157
}

1158
#ifdef NOT_USED
1159
List *
1160
generate_fjoin(List *tlist)
1161
{
1162 1163 1164 1165
	List		tlistP;
	List		newTlist = NIL;
	List		fjoinList = NIL;
	int			nIters = 0;
1166 1167 1168 1169 1170 1171 1172

	/*
	 * Break the target list into elements with Iter nodes, and those
	 * without them.
	 */
	foreach(tlistP, tlist)
	{
1173
		List		tlistElem;
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189

		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)
	{
1190 1191 1192 1193 1194
		List	   *inner;
		List	   *tempList;
		Fjoin	   *fjoinNode;
		DatumPtr	results = (DatumPtr) palloc(nIters * sizeof(Datum));
		BoolPtr		alwaysDone = (BoolPtr) palloc(nIters * sizeof(bool));
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205

		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);
1206
	}
1207 1208
	return newTlist;
	return tlist;				/* do nothing for now - ay 10/94 */
1209
}
1210

1211
#endif