⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 explain.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	appendStringInfoString(str, pname);	switch (nodeTag(plan))	{		case T_IndexScan:			if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))				appendStringInfoString(str, " Backward");			appendStringInfo(str, " using %s",			  quote_identifier(get_rel_name(((IndexScan *) plan)->indexid)));			/* FALL THRU */		case T_SeqScan:		case T_BitmapHeapScan:		case T_TidScan:			if (((Scan *) plan)->scanrelid > 0)			{				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,											  es->rtable);				char	   *relname;				/* Assume it's on a real relation */				Assert(rte->rtekind == RTE_RELATION);				/* We only show the rel name, not schema name */				relname = get_rel_name(rte->relid);				appendStringInfo(str, " on %s",								 quote_identifier(relname));				if (strcmp(rte->eref->aliasname, relname) != 0)					appendStringInfo(str, " %s",									 quote_identifier(rte->eref->aliasname));			}			break;		case T_BitmapIndexScan:			appendStringInfo(str, " on %s",							 quote_identifier(get_rel_name(((BitmapIndexScan *) plan)->indexid)));			break;		case T_SubqueryScan:			if (((Scan *) plan)->scanrelid > 0)			{				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,											  es->rtable);				appendStringInfo(str, " %s",								 quote_identifier(rte->eref->aliasname));			}			break;		case T_FunctionScan:			if (((Scan *) plan)->scanrelid > 0)			{				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,											  es->rtable);				char	   *proname;				/* Assert it's on a RangeFunction */				Assert(rte->rtekind == RTE_FUNCTION);				/*				 * If the expression is still a function call, we can get the				 * real name of the function.  Otherwise, punt (this can				 * happen if the optimizer simplified away the function call,				 * for example).				 */				if (rte->funcexpr && IsA(rte->funcexpr, FuncExpr))				{					FuncExpr   *funcexpr = (FuncExpr *) rte->funcexpr;					Oid			funcid = funcexpr->funcid;					/* We only show the func name, not schema name */					proname = get_func_name(funcid);				}				else					proname = rte->eref->aliasname;				appendStringInfo(str, " on %s",								 quote_identifier(proname));				if (strcmp(rte->eref->aliasname, proname) != 0)					appendStringInfo(str, " %s",									 quote_identifier(rte->eref->aliasname));			}			break;		default:			break;	}	appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",					 plan->startup_cost, plan->total_cost,					 plan->plan_rows, plan->plan_width);	/*	 * We have to forcibly clean up the instrumentation state because we	 * haven't done ExecutorEnd yet.  This is pretty grotty ...	 */	if (planstate->instrument)		InstrEndLoop(planstate->instrument);	if (planstate->instrument && planstate->instrument->nloops > 0)	{		double		nloops = planstate->instrument->nloops;		appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",						 1000.0 * planstate->instrument->startup / nloops,						 1000.0 * planstate->instrument->total / nloops,						 planstate->instrument->ntuples / nloops,						 planstate->instrument->nloops);	}	else if (es->printAnalyze)		appendStringInfo(str, " (never executed)");	appendStringInfoChar(str, '\n');	/* quals, sort keys, etc */	switch (nodeTag(plan))	{		case T_IndexScan:			show_scan_qual(((IndexScan *) plan)->indexqualorig,						   "Index Cond",						   ((Scan *) plan)->scanrelid,						   outer_plan,						   str, indent, es);			show_scan_qual(plan->qual,						   "Filter",						   ((Scan *) plan)->scanrelid,						   outer_plan,						   str, indent, es);			break;		case T_BitmapIndexScan:			show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,						   "Index Cond",						   ((Scan *) plan)->scanrelid,						   outer_plan,						   str, indent, es);			break;		case T_BitmapHeapScan:			/* XXX do we want to show this in production? */			show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,						   "Recheck Cond",						   ((Scan *) plan)->scanrelid,						   outer_plan,						   str, indent, es);			/* FALL THRU */		case T_SeqScan:		case T_TidScan:		case T_SubqueryScan:		case T_FunctionScan:			show_scan_qual(plan->qual,						   "Filter",						   ((Scan *) plan)->scanrelid,						   outer_plan,						   str, indent, es);			break;		case T_NestLoop:			show_upper_qual(((NestLoop *) plan)->join.joinqual,							"Join Filter",							"outer", OUTER, outerPlan(plan),							"inner", INNER, innerPlan(plan),							str, indent, es);			show_upper_qual(plan->qual,							"Filter",							"outer", OUTER, outerPlan(plan),							"inner", INNER, innerPlan(plan),							str, indent, es);			break;		case T_MergeJoin:			show_upper_qual(((MergeJoin *) plan)->mergeclauses,							"Merge Cond",							"outer", OUTER, outerPlan(plan),							"inner", INNER, innerPlan(plan),							str, indent, es);			show_upper_qual(((MergeJoin *) plan)->join.joinqual,							"Join Filter",							"outer", OUTER, outerPlan(plan),							"inner", INNER, innerPlan(plan),							str, indent, es);			show_upper_qual(plan->qual,							"Filter",							"outer", OUTER, outerPlan(plan),							"inner", INNER, innerPlan(plan),							str, indent, es);			break;		case T_HashJoin:			show_upper_qual(((HashJoin *) plan)->hashclauses,							"Hash Cond",							"outer", OUTER, outerPlan(plan),							"inner", INNER, innerPlan(plan),							str, indent, es);			show_upper_qual(((HashJoin *) plan)->join.joinqual,							"Join Filter",							"outer", OUTER, outerPlan(plan),							"inner", INNER, innerPlan(plan),							str, indent, es);			show_upper_qual(plan->qual,							"Filter",							"outer", OUTER, outerPlan(plan),							"inner", INNER, innerPlan(plan),							str, indent, es);			break;		case T_Agg:		case T_Group:			show_upper_qual(plan->qual,							"Filter",							"subplan", 0, outerPlan(plan),							"", 0, NULL,							str, indent, es);			break;		case T_Sort:			show_sort_keys(plan->targetlist,						   ((Sort *) plan)->numCols,						   ((Sort *) plan)->sortColIdx,						   "Sort Key",						   str, indent, es);			break;		case T_Result:			show_upper_qual((List *) ((Result *) plan)->resconstantqual,							"One-Time Filter",							"subplan", OUTER, outerPlan(plan),							"", 0, NULL,							str, indent, es);			show_upper_qual(plan->qual,							"Filter",							"subplan", OUTER, outerPlan(plan),							"", 0, NULL,							str, indent, es);			break;		default:			break;	}	/* initPlan-s */	if (plan->initPlan)	{		List	   *saved_rtable = es->rtable;		ListCell   *lst;		for (i = 0; i < indent; i++)			appendStringInfo(str, "  ");		appendStringInfo(str, "  InitPlan\n");		foreach(lst, planstate->initPlan)		{			SubPlanState *sps = (SubPlanState *) lfirst(lst);			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;			es->rtable = sp->rtable;			for (i = 0; i < indent; i++)				appendStringInfo(str, "  ");			appendStringInfo(str, "    ->  ");			explain_outNode(str, sp->plan,							sps->planstate,							NULL,							indent + 4, es);		}		es->rtable = saved_rtable;	}	/* lefttree */	if (outerPlan(plan))	{		for (i = 0; i < indent; i++)			appendStringInfo(str, "  ");		appendStringInfo(str, "  ->  ");		/*		 * Ordinarily we don't pass down our own outer_plan value to our child		 * nodes, but in bitmap scan trees we must, since the bottom		 * BitmapIndexScan nodes may have outer references.		 */		explain_outNode(str, outerPlan(plan),						outerPlanState(planstate),						IsA(plan, BitmapHeapScan) ? outer_plan : NULL,						indent + 3, es);	}	/* righttree */	if (innerPlan(plan))	{		for (i = 0; i < indent; i++)			appendStringInfo(str, "  ");		appendStringInfo(str, "  ->  ");		explain_outNode(str, innerPlan(plan),						innerPlanState(planstate),						outerPlan(plan),						indent + 3, es);	}	if (IsA(plan, Append))	{		Append	   *appendplan = (Append *) plan;		AppendState *appendstate = (AppendState *) planstate;		ListCell   *lst;		int			j;		j = 0;		foreach(lst, appendplan->appendplans)		{			Plan	   *subnode = (Plan *) lfirst(lst);			for (i = 0; i < indent; i++)				appendStringInfo(str, "  ");			appendStringInfo(str, "  ->  ");			explain_outNode(str, subnode,							appendstate->appendplans[j],							NULL,							indent + 3, es);			j++;		}	}	if (IsA(plan, BitmapAnd))	{		BitmapAnd  *bitmapandplan = (BitmapAnd *) plan;		BitmapAndState *bitmapandstate = (BitmapAndState *) planstate;		ListCell   *lst;		int			j;		j = 0;		foreach(lst, bitmapandplan->bitmapplans)		{			Plan	   *subnode = (Plan *) lfirst(lst);			for (i = 0; i < indent; i++)				appendStringInfo(str, "  ");			appendStringInfo(str, "  ->  ");			explain_outNode(str, subnode,							bitmapandstate->bitmapplans[j],							outer_plan, /* pass down same outer plan */							indent + 3, es);			j++;		}	}	if (IsA(plan, BitmapOr))	{		BitmapOr   *bitmaporplan = (BitmapOr *) plan;		BitmapOrState *bitmaporstate = (BitmapOrState *) planstate;		ListCell   *lst;		int			j;		j = 0;		foreach(lst, bitmaporplan->bitmapplans)		{			Plan	   *subnode = (Plan *) lfirst(lst);			for (i = 0; i < indent; i++)				appendStringInfo(str, "  ");			appendStringInfo(str, "  ->  ");			explain_outNode(str, subnode,							bitmaporstate->bitmapplans[j],							outer_plan, /* pass down same outer plan */							indent + 3, es);			j++;		}	}	if (IsA(plan, SubqueryScan))	{		SubqueryScan *subqueryscan = (SubqueryScan *) plan;		SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;		Plan	   *subnode = subqueryscan->subplan;		RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,									  es->rtable);		List	   *saved_rtable = es->rtable;		Assert(rte->rtekind == RTE_SUBQUERY);		es->rtable = rte->subquery->rtable;		for (i = 0; i < indent; i++)			appendStringInfo(str, "  ");		appendStringInfo(str, "  ->  ");		explain_outNode(str, subnode,						subquerystate->subplan,						NULL,						indent + 3, es);		es->rtable = saved_rtable;	}	/* subPlan-s */	if (planstate->subPlan)	{		List	   *saved_rtable = es->rtable;		ListCell   *lst;		for (i = 0; i < indent; i++)			appendStringInfo(str, "  ");		appendStringInfo(str, "  SubPlan\n");		foreach(lst, planstate->subPlan)		{			SubPlanState *sps = (SubPlanState *) lfirst(lst);			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;			es->rtable = sp->rtable;			for (i = 0; i < indent; i++)				appendStringInfo(str, "  ");			appendStringInfo(str, "    ->  ");			explain_outNode(str, sp->plan,							sps->planstate,							NULL,							indent + 4, es);		}		es->rtable = saved_rtable;	}}/* * Show a qualifier expression for a scan plan node */static voidshow_scan_qual(List *qual, const char *qlabel,			   int scanrelid, Plan *outer_plan,			   StringInfo str, int indent, ExplainState *es){	RangeTblEntry *rte;	Node	   *scancontext;	Node	   *outercontext;	List	   *context;	Node	   *node;	char	   *exprstr;	int			i;	/* No work if empty qual */	if (qual == NIL)		return;	/* Convert AND list to explicit AND */	node = (Node *) make_ands_explicit(qual);	/* Generate deparse context */	Assert(scanrelid > 0 && scanrelid <= list_length(es->rtable));	rte = rt_fetch(scanrelid, es->rtable);	scancontext = deparse_context_for_rte(rte);	/*	 * If we have an outer plan that is referenced by the qual, add it to the	 * deparse context.  If not, don't (so that we don't force prefixes	 * unnecessarily).	 */	if (outer_plan)	{		Relids		varnos = pull_varnos(node);		if (bms_is_member(OUTER, varnos))			outercontext = deparse_context_for_subplan("outer",													   outer_plan->targetlist,													   es->rtable);		else			outercontext = NULL;		bms_free(varnos);	}	else		outercontext = NULL;	context = deparse_context_for_plan(scanrelid, scancontext,									   OUTER, outercontext,									   NIL);	/* Deparse the expression */	exprstr = deparse_expression(node, context, (outercontext != NULL), false);	/* And add to str */	for (i = 0; i < indent; i++)		appendStringInfo(str, "  ");	appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);}/* * Show a qualifier expression for an upper-level plan node */static voidshow_upper_qual(List *qual, const char *qlabel,				const char *outer_name, int outer_varno, Plan *outer_plan,				const char *inner_name, int inner_varno, Plan *inner_plan,				StringInfo str, int indent, ExplainState *es){	List	   *context;	Node	   *outercontext;	Node	   *innercontext;	Node	   *node;	char	   *exprstr;	int			i;	/* No work if empty qual */	if (qual == NIL)		return;	/* Generate deparse context */	if (outer_plan)		outercontext = deparse_context_for_subplan(outer_name,												   outer_plan->targetlist,												   es->rtable);	else		outercontext = NULL;	if (inner_plan)		innercontext = deparse_context_for_subplan(inner_name,												   inner_plan->targetlist,												   es->rtable);	else		innercontext = NULL;	context = deparse_context_for_plan(outer_varno, outercontext,									   inner_varno, innercontext,									   NIL);	/* Deparse the expression */	node = (Node *) make_ands_explicit(qual);	exprstr = deparse_expression(node, context, (inner_plan != NULL), false);	/* And add to str */	for (i = 0; i < indent; i++)		appendStringInfo(str, "  ");	appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);}/* * Show the sort keys for a Sort node. */static voidshow_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,			   const char *qlabel,			   StringInfo str, int indent, ExplainState *es){	List	   *context;	bool		useprefix;	int			keyno;	char	   *exprstr;	Relids		varnos;	int			i;	if (nkeys <= 0)		return;	for (i = 0; i < indent; i++)		appendStringInfo(str, "  ");	appendStringInfo(str, "  %s: ", qlabel);	/*	 * In this routine we expect that the plan node's tlist has not been	 * processed by set_plan_references().	Normally, any Vars will contain	 * valid varnos referencing the actual rtable.	But we might instead be	 * looking at a dummy tlist generated by prepunion.c; if there are Vars	 * with zero varno, use the tlist itself to determine their names.	 */	varnos = pull_varnos((Node *) tlist);	if (bms_is_member(0, varnos))	{		Node	   *outercontext;		outercontext = deparse_context_for_subplan("sort",												   tlist,												   es->rtable);		context = deparse_context_for_plan(0, outercontext,										   0, NULL,										   NIL);		useprefix = false;	}	else	{		context = deparse_context_for_plan(0, NULL,										   0, NULL,										   es->rtable);		useprefix = list_length(es->rtable) > 1;	}	bms_free(varnos);	for (keyno = 0; keyno < nkeys; keyno++)	{		/* find key expression in tlist */		AttrNumber	keyresno = keycols[keyno];		TargetEntry *target = get_tle_by_resno(tlist, keyresno);		if (!target)			elog(ERROR, "no tlist entry for key %d", keyresno);		/* Deparse the expression, showing any top-level cast */		exprstr = deparse_expression((Node *) target->expr, context,									 useprefix, true);		/* And add to str */		if (keyno > 0)			appendStringInfo(str, ", ");		appendStringInfoString(str, exprstr);	}	appendStringInfo(str, "\n");}

⌨️ 快捷键说明

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