allpaths.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 1,160 行 · 第 1/3 页

C
1,160
字号
	foreach(l, tlist)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		if (tle->resjunk)			continue;			/* ignore resjunk columns */		if (colType == NULL)			elog(ERROR, "wrong number of tlist entries");		if (exprType((Node *) tle->expr) != lfirst_oid(colType))			differentTypes[tle->resno] = true;		colType = lnext(colType);	}	if (colType != NULL)		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 the whole-row output of the subquery * (since there is no easy way to name that within the subquery itself). * * 3. 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(). * * 4. 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. * * 5. 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;	ListCell   *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);		/* Check point 2 */		if (var->varattno == 0)		{			safe = false;			break;		}		/*		 * 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 3 */		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->resjunk);		/* If subquery uses DISTINCT or DISTINCT ON, check point 4 */		if (subquery->distinctClause != NIL &&			!targetIsInSortList(tle, subquery->distinctClause))		{			/* non-DISTINCT column, so fail */			safe = false;			break;		}		/* Refuse functions returning sets (point 5) */		if (expression_returns_set((Node *) tle->expr))		{			safe = false;			break;		}	}	list_free(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, RangeTblEntry *rte, Index rti, Node *qual){	if (subquery->setOperations != NULL)	{		/* Recurse to push it separately to each component query */		recurse_push_qual(subquery->setOperations, subquery,						  rte, 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, rte,						  subquery->targetList,						  CMD_SELECT, 0);		/*		 * Now attach the qual to the proper place: normally WHERE, but if the		 * subquery uses grouping or aggregation, put it in HAVING (since the		 * qual really refers to the group-result rows).		 */		if (subquery->hasAggs || subquery->groupClause || subquery->havingQual)			subquery->havingQual = make_and_qual(subquery->havingQual, qual);		else			subquery->jointree->quals =				make_and_qual(subquery->jointree->quals, 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,				  RangeTblEntry *rte, Index rti, Node *qual){	if (IsA(setOp, RangeTblRef))	{		RangeTblRef *rtr = (RangeTblRef *) setOp;		RangeTblEntry *subrte = rt_fetch(rtr->rtindex, topquery->rtable);		Query	   *subquery = subrte->subquery;		Assert(subquery != NULL);		subquery_push_qual(subquery, rte, rti, qual);	}	else if (IsA(setOp, SetOperationStmt))	{		SetOperationStmt *op = (SetOperationStmt *) setOp;		recurse_push_qual(op->larg, topquery, rte, rti, qual);		recurse_push_qual(op->rarg, topquery, rte, 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(PlannerInfo *root, List *clauses){	ListCell   *l;	foreach(l, clauses)	{		RestrictInfo *c = lfirst(l);		print_expr((Node *) c->clause, root->parse->rtable);		if (lnext(l))			printf(", ");	}}static voidprint_path(PlannerInfo *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_BitmapHeapPath:			ptype = "BitmapHeapScan";			break;		case T_BitmapAndPath:			ptype = "BitmapAndPath";			break;		case T_BitmapOrPath:			ptype = "BitmapOrPath";			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->parse->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(PlannerInfo *root, RelOptInfo *rel){	ListCell   *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");	}	if (rel->joininfo)	{		printf("\tjoininfo: ");		print_restrictclauses(root, rel->joininfo);		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 + -
显示快捷键?