allpaths.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,027 行 · 第 1/2 页

C
1,027
字号
		 * pair of lower-level relations.		 */		joinitems[lev] = make_rels_by_joins(root, lev, joinitems);		/*		 * Do cleanup work on each just-processed rel.		 */		foreach(x, joinitems[lev])		{			rel = (RelOptInfo *) lfirst(x);#ifdef NOT_USED			/*			 * * for each expensive predicate in each path in each			 * distinct rel, * consider doing pullup  -- JMH			 */			if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)				xfunc_trypullup(rel);#endif			/* Find and save the cheapest paths for this rel */			set_cheapest(rel);#ifdef OPTIMIZER_DEBUG			debug_print_rel(root, rel);#endif		}	}	/*	 * We should have a single rel at the final level.	 */	if (joinitems[levels_needed] == NIL)		elog(ERROR, "failed to build any %d-way joins", levels_needed);	Assert(length(joinitems[levels_needed]) == 1);	rel = (RelOptInfo *) lfirst(joinitems[levels_needed]);	return rel;}/***************************************************************************** *			PUSHING QUALS DOWN INTO SUBQUERIES *****************************************************************************//* * subquery_is_pushdown_safe - is a subquery safe for pushing down quals? * * subquery is the particular component query being checked.  topquery * is the top component of a set-operations tree (the same Query if no * set-op is involved). * * Conditions checked here: * * 1. If the subquery has a LIMIT clause, we must not push down any quals, * since that could change the set of rows returned. * * 2. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push * quals into it, because that would change the results. * * 3. For subqueries using UNION/UNION ALL/INTERSECT/INTERSECT ALL, we can * push quals into each component query, but the quals can only reference * subquery columns that suffer no type coercions in the set operation. * Otherwise there are possible semantic gotchas.  So, we check the * component queries to see if any of them have different output types; * differentTypes[k] is set true if column k has different type in any * component. */static boolsubquery_is_pushdown_safe(Query *subquery, Query *topquery,						  bool *differentTypes){	SetOperationStmt *topop;	/* Check point 1 */	if (subquery->limitOffset != NULL || subquery->limitCount != NULL)		return false;	/* Are we at top level, or looking at a setop component? */	if (subquery == topquery)	{		/* Top level, so check any component queries */		if (subquery->setOperations != NULL)			if (!recurse_pushdown_safe(subquery->setOperations, topquery,									   differentTypes))				return false;	}	else	{		/* Setop component must not have more components (too weird) */		if (subquery->setOperations != NULL)			return false;		/* Check whether setop component output types match top level */		topop = (SetOperationStmt *) topquery->setOperations;		Assert(topop && IsA(topop, SetOperationStmt));		compare_tlist_datatypes(subquery->targetList,								topop->colTypes,								differentTypes);	}	return true;}/* * Helper routine to recurse through setOperations tree */static boolrecurse_pushdown_safe(Node *setOp, Query *topquery,					  bool *differentTypes){	if (IsA(setOp, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) setOp;		RangeTblEntry *rte = rt_fetch(rtr->rtindex, topquery->rtable);		Query	   *subquery = rte->subquery;		Assert(subquery != NULL);		return subquery_is_pushdown_safe(subquery, topquery, differentTypes);	}	else if (IsA(setOp, SetOperationStmt))	{		SetOperationStmt *op = (SetOperationStmt *) setOp;		/* EXCEPT is no good */		if (op->op == SETOP_EXCEPT)			return false;		/* Else recurse */		if (!recurse_pushdown_safe(op->larg, topquery, differentTypes))			return false;		if (!recurse_pushdown_safe(op->rarg, topquery, differentTypes))			return false;	}	else	{		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(setOp));	}	return true;}/* * Compare tlist's datatypes against the list of set-operation result types. * For any items that are different, mark the appropriate element of * differentTypes[] to show that this column will have type conversions. */static voidcompare_tlist_datatypes(List *tlist, List *colTypes,						bool *differentTypes){	List	   *i;	foreach(i, tlist)	{		TargetEntry *tle = (TargetEntry *) lfirst(i);		if (tle->resdom->resjunk)			continue;			/* ignore resjunk columns */		if (colTypes == NIL)			elog(ERROR, "wrong number of tlist entries");		if (tle->resdom->restype != lfirsto(colTypes))			differentTypes[tle->resdom->resno] = true;		colTypes = lnext(colTypes);	}	if (colTypes != NIL)		elog(ERROR, "wrong number of tlist entries");}/* * qual_is_pushdown_safe - is a particular qual safe to push down? * * qual is a restriction clause applying to the given subquery (whose RTE * has index rti in the parent query). * * Conditions checked here: * * 1. The qual must not contain any subselects (mainly because I'm not sure * it will work correctly: sublinks will already have been transformed into * subplans in the qual, but not in the subquery). * * 2. The qual must not refer to any subquery output columns that were * found to have inconsistent types across a set operation tree by * subquery_is_pushdown_safe(). * * 3. If the subquery uses DISTINCT ON, we must not push down any quals that * refer to non-DISTINCT output columns, because that could change the set * of rows returned.  This condition is vacuous for DISTINCT, because then * there are no non-DISTINCT output columns, but unfortunately it's fairly * expensive to tell the difference between DISTINCT and DISTINCT ON in the * parsetree representation.  It's cheaper to just make sure all the Vars * in the qual refer to DISTINCT columns. * * 4. We must not push down any quals that refer to subselect outputs that * return sets, else we'd introduce functions-returning-sets into the * subquery's WHERE/HAVING quals. */static boolqual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,					  bool *differentTypes){	bool		safe = true;	List	   *vars;	List	   *vl;	Bitmapset  *tested = NULL;	/* Refuse subselects (point 1) */	if (contain_subplans(qual))		return false;	/*	 * Examine all Vars used in clause; since it's a restriction clause,	 * all such Vars must refer to subselect output columns.	 */	vars = pull_var_clause(qual, false);	foreach(vl, vars)	{		Var		   *var = (Var *) lfirst(vl);		TargetEntry *tle;		Assert(var->varno == rti);		/*		 * We use a bitmapset to avoid testing the same attno more than		 * once.  (NB: this only works because subquery outputs can't have		 * negative attnos.)		 */		if (bms_is_member(var->varattno, tested))			continue;		tested = bms_add_member(tested, var->varattno);		/* Check point 2 */		if (differentTypes[var->varattno])		{			safe = false;			break;		}		/* Must find the tlist element referenced by the Var */		tle = get_tle_by_resno(subquery->targetList, var->varattno);		Assert(tle != NULL);		Assert(!tle->resdom->resjunk);		/* If subquery uses DISTINCT or DISTINCT ON, check point 3 */		if (subquery->distinctClause != NIL &&			!targetIsInSortList(tle, subquery->distinctClause))		{			/* non-DISTINCT column, so fail */			safe = false;			break;		}		/* Refuse functions returning sets (point 4) */		if (expression_returns_set((Node *) tle->expr))		{			safe = false;			break;		}	}	freeList(vars);	bms_free(tested);	return safe;}/* * subquery_push_qual - push down a qual that we have determined is safe */static voidsubquery_push_qual(Query *subquery, Index rti, Node *qual){	if (subquery->setOperations != NULL)	{		/* Recurse to push it separately to each component query */		recurse_push_qual(subquery->setOperations, subquery, rti, qual);	}	else	{		/*		 * We need to replace Vars in the qual (which must refer to		 * outputs of the subquery) with copies of the subquery's		 * targetlist expressions.	Note that at this point, any uplevel		 * Vars in the qual should have been replaced with Params, so they		 * need no work.		 *		 * This step also ensures that when we are pushing into a setop tree,		 * each component query gets its own copy of the qual.		 */		qual = ResolveNew(qual, rti, 0,						  subquery->targetList,						  CMD_SELECT, 0);		subquery->havingQual = make_and_qual(subquery->havingQual,											 qual);		/*		 * We need not change the subquery's hasAggs or hasSublinks flags,		 * since we can't be pushing down any aggregates that weren't		 * there before, and we don't push down subselects at all.		 */	}}/* * Helper routine to recurse through setOperations tree */static voidrecurse_push_qual(Node *setOp, Query *topquery,				  Index rti, Node *qual){	if (IsA(setOp, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) setOp;		RangeTblEntry *rte = rt_fetch(rtr->rtindex, topquery->rtable);		Query	   *subquery = rte->subquery;		Assert(subquery != NULL);		subquery_push_qual(subquery, rti, qual);	}	else if (IsA(setOp, SetOperationStmt))	{		SetOperationStmt *op = (SetOperationStmt *) setOp;		recurse_push_qual(op->larg, topquery, rti, qual);		recurse_push_qual(op->rarg, topquery, rti, qual);	}	else	{		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(setOp));	}}/***************************************************************************** *			DEBUG SUPPORT *****************************************************************************/#ifdef OPTIMIZER_DEBUGstatic voidprint_relids(Relids relids){	Relids		tmprelids;	int			x;	bool		first = true;	tmprelids = bms_copy(relids);	while ((x = bms_first_member(tmprelids)) >= 0)	{		if (!first)			printf(" ");		printf("%d", x);		first = false;	}	bms_free(tmprelids);}static voidprint_restrictclauses(Query *root, List *clauses){	List	   *l;	foreach(l, clauses)	{		RestrictInfo *c = lfirst(l);		print_expr((Node *) c->clause, root->rtable);		if (lnext(l))			printf(", ");	}}static voidprint_path(Query *root, Path *path, int indent){	const char *ptype;	bool		join = false;	Path	   *subpath = NULL;	int			i;	switch (nodeTag(path))	{		case T_Path:			ptype = "SeqScan";			break;		case T_IndexPath:			ptype = "IdxScan";			break;		case T_TidPath:			ptype = "TidScan";			break;		case T_AppendPath:			ptype = "Append";			break;		case T_ResultPath:			ptype = "Result";			subpath = ((ResultPath *) path)->subpath;			break;		case T_MaterialPath:			ptype = "Material";			subpath = ((MaterialPath *) path)->subpath;			break;		case T_UniquePath:			ptype = "Unique";			subpath = ((UniquePath *) path)->subpath;			break;		case T_NestPath:			ptype = "NestLoop";			join = true;			break;		case T_MergePath:			ptype = "MergeJoin";			join = true;			break;		case T_HashPath:			ptype = "HashJoin";			join = true;			break;		default:			ptype = "???Path";			break;	}	for (i = 0; i < indent; i++)		printf("\t");	printf("%s", ptype);	if (path->parent)	{		printf("(");		print_relids(path->parent->relids);		printf(") rows=%.0f", path->parent->rows);	}	printf(" cost=%.2f..%.2f\n", path->startup_cost, path->total_cost);	if (path->pathkeys)	{		for (i = 0; i < indent; i++)			printf("\t");		printf("  pathkeys: ");		print_pathkeys(path->pathkeys, root->rtable);	}	if (join)	{		JoinPath   *jp = (JoinPath *) path;		for (i = 0; i < indent; i++)			printf("\t");		printf("  clauses: ");		print_restrictclauses(root, jp->joinrestrictinfo);		printf("\n");		if (IsA(path, MergePath))		{			MergePath  *mp = (MergePath *) path;			if (mp->outersortkeys || mp->innersortkeys)			{				for (i = 0; i < indent; i++)					printf("\t");				printf("  sortouter=%d sortinner=%d\n",					   ((mp->outersortkeys) ? 1 : 0),					   ((mp->innersortkeys) ? 1 : 0));			}		}		print_path(root, jp->outerjoinpath, indent + 1);		print_path(root, jp->innerjoinpath, indent + 1);	}	if (subpath)		print_path(root, subpath, indent + 1);}voiddebug_print_rel(Query *root, RelOptInfo *rel){	List	   *l;	printf("RELOPTINFO (");	print_relids(rel->relids);	printf("): rows=%.0f width=%d\n", rel->rows, rel->width);	if (rel->baserestrictinfo)	{		printf("\tbaserestrictinfo: ");		print_restrictclauses(root, rel->baserestrictinfo);		printf("\n");	}	foreach(l, rel->joininfo)	{		JoinInfo   *j = (JoinInfo *) lfirst(l);		printf("\tjoininfo (");		print_relids(j->unjoined_relids);		printf("): ");		print_restrictclauses(root, j->jinfo_restrictinfo);		printf("\n");	}	printf("\tpath list:\n");	foreach(l, rel->pathlist)		print_path(root, lfirst(l), 1);	printf("\n\tcheapest startup path:\n");	print_path(root, rel->cheapest_startup_path, 1);	printf("\n\tcheapest total path:\n");	print_path(root, rel->cheapest_total_path, 1);	printf("\n");	fflush(stdout);}#endif   /* OPTIMIZER_DEBUG */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?