mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Clean up messy clause-selectivity code in clausesel.c; repair bug
identified by Hiroshi (incorrect cost attributed to OR clauses after multiple passes through set_rest_selec()). I think the code was trying to allow selectivities of OR subclauses to be passed in from outside, but noplace was actually passing any useful data, and set_rest_selec() was passing wrong data. Restructure representation of "indexqual" in IndexPath nodes so that it is the same as for indxqual in completed IndexScan nodes: namely, a toplevel list with an entry for each pass of the index scan, having sublists that are implicitly-ANDed index qual conditions for that pass. You don't want to know what the old representation was :-( Improve documentation of OR-clause indexscan functions. Remove useless 'notclause' field from RestrictInfo nodes. (This might force an initdb for anyone who has stored rules containing RestrictInfos, but I do not think that RestrictInfo ever appears in completed plans.)
This commit is contained in:
		@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.86 1999/07/17 20:17:05 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.87 1999/07/24 23:21:06 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -1317,7 +1317,6 @@ _copyRestrictInfo(RestrictInfo *from)
 | 
				
			|||||||
	Node_Copy(from, newnode, clause);
 | 
						Node_Copy(from, newnode, clause);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	newnode->selectivity = from->selectivity;
 | 
						newnode->selectivity = from->selectivity;
 | 
				
			||||||
	newnode->notclause = from->notclause;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Node_Copy(from, newnode, indexids);
 | 
						Node_Copy(from, newnode, indexids);
 | 
				
			||||||
	Node_Copy(from, newnode, mergejoinorder);
 | 
						Node_Copy(from, newnode, mergejoinorder);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.43 1999/07/17 20:17:05 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.44 1999/07/24 23:21:06 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -305,8 +305,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
 | 
				
			|||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (a->selectivity != b->selectivity)
 | 
						if (a->selectivity != b->selectivity)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	if (a->notclause != b->notclause)
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
#ifdef EqualMergeOrderExists
 | 
					#ifdef EqualMergeOrderExists
 | 
				
			||||||
	if (!EqualMergeOrder(a->mergejoinorder, b->mergejoinorder))
 | 
						if (!EqualMergeOrder(a->mergejoinorder, b->mergejoinorder))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (c) 1994, Regents of the University of California
 | 
					 * Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *	$Id: outfuncs.c,v 1.90 1999/07/18 19:02:49 tgl Exp $
 | 
					 *	$Id: outfuncs.c,v 1.91 1999/07/24 23:21:07 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * NOTES
 | 
					 * NOTES
 | 
				
			||||||
 *	  Every (plan) node in POSTGRES has an associated "out" routine which
 | 
					 *	  Every (plan) node in POSTGRES has an associated "out" routine which
 | 
				
			||||||
