mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Adjust indexscan planning logic to keep RestrictInfo nodes associated
with index qual clauses in the Path representation. This saves a little work during createplan and (probably more importantly) allows reuse of cached selectivity estimates during indexscan planning. Also fix latent bug: wrong plan would have been generated for a 'special operator' used in a nestloop-inner-indexscan join qual, because the special operator would not have gotten into the list of quals to recheck. This bug is only latent because at present the special-operator code could never trigger on a join qual, but sooner or later someone will want to do it.
This commit is contained in:
		@@ -10,7 +10,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.163 2004/01/05 18:04:38 tgl Exp $
 | 
			
		||||
 *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.164 2004/01/05 23:39:54 tgl Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@@ -44,15 +44,15 @@ static Append *create_append_plan(Query *root, AppendPath *best_path);
 | 
			
		||||
static Result *create_result_plan(Query *root, ResultPath *best_path);
 | 
			
		||||
static Material *create_material_plan(Query *root, MaterialPath *best_path);
 | 
			
		||||
static Plan *create_unique_plan(Query *root, UniquePath *best_path);
 | 
			
		||||
static SeqScan *create_seqscan_plan(Path *best_path, List *tlist,
 | 
			
		||||
					List *scan_clauses);
 | 
			
		||||
static SeqScan *create_seqscan_plan(Query *root, Path *best_path,
 | 
			
		||||
									List *tlist, List *scan_clauses);
 | 
			
		||||
static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
 | 
			
		||||
					  List *tlist, List *scan_clauses);
 | 
			
		||||
static TidScan *create_tidscan_plan(TidPath *best_path, List *tlist,
 | 
			
		||||
					List *scan_clauses);
 | 
			
		||||
