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

📄 planner.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
	extravars = nconc(extravars, pull_var_clause(parse->havingQual));	foreach(gl, extravars)	{		Var		   *v = (Var *) lfirst(gl);		if (tlist_member(v, sub_tlist) == NULL)		{			/*			 * Make sure sub_tlist element is a fresh object not shared			 * with any other structure; not sure if anything will break			 * if it is shared, but better to be safe...			 */			sub_tlist = lappend(sub_tlist,								create_tl_element((Var *) copyObject(v),												  next_resno));			next_resno++;		}	}	return sub_tlist;}static Plan *make_groupplan(List *group_tlist,			   bool tuplePerGroup,			   List *groupClause,			   AttrNumber *grpColIdx,			   Plan *subplan){	List	   *sort_tlist;	List	   *sl;	Sort	   *sortplan;	Group	   *grpplan;	int			numCols = length(groupClause);	/*	 * Make the targetlist for the Sort node; it always just references	 * each of the corresponding target items of the subplan.  We need to	 * ensure that simple Vars in the subplan's target list are	 * recognizable by replace_vars_with_subplan_refs when it's applied to	 * the Sort/Group target list, so copy up their varnoold/varoattno.	 */	sort_tlist = NIL;	foreach(sl, subplan->targetlist)	{		TargetEntry *te = (TargetEntry *) lfirst(sl);		Resdom	   *resdom = te->resdom;		Var		   *newvar;		if (IsA(te->expr, Var))		{			Var		   *subvar = (Var *) te->expr;			newvar = makeVar(1, resdom->resno,							 resdom->restype, resdom->restypmod,							 0, subvar->varnoold, subvar->varoattno);		}		else		{			newvar = makeVar(1, resdom->resno,							 resdom->restype, resdom->restypmod,							 0, -1, resdom->resno);		}		sort_tlist = lappend(sort_tlist,						   makeTargetEntry((Resdom *) copyObject(resdom),										   (Node *) newvar));	}	/*	 * Make the Sort node	 */	sortplan = make_sort(sort_tlist,						 _NONAME_RELATION_ID_,						 subplan,						 numCols);	sortplan->plan.cost = subplan->cost;		/* XXX assume no cost */	/*	 * If the caller gave us a target list, use it after fixing the	 * variables. If not, we need the same sort of "repeater" tlist as for	 * the Sort node.	 */	if (group_tlist)	{		group_tlist = copyObject(group_tlist);	/* necessary?? */		replace_tlist_with_subplan_refs(group_tlist,										(Index) 0,										subplan->targetlist);	}	else		group_tlist = copyObject(sort_tlist);	/*	 * Make the Group node	 */	grpplan = make_group(group_tlist, tuplePerGroup, numCols,						 grpColIdx, sortplan);	return (Plan *) grpplan;}/* * make_sortplan *	  Returns a sortplan which is basically a SORT node attached to the *	  top of the plan returned from the planner.  It also adds the *	   cost of sorting into the plan. * * sortkeys: ( resdom1 resdom2 resdom3 ...) * sortops:  (sortop1 sortop2 sortop3 ...) */static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode){	Plan	   *sortplan = (Plan *) NULL;	List	   *temp_tlist = NIL;	List	   *i = NIL;	Resdom	   *resnode = (Resdom *) NULL;	Resdom	   *resdom = (Resdom *) NULL;	int			keyno = 1;	/*	 * First make a copy of the tlist so that we don't corrupt the the	 * original .	 */	temp_tlist = new_unsorted_tlist(tlist);	foreach(i, sortcls)	{		SortClause *sortcl = (SortClause *) lfirst(i);		resnode = sortcl->resdom;		resdom = tlist_resdom(temp_tlist, resnode);		/*		 * Order the resdom keys and replace the operator OID for each key		 * with the regproc OID.		 */		resdom->reskey = keyno;		resdom->reskeyop = get_opcode(sortcl->opoid);		keyno += 1;	}	sortplan = (Plan *) make_sort(temp_tlist,								  _NONAME_RELATION_ID_,								  (Plan *) plannode,								  length(sortcls));	/*	 * XXX Assuming that an internal sort has no. cost. This is wrong, but	 * given that at this point, we don't know the no. of tuples returned,	 * etc, we can't do better than to add a constant cost. This will be	 * fixed once we move the sort further into the planner, but for now	 * ... functionality....	 */	sortplan->cost = plannode->cost;	return sortplan;}/* * pg_checkretval() -- check return value of a list of sql parse *						trees. * * The return value of a sql function is the value returned by * the final query in the function.  We do some ad-hoc define-time * type checking here to be sure that the user is returning the * type he claims. * * XXX Why is this function in this module? */voidpg_checkretval(Oid rettype, List *queryTreeList){	Query	   *parse;	List	   *tlist;	List	   *rt;	int			cmd;	Type		typ;	Resdom	   *resnode;	Relation	reln;	Oid			relid;	Oid			tletype;	int			relnatts;	int			i;	/* find the final query */	parse = (Query *) nth(length(queryTreeList) - 1, queryTreeList);	/*	 * test 1:	if the last query is a utility invocation, then there had	 * better not be a return value declared.	 */	if (parse->commandType == CMD_UTILITY)	{		if (rettype == InvalidOid)			return;		else			elog(ERROR, "return type mismatch in function decl: final query is a catalog utility");	}	/* okay, it's an ordinary query */	tlist = parse->targetList;	rt = parse->rtable;	cmd = parse->commandType;	/*	 * test 2:	if the function is declared to return no value, then the	 * final query had better not be a retrieve.	 */	if (rettype == InvalidOid)	{		if (cmd == CMD_SELECT)			elog(ERROR,				 "function declared with no return type, but final query is a retrieve");		else			return;	}	/* by here, the function is declared to return some type */	if ((typ = typeidType(rettype)) == NULL)		elog(ERROR, "can't find return type %u for function\n", rettype);	/*	 * test 3:	if the function is declared to return a value, then the	 * final query had better be a retrieve.	 */	if (cmd != CMD_SELECT)		elog(ERROR, "function declared to return type %s, but final query is not a retrieve", typeTypeName(typ));	/*	 * test 4:	for base type returns, the target list should have exactly	 * one entry, and its type should agree with what the user declared.	 */	if (typeTypeRelid(typ) == InvalidOid)	{		if (ExecTargetListLength(tlist) > 1)			elog(ERROR, "function declared to return %s returns multiple values in final retrieve", typeTypeName(typ));		resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;		if (resnode->restype != rettype)			elog(ERROR, "return type mismatch in function: declared to return %s, returns %s", typeTypeName(typ), typeidTypeName(resnode->restype));		/* by here, base return types match */		return;	}	/*	 * If the target list is of length 1, and the type of the varnode in	 * the target list is the same as the declared return type, this is	 * okay.  This can happen, for example, where the body of the function	 * is 'retrieve (x = func2())', where func2 has the same return type	 * as the function that's calling it.	 */	if (ExecTargetListLength(tlist) == 1)	{		resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;		if (resnode->restype == rettype)			return;	}	/*	 * By here, the procedure returns a (set of) tuples.  This part of the	 * typechecking is a hack.	We look up the relation that is the	 * declared return type, and be sure that attributes 1 .. n in the	 * target list match the declared types.	 */	reln = heap_open(typeTypeRelid(typ));	if (!RelationIsValid(reln))		elog(ERROR, "cannot open relation relid %u", typeTypeRelid(typ));	relid = reln->rd_id;	relnatts = reln->rd_rel->relnatts;	if (ExecTargetListLength(tlist) != relnatts)		elog(ERROR, "function declared to return type %s does not retrieve (%s.*)", typeTypeName(typ), typeTypeName(typ));	/* expect attributes 1 .. n in order */	for (i = 1; i <= relnatts; i++)	{		TargetEntry *tle = lfirst(tlist);		Node	   *thenode = tle->expr;		tlist = lnext(tlist);		tletype = exprType(thenode);#ifdef NOT_USED					/* fix me */		/* this is tedious */		if (IsA(thenode, Var))			tletype = (Oid) ((Var *) thenode)->vartype;		else if (IsA(thenode, Const))			tletype = (Oid) ((Const *) thenode)->consttype;		else if (IsA(thenode, Param))			tletype = (Oid) ((Param *) thenode)->paramtype;		else if (IsA(thenode, Expr))			tletype = Expr;		else if (IsA(thenode, LispList))		{			thenode = lfirst(thenode);			if (IsA(thenode, Oper))				tletype = (Oid) get_opresulttype((Oper *) thenode);			else if (IsA(thenode, Func))				tletype = (Oid) get_functype((Func *) thenode);			else				elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));		}		else			elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));#endif		/* reach right in there, why don't you? */		if (tletype != reln->rd_att->attrs[i - 1]->atttypid)			elog(ERROR, "function declared to return type %s does not retrieve (%s.all)", typeTypeName(typ), typeTypeName(typ));	}	heap_close(reln);	/* success */	return;}/* ---------- * Support function for need_sortplan * ---------- */static TargetEntry *get_matching_tle(Plan *plan, Resdom *resdom){	List	   *i;	TargetEntry *tle;	foreach(i, plan->targetlist)	{		tle = (TargetEntry *) lfirst(i);		if (tle->resdom->resno == resdom->resno)			return tle;	}	return NULL;}/* ---------- * Check if a user requested ORDER BY is already satisfied by * the choosen index scan. * * Returns TRUE if sort is required, FALSE if can be omitted. * ---------- */static boolneed_sortplan(List *sortcls, Plan *plan){	Relation	indexRel;	IndexScan  *indexScan;	Oid			indexId;	List	   *i;	HeapTuple	htup;	Form_pg_index index_tup;	int			key_no = 0;	/* ----------	 * Must be an IndexScan	 * ----------	 */	if (nodeTag(plan) != T_IndexScan)		return TRUE;	indexScan = (IndexScan *) plan;	/* ----------	 * Should not have left- or righttree	 * ----------	 */	if (plan->lefttree != NULL)		return TRUE;	if (plan->righttree != NULL)		return TRUE;	/* ----------	 * Must be a single index scan	 * ----------	 */	if (length(indexScan->indxid) != 1)		return TRUE;	/* ----------	 * Indices can only have up to 8 attributes. So an ORDER BY using	 * more that 8 attributes could never be satisfied by an index.	 * ----------	 */	if (length(sortcls) > 8)		return TRUE;	/* ----------	 * The choosen Index must be a btree	 * ----------	 */	indexId = lfirsti(indexScan->indxid);	indexRel = index_open(indexId);	if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0)	{		heap_close(indexRel);		return TRUE;	}	heap_close(indexRel);	/* ----------	 * Fetch the index tuple	 * ----------	 */	htup = SearchSysCacheTuple(INDEXRELID,							   ObjectIdGetDatum(indexId), 0, 0, 0);	if (!HeapTupleIsValid(htup))		elog(ERROR, "cache lookup for index %u failed", indexId);	index_tup = (Form_pg_index) GETSTRUCT(htup);	/* ----------	 * Check if all the sort clauses match the attributes in the index	 * ----------	 */	foreach(i, sortcls)	{		SortClause *sortcl;		Resdom	   *resdom;		TargetEntry *tle;		Var		   *var;		sortcl = (SortClause *) lfirst(i);		resdom = sortcl->resdom;		tle = get_matching_tle(plan, resdom);		if (tle == NULL)		{			/* ----------			 * Could this happen?			 * ----------			 */			return TRUE;		}		if (nodeTag(tle->expr) != T_Var)		{			/* ----------			 * The target list expression isn't a var, so it			 * cannot be the indexed attribute			 * ----------			 */			return TRUE;		}		var = (Var *) (tle->expr);		if (var->varno != indexScan->scan.scanrelid)		{			/* ----------			 * This Var isn't from the scan relation. So it isn't			 * that of the index			 * ----------			 */			return TRUE;		}		if (var->varattno != index_tup->indkey[key_no])		{			/* ----------			 * It isn't the indexed attribute.			 * ----------			 */			return TRUE;		}		if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid)		{			/* ----------			 * Sort order isn't in ascending order.			 * ----------			 */			return TRUE;		}		key_no++;	}	/* ----------	 * Index matches ORDER BY - sort not required	 * ----------	 */	return FALSE;}

⌨️ 快捷键说明

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