@@ -1110,9 +1110,8 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
 | 
				
			|||||||
	_outNode(str, node->clause);
 | 
						_outNode(str, node->clause);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	appendStringInfo(str,
 | 
						appendStringInfo(str,
 | 
				
			||||||
					 " :selectivity %f :notclause %s :indexids ",
 | 
										 " :selectivity %f :indexids ",
 | 
				
			||||||
					 node->selectivity,
 | 
										 node->selectivity);
 | 
				
			||||||
					 node->notclause ? "true" : "false");
 | 
					 | 
				
			||||||
	_outNode(str, node->indexids);
 | 
						_outNode(str, node->indexids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	appendStringInfo(str, " :mergejoinorder ");
 | 
						appendStringInfo(str, " :mergejoinorder ");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.69 1999/07/17 20:17:08 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.70 1999/07/24 23:21:08 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * NOTES
 | 
					 * NOTES
 | 
				
			||||||
 *	  Most of the read functions for plan nodes are tested. (In fact, they
 | 
					 *	  Most of the read functions for plan nodes are tested. (In fact, they
 | 
				
			||||||
@@ -1856,14 +1856,6 @@ _readRestrictInfo()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	local_node->selectivity = atof(token);
 | 
						local_node->selectivity = atof(token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	token = lsptok(NULL, &length);		/* get :notclause */
 | 
					 | 
				
			||||||
	token = lsptok(NULL, &length);		/* now read it */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!strncmp(token, "true", 4))
 | 
					 | 
				
			||||||
		local_node->notclause = true;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		local_node->notclause = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	token = lsptok(NULL, &length);		/* get :indexids */
 | 
						token = lsptok(NULL, &length);		/* get :indexids */
 | 
				
			||||||
	local_node->indexids = nodeRead(true);		/* now read it */
 | 
						local_node->indexids = nodeRead(true);		/* now read it */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.50 1999/07/17 20:17:11 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.51 1999/07/24 23:21:08 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -87,7 +87,7 @@ make_one_rel(Query *root, List *rels)
 | 
				
			|||||||
 *	  Finds all paths available for scanning each relation entry in
 | 
					 *	  Finds all paths available for scanning each relation entry in
 | 
				
			||||||
 *	  'rels'.  Sequential scan and any available indices are considered
 | 
					 *	  'rels'.  Sequential scan and any available indices are considered
 | 
				
			||||||
 *	  if possible (indices are not considered for lower nesting levels).
 | 
					 *	  if possible (indices are not considered for lower nesting levels).
 | 
				
			||||||
 *	  All unique paths are attached to the relation's 'pathlist' field.
 | 
					 *	  All useful paths are attached to the relation's 'pathlist' field.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *	  MODIFIES: rels
 | 
					 *	  MODIFIES: rels
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -98,21 +98,32 @@ set_base_rel_pathlist(Query *root, List *rels)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	foreach(temp, rels)
 | 
						foreach(temp, rels)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							RelOptInfo *rel = (RelOptInfo *) lfirst(temp);
 | 
				
			||||||
 | 
							List	   *indices = find_relation_indices(root, rel);
 | 
				
			||||||
		List	   *sequential_scan_list;
 | 
							List	   *sequential_scan_list;
 | 
				
			||||||
		List	   *rel_index_scan_list;
 | 
							List	   *rel_index_scan_list;
 | 
				
			||||||
		List	   *or_index_scan_list;
 | 
							List	   *or_index_scan_list;
 | 
				
			||||||
		RelOptInfo *rel = (RelOptInfo *) lfirst(temp);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sequential_scan_list = lcons(create_seqscan_path(rel), NIL);
 | 
							sequential_scan_list = lcons(create_seqscan_path(rel), NIL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rel_index_scan_list = create_index_paths(root,
 | 
							rel_index_scan_list = create_index_paths(root,
 | 
				
			||||||
												 rel,
 | 
																	 rel,
 | 
				
			||||||
										find_relation_indices(root, rel),
 | 
																	 indices,
 | 
				
			||||||
												 rel->restrictinfo,
 | 
																	 rel->restrictinfo,
 | 
				
			||||||
												 rel->joininfo);
 | 
																	 rel->joininfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		or_index_scan_list = create_or_index_paths(root, rel, rel->restrictinfo);
 | 
							/* Note: create_or_index_paths depends on create_index_paths
 | 
				
			||||||
 | 
							 * to have marked OR restriction clauses with relevant indices;
 | 
				
			||||||
 | 
							 * this is why it doesn't need to be given the full list of indices.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							or_index_scan_list = create_or_index_paths(root, rel,
 | 
				
			||||||
 | 
																	   rel->restrictinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* add_pathlist will discard any paths that are dominated by
 | 
				
			||||||
 | 
							 * another available path, keeping only those paths that are
 | 
				
			||||||
 | 
							 * superior along at least one dimension of cost or sortedness.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		rel->pathlist = add_pathlist(rel,
 | 
							rel->pathlist = add_pathlist(rel,
 | 
				
			||||||
									 sequential_scan_list,
 | 
														 sequential_scan_list,
 | 
				
			||||||
									 nconc(rel_index_scan_list,
 | 
														 nconc(rel_index_scan_list,
 | 
				
			||||||
@@ -128,7 +139,6 @@ set_base_rel_pathlist(Query *root, List *rels)
 | 
				
			|||||||
		rel->size = compute_rel_size(rel);
 | 
							rel->size = compute_rel_size(rel);
 | 
				
			||||||
		rel->width = compute_rel_width(rel);
 | 
							rel->width = compute_rel_width(rel);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.23 1999/07/16 04:59:14 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.24 1999/07/24 23:21:09 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -23,32 +23,26 @@
 | 
				
			|||||||
#include "utils/lsyscache.h"
 | 
					#include "utils/lsyscache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static Cost compute_selec(Query *root, List *clauses, List *or_selectivities);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/****************************************************************************
 | 
					/****************************************************************************
 | 
				
			||||||
 *		ROUTINES TO SET CLAUSE SELECTIVITIES
 | 
					 *		ROUTINES TO SET CLAUSE SELECTIVITIES
 | 
				
			||||||
 ****************************************************************************/
 | 
					 ****************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * set_clause_selectivities -
 | 
					 * set_clause_selectivities -
 | 
				
			||||||
 *	  Sets the selectivity field for each of clause in 'restrictinfo-list'
 | 
					 *	  Sets the selectivity field for each clause in 'restrictinfo-list'
 | 
				
			||||||
 *	  to 'new-selectivity'.  If the selectivity has already been set, reset
 | 
					 *	  to 'new-selectivity'.  If the selectivity has already been set,
 | 
				
			||||||
 *	  it only if the new one is better.
 | 
					 *	  change it only if the new one is better.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns nothing of interest.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity)
 | 
					set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	List	   *temp;
 | 
						List	   *rlist;
 | 
				
			||||||
	RestrictInfo *clausenode;
 | 
					 | 
				
			||||||
	Cost		cost_clause;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(temp, restrictinfo_list)
 | 
						foreach(rlist, restrictinfo_list)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		clausenode = (RestrictInfo *) lfirst(temp);
 | 
							RestrictInfo *clausenode = (RestrictInfo *) lfirst(rlist);
 | 
				
			||||||
		cost_clause = clausenode->selectivity;
 | 
							Cost		cost_clause = clausenode->selectivity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (cost_clause <= 0 || new_selectivity < cost_clause)
 | 
							if (cost_clause <= 0 || new_selectivity < cost_clause)
 | 
				
			||||||
			clausenode->selectivity = new_selectivity;
 | 
								clausenode->selectivity = new_selectivity;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -63,18 +57,12 @@ set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity)
 | 
				
			|||||||
Cost
 | 
					Cost
 | 
				
			||||||
product_selec(List *restrictinfo_list)
 | 
					product_selec(List *restrictinfo_list)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Cost		result = 1.0;
 | 
						Cost		result = (Cost) 1.0;
 | 
				
			||||||
 | 
						List	   *rlist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (restrictinfo_list != NIL)
 | 
						foreach(rlist, restrictinfo_list)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		List	   *xclausenode = NIL;
 | 
							result *= ((RestrictInfo *) lfirst(rlist))->selectivity;
 | 
				
			||||||
		Cost		temp;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		foreach(xclausenode, restrictinfo_list)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			temp = ((RestrictInfo *) lfirst(xclausenode))->selectivity;
 | 
					 | 
				
			||||||
			result = result * temp;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -84,19 +72,16 @@ product_selec(List *restrictinfo_list)
 | 
				
			|||||||
 *	  Scans through clauses on each relation and assigns a selectivity to
 | 
					 *	  Scans through clauses on each relation and assigns a selectivity to
 | 
				
			||||||
 *	  those clauses that haven't been assigned a selectivity by an index.
 | 
					 *	  those clauses that haven't been assigned a selectivity by an index.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns nothing of interest.
 | 
					 * MODIFIES: selectivities of the various rel's restrictinfo slots.
 | 
				
			||||||
 * MODIFIES: selectivities of the various rel's restrictinfo
 | 
					 | 
				
			||||||
 *		  slots.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
set_rest_relselec(Query *root, List *rel_list)
 | 
					set_rest_relselec(Query *root, List *rel_list)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	RelOptInfo *rel;
 | 
					 | 
				
			||||||
	List	   *x;
 | 
						List	   *x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(x, rel_list)
 | 
						foreach(x, rel_list)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		rel = (RelOptInfo *) lfirst(x);
 | 
							RelOptInfo *rel = (RelOptInfo *) lfirst(x);
 | 
				
			||||||
		set_rest_selec(root, rel->restrictinfo);
 | 
							set_rest_selec(root, rel->restrictinfo);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -105,31 +90,20 @@ set_rest_relselec(Query *root, List *rel_list)
 | 
				
			|||||||
 * set_rest_selec -
 | 
					 * set_rest_selec -
 | 
				
			||||||
 *	  Sets the selectivity fields for those clauses within a single
 | 
					 *	  Sets the selectivity fields for those clauses within a single
 | 
				
			||||||
 *	  relation's 'restrictinfo-list' that haven't already been set.
 | 
					 *	  relation's 'restrictinfo-list' that haven't already been set.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns nothing of interest.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
set_rest_selec(Query *root, List *restrictinfo_list)
 | 
					set_rest_selec(Query *root, List *restrictinfo_list)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	List	   *temp = NIL;
 | 
						List	   *rlist;
 | 
				
			||||||
	RestrictInfo *clausenode = (RestrictInfo *) NULL;
 | 
					 | 
				
			||||||
	Cost		cost_clause;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(temp, restrictinfo_list)
 | 
						foreach(rlist, restrictinfo_list)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		clausenode = (RestrictInfo *) lfirst(temp);
 | 
							RestrictInfo *clause = (RestrictInfo *) lfirst(rlist);
 | 
				
			||||||
		cost_clause = clausenode->selectivity;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							if (clause->selectivity <= 0)
 | 
				
			||||||
		 * Check to see if the selectivity of this clause or any 'or'
 | 
					 | 
				
			||||||
		 * subclauses (if any) haven't been set yet.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (cost_clause <= 0 || valid_or_clause(clausenode))
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			clausenode->selectivity = compute_clause_selec(root,
 | 
								clause->selectivity =
 | 
				
			||||||
											 (Node *) clausenode->clause,
 | 
									compute_clause_selec(root, (Node *) clause->clause);
 | 
				
			||||||
									 lcons(makeFloat(cost_clause), NIL));
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -140,89 +114,29 @@ set_rest_selec(Query *root, List *restrictinfo_list)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * compute_clause_selec -
 | 
					 * compute_clause_selec -
 | 
				
			||||||
 *	  Given a clause, this routine will compute the selectivity of the
 | 
					 *	  Computes the selectivity of a clause.
 | 
				
			||||||
 *	  clause by calling 'compute_selec' with the appropriate parameters
 | 
					 | 
				
			||||||
 *	  and possibly use that return value to compute the real selectivity
 | 
					 | 
				
			||||||
 *	  of a clause.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 'or-selectivities' are selectivities that have already been assigned
 | 
					 | 
				
			||||||
 *		to subclauses of an 'or' clause.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns a flonum corresponding to the clause selectivity.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
Cost
 | 
					Cost
 | 
				
			||||||
compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
 | 
					compute_clause_selec(Query *root, Node *clause)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (is_opclause(clause))
 | 
						Cost		s1 = 1.0;		/* default for any unhandled clause type */
 | 
				
			||||||
		return compute_selec(root, lcons(clause, NIL), or_selectivities);
 | 
					 | 
				
			||||||
	else if (not_clause(clause))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * 'not' gets "1.0 - selectivity-of-inner-clause".
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		return (1.000000 - compute_selec(root,
 | 
					 | 
				
			||||||
								 lcons(get_notclausearg((Expr *) clause),
 | 
					 | 
				
			||||||
									   NIL),
 | 
					 | 
				
			||||||
										 or_selectivities));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else if (or_clause(clause))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * Both 'or' and 'and' clauses are evaluated as described in
 | 
					 | 
				
			||||||
		 * (compute_selec).
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		return compute_selec(root, ((Expr *) clause)->args, or_selectivities);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		return compute_selec(root, lcons(clause, NIL), or_selectivities);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * compute_selec -
 | 
					 | 
				
			||||||
 *	  Computes the selectivity of a clause.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *	  If there is more than one clause in the argument 'clauses', then the
 | 
					 | 
				
			||||||
 *	  desired selectivity is that of an 'or' clause.  Selectivities for an
 | 
					 | 
				
			||||||
 *	  'or' clause such as (OR a b) are computed by finding the selectivity
 | 
					 | 
				
			||||||
 *	  of a (s1) and b (s2) and computing s1+s2 - s1*s2.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *	  In addition, if the clause is an 'or' clause, individual selectivities
 | 
					 | 
				
			||||||
 *	  may have already been assigned by indices to subclauses.	These values
 | 
					 | 
				
			||||||
 *	  are contained in the list 'or-selectivities'.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns the clause selectivity as a flonum.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static Cost
 | 
					 | 
				
			||||||
compute_selec(Query *root, List *clauses, List *or_selectivities)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	Cost		s1 = 0;
 | 
					 | 
				
			||||||
	List	   *clause = lfirst(clauses);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (clause == NULL)
 | 
						if (clause == NULL)
 | 
				
			||||||
		s1 = 1.0;
 | 
							return s1;
 | 
				
			||||||
	else if (IsA(clause, Param))
 | 
						if (IsA(clause, Var))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		/* XXX How're we handling this before?? -ay */
 | 
					 | 
				
			||||||
		s1 = 1.0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else if (IsA(clause, Const))
 | 
					 | 
				
			||||||
		s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
 | 
					 | 
				
			||||||
	else if (IsA(clause, Var))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Oid			relid = getrelid(((Var *) clause)->varno,
 | 
					 | 
				
			||||||
									 root->rtable);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * we have a bool Var.	This is exactly equivalent to the clause:
 | 
							 * we have a bool Var.	This is exactly equivalent to the clause:
 | 
				
			||||||
		 * reln.attribute = 't' so we compute the selectivity as if that
 | 
							 * reln.attribute = 't' so we compute the selectivity as if that
 | 
				
			||||||
		 * is what we have. The magic #define constants are a hack.  I
 | 
							 * is what we have. The magic #define constants are a hack.  I
 | 
				
			||||||
		 * didn't want to have to do system cache look ups to find out all
 | 
							 * didn't want to have to do system cache look ups to find out all
 | 
				
			||||||
		 * of that info.
 | 
							 * of that info.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * XXX why are we using varno and varoattno?  Seems like it should
 | 
				
			||||||
 | 
							 * be varno/varattno or varnoold/varoattno, not mix & match...
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
 | 
							Oid			relid = getrelid(((Var *) clause)->varno,
 | 
				
			||||||
 | 
														 root->rtable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		s1 = restriction_selectivity(F_EQSEL,
 | 
							s1 = restriction_selectivity(F_EQSEL,
 | 
				
			||||||
									 BooleanEqualOperator,
 | 
														 BooleanEqualOperator,
 | 
				
			||||||
@@ -231,45 +145,73 @@ compute_selec(Query *root, List *clauses, List *or_selectivities)
 | 
				
			|||||||
									 "t",
 | 
														 "t",
 | 
				
			||||||
									 _SELEC_CONSTANT_RIGHT_);
 | 
														 _SELEC_CONSTANT_RIGHT_);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (or_selectivities)
 | 
						else if (IsA(clause, Param))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		/* If s1 has already been assigned by an index, use that value. */
 | 
							/* XXX any way to do better? */
 | 
				
			||||||
		List	   *this_sel = lfirst(or_selectivities);
 | 
							s1 = 1.0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		s1 = floatVal(this_sel);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (is_funcclause((Node *) clause))
 | 
						else if (IsA(clause, Const))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* bool constant is pretty easy... */
 | 
				
			||||||
 | 
							s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (not_clause(clause))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* inverse of the selectivity of the underlying clause */
 | 
				
			||||||
 | 
							s1 = 1.0 - compute_clause_selec(root,
 | 
				
			||||||
 | 
															(Node *) get_notclausearg((Expr *) clause));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (and_clause(clause))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* Use the product of the selectivities of the subclauses.
 | 
				
			||||||
 | 
							 * XXX this is probably too optimistic, since the subclauses
 | 
				
			||||||
 | 
							 * are very likely not independent...
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							List   *arg;
 | 
				
			||||||
 | 
							s1 = 1.0;
 | 
				
			||||||
 | 
							foreach(arg, ((Expr *) clause)->args)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Cost		s2 = compute_clause_selec(root, (Node *) lfirst(arg));
 | 
				
			||||||
 | 
								s1 = s1 * s2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (or_clause(clause))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/* Selectivities for an 'or' clause are computed as s1+s2 - s1*s2
 | 
				
			||||||
 | 
							 * to account for the probable overlap of selected tuple sets.
 | 
				
			||||||
 | 
							 * XXX is this too conservative?
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							List   *arg;
 | 
				
			||||||
 | 
							s1 = 0.0;
 | 
				
			||||||
 | 
							foreach(arg, ((Expr *) clause)->args)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Cost		s2 = compute_clause_selec(root, (Node *) lfirst(arg));
 | 
				
			||||||
 | 
								s1 = s1 + s2 - s1 * s2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else if (is_funcclause(clause))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		/* this isn't an Oper, it's a Func!! */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * This is not an operator, so we guess at the selectivity. THIS
 | 
							 * This is not an operator, so we guess at the selectivity. THIS
 | 
				
			||||||
		 * IS A HACK TO GET V4 OUT THE DOOR.  FUNCS SHOULD BE ABLE TO HAVE
 | 
							 * IS A HACK TO GET V4 OUT THE DOOR.  FUNCS SHOULD BE ABLE TO HAVE
 | 
				
			||||||
		 * SELECTIVITIES THEMSELVES.	   -- JMH 7/9/92
 | 
							 * SELECTIVITIES THEMSELVES.	   -- JMH 7/9/92
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		s1 = 0.1;
 | 
							s1 = (Cost) 0.3333333;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (not_clause((Node *) clause))
 | 
						else if (is_subplan(clause))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		/* negate this baby */
 | 
					 | 
				
			||||||
		return 1 - compute_selec(root, ((Expr *) clause)->args, or_selectivities);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else if (is_subplan((Node *) clause))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Just for the moment! FIX ME! - vadim 02/04/98
 | 
							 * Just for the moment! FIX ME! - vadim 02/04/98
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		s1 = 1.0;
 | 
							s1 = 1.0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if (NumRelids((Node *) clause) == 1)
 | 
						else if (is_opclause(clause))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							if (NumRelids(clause) == 1)
 | 
				
			||||||
		/*
 | 
							{
 | 
				
			||||||
		 * ...otherwise, calculate s1 from 'clauses'. The clause is not a
 | 
								/* The clause is not a join clause, since there is only one
 | 
				
			||||||
		 * join clause, since there is only one relid in the clause.  The
 | 
								 * relid in the clause.  The clause selectivity will be based on
 | 
				
			||||||
		 * clause selectivity will be based on the operator selectivity
 | 
								 * the operator selectivity and operand values.
 | 
				
			||||||
		 * and operand values.
 | 
					 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			Oid			opno = ((Oper *) ((Expr *) clause)->oper)->opno;
 | 
								Oid			opno = ((Oper *) ((Expr *) clause)->oper)->opno;
 | 
				
			||||||
			RegProcedure oprrest = get_oprrest(opno);
 | 
								RegProcedure oprrest = get_oprrest(opno);
 | 
				
			||||||
@@ -279,7 +221,7 @@ compute_selec(Query *root, List *clauses, List *or_selectivities)
 | 
				
			|||||||
			Datum		constval;
 | 
								Datum		constval;
 | 
				
			||||||
			int			flag;
 | 
								int			flag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		get_relattval((Node *) clause, &relidx, &attno, &constval, &flag);
 | 
								get_relattval(clause, &relidx, &attno, &constval, &flag);
 | 
				
			||||||
			relid = getrelid(relidx, root->rtable);
 | 
								relid = getrelid(relidx, root->rtable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
@@ -287,10 +229,9 @@ compute_selec(Query *root, List *clauses, List *or_selectivities)
 | 
				
			|||||||
			 * selectivity of 0.5
 | 
								 * selectivity of 0.5
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			if (!oprrest)
 | 
								if (!oprrest)
 | 
				
			||||||
			s1 = (Cost) (0.5);
 | 
									s1 = (Cost) 0.5;
 | 
				
			||||||
			else if (attno == InvalidAttrNumber)
 | 
								else if (attno == InvalidAttrNumber)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
 | 
					 | 
				
			||||||
				/*
 | 
									/*
 | 
				
			||||||
				 * attno can be Invalid if the clause had a function in it,
 | 
									 * attno can be Invalid if the clause had a function in it,
 | 
				
			||||||
				 * i.e.   WHERE myFunc(f) = 10
 | 
									 * i.e.   WHERE myFunc(f) = 10
 | 
				
			||||||
@@ -305,11 +246,9 @@ compute_selec(Query *root, List *clauses, List *or_selectivities)
 | 
				
			|||||||
													attno,
 | 
																		attno,
 | 
				
			||||||
													(char *) constval,
 | 
																		(char *) constval,
 | 
				
			||||||
													flag);
 | 
																		flag);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
 | 
					 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * The clause must be a join clause.  The clause selectivity will
 | 
								 * The clause must be a join clause.  The clause selectivity will
 | 
				
			||||||
			 * be based on the relations to be scanned and the attributes they
 | 
								 * be based on the relations to be scanned and the attributes they
 | 
				
			||||||
@@ -322,7 +261,7 @@ compute_selec(Query *root, List *clauses, List *or_selectivities)
 | 
				
			|||||||
			AttrNumber	attno1,
 | 
								AttrNumber	attno1,
 | 
				
			||||||
						attno2;
 | 
											attno2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		get_rels_atts((Node *) clause, &relid1, &attno1, &relid2, &attno2);
 | 
								get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
 | 
				
			||||||
			relid1 = getrelid(relid1, root->rtable);
 | 
								relid1 = getrelid(relid1, root->rtable);
 | 
				
			||||||
			relid2 = getrelid(relid2, root->rtable);
 | 
								relid2 = getrelid(relid2, root->rtable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -340,25 +279,7 @@ compute_selec(Query *root, List *clauses, List *or_selectivities)
 | 
				
			|||||||
											 relid2,
 | 
																 relid2,
 | 
				
			||||||
											 attno2);
 | 
																 attno2);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * A null clause list eliminates no tuples, so return a selectivity of
 | 
					 | 
				
			||||||
	 * 1.0.  If there is only one clause, the selectivity is not that of
 | 
					 | 
				
			||||||
	 * an 'or' clause, but rather that of the single clause.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (lnext(clauses) == NIL)
 | 
					 | 
				
			||||||
	return s1;
 | 
						return s1;
 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		/* Compute selectivity of the 'or'ed subclauses. */
 | 
					 | 
				
			||||||
		/* Added check for taking lnext(NIL).  -- JMH 3/9/92 */
 | 
					 | 
				
			||||||
		Cost		s2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (or_selectivities != NIL)
 | 
					 | 
				
			||||||
			s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities));
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			s2 = compute_selec(root, lnext(clauses), NIL);
 | 
					 | 
				
			||||||
		return s1 + s2 - s1 * s2;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.62 1999/07/23 03:34:49 tgl Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.63 1999/07/24 23:21:09 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -109,12 +109,25 @@ create_index_paths(Query *root,
 | 
				
			|||||||
				continue;
 | 
									continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * 1. Try matching the index against subclauses of an 'or' clause.
 | 
							 * 1. Try matching the index against subclauses of restriction 'or'
 | 
				
			||||||
		 * The fields of the restrictinfo nodes are marked with lists of
 | 
							 * clauses (ie, 'or' clauses that reference only this relation).
 | 
				
			||||||
		 * the matching indices.  No paths are actually created.  We
 | 
							 * The restrictinfo nodes for the 'or' clauses are marked with lists
 | 
				
			||||||
		 * currently only look to match the first key.	We don't find
 | 
							 * of the matching indices.  No paths are actually created now;
 | 
				
			||||||
		 * multi-key index cases where an AND matches the first key, and
 | 
							 * that will be done in orindxpath.c after all indexes for the rel
 | 
				
			||||||
		 * the OR matches the second key.
 | 
							 * have been examined.  (We need to do it that way because we can
 | 
				
			||||||
 | 
							 * potentially use a different index for each subclause of an 'or',
 | 
				
			||||||
 | 
							 * so we can't build a path for an 'or' clause until all indexes have
 | 
				
			||||||
 | 
							 * been matched against it.)
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * We currently only look to match the first key of each index against
 | 
				
			||||||
 | 
							 * 'or' subclauses.  There are cases where a later key of a multi-key
 | 
				
			||||||
 | 
							 * index could be used (if other top-level clauses match earlier keys
 | 
				
			||||||
 | 
							 * of the index), but our poor brains are hurting already...
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * We don't even think about special handling of 'or' clauses that
 | 
				
			||||||
 | 
							 * involve more than one relation, since they can't be processed by
 | 
				
			||||||
 | 
							 * a single indexscan path anyway.  Currently, cnfify() is certain
 | 
				
			||||||
 | 
							 * to have restructured any such toplevel 'or' clauses anyway.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		match_index_orclauses(rel,
 | 
							match_index_orclauses(rel,
 | 
				
			||||||
							  index,
 | 
												  index,
 | 
				
			||||||
@@ -123,7 +136,7 @@ create_index_paths(Query *root,
 | 
				
			|||||||
							  restrictinfo_list);
 | 
												  restrictinfo_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * 2. If the keys of this index match any of the available
 | 
							 * 2. If the keys of this index match any of the available non-'or'
 | 
				
			||||||
		 * restriction clauses, then create a path using those clauses
 | 
							 * restriction clauses, then create a path using those clauses
 | 
				
			||||||
		 * as indexquals.
 | 
							 * as indexquals.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
@@ -179,11 +192,14 @@ create_index_paths(Query *root,
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * match_index_orclauses
 | 
					 * match_index_orclauses
 | 
				
			||||||
 *	  Attempt to match an index against subclauses within 'or' clauses.
 | 
					 *	  Attempt to match an index against subclauses within 'or' clauses.
 | 
				
			||||||
 *	  If the index does match, then the clause is marked with information
 | 
					 *	  Each subclause that does match is marked with the index's node.
 | 
				
			||||||
 *	  about the index.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *	  Essentially, this adds 'index' to the list of indices in the
 | 
					 *	  Essentially, this adds 'index' to the list of subclause indices in
 | 
				
			||||||
 *	  RestrictInfo field of each of the clauses which it matches.
 | 
					 *	  the RestrictInfo field of each of the 'or' clauses where it matches.
 | 
				
			||||||
 | 
					 *	  NOTE: we can use storage in the RestrictInfo for this purpose because
 | 
				
			||||||
 | 
					 *	  this processing is only done on single-relation restriction clauses.
 | 
				
			||||||
 | 
					 *	  Therefore, we will never have indexes for more than one relation
 | 
				
			||||||
 | 
					 *	  mentioned in the same RestrictInfo node's list.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * 'rel' is the node of the relation on which the index is defined.
 | 
					 * 'rel' is the node of the relation on which the index is defined.
 | 
				
			||||||
 * 'index' is the index node.
 | 
					 * 'index' is the index node.
 | 
				
			||||||
@@ -204,12 +220,11 @@ match_index_orclauses(RelOptInfo *rel,
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
 | 
							RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (valid_or_clause(restrictinfo))
 | 
							if (restriction_is_or_clause(restrictinfo))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * Mark the 'or' clause with a list of indices which match
 | 
								 * Add this index to the subclause index list for each
 | 
				
			||||||
			 * each of its subclauses.	We add entries to the existing
 | 
								 * subclause that it matches.
 | 
				
			||||||
			 * list, if any.
 | 
					 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			restrictinfo->indexids =
 | 
								restrictinfo->indexids =
 | 
				
			||||||
				match_index_orclause(rel, index,
 | 
									match_index_orclause(rel, index,
 | 
				
			||||||
@@ -253,7 +268,9 @@ match_index_orclause(RelOptInfo *rel,
 | 
				
			|||||||
	List	   *index_list;
 | 
						List	   *index_list;
 | 
				
			||||||
	List	   *clist;
 | 
						List	   *clist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* first time through, we create empty list of same length as OR clause */
 | 
						/* first time through, we create list of same length as OR clause,
 | 
				
			||||||
 | 
						 * containing an empty sublist for each subclause.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	if (!other_matching_indices)
 | 
						if (!other_matching_indices)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		matching_indices = NIL;
 | 
							matching_indices = NIL;
 | 
				
			||||||
@@ -1186,9 +1203,13 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
 | 
				
			|||||||
		pathnode->path.pathorder->ord.sortop = index->ordering;
 | 
							pathnode->path.pathorder->ord.sortop = index->ordering;
 | 
				
			||||||
		pathnode->path.pathkeys = NIL;
 | 
							pathnode->path.pathkeys = NIL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Note that we are making a pathnode for a single-scan indexscan;
 | 
				
			||||||
 | 
							 * therefore, both indexid and indexqual should be single-element
 | 
				
			||||||
 | 
							 * lists.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		pathnode->indexid = index->relids;
 | 
							pathnode->indexid = index->relids;
 | 
				
			||||||
		pathnode->indexkeys = index->indexkeys;
 | 
							pathnode->indexkeys = index->indexkeys;
 | 
				
			||||||
		pathnode->indexqual = clausegroup;
 | 
							pathnode->indexqual = lcons(get_actual_clauses(clausegroup), NIL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pathnode->path.joinid = ((RestrictInfo *) lfirst(clausegroup))->restrictinfojoinid;
 | 
							pathnode->path.joinid = ((RestrictInfo *) lfirst(clausegroup))->restrictinfojoinid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.28 1999/07/16 04:59:15 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.29 1999/07/24 23:21:10 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -26,61 +26,66 @@
 | 
				
			|||||||
#include "parser/parsetree.h"
 | 
					#include "parser/parsetree.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void best_or_subclause_indices(Query *root, RelOptInfo *rel, List *subclauses,
 | 
					static void best_or_subclause_indices(Query *root, RelOptInfo *rel,
 | 
				
			||||||
				List *indices, List **indexids, Cost *cost, Cost *selec);
 | 
														  List *subclauses, List *indices,
 | 
				
			||||||
static void best_or_subclause_index(Query *root, RelOptInfo *rel, Expr *subclause,
 | 
														  List **indexids,
 | 
				
			||||||
				   List *indices, int *indexid, Cost *cost, Cost *selec);
 | 
														  Cost *cost, Cost *selec);
 | 
				
			||||||
 | 
					static void best_or_subclause_index(Query *root, RelOptInfo *rel,
 | 
				
			||||||
 | 
														Expr *subclause, List *indices,
 | 
				
			||||||
 | 
														int *indexid, Cost *cost, Cost *selec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * create_or_index_paths
 | 
					 * create_or_index_paths
 | 
				
			||||||
 *	  Creates index paths for indices that match 'or' clauses.
 | 
					 *	  Creates index paths for indices that match 'or' clauses.
 | 
				
			||||||
 | 
					 *	  create_index_paths() must already have been called.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * 'rel' is the relation entry for which the paths are to be defined on
 | 
					 * 'rel' is the relation entry for which the paths are to be defined on
 | 
				
			||||||
 * 'clauses' is the list of available restriction clause nodes
 | 
					 * 'clauses' is the list of available restriction clause nodes
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns a list of these index path nodes.
 | 
					 * Returns a list of index path nodes.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
List *
 | 
					List *
 | 
				
			||||||
create_or_index_paths(Query *root,
 | 
					create_or_index_paths(Query *root,
 | 
				
			||||||
					  RelOptInfo *rel, List *clauses)
 | 
										  RelOptInfo *rel, List *clauses)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	List	   *t_list = NIL;
 | 
						List	   *path_list = NIL;
 | 
				
			||||||
	List	   *clist;
 | 
						List	   *clist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(clist, clauses)
 | 
						foreach(clist, clauses)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		RestrictInfo *clausenode = (RestrictInfo *) (lfirst(clist));
 | 
							RestrictInfo *clausenode = (RestrictInfo *) lfirst(clist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Check to see if this clause is an 'or' clause, and, if so,
 | 
							 * Check to see if this clause is an 'or' clause, and, if so,
 | 
				
			||||||
		 * whether or not each of the subclauses within the 'or' clause
 | 
							 * whether or not each of the subclauses within the 'or' clause
 | 
				
			||||||
		 * has been matched by an index (the 'Index field was set in
 | 
							 * has been matched by an index.  The information used was
 | 
				
			||||||
		 * (match_or)  if no index matches a given subclause, one of the
 | 
							 * saved by create_index_paths().
 | 
				
			||||||
		 * lists of index nodes returned by (get_index) will be 'nil').
 | 
					 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (valid_or_clause(clausenode) &&
 | 
							if (restriction_is_or_clause(clausenode) &&
 | 
				
			||||||
			clausenode->indexids)
 | 
								clausenode->indexids)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			List	   *temp = NIL;
 | 
								bool		all_indexable = true;
 | 
				
			||||||
			List	   *index_list = NIL;
 | 
								List	   *temp;
 | 
				
			||||||
			bool		index_flag = true;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			index_list = clausenode->indexids;
 | 
								foreach(temp, clausenode->indexids)
 | 
				
			||||||
			foreach(temp, index_list)
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (!lfirst(temp))
 | 
									if (lfirst(temp) == NIL)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					index_flag = false;
 | 
										all_indexable = false;
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			/* do they all have indexes? */
 | 
								if (all_indexable)
 | 
				
			||||||
			if (index_flag)
 | 
								{
 | 
				
			||||||
			{					/* used to be a lisp every function */
 | 
									/*
 | 
				
			||||||
 | 
									 * OK, build an IndexPath for this OR clause, using the
 | 
				
			||||||
 | 
									 * best available index for each subclause.
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
				IndexPath  *pathnode = makeNode(IndexPath);
 | 
									IndexPath  *pathnode = makeNode(IndexPath);
 | 
				
			||||||
				List	   *indexids = NIL;
 | 
									List	   *indexids;
 | 
				
			||||||
 | 
									List	   *orclause;
 | 
				
			||||||
				Cost		cost;
 | 
									Cost		cost;
 | 
				
			||||||
				Cost		selec;
 | 
									Cost		selec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -98,16 +103,35 @@ create_or_index_paths(Query *root,
 | 
				
			|||||||
				pathnode->path.pathorder->ordtype = SORTOP_ORDER;
 | 
									pathnode->path.pathorder->ordtype = SORTOP_ORDER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/*
 | 
									/*
 | 
				
			||||||
				 * This is an IndexScan, but it does index lookups based
 | 
									 * This is an IndexScan, but the overall result will consist
 | 
				
			||||||
				 * on the order of the fields specified in the WHERE
 | 
									 * of tuples extracted in multiple passes (one for each
 | 
				
			||||||
				 * clause, not in any order, so the sortop is NULL.
 | 
									 * subclause of the OR), so the result cannot be claimed
 | 
				
			||||||
 | 
									 * to have any particular ordering.
 | 
				
			||||||
				 */
 | 
									 */
 | 
				
			||||||
				pathnode->path.pathorder->ord.sortop = NULL;
 | 
									pathnode->path.pathorder->ord.sortop = NULL;
 | 
				
			||||||
				pathnode->path.pathkeys = NIL;
 | 
									pathnode->path.pathkeys = NIL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				pathnode->indexqual = lcons(clausenode, NIL);
 | 
									/*
 | 
				
			||||||
 | 
									 * Generate an indexqual list from the OR clause's args.
 | 
				
			||||||
 | 
									 * We want two levels of sublist: the first is implicit OR
 | 
				
			||||||
 | 
									 * and the second is implicit AND.  (Currently, we will never
 | 
				
			||||||
 | 
									 * see a sub-AND-clause because of cnfify(), but someday maybe
 | 
				
			||||||
 | 
									 * the code below will do something useful...)
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									pathnode->indexqual = NIL;
 | 
				
			||||||
 | 
									foreach(orclause, clausenode->clause->args)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										List	*sublist;
 | 
				
			||||||
 | 
										if (and_clause(lfirst(orclause)))
 | 
				
			||||||
 | 
											sublist = ((Expr *) lfirst(orclause))->args;
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											sublist = lcons(lfirst(orclause), NIL);
 | 
				
			||||||
 | 
										pathnode->indexqual = lappend(pathnode->indexqual,
 | 
				
			||||||
 | 
																	  sublist);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				pathnode->indexid = indexids;
 | 
									pathnode->indexid = indexids;
 | 
				
			||||||
				pathnode->path.path_cost = cost;
 | 
									pathnode->path.path_cost = cost;
 | 
				
			||||||
 | 
									clausenode->selectivity = (Cost) selec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				/*
 | 
									/*
 | 
				
			||||||
				 * copy restrictinfo list into path for expensive function
 | 
									 * copy restrictinfo list into path for expensive function
 | 
				
			||||||
@@ -121,33 +145,28 @@ create_or_index_paths(Query *root,
 | 
				
			|||||||
				if (XfuncMode != XFUNC_OFF)
 | 
									if (XfuncMode != XFUNC_OFF)
 | 
				
			||||||
					((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path) pathnode);
 | 
										((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path) pathnode);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
				clausenode->selectivity = (Cost) selec;
 | 
									path_list = lappend(path_list, pathnode);
 | 
				
			||||||
				t_list = lappend(t_list, pathnode);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return t_list;
 | 
						return path_list;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * best_or_subclause_indices
 | 
					 * best_or_subclause_indices
 | 
				
			||||||
 *	  Determines the best index to be used in conjunction with each subclause
 | 
					 *	  Determines the best index to be used in conjunction with each subclause
 | 
				
			||||||
 *	  of an 'or' clause and the cost of scanning a relation using these
 | 
					 *	  of an 'or' clause and the cost of scanning a relation using these
 | 
				
			||||||
 *	  indices.	The cost is the sum of the individual index costs.
 | 
					 *	  indices.	The cost is the sum of the individual index costs, since
 | 
				
			||||||
 | 
					 *	  the executor will perform a scan for each subclause of the 'or'.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * 'rel' is the node of the relation on which the index is defined
 | 
					 * 'rel' is the node of the relation on which the indexes are defined
 | 
				
			||||||
 * 'subclauses' are the subclauses of the 'or' clause
 | 
					 * 'subclauses' are the subclauses of the 'or' clause
 | 
				
			||||||
 * 'indices' are those index nodes that matched subclauses of the 'or'
 | 
					 * 'indices' is a list of sublists of the index nodes that matched each
 | 
				
			||||||
 *		clause
 | 
					 *		subclause of the 'or' clause
 | 
				
			||||||
 * 'examined_indexids' is a list of those index ids to be used with
 | 
					 * '*indexids' gets a list of the best index ID to use for each subclause
 | 
				
			||||||
 *		subclauses that have already been examined
 | 
					 * '*cost' gets the total cost of the path
 | 
				
			||||||
 * 'subcost' is the cost of using the indices in 'examined_indexids'
 | 
					 * '*selec' gets the total selectivity of the path.
 | 
				
			||||||
 * 'selec' is a list of all subclauses that have already been examined
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns a list of the indexids, cost, and selectivities of each
 | 
					 | 
				
			||||||
 * subclause, e.g., ((i1 i2 i3) cost (s1 s2 s3)), where 'i' is an OID,
 | 
					 | 
				
			||||||
 * 'cost' is a flonum, and 's' is a flonum.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
best_or_subclause_indices(Query *root,
 | 
					best_or_subclause_indices(Query *root,
 | 
				
			||||||
@@ -160,6 +179,7 @@ best_or_subclause_indices(Query *root,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	List	   *slist;
 | 
						List	   *slist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*indexids = NIL;
 | 
				
			||||||
	*selec = (Cost) 0.0;
 | 
						*selec = (Cost) 0.0;
 | 
				
			||||||
	*cost = (Cost) 0.0;
 | 
						*cost = (Cost) 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -180,8 +200,6 @@ best_or_subclause_indices(Query *root,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		indices = lnext(indices);
 | 
							indices = lnext(indices);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -193,10 +211,9 @@ best_or_subclause_indices(Query *root,
 | 
				
			|||||||
 * 'rel' is the node of the relation on which the index is defined
 | 
					 * 'rel' is the node of the relation on which the index is defined
 | 
				
			||||||
 * 'subclause' is the subclause
 | 
					 * 'subclause' is the subclause
 | 
				
			||||||
 * 'indices' is a list of index nodes that match the subclause
 | 
					 * 'indices' is a list of index nodes that match the subclause
 | 
				
			||||||
 *
 | 
					 * '*retIndexid' gets the ID of the best index
 | 
				
			||||||
 * Returns a list (index_id index_subcost index_selectivity)
 | 
					 * '*retCost' gets the cost of a scan with that index
 | 
				
			||||||
 * (a fixnum, a fixnum, and a flonum respectively).
 | 
					 * '*retSelec' gets the selectivity of that scan
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
best_or_subclause_index(Query *root,
 | 
					best_or_subclause_index(Query *root,
 | 
				
			||||||
@@ -207,28 +224,26 @@ best_or_subclause_index(Query *root,
 | 
				
			|||||||
						Cost *retCost,	/* return value */
 | 
											Cost *retCost,	/* return value */
 | 
				
			||||||
						Cost *retSelec) /* return value */
 | 
											Cost *retSelec) /* return value */
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	List	   *ilist;
 | 
						Oid			relid = getrelid(lfirsti(rel->relids),
 | 
				
			||||||
 | 
													 root->rtable);
 | 
				
			||||||
 | 
						Oid			opno = ((Oper *) subclause->oper)->opno;
 | 
				
			||||||
 | 
						AttrNumber	attno = (get_leftop(subclause))->varattno;
 | 
				
			||||||
 | 
						bool		constant_on_right = non_null((Expr *) get_rightop(subclause));
 | 
				
			||||||
 | 
						Datum		value;
 | 
				
			||||||
 | 
						int			flag;
 | 
				
			||||||
 | 
						List	   *opnos,
 | 
				
			||||||
 | 
								   *attnos,
 | 
				
			||||||
 | 
								   *values,
 | 
				
			||||||
 | 
								   *flags;
 | 
				
			||||||
	bool		first_run = true;
 | 
						bool		first_run = true;
 | 
				
			||||||
 | 
						List	   *ilist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* if we don't match anything, return zeros */
 | 
						/* if we don't match anything, return zeros */
 | 
				
			||||||
	*retIndexid = 0;
 | 
						*retIndexid = 0;
 | 
				
			||||||
	*retCost = 0.0;
 | 
						*retCost = (Cost) 0.0;
 | 
				
			||||||
	*retSelec = 0.0;
 | 
						*retSelec = (Cost) 0.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(ilist, indices)
 | 
						if (constant_on_right)		/* XXX looks pretty bogus ... tgl */
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Datum		value;
 | 
					 | 
				
			||||||
		int			flag = 0;
 | 
					 | 
				
			||||||
		Cost		subcost;
 | 
					 | 
				
			||||||
		AttrNumber	attno = (get_leftop(subclause))->varattno;
 | 
					 | 
				
			||||||
		Oid			opno = ((Oper *) subclause->oper)->opno;
 | 
					 | 
				
			||||||
		bool		constant_on_right = non_null((Expr *) get_rightop(subclause));
 | 
					 | 
				
			||||||
		float		npages,
 | 
					 | 
				
			||||||
					selec;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (constant_on_right)
 | 
					 | 
				
			||||||
		value = ((Const *) get_rightop(subclause))->constvalue;
 | 
							value = ((Const *) get_rightop(subclause))->constvalue;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		value = NameGetDatum("");
 | 
							value = NameGetDatum("");
 | 
				
			||||||
@@ -237,19 +252,32 @@ best_or_subclause_index(Query *root,
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		flag = _SELEC_CONSTANT_RIGHT_;
 | 
							flag = _SELEC_CONSTANT_RIGHT_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		index_selectivity(lfirsti(index->relids),
 | 
						/* prebuild lists since we will pass same list to each index */
 | 
				
			||||||
 | 
						opnos = lconsi(opno, NIL);
 | 
				
			||||||
 | 
						attnos = lconsi(attno, NIL);
 | 
				
			||||||
 | 
						values = lconsi(value, NIL);
 | 
				
			||||||
 | 
						flags = lconsi(flag, NIL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						foreach(ilist, indices)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
 | 
				
			||||||
 | 
							Oid			indexid = (Oid) lfirsti(index->relids);
 | 
				
			||||||
 | 
							Cost		subcost;
 | 
				
			||||||
 | 
							float		npages,
 | 
				
			||||||
 | 
										selec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							index_selectivity(indexid,
 | 
				
			||||||
						  index->classlist,
 | 
											  index->classlist,
 | 
				
			||||||
						  lconsi(opno, NIL),
 | 
											  opnos,
 | 
				
			||||||
						  getrelid(lfirsti(rel->relids),
 | 
											  relid,
 | 
				
			||||||
								   root->rtable),
 | 
											  attnos,
 | 
				
			||||||
						  lconsi(attno, NIL),
 | 
											  values,
 | 
				
			||||||
						  lconsi(value, NIL),
 | 
											  flags,
 | 
				
			||||||
						  lconsi(flag, NIL),
 | 
					 | 
				
			||||||
						  1,
 | 
											  1,
 | 
				
			||||||
						  &npages,
 | 
											  &npages,
 | 
				
			||||||
						  &selec);
 | 
											  &selec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		subcost = cost_index((Oid) lfirsti(index->relids),
 | 
							subcost = cost_index(indexid,
 | 
				
			||||||
							 (int) npages,
 | 
												 (int) npages,
 | 
				
			||||||
							 (Cost) selec,
 | 
												 (Cost) selec,
 | 
				
			||||||
							 rel->pages,
 | 
												 rel->pages,
 | 
				
			||||||
@@ -260,12 +288,11 @@ best_or_subclause_index(Query *root,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (first_run || subcost < *retCost)
 | 
							if (first_run || subcost < *retCost)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			*retIndexid = lfirsti(index->relids);
 | 
								*retIndexid = indexid;
 | 
				
			||||||
			*retCost = subcost;
 | 
								*retCost = subcost;
 | 
				
			||||||
			*retSelec = selec;
 | 
								*retSelec = selec;
 | 
				
			||||||
			first_run = false;
 | 
								first_run = false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.62 1999/07/17 20:17:13 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.63 1999/07/24 23:21:11 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -301,54 +301,30 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
 | 
				
			|||||||
 * create_indexscan_node
 | 
					 * create_indexscan_node
 | 
				
			||||||
 *	  Returns a indexscan node for the base relation scanned by 'best_path'
 | 
					 *	  Returns a indexscan node for the base relation scanned by 'best_path'
 | 
				
			||||||
 *	  with restriction clauses 'scan_clauses' and targetlist 'tlist'.
 | 
					 *	  with restriction clauses 'scan_clauses' and targetlist 'tlist'.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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)).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static IndexScan *
 | 
					static IndexScan *
 | 
				
			||||||
create_indexscan_node(IndexPath *best_path,
 | 
					create_indexscan_node(IndexPath *best_path,
 | 
				
			||||||
					  List *tlist,
 | 
										  List *tlist,
 | 
				
			||||||
					  List *scan_clauses)
 | 
										  List *scan_clauses)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						List	   *indxqual = best_path->indexqual;
 | 
				
			||||||
	/*
 | 
						List	   *qpqual;
 | 
				
			||||||
	 * Extract the(first if conjunct, only if disjunct) clause from the
 | 
						List	   *fixed_indxqual;
 | 
				
			||||||
	 * restrictinfo list.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	Expr	   *index_clause = (Expr *) NULL;
 | 
					 | 
				
			||||||
	List	   *indxqual = NIL;
 | 
					 | 
				
			||||||
	List	   *qpqual = NIL;
 | 
					 | 
				
			||||||
	List	   *fixed_indxqual = NIL;
 | 
					 | 
				
			||||||
	List	   *ixid;
 | 
						List	   *ixid;
 | 
				
			||||||
	IndexScan  *scan_node = (IndexScan *) NULL;
 | 
						IndexScan  *scan_node;
 | 
				
			||||||
	bool		lossy = FALSE;
 | 
						bool		lossy = false;
 | 
				
			||||||
	HeapTuple	indexTuple;
 | 
					 | 
				
			||||||
	Form_pg_index index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * 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))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		List	   *temp = NIL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		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 */
 | 
						/* check and see if any indices are lossy */
 | 
				
			||||||
	foreach(ixid, best_path->indexid)
 | 
						foreach(ixid, best_path->indexid)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							HeapTuple	indexTuple;
 | 
				
			||||||
 | 
							Form_pg_index index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		indexTuple = SearchSysCacheTuple(INDEXRELID,
 | 
							indexTuple = SearchSysCacheTuple(INDEXRELID,
 | 
				
			||||||
										 ObjectIdGetDatum(lfirsti(ixid)),
 | 
															 ObjectIdGetDatum(lfirsti(ixid)),
 | 
				
			||||||
										 0, 0, 0);
 | 
															 0, 0, 0);
 | 
				
			||||||
@@ -356,34 +332,70 @@ create_indexscan_node(IndexPath *best_path,
 | 
				
			|||||||
			elog(ERROR, "create_plan: index %u not found", lfirsti(ixid));
 | 
								elog(ERROR, "create_plan: index %u not found", lfirsti(ixid));
 | 
				
			||||||
		index = (Form_pg_index) GETSTRUCT(indexTuple);
 | 
							index = (Form_pg_index) GETSTRUCT(indexTuple);
 | 
				
			||||||
		if (index->indislossy)
 | 
							if (index->indislossy)
 | 
				
			||||||
			lossy = TRUE;
 | 
							{
 | 
				
			||||||
 | 
								lossy = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The qpqual field contains all restrictions not automatically
 | 
						 * The qpqual list must contain all restrictions not automatically
 | 
				
			||||||
	 * handled by the index.  Note that for non-lossy indices, the
 | 
						 * handled by the index.  Note that for non-lossy indices, the
 | 
				
			||||||
	 * predicates in the indxqual are handled by the index, while for
 | 
						 * predicates in the indxqual are handled by the index, while for
 | 
				
			||||||
	 * lossy indices the indxqual predicates need to be double-checked
 | 
						 * lossy indices the indxqual predicates need to be double-checked
 | 
				
			||||||
	 * after the index fetches the best-guess tuples.
 | 
						 * after the index fetches the best-guess tuples.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * There should not be any clauses in scan_clauses that duplicate
 | 
				
			||||||
 | 
						 * expressions checked by the index, but just in case, we will
 | 
				
			||||||
 | 
						 * get rid of them via set_difference.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (or_clause((Node *) index_clause))
 | 
						if (length(indxqual) > 1)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Build an expression representation of the indexqual, expanding
 | 
				
			||||||
 | 
							 * the implicit OR and AND semantics of the first- and second-level
 | 
				
			||||||
 | 
							 * lists.  XXX Is it really necessary to do a deep copy here?
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							List	   *orclauses = NIL;
 | 
				
			||||||
 | 
							List	   *orclause;
 | 
				
			||||||
 | 
							Expr	   *indxqual_expr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							foreach(orclause, indxqual)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								orclauses = lappend(orclauses,
 | 
				
			||||||
 | 
													make_ands_explicit((List *) copyObject(lfirst(orclause))));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							indxqual_expr = make_orclause(orclauses);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* this set_difference is almost certainly a waste of time... */
 | 
				
			||||||
		qpqual = set_difference(scan_clauses,
 | 
							qpqual = set_difference(scan_clauses,
 | 
				
			||||||
								lcons(index_clause, NIL));
 | 
													lcons(indxqual_expr, NIL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (lossy)
 | 
							if (lossy)
 | 
				
			||||||
			qpqual = lappend(qpqual, (List *) copyObject(index_clause));
 | 
								qpqual = lappend(qpqual, indxqual_expr);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else if (indxqual != NIL)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							/* Here, we can simply treat the first sublist as an independent
 | 
				
			||||||
 | 
							 * set of qual expressions, since there is no top-level OR behavior.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		qpqual = set_difference(scan_clauses, lfirst(indxqual));
 | 
							qpqual = set_difference(scan_clauses, lfirst(indxqual));
 | 
				
			||||||
		if (lossy)
 | 
							if (lossy)
 | 
				
			||||||
			qpqual = nconc(qpqual,
 | 
								qpqual = nconc(qpqual, (List *) copyObject(lfirst(indxqual)));
 | 
				
			||||||
						   (List *) copyObject(lfirst(indxqual)));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							qpqual = NIL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fixed_indxqual = (List *) fix_indxqual_references((Node *) indxqual, (Path *) best_path);
 | 
						/*
 | 
				
			||||||
 | 
						 * Fix opids in the completed indxqual.  We don't want to do this sooner
 | 
				
			||||||
 | 
						 * since it would screw up the set_difference calcs above.  Really,
 | 
				
			||||||
 | 
						 * this ought to only happen at final exit from the planner...
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						indxqual = fix_opids(indxqual);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The executor needs a copy with index attrs substituted for table ones */
 | 
				
			||||||
 | 
						fixed_indxqual = (List *) fix_indxqual_references((Node *) indxqual,
 | 
				
			||||||
 | 
																		  (Path *) best_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	scan_node = make_indexscan(tlist,
 | 
						scan_node = make_indexscan(tlist,
 | 
				
			||||||
							   qpqual,
 | 
												   qpqual,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.34 1999/07/16 04:59:19 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.35 1999/07/24 23:21:12 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -25,12 +25,11 @@
 | 
				
			|||||||
#include "optimizer/var.h"
 | 
					#include "optimizer/var.h"
 | 
				
			||||||
#include "utils/lsyscache.h"
 | 
					#include "utils/lsyscache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int	Quiet;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void add_restrict_and_join_to_rel(Query *root, List *clause);
 | 
					static void add_restrict_and_join_to_rel(Query *root, Node *clause);
 | 
				
			||||||
static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 | 
					static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 | 
				
			||||||
					  Relids join_relids);
 | 
										  Relids join_relids);
 | 
				
			||||||
static void add_vars_to_targetlist(Query *root, List *vars, Relids join_relids);
 | 
					static void add_vars_to_targetlist(Query *root, List *vars);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static MergeOrder *mergejoinop(Expr *clause);
 | 
					static MergeOrder *mergejoinop(Expr *clause);
 | 
				
			||||||
static Oid	hashjoinop(Expr *clause);
 | 
					static Oid	hashjoinop(Expr *clause);
 | 
				
			||||||
@@ -129,7 +128,7 @@ add_missing_vars_to_tlist(Query *root, List *tlist)
 | 
				
			|||||||
 *	  relations appearing within clauses.  Creates new relation entries if
 | 
					 *	  relations appearing within clauses.  Creates new relation entries if
 | 
				
			||||||
 *	  necessary, adding them to *query_relation_list*.
 | 
					 *	  necessary, adding them to *query_relation_list*.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *	  Returns nothing of interest.
 | 
					 * 'clauses': the list of clauses in the cnfify'd query qualification.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
add_restrict_and_join_to_rels(Query *root, List *clauses)
 | 
					add_restrict_and_join_to_rels(Query *root, List *clauses)
 | 
				
			||||||
@@ -137,8 +136,7 @@ add_restrict_and_join_to_rels(Query *root, List *clauses)
 | 
				
			|||||||
	List	   *clause;
 | 
						List	   *clause;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(clause, clauses)
 | 
						foreach(clause, clauses)
 | 
				
			||||||
		add_restrict_and_join_to_rel(root, lfirst(clause));
 | 
							add_restrict_and_join_to_rel(root, (Node*) lfirst(clause));
 | 
				
			||||||
	return;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -147,73 +145,51 @@ add_restrict_and_join_to_rels(Query *root, List *clauses)
 | 
				
			|||||||
 *	  of a relation entry (depending on whether or not the clause is a join)
 | 
					 *	  of a relation entry (depending on whether or not the clause is a join)
 | 
				
			||||||
 *	  by creating a new RestrictInfo node and setting appropriate fields
 | 
					 *	  by creating a new RestrictInfo node and setting appropriate fields
 | 
				
			||||||
 *	  within the nodes.
 | 
					 *	  within the nodes.
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *	  Returns nothing of interest.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
add_restrict_and_join_to_rel(Query *root, List *clause)
 | 
					add_restrict_and_join_to_rel(Query *root, Node *clause)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						RestrictInfo *restrictinfo = makeNode(RestrictInfo);
 | 
				
			||||||
	Relids		relids;
 | 
						Relids		relids;
 | 
				
			||||||
	List	   *vars;
 | 
						List	   *vars;
 | 
				
			||||||
	RestrictInfo *restrictinfo = makeNode(RestrictInfo);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Retrieve all relids and vars contained within the clause.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	clause_get_relids_vars((Node *) clause, &relids, &vars);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	restrictinfo->clause = (Expr *) clause;
 | 
						restrictinfo->clause = (Expr *) clause;
 | 
				
			||||||
	restrictinfo->notclause = contains_not((Node *) clause);
 | 
					 | 
				
			||||||
	restrictinfo->selectivity = 0;
 | 
					 | 
				
			||||||
	restrictinfo->indexids = NIL;
 | 
						restrictinfo->indexids = NIL;
 | 
				
			||||||
	restrictinfo->mergejoinorder = (MergeOrder *) NULL;
 | 
						restrictinfo->mergejoinorder = (MergeOrder *) NULL;
 | 
				
			||||||
	restrictinfo->hashjoinoperator = (Oid) 0;
 | 
						restrictinfo->hashjoinoperator = (Oid) 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (length(relids) == 1)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * There is only one relation participating in 'clause', so
 | 
					 | 
				
			||||||
		 * 'clause' must be a restriction clause.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The selectivity of the clause must be computed regardless of
 | 
						 * The selectivity of the clause must be computed regardless of
 | 
				
			||||||
	 * whether it's a restriction or a join clause
 | 
						 * whether it's a restriction or a join clause
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
		if (is_funcclause((Node *) clause))
 | 
						restrictinfo->selectivity = compute_clause_selec(root, clause);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
			 * XXX If we have a func clause set selectivity to 1/3, really
 | 
						 * Retrieve all relids and vars contained within the clause.
 | 
				
			||||||
			 * need a true selectivity function.
 | 
					 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
			restrictinfo->selectivity = (Cost) 0.3333333;
 | 
						clause_get_relids_vars(clause, &relids, &vars);
 | 
				
			||||||
		else
 | 
					
 | 
				
			||||||
			restrictinfo->selectivity = compute_clause_selec(root, (Node *) clause, NIL);
 | 
						if (length(relids) == 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * There is only one relation participating in 'clause', so
 | 
				
			||||||
 | 
							 * 'clause' must be a restriction clause for that relation.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rel->restrictinfo = lcons(restrictinfo, rel->restrictinfo);
 | 
							rel->restrictinfo = lcons(restrictinfo, rel->restrictinfo);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * 'clause' is a join clause, since there is more than one atom in
 | 
							 * 'clause' is a join clause, since there is more than one atom in
 | 
				
			||||||
		 * the relid list.
 | 
							 * the relid list.  Add it to the join lists of all the relevant
 | 
				
			||||||
 | 
							 * relations.  (If, perchance, 'clause' contains NO vars, then
 | 
				
			||||||
 | 
							 * nothing will happen...)
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (is_funcclause((Node *) clause))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 * XXX If we have a func clause set selectivity to 1/3, really
 | 
					 | 
				
			||||||
			 * need a true selectivity function.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			restrictinfo->selectivity = (Cost) 0.3333333;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			restrictinfo->selectivity = compute_clause_selec(root, (Node *) clause, NIL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		add_join_info_to_rels(root, restrictinfo, relids);
 | 
							add_join_info_to_rels(root, restrictinfo, relids);
 | 
				
			||||||
		/* we are going to be doing a join, so add var to targetlist */
 | 
							/* we are going to be doing a join, so add vars to targetlists */
 | 
				
			||||||
		add_vars_to_targetlist(root, vars, relids);
 | 
							add_vars_to_targetlist(root, vars);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -225,7 +201,6 @@ add_restrict_and_join_to_rel(Query *root, List *clause)
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * 'restrictinfo' describes the join clause
 | 
					 * 'restrictinfo' describes the join clause
 | 
				
			||||||
 * 'join_relids' is the list of relations participating in the join clause
 | 
					 * 'join_relids' is the list of relations participating in the join clause
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 | 
					add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 | 
				
			||||||
@@ -233,7 +208,7 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	List	   *join_relid;
 | 
						List	   *join_relid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* For every relid, find the rel, and add the proper join entries */
 | 
						/* For every relid, find the joininfo, and add the proper join entries */
 | 
				
			||||||
	foreach(join_relid, join_relids)
 | 
						foreach(join_relid, join_relids)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		JoinInfo   *joininfo;
 | 
							JoinInfo   *joininfo;
 | 
				
			||||||
@@ -247,8 +222,18 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 | 
				
			|||||||
				unjoined_relids = lappendi(unjoined_relids, lfirsti(rel));
 | 
									unjoined_relids = lappendi(unjoined_relids, lfirsti(rel));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Find or make the joininfo node for this combination of rels
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		joininfo = find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
 | 
							joininfo = find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
 | 
				
			||||||
									  unjoined_relids);
 | 
														  unjoined_relids);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * And add the restrictinfo node to it.  NOTE that each joininfo
 | 
				
			||||||
 | 
							 * gets its own copy of the restrictinfo node!  (Is this really
 | 
				
			||||||
 | 
							 * necessary?  Possibly ... later parts of the optimizer destructively
 | 
				
			||||||
 | 
							 * modify restrict/join clauses...)
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		joininfo->jinfo_restrictinfo = lcons(copyObject((void *) restrictinfo),
 | 
							joininfo->jinfo_restrictinfo = lcons(copyObject((void *) restrictinfo),
 | 
				
			||||||
											 joininfo->jinfo_restrictinfo);
 | 
																 joininfo->jinfo_restrictinfo);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -256,34 +241,20 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * add_vars_to_targetlist
 | 
					 * add_vars_to_targetlist
 | 
				
			||||||
 *	  For each variable appearing in a clause,
 | 
					 *	  For each variable appearing in a clause, add it to the relation's
 | 
				
			||||||
 *	  (1) If a targetlist entry for the variable is not already present in
 | 
					 *	  targetlist if not already present.
 | 
				
			||||||
 *		  the appropriate relation's target list, add one.
 | 
					 | 
				
			||||||
 *	  (2) If a targetlist entry is already present, but the var is part of a
 | 
					 | 
				
			||||||
 *		  join clause, add the relids of the join relations to the JoinList
 | 
					 | 
				
			||||||
 *		  entry of the targetlist entry.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *	  'vars' is the list of var nodes
 | 
					 | 
				
			||||||
 *	  'join_relids' is the list of relids appearing in the join clause
 | 
					 | 
				
			||||||
 *		(if this is a join clause)
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *	  Returns nothing.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
add_vars_to_targetlist(Query *root, List *vars, Relids join_relids)
 | 
					add_vars_to_targetlist(Query *root, List *vars)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Var		   *var;
 | 
						List	   *temp;
 | 
				
			||||||
	List	   *temp = NIL;
 | 
					 | 
				
			||||||
	RelOptInfo *rel = (RelOptInfo *) NULL;
 | 
					 | 
				
			||||||
	TargetEntry *tlistentry;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	foreach(temp, vars)
 | 
						foreach(temp, vars)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var = (Var *) lfirst(temp);
 | 
							Var		   *var = (Var *) lfirst(temp);
 | 
				
			||||||
		rel = get_base_rel(root, var->varno);
 | 
							RelOptInfo *rel = get_base_rel(root, var->varno);
 | 
				
			||||||
		tlistentry = tlistentry_member(var, rel->targetlist);
 | 
					
 | 
				
			||||||
		if (tlistentry == NULL)
 | 
							if (tlistentry_member(var, rel->targetlist) == NULL)
 | 
				
			||||||
			/* add a new entry */
 | 
					 | 
				
			||||||
			add_var_to_tlist(rel, var);
 | 
								add_var_to_tlist(rel, var);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.40 1999/07/16 04:59:23 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.41 1999/07/24 23:21:13 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * HISTORY
 | 
					 * HISTORY
 | 
				
			||||||
 *	  AUTHOR			DATE			MAJOR EVENT
 | 
					 *	  AUTHOR			DATE			MAJOR EVENT
 | 
				
			||||||
@@ -290,6 +290,21 @@ make_andclause(List *andclauses)
 | 
				
			|||||||
	return expr;
 | 
						return expr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Sometimes (such as in the result of cnfify), we use lists of expression
 | 
				
			||||||
 | 
					 * nodes with implicit AND semantics.  This function converts back to an
 | 
				
			||||||
 | 
					 * explicit-AND representation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					Expr *
 | 
				
			||||||
 | 
					make_ands_explicit(List *andclauses)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (andclauses == NIL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						else if (length(andclauses) == 1)
 | 
				
			||||||
 | 
							return (Expr *) lfirst(andclauses);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return make_andclause(andclauses);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*****************************************************************************
 | 
					/*****************************************************************************
 | 
				
			||||||
 *		CASE clause functions
 | 
					 *		CASE clause functions
 | 
				
			||||||
@@ -410,38 +425,6 @@ NumRelids(Node *clause)
 | 
				
			|||||||
	return length(var_list);
 | 
						return length(var_list);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * contains_not
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns t iff the clause is a 'not' clause or if any of the
 | 
					 | 
				
			||||||
 * subclauses within an 'or' clause contain 'not's.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * NOTE that only the top-level AND/OR structure is searched for NOTs;
 | 
					 | 
				
			||||||
 * we are not interested in buried substructure.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
bool
 | 
					 | 
				
			||||||
contains_not(Node *clause)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (single_node(clause))
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (not_clause(clause))
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (or_clause(clause) || and_clause(clause))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		List	   *a;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		foreach(a, ((Expr *) clause)->args)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (contains_not(lfirst(a)))
 | 
					 | 
				
			||||||
				return true;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * is_joinable
 | 
					 * is_joinable
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.46 1999/07/16 04:59:25 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.47 1999/07/24 23:21:14 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -426,7 +426,8 @@ create_index_path(Query *root,
 | 
				
			|||||||
		/* each clause gets an equal selectivity */
 | 
							/* each clause gets an equal selectivity */
 | 
				
			||||||
		clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
 | 
							clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pathnode->indexqual = restriction_clauses;
 | 
							pathnode->indexqual = lcons(get_actual_clauses(restriction_clauses),
 | 
				
			||||||
 | 
														NIL);
 | 
				
			||||||
		pathnode->path.path_cost = cost_index(lfirsti(index->relids),
 | 
							pathnode->path.path_cost = cost_index(lfirsti(index->relids),
 | 
				
			||||||
											  (int) npages,
 | 
																  (int) npages,
 | 
				
			||||||
											  selec,
 | 
																  selec,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.6 1999/07/16 04:59:27 momjian Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.7 1999/07/24 23:21:14 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -20,17 +20,15 @@
 | 
				
			|||||||
#include "optimizer/restrictinfo.h"
 | 
					#include "optimizer/restrictinfo.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * valid_or_clause
 | 
					 * restriction_is_or_clause
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Returns t iff the restrictinfo node contains a 'normal' 'or' clause.
 | 
					 * Returns t iff the restrictinfo node contains an 'or' clause.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool
 | 
					bool
 | 
				
			||||||
valid_or_clause(RestrictInfo *restrictinfo)
 | 
					restriction_is_or_clause(RestrictInfo *restrictinfo)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (restrictinfo != NULL &&
 | 
						if (restrictinfo != NULL &&
 | 
				
			||||||
		!single_node((Node *) restrictinfo->clause) &&
 | 
					 | 
				
			||||||
		!restrictinfo->notclause &&
 | 
					 | 
				
			||||||
		or_clause((Node *) restrictinfo->clause))
 | 
							or_clause((Node *) restrictinfo->clause))
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (c) 1994, Regents of the University of California
 | 
					 * Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $Id: relation.h,v 1.34 1999/07/15 23:03:56 momjian Exp $
 | 
					 * $Id: relation.h,v 1.35 1999/07/24 23:21:04 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -151,6 +151,23 @@ typedef struct Path
 | 
				
			|||||||
	List	   *loc_restrictinfo;
 | 
						List	   *loc_restrictinfo;
 | 
				
			||||||
} Path;
 | 
					} Path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*----------
 | 
				
			||||||
 | 
					 * IndexPath represents an index scan.  Although an indexscan can only read
 | 
				
			||||||
 | 
					 * a single relation, it can scan it more than once, potentially using a
 | 
				
			||||||
 | 
					 * different index during each scan.  The result is the union (OR) of all the
 | 
				
			||||||
 | 
					 * tuples matched during any scan.  (The executor is smart enough not to return
 | 
				
			||||||
 | 
					 * the same tuple more than once, even if it is matched in multiple scans.)
 | 
				
			||||||
 | 
					 * 'indexid' is a list of index relation OIDs, one per scan to be performed.
 | 
				
			||||||
 | 
					 * 'indexqual' is a list of index qualifications, also one per scan.
 | 
				
			||||||
 | 
					 * Each entry in 'indexqual' is a sublist of qualification expressions with
 | 
				
			||||||
 | 
					 * implicit AND semantics across the sublist items.  Each one of the sublist
 | 
				
			||||||
 | 
					 * items must be an operator expression of the form (var op something) or
 | 
				
			||||||
 | 
					 * (something op var), where the var is a field the associated index keys on
 | 
				
			||||||
 | 
					 * and the op is a member of the operator class of the index.
 | 
				
			||||||
 | 
					 * NOTE that the semantics of the top-level list in 'indexqual' is OR
 | 
				
			||||||
 | 
					 * combination, while the sublists are implicitly AND combinations!
 | 
				
			||||||
 | 
					 *----------
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
typedef struct IndexPath
 | 
					typedef struct IndexPath
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Path		path;
 | 
						Path		path;
 | 
				
			||||||
@@ -205,16 +222,20 @@ typedef struct JoinKey
 | 
				
			|||||||
} JoinKey;
 | 
					} JoinKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * clause info
 | 
					 * Restriction clause info.
 | 
				
			||||||
 | 
					 * We create one of these for each AND sub-clause of a restriction condition
 | 
				
			||||||
 | 
					 * (WHERE clause).  Since the restriction clauses are logically ANDed, we
 | 
				
			||||||
 | 
					 * can use any one of them or any subset of them to filter out tuples,
 | 
				
			||||||
 | 
					 * without having to evaluate the rest.  The RestrictInfo node itself stores
 | 
				
			||||||
 | 
					 * data used by the optimizer while choosing the best query plan.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct RestrictInfo
 | 
					typedef struct RestrictInfo
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	NodeTag		type;
 | 
						NodeTag		type;
 | 
				
			||||||
	Expr	   *clause;			/* should be an OP clause */
 | 
						Expr	   *clause;			/* the represented subclause of WHERE cond */
 | 
				
			||||||
	Cost		selectivity;
 | 
						Cost		selectivity;	/* estimated selectivity */
 | 
				
			||||||
	bool		notclause;
 | 
						List	   *indexids;		/* subclause index IDs if clause is an OR */
 | 
				
			||||||
	List	   *indexids;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* mergejoin only */
 | 
						/* mergejoin only */
 | 
				
			||||||
	MergeOrder *mergejoinorder;
 | 
						MergeOrder *mergejoinorder;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (c) 1994, Regents of the University of California
 | 
					 * Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $Id: clauses.h,v 1.21 1999/07/15 23:03:57 momjian Exp $
 | 
					 * $Id: clauses.h,v 1.22 1999/07/24 23:21:05 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -34,13 +34,13 @@ extern Expr *get_notclausearg(Expr *notclause);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern bool and_clause(Node *clause);
 | 
					extern bool and_clause(Node *clause);
 | 
				
			||||||
extern Expr *make_andclause(List *andclauses);
 | 
					extern Expr *make_andclause(List *andclauses);
 | 
				
			||||||
 | 
					extern Expr *make_ands_explicit(List *andclauses);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern bool case_clause(Node *clause);
 | 
					extern bool case_clause(Node *clause);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern List *pull_constant_clauses(List *quals, List **constantQual);
 | 
					extern List *pull_constant_clauses(List *quals, List **constantQual);
 | 
				
			||||||
extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
 | 
					extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
 | 
				
			||||||
extern int	NumRelids(Node *clause);
 | 
					extern int	NumRelids(Node *clause);
 | 
				
			||||||
extern bool contains_not(Node *clause);
 | 
					 | 
				
			||||||
extern bool is_joinable(Node *clause);
 | 
					extern bool is_joinable(Node *clause);
 | 
				
			||||||
extern bool qual_clause_p(Node *clause);
 | 
					extern bool qual_clause_p(Node *clause);
 | 
				
			||||||
extern void fix_opid(Node *clause);
 | 
					extern void fix_opid(Node *clause);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (c) 1994, Regents of the University of California
 | 
					 * Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $Id: cost.h,v 1.21 1999/07/15 15:21:20 momjian Exp $
 | 
					 * $Id: cost.h,v 1.22 1999/07/24 23:21:05 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -59,7 +59,6 @@ extern void set_clause_selectivities(List *restrictinfo_list, Cost new_selectivi
 | 
				
			|||||||
extern Cost product_selec(List *restrictinfo_list);
 | 
					extern Cost product_selec(List *restrictinfo_list);
 | 
				
			||||||
extern void set_rest_relselec(Query *root, List *rel_list);
 | 
					extern void set_rest_relselec(Query *root, List *rel_list);
 | 
				
			||||||
extern void set_rest_selec(Query *root, List *restrictinfo_list);
 | 
					extern void set_rest_selec(Query *root, List *restrictinfo_list);
 | 
				
			||||||
extern Cost compute_clause_selec(Query *root,
 | 
					extern Cost compute_clause_selec(Query *root, Node *clause);
 | 
				
			||||||
					 Node *clause, List *or_selectivities);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif	 /* COST_H */
 | 
					#endif	 /* COST_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (c) 1994, Regents of the University of California
 | 
					 * Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $Id: restrictinfo.h,v 1.5 1999/07/15 15:21:23 momjian Exp $
 | 
					 * $Id: restrictinfo.h,v 1.6 1999/07/24 23:21:05 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "nodes/relation.h"
 | 
					#include "nodes/relation.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern bool valid_or_clause(RestrictInfo *restrictinfo);
 | 
					extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
 | 
				
			||||||
extern List *get_actual_clauses(List *restrictinfo_list);
 | 
					extern List *get_actual_clauses(List *restrictinfo_list);
 | 
				
			||||||
extern void get_relattvals(List *restrictinfo_list, List **attnos,
 | 
					extern void get_relattvals(List *restrictinfo_list, List **attnos,
 | 
				
			||||||
			   List **values, List **flags);
 | 
								   List **values, List **flags);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user