static SubqueryScan *create_subqueryscan_plan(Path *best_path,
 | 
			
		||||
static TidScan *create_tidscan_plan(Query *root, TidPath *best_path,
 | 
			
		||||
									List *tlist, List *scan_clauses);
 | 
			
		||||
static SubqueryScan *create_subqueryscan_plan(Query *root, Path *best_path,
 | 
			
		||||
						 List *tlist, List *scan_clauses);
 | 
			
		||||
static FunctionScan *create_functionscan_plan(Path *best_path,
 | 
			
		||||
static FunctionScan *create_functionscan_plan(Query *root, Path *best_path,
 | 
			
		||||
						 List *tlist, List *scan_clauses);
 | 
			
		||||
static NestLoop *create_nestloop_plan(Query *root, NestPath *best_path,
 | 
			
		||||
					 Plan *outer_plan, Plan *inner_plan);
 | 
			
		||||
@@ -219,15 +219,13 @@ create_scan_plan(Query *root, Path *best_path)
 | 
			
		||||
	 * Extract the relevant restriction clauses from the parent relation;
 | 
			
		||||
	 * the executor must apply all these restrictions during the scan.
 | 
			
		||||
	 */
 | 
			
		||||
	scan_clauses = get_actual_clauses(rel->baserestrictinfo);
 | 
			
		||||
 | 
			
		||||
	/* Sort clauses into best execution order */
 | 
			
		||||
	scan_clauses = order_qual_clauses(root, scan_clauses);
 | 
			
		||||
	scan_clauses = rel->baserestrictinfo;
 | 
			
		||||
 | 
			
		||||
	switch (best_path->pathtype)
 | 
			
		||||
	{
 | 
			
		||||
		case T_SeqScan:
 | 
			
		||||
			plan = (Scan *) create_seqscan_plan(best_path,
 | 
			
		||||
			plan = (Scan *) create_seqscan_plan(root,
 | 
			
		||||
												best_path,
 | 
			
		||||
												tlist,
 | 
			
		||||
												scan_clauses);
 | 
			
		||||
			break;
 | 
			
		||||
@@ -240,19 +238,22 @@ create_scan_plan(Query *root, Path *best_path)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case T_TidScan:
 | 
			
		||||
			plan = (Scan *) create_tidscan_plan((TidPath *) best_path,
 | 
			
		||||
			plan = (Scan *) create_tidscan_plan(root,
 | 
			
		||||
												(TidPath *) best_path,
 | 
			
		||||
												tlist,
 | 
			
		||||
												scan_clauses);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case T_SubqueryScan:
 | 
			
		||||
			plan = (Scan *) create_subqueryscan_plan(best_path,
 | 
			
		||||
			plan = (Scan *) create_subqueryscan_plan(root,
 | 
			
		||||
													 best_path,
 | 
			
		||||
													 tlist,
 | 
			
		||||
													 scan_clauses);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case T_FunctionScan:
 | 
			
		||||
			plan = (Scan *) create_functionscan_plan(best_path,
 | 
			
		||||
			plan = (Scan *) create_functionscan_plan(root,
 | 
			
		||||
													 best_path,
 | 
			
		||||
													 tlist,
 | 
			
		||||
													 scan_clauses);
 | 
			
		||||
			break;
 | 
			
		||||
@@ -667,7 +668,8 @@ create_unique_plan(Query *root, UniquePath *best_path)
 | 
			
		||||
 *	 with restriction clauses 'scan_clauses' and targetlist 'tlist'.
 | 
			
		||||
 */
 | 
			
		||||
static SeqScan *
 | 
			
		||||
create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
create_seqscan_plan(Query *root, Path *best_path,
 | 
			
		||||
					List *tlist, List *scan_clauses)
 | 
			
		||||
{
 | 
			
		||||
	SeqScan    *scan_plan;
 | 
			
		||||
	Index		scan_relid = best_path->parent->relid;
 | 
			
		||||
@@ -676,6 +678,12 @@ create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
	Assert(scan_relid > 0);
 | 
			
		||||
	Assert(best_path->parent->rtekind == RTE_RELATION);
 | 
			
		||||
 | 
			
		||||
	/* Reduce RestrictInfo list to bare expressions */
 | 
			
		||||
	scan_clauses = get_actual_clauses(scan_clauses);
 | 
			
		||||
 | 
			
		||||
	/* Sort clauses into best execution order */
 | 
			
		||||
	scan_clauses = order_qual_clauses(root, scan_clauses);
 | 
			
		||||
 | 
			
		||||
	scan_plan = make_seqscan(tlist,
 | 
			
		||||
							 scan_clauses,
 | 
			
		||||
							 scan_relid);
 | 
			
		||||
@@ -690,9 +698,9 @@ create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
 *	  Returns a indexscan plan for the base relation scanned by 'best_path'
 | 
			
		||||
 *	  with restriction clauses 'scan_clauses' and targetlist 'tlist'.
 | 
			
		||||
 *
 | 
			
		||||
 * The indexqual of the path contains a sublist of implicitly-ANDed qual
 | 
			
		||||
 * conditions for each scan of the index(es); if there is more than one
 | 
			
		||||
 * scan then the retrieved tuple sets are ORed together.  The indexqual
 | 
			
		||||
 * The indexquals list of the path contains a sublist of implicitly-ANDed
 | 
			
		||||
 * qual conditions for each scan of the index(es); if there is more than one
 | 
			
		||||
 * scan then the retrieved tuple sets are ORed together.  The indexquals
 | 
			
		||||
 * and indexinfo lists must have the same length, ie, the number of scans
 | 
			
		||||
 * that will occur.  Note it is possible for a qual condition sublist
 | 
			
		||||
 * to be empty --- then no index restrictions will be applied during that
 | 
			
		||||
@@ -704,16 +712,17 @@ create_indexscan_plan(Query *root,
 | 
			
		||||
					  List *tlist,
 | 
			
		||||
					  List *scan_clauses)
 | 
			
		||||
{
 | 
			
		||||
	List	   *indxqual = best_path->indexqual;
 | 
			
		||||
	List	   *indxquals = best_path->indexquals;
 | 
			
		||||
	Index		baserelid = best_path->path.parent->relid;
 | 
			
		||||
	List	   *qpqual;
 | 
			
		||||
	Expr	   *indxqual_or_expr = NULL;
 | 
			
		||||
	List	   *fixed_indxqual;
 | 
			
		||||
	List	   *recheck_indxqual;
 | 
			
		||||
	List	   *stripped_indxquals;
 | 
			
		||||
	List	   *fixed_indxquals;
 | 
			
		||||
	List	   *recheck_indxquals;
 | 
			
		||||
	List	   *indxstrategy;
 | 
			
		||||
	List	   *indxsubtype;
 | 
			
		||||
	FastList	indexids;
 | 
			
		||||
	List	   *ixinfo;
 | 
			
		||||
	List	   *i;
 | 
			
		||||
	IndexScan  *scan_plan;
 | 
			
		||||
 | 
			
		||||
	/* it should be a base rel... */
 | 
			
		||||
@@ -721,64 +730,94 @@ create_indexscan_plan(Query *root,
 | 
			
		||||
	Assert(best_path->path.parent->rtekind == RTE_RELATION);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Build list of index OIDs.
 | 
			
		||||
	 * If this is a innerjoin scan, the indexclauses will contain join
 | 
			
		||||
	 * clauses that are not present in scan_clauses (since the passed-in
 | 
			
		||||
	 * value is just the rel's baserestrictinfo list).  We must add these
 | 
			
		||||
	 * clauses to scan_clauses to ensure they get checked.  In most cases
 | 
			
		||||
	 * we will remove the join clauses again below, but if a join clause
 | 
			
		||||
	 * contains a lossy or special operator, we need to make sure it gets
 | 
			
		||||
	 * into scan_clauses.
 | 
			
		||||
	 */
 | 
			
		||||
	FastListInit(&indexids);
 | 
			
		||||
	foreach(ixinfo, best_path->indexinfo)
 | 
			
		||||
	if (best_path->isjoininner)
 | 
			
		||||
	{
 | 
			
		||||
		IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
 | 
			
		||||
		/*
 | 
			
		||||
		 * We don't currently support OR indexscans in joins, so we only
 | 
			
		||||
		 * need to worry about the plain AND case.  Also, pointer comparison
 | 
			
		||||
		 * should be enough to determine RestrictInfo matches.
 | 
			
		||||
		 */
 | 
			
		||||
		Assert(length(best_path->indexclauses) == 1);
 | 
			
		||||
		scan_clauses = set_ptrUnion(scan_clauses,
 | 
			
		||||
									(List *) lfirst(best_path->indexclauses));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Reduce RestrictInfo list to bare expressions */
 | 
			
		||||
	scan_clauses = get_actual_clauses(scan_clauses);
 | 
			
		||||
 | 
			
		||||
	/* Sort clauses into best execution order */
 | 
			
		||||
	scan_clauses = order_qual_clauses(root, scan_clauses);
 | 
			
		||||
 | 
			
		||||
	/* Build list of index OIDs */
 | 
			
		||||
	FastListInit(&indexids);
 | 
			
		||||
	foreach(i, best_path->indexinfo)
 | 
			
		||||
	{
 | 
			
		||||
		IndexOptInfo *index = (IndexOptInfo *) lfirst(i);
 | 
			
		||||
 | 
			
		||||
		FastAppendo(&indexids, index->indexoid);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Build "stripped" indexquals structure (no RestrictInfos) to pass to
 | 
			
		||||
	 * executor as indxqualorig
 | 
			
		||||
	 */
 | 
			
		||||
	stripped_indxquals = NIL;
 | 
			
		||||
	foreach(i, indxquals)
 | 
			
		||||
	{
 | 
			
		||||
		List   *andlist = (List *) lfirst(i);
 | 
			
		||||
 | 
			
		||||
		stripped_indxquals = lappend(stripped_indxquals,
 | 
			
		||||
									 get_actual_clauses(andlist));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The qpqual list must contain all restrictions not automatically
 | 
			
		||||
	 * handled by the index.  Normally the predicates in the indxqual are
 | 
			
		||||
	 * handled by the index.  Normally the predicates in the indexquals are
 | 
			
		||||
	 * checked fully by the index, but if the index is "lossy" for a
 | 
			
		||||
	 * particular operator (as signaled by the amopreqcheck flag in
 | 
			
		||||
	 * pg_amop), then we need to double-check that predicate in qpqual,
 | 
			
		||||
	 * because the index may return more tuples than match the predicate.
 | 
			
		||||
	 *
 | 
			
		||||
	 * Since the indexquals were generated from the restriction clauses given
 | 
			
		||||
	 * by scan_clauses, there will normally be some duplications between
 | 
			
		||||
	 * the lists.  We get rid of the duplicates, then add back if lossy.
 | 
			
		||||
	 * by scan_clauses, there will normally be duplications between the lists.
 | 
			
		||||
	 * We get rid of the duplicates, then add back if lossy.
 | 
			
		||||
	 */
 | 
			
		||||
	if (length(indxqual) > 1)
 | 
			
		||||
	if (length(indxquals) > 1)
 | 
			
		||||
	{
 | 
			
		||||
		/*
 | 
			
		||||
		 * Build an expression representation of the indexqual, expanding
 | 
			
		||||
		 * the implicit OR and AND semantics of the first- and
 | 
			
		||||
		 * second-level lists.
 | 
			
		||||
		 */
 | 
			
		||||
		FastList	orclauses;
 | 
			
		||||
		List	   *orclause;
 | 
			
		||||
 | 
			
		||||
		FastListInit(&orclauses);
 | 
			
		||||
		foreach(orclause, indxqual)
 | 
			
		||||
			FastAppend(&orclauses, make_ands_explicit(lfirst(orclause)));
 | 
			
		||||
		indxqual_or_expr = make_orclause(FastListValue(&orclauses));
 | 
			
		||||
 | 
			
		||||
		indxqual_or_expr = make_expr_from_indexclauses(indxquals);
 | 
			
		||||
		qpqual = set_difference(scan_clauses, makeList1(indxqual_or_expr));
 | 
			
		||||
	}
 | 
			
		||||
	else if (indxqual != NIL)
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		/*
 | 
			
		||||
		 * 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));
 | 
			
		||||
		Assert(stripped_indxquals != NIL);
 | 
			
		||||
		qpqual = set_difference(scan_clauses, lfirst(stripped_indxquals));
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		qpqual = scan_clauses;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The executor needs a copy with the indexkey on the left of each
 | 
			
		||||
	 * clause and with index attr numbers substituted for table ones. This
 | 
			
		||||
	 * pass also looks for "lossy" operators.
 | 
			
		||||
	 */
 | 
			
		||||
	fix_indxqual_references(indxqual, best_path,
 | 
			
		||||
							&fixed_indxqual, &recheck_indxqual,
 | 
			
		||||
	fix_indxqual_references(indxquals, best_path,
 | 
			
		||||
							&fixed_indxquals, &recheck_indxquals,
 | 
			
		||||
							&indxstrategy, &indxsubtype);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -786,10 +825,10 @@ create_indexscan_plan(Query *root,
 | 
			
		||||
	 * appropriate qual clauses to the qpqual.	When there is just one
 | 
			
		||||
	 * indexscan being performed (ie, we have simple AND semantics), we
 | 
			
		||||
	 * can just add the lossy clauses themselves to qpqual.  If we have
 | 
			
		||||
	 * OR-of-ANDs, we'd better add the entire original indexqual to make
 | 
			
		||||
	 * OR-of-ANDs, we'd better add the entire original indexquals to make
 | 
			
		||||
	 * sure that the semantics are correct.
 | 
			
		||||
	 */
 | 
			
		||||
	if (recheck_indxqual != NIL)
 | 
			
		||||
	if (recheck_indxquals != NIL)
 | 
			
		||||
	{
 | 
			
		||||
		if (indxqual_or_expr)
 | 
			
		||||
		{
 | 
			
		||||
@@ -799,8 +838,8 @@ create_indexscan_plan(Query *root,
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			/* Subroutine already copied quals, so just append to list */
 | 
			
		||||
			Assert(length(recheck_indxqual) == 1);
 | 
			
		||||
			qpqual = nconc(qpqual, (List *) lfirst(recheck_indxqual));
 | 
			
		||||
			Assert(length(recheck_indxquals) == 1);
 | 
			
		||||
			qpqual = nconc(qpqual, (List *) lfirst(recheck_indxquals));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -809,8 +848,8 @@ create_indexscan_plan(Query *root,
 | 
			
		||||
							   qpqual,
 | 
			
		||||
							   baserelid,
 | 
			
		||||
							   FastListValue(&indexids),
 | 
			
		||||
							   fixed_indxqual,
 | 
			
		||||
							   indxqual,
 | 
			
		||||
							   fixed_indxquals,
 | 
			
		||||
							   stripped_indxquals,
 | 
			
		||||
							   indxstrategy,
 | 
			
		||||
							   indxsubtype,
 | 
			
		||||
							   best_path->indexscandir);
 | 
			
		||||
@@ -828,7 +867,8 @@ create_indexscan_plan(Query *root,
 | 
			
		||||
 *	 with restriction clauses 'scan_clauses' and targetlist 'tlist'.
 | 
			
		||||
 */
 | 
			
		||||
static TidScan *
 | 
			
		||||
create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
create_tidscan_plan(Query *root, TidPath *best_path,
 | 
			
		||||
					List *tlist, List *scan_clauses)
 | 
			
		||||
{
 | 
			
		||||
	TidScan    *scan_plan;
 | 
			
		||||
	Index		scan_relid = best_path->path.parent->relid;
 | 
			
		||||
@@ -837,6 +877,12 @@ create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
	Assert(scan_relid > 0);
 | 
			
		||||
	Assert(best_path->path.parent->rtekind == RTE_RELATION);
 | 
			
		||||
 | 
			
		||||
	/* Reduce RestrictInfo list to bare expressions */
 | 
			
		||||
	scan_clauses = get_actual_clauses(scan_clauses);
 | 
			
		||||
 | 
			
		||||
	/* Sort clauses into best execution order */
 | 
			
		||||
	scan_clauses = order_qual_clauses(root, scan_clauses);
 | 
			
		||||
 | 
			
		||||
	scan_plan = make_tidscan(tlist,
 | 
			
		||||
							 scan_clauses,
 | 
			
		||||
							 scan_relid,
 | 
			
		||||
@@ -853,7 +899,8 @@ create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
 *	 with restriction clauses 'scan_clauses' and targetlist 'tlist'.
 | 
			
		||||
 */
 | 
			
		||||
static SubqueryScan *
 | 
			
		||||
create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
create_subqueryscan_plan(Query *root, Path *best_path,
 | 
			
		||||
						 List *tlist, List *scan_clauses)
 | 
			
		||||
{
 | 
			
		||||
	SubqueryScan *scan_plan;
 | 
			
		||||
	Index		scan_relid = best_path->parent->relid;
 | 
			
		||||
@@ -862,6 +909,12 @@ create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
	Assert(scan_relid > 0);
 | 
			
		||||
	Assert(best_path->parent->rtekind == RTE_SUBQUERY);
 | 
			
		||||
 | 
			
		||||
	/* Reduce RestrictInfo list to bare expressions */
 | 
			
		||||
	scan_clauses = get_actual_clauses(scan_clauses);
 | 
			
		||||
 | 
			
		||||
	/* Sort clauses into best execution order */
 | 
			
		||||
	scan_clauses = order_qual_clauses(root, scan_clauses);
 | 
			
		||||
 | 
			
		||||
	scan_plan = make_subqueryscan(tlist,
 | 
			
		||||
								  scan_clauses,
 | 
			
		||||
								  scan_relid,
 | 
			
		||||
@@ -878,7 +931,8 @@ create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
 *	 with restriction clauses 'scan_clauses' and targetlist 'tlist'.
 | 
			
		||||
 */
 | 
			
		||||
static FunctionScan *
 | 
			
		||||
create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
create_functionscan_plan(Query *root, Path *best_path,
 | 
			
		||||
						 List *tlist, List *scan_clauses)
 | 
			
		||||
{
 | 
			
		||||
	FunctionScan *scan_plan;
 | 
			
		||||
	Index		scan_relid = best_path->parent->relid;
 | 
			
		||||
@@ -887,6 +941,12 @@ create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses)
 | 
			
		||||
	Assert(scan_relid > 0);
 | 
			
		||||
	Assert(best_path->parent->rtekind == RTE_FUNCTION);
 | 
			
		||||
 | 
			
		||||
	/* Reduce RestrictInfo list to bare expressions */
 | 
			
		||||
	scan_clauses = get_actual_clauses(scan_clauses);
 | 
			
		||||
 | 
			
		||||
	/* Sort clauses into best execution order */
 | 
			
		||||
	scan_clauses = order_qual_clauses(root, scan_clauses);
 | 
			
		||||
 | 
			
		||||
	scan_plan = make_functionscan(tlist, scan_clauses, scan_relid);
 | 
			
		||||
 | 
			
		||||
	copy_path_costsize(&scan_plan->scan.plan, best_path);
 | 
			
		||||
@@ -928,20 +988,19 @@ create_nestloop_plan(Query *root,
 | 
			
		||||
		 * have caught this case because the join clauses would never have
 | 
			
		||||
		 * been put in the same joininfo list.
 | 
			
		||||
		 *
 | 
			
		||||
		 * This would be a waste of time if the indexpath was an ordinary
 | 
			
		||||
		 * indexpath and not a special innerjoin path.	We will skip it in
 | 
			
		||||
		 * that case since indexjoinclauses is NIL in an ordinary
 | 
			
		||||
		 * indexpath.
 | 
			
		||||
		 * We can skip this if the index path is an ordinary indexpath and
 | 
			
		||||
		 * not a special innerjoin path.
 | 
			
		||||
		 */
 | 
			
		||||
		IndexPath  *innerpath = (IndexPath *) best_path->innerjoinpath;
 | 
			
		||||
		List	   *indexjoinclauses = innerpath->indexjoinclauses;
 | 
			
		||||
		List	   *indexclauses = innerpath->indexclauses;
 | 
			
		||||
 | 
			
		||||
		if (length(indexjoinclauses) == 1)		/* single indexscan? */
 | 
			
		||||
		if (innerpath->isjoininner &&
 | 
			
		||||
			length(indexclauses) == 1)		/* single indexscan? */
 | 
			
		||||
		{
 | 
			
		||||
			joinrestrictclauses =
 | 
			
		||||
				select_nonredundant_join_clauses(root,
 | 
			
		||||
												 joinrestrictclauses,
 | 
			
		||||
												 lfirst(indexjoinclauses),
 | 
			
		||||
												 lfirst(indexclauses),
 | 
			
		||||
												 best_path->jointype);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -1138,7 +1197,8 @@ create_hashjoin_plan(Query *root,
 | 
			
		||||
 *	  Adjust indexqual clauses to the form the executor's indexqual
 | 
			
		||||
 *	  machinery needs, and check for recheckable (lossy) index conditions.
 | 
			
		||||
 *
 | 
			
		||||
 * We have four tasks here:
 | 
			
		||||
 * We have five tasks here:
 | 
			
		||||
 *	* Remove RestrictInfo nodes from the input clauses.
 | 
			
		||||
 *	* Index keys must be represented by Var nodes with varattno set to the
 | 
			
		||||
 *	  index's attribute number, not the attribute number in the original rel.
 | 
			
		||||
 *	* If the index key is on the right, commute the clause to put it on the
 | 
			
		||||
@@ -1154,14 +1214,15 @@ create_hashjoin_plan(Query *root,
 | 
			
		||||
 *
 | 
			
		||||
 * Both the input list and the output lists have the form of lists of sublists
 | 
			
		||||
 * of qual clauses --- the top-level list has one entry for each indexscan
 | 
			
		||||
 * to be performed.  The semantics are OR-of-ANDs.
 | 
			
		||||
 * to be performed.  The semantics are OR-of-ANDs.  Note however that the
 | 
			
		||||
 * input list contains RestrictInfos, while the output lists do not.
 | 
			
		||||
 *
 | 
			
		||||
 * fixed_indexquals receives a modified copy of the indexqual list --- the
 | 
			
		||||
 * original is not changed.  Note also that the copy shares no substructure
 | 
			
		||||
 * with the original; this is needed in case there is a subplan in it (we need
 | 
			
		||||
 * two separate copies of the subplan tree, or things will go awry).
 | 
			
		||||
 *
 | 
			
		||||
 * recheck_indexquals similarly receives a full copy of whichever clauses
 | 
			
		||||
 * recheck_indexquals similarly receives a copy of whichever clauses
 | 
			
		||||
 * need rechecking.
 | 
			
		||||
 *
 | 
			
		||||
 * indxstrategy receives a list of integer sublists of strategy numbers.
 | 
			
		||||
@@ -1243,14 +1304,16 @@ fix_indxqual_sublist(List *indexqual,
 | 
			
		||||
	*subtype = NIL;
 | 
			
		||||
	foreach(i, indexqual)
 | 
			
		||||
	{
 | 
			
		||||
		OpExpr	   *clause = (OpExpr *) lfirst(i);
 | 
			
		||||
		RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
 | 
			
		||||
		OpExpr	   *clause;
 | 
			
		||||
		OpExpr	   *newclause;
 | 
			
		||||
		Relids		leftvarnos;
 | 
			
		||||
		Oid			opclass;
 | 
			
		||||
		int			stratno;
 | 
			
		||||
		Oid			stratsubtype;
 | 
			
		||||
		bool		recheck;
 | 
			
		||||
 | 
			
		||||
		Assert(IsA(rinfo, RestrictInfo));
 | 
			
		||||
		clause = (OpExpr *) rinfo->clause;
 | 
			
		||||
		if (!IsA(clause, OpExpr) ||
 | 
			
		||||
			length(clause->args) != 2)
 | 
			
		||||
			elog(ERROR, "indexqual clause is not binary opclause");
 | 
			
		||||
@@ -1269,10 +1332,8 @@ fix_indxqual_sublist(List *indexqual,
 | 
			
		||||
		 * the clause.	The indexkey should be the side that refers to
 | 
			
		||||
		 * (only) the base relation.
 | 
			
		||||
		 */
 | 
			
		||||
		leftvarnos = pull_varnos((Node *) lfirst(newclause->args));
 | 
			
		||||
		if (!bms_equal(leftvarnos, baserelids))
 | 
			
		||||
		if (!bms_equal(rinfo->left_relids, baserelids))
 | 
			
		||||
			CommuteClause(newclause);
 | 
			
		||||
		bms_free(leftvarnos);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Now, determine which index attribute this is, change the
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user