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

📄 parse_func.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * parse_func.c *		handle function calls in parser * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.47 1999/06/17 22:21:40 tgl Exp $ * *------------------------------------------------------------------------- */#include <string.h>#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "access/itup.h"#include "access/relscan.h"#include "access/sdir.h"#include "catalog/catname.h"#include "catalog/heap.h"#include "catalog/indexing.h"#include "catalog/pg_inherits.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "catalog/pg_aggregate.h"#include "fmgr.h"#include "lib/dllist.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "nodes/relation.h"#include "parser/parse_agg.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_node.h"#include "parser/parse_relation.h"#include "parser/parse_target.h"#include "parser/parse_type.h"#include "parser/parse_coerce.h"#include "storage/bufmgr.h"#include "storage/lmgr.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/syscache.h"static Node *ParseComplexProjection(ParseState *pstate,					   char *funcname,					   Node *first_arg,					   bool *attisset);static Oid **argtype_inherit(int nargs, Oid *oid_array);static int	find_inheritors(Oid relid, Oid **supervec);static CandidateList func_get_candidates(char *funcname, int nargs);static boolfunc_get_detail(char *funcname,				int nargs,				Oid *oid_array,				Oid *funcid,	/* return value */				Oid *rettype,	/* return value */				bool *retset,	/* return value */				Oid **true_typeids);static Oid	funcid_get_rettype(Oid funcid);static Oid **gen_cross_product(InhPaths *arginh, int nargs);static void make_arguments(ParseState *pstate,			   int nargs,			   List *fargs,			   Oid *input_typeids,			   Oid *function_typeids);static int match_argtypes(int nargs,			   Oid *input_typeids,			   CandidateList function_typeids,			   CandidateList *candidates);static List *setup_tlist(char *attname, Oid relid);static List *setup_base_tlist(Oid typeid);static Oid *func_select_candidate(int nargs, Oid *input_typeids,					  CandidateList candidates);static int	agg_get_candidates(char *aggname, Oid typeId, CandidateList *candidates);static Oid	agg_select_candidate(Oid typeid, CandidateList candidates);#define ISCOMPLEX(type) (typeidTypeRelid(type) ? true : false)typedef struct _SuperQE{	Oid			sqe_relid;} SuperQE;/* ** ParseNestedFuncOrColumn **    Given a nested dot expression (i.e. (relation func ... attr), build up ** a tree with of Iter and Func nodes. */Node *ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int *curr_resno, int precedence){	List	   *mutator_iter;	Node	   *retval = NULL;	if (attr->paramNo != NULL)	{		Param	   *param = (Param *) transformExpr(pstate, (Node *) attr->paramNo, EXPR_RELATION_FIRST);		retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),								   lcons(param, NIL),								   curr_resno,								   precedence);	}	else	{		Ident	   *ident = makeNode(Ident);		ident->name = attr->relname;		ident->isRel = TRUE;		retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),								   lcons(ident, NIL),								   curr_resno,								   precedence);	}	/* Do more attributes follow this one? */	foreach(mutator_iter, lnext(attr->attrs))	{		retval = ParseFuncOrColumn(pstate, strVal(lfirst(mutator_iter)),								   lcons(retval, NIL),								   curr_resno,								   precedence);	}	return retval;}static intagg_get_candidates(char *aggname,				   Oid typeId,				   CandidateList *candidates){	CandidateList current_candidate;	Relation	pg_aggregate_desc;	HeapScanDesc pg_aggregate_scan;	HeapTuple	tup;	Form_pg_aggregate agg;	int			ncandidates = 0;	static ScanKeyData aggKey[1] = {	{0, Anum_pg_aggregate_aggname, F_NAMEEQ}};	*candidates = NULL;	fmgr_info(F_NAMEEQ, (FmgrInfo *) &aggKey[0].sk_func);	aggKey[0].sk_argument = NameGetDatum(aggname);	pg_aggregate_desc = heap_openr(AggregateRelationName);	pg_aggregate_scan = heap_beginscan(pg_aggregate_desc,									   0,									   SnapshotSelf,	/* ??? */									   1,									   aggKey);	while (HeapTupleIsValid(tup = heap_getnext(pg_aggregate_scan, 0)))	{		current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));		current_candidate->args = (Oid *) palloc(sizeof(Oid));		agg = (Form_pg_aggregate) GETSTRUCT(tup);		current_candidate->args[0] = agg->aggbasetype;		current_candidate->next = *candidates;		*candidates = current_candidate;		ncandidates++;	}	heap_endscan(pg_aggregate_scan);	heap_close(pg_aggregate_desc);	return ncandidates;}	/* agg_get_candidates() *//* agg_select_candidate() * Try to choose only one candidate aggregate function from a list of possibles. */static Oidagg_select_candidate(Oid typeid, CandidateList candidates){	CandidateList current_candidate;	CandidateList last_candidate;	Oid			current_typeid;	int			ncandidates;	CATEGORY	category,				current_category;/* * Look for candidates which allow coersion and have a preferred type. * Keep all candidates if none match. */	category = TypeCategory(typeid);	ncandidates = 0;	last_candidate = NULL;	for (current_candidate = candidates;		 current_candidate != NULL;		 current_candidate = current_candidate->next)	{		current_typeid = current_candidate->args[0];		current_category = TypeCategory(current_typeid);		if ((current_category == category)			&& IsPreferredType(current_category, current_typeid)			&& can_coerce_type(1, &typeid, &current_typeid))		{			/* only one so far? then keep it... */			if (last_candidate == NULL)			{				candidates = current_candidate;				last_candidate = current_candidate;				ncandidates = 1;			}			/* otherwise, keep this one too... */			else			{				last_candidate->next = current_candidate;				last_candidate = current_candidate;				ncandidates++;			}		}		/* otherwise, don't bother keeping this one around... */		else if (last_candidate != NULL)			last_candidate->next = NULL;	}	return ((ncandidates == 1) ? candidates->args[0] : 0);}	/* agg_select_candidate() *//* * parse function */Node *ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,				  int *curr_resno, int precedence){	Oid			rettype = InvalidOid;	Oid			argrelid = InvalidOid;	Oid			funcid = InvalidOid;	List	   *i = NIL;	Node	   *first_arg = NULL;	char	   *relname = NULL;	char	   *refname = NULL;	Relation	rd;	Oid			relid;	int			nargs;	Func	   *funcnode;	Oid			oid_array[MAXFARGS];	Oid		   *true_oid_array;	Node	   *retval;	bool		retset;	bool		attisset = false;	Oid			toid = InvalidOid;	Expr	   *expr;	if (fargs)	{		first_arg = lfirst(fargs);		if (first_arg == NULL)			elog(ERROR, "Function '%s' does not allow NULL input", funcname);	}	/*	 * check for projection methods: if function takes one argument, and	 * that argument is a relation, param, or PQ function returning a	 * complex * type, then the function could be a projection.	 */	/* We only have one parameter */	if (length(fargs) == 1)	{		/* Is is a plain Relation name from the parser? */		if (nodeTag(first_arg) == T_Ident && ((Ident *) first_arg)->isRel)		{			RangeTblEntry *rte;			Ident	   *ident = (Ident *) first_arg;			/*			 * first arg is a relation. This could be a projection.			 */			refname = ident->name;			rte = refnameRangeTableEntry(pstate, refname);			if (rte == NULL)				rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE);			relname = rte->relname;			relid = rte->relid;			/*			 * If the attr isn't a set, just make a var for it.  If it is			 * a set, treat it like a function and drop through.			 */			if (get_attnum(relid, funcname) != InvalidAttrNumber)			{				return (Node *) make_var(pstate,										 relid,										 refname,										 funcname);			}			else			{				/* drop through - attr is a set */				;			}		}		else if (ISCOMPLEX(exprType(first_arg)))		{			/*			 * Attempt to handle projection of a complex argument. If			 * ParseComplexProjection can't handle the projection, we have			 * to keep going.			 */			retval = ParseComplexProjection(pstate,											funcname,											first_arg,											&attisset);			if (attisset)			{				toid = exprType(first_arg);				rd = heap_openr(typeidTypeName(toid));				if (RelationIsValid(rd))				{					relname = RelationGetRelationName(rd)->data;					heap_close(rd);				}				else					elog(ERROR, "Type '%s' is not a relation type",						 typeidTypeName(toid));				argrelid = typeidTypeRelid(toid);				/*				 * A projection contains either an attribute name or the				 * "*".				 */				if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)					&& strcmp(funcname, "*"))					elog(ERROR, "Functions on sets are not yet supported");			}			if (retval)				return retval;		}		else		{			/*			 * Parsing aggregates.			 */			Type		tp;			Oid			basetype;			int			ncandidates;			CandidateList candidates;			/*			 * the aggregate COUNT is a special case, ignore its base			 * type.  Treat it as zero			 */			if (strcmp(funcname, "count") == 0)				basetype = 0;			else				basetype = exprType(lfirst(fargs));			/* try for exact match first... */			if (SearchSysCacheTuple(AGGNAME,									PointerGetDatum(funcname),									ObjectIdGetDatum(basetype),									0, 0))				return (Node *) ParseAgg(pstate, funcname, basetype,										 fargs, precedence);			/*			 * No exact match yet, so see if there is another entry in the			 * aggregate table which is compatible. - thomas 1998-12-05			 */			ncandidates = agg_get_candidates(funcname, basetype, &candidates);			if (ncandidates > 0)			{				Oid			type;				type = agg_select_candidate(basetype, candidates);				if (OidIsValid(type))				{					lfirst(fargs) = coerce_type(pstate, lfirst(fargs),												basetype, type, -1);					basetype = type;					return (Node *) ParseAgg(pstate, funcname, basetype,											 fargs, precedence);				}				else				{					elog(ERROR, "Unable to select an aggregate function %s(%s)",						 funcname, typeidTypeName(basetype));				}			}			/*			 * See if this is a single argument function with the function			 * name also a type name and the input argument and type name			 * binary compatible... This means that you are trying for a			 * type conversion which does not need to take place, so we'll			 * just pass through the argument itself. (make this clearer			 * with some extra brackets - thomas 1998-12-05)			 */			if ((HeapTupleIsValid(tp = SearchSysCacheTuple(TYPNAME,											   PointerGetDatum(funcname),														   0, 0, 0)))				&& IS_BINARY_COMPATIBLE(typeTypeId(tp), basetype))				return ((Node *) lfirst(fargs));		}	}	/*	 * If we dropped through to here it's really a function (or a set,	 * which is implemented as a function). Extract arg type info and	 * transform relation name arguments into varnodes of the appropriate	 * form.	 */	MemSet(oid_array, 0, MAXFARGS * sizeof(Oid));	nargs = 0;	foreach(i, fargs)	{		int			vnum;		RangeTblEntry *rte;		Node	   *pair = lfirst(i);		if (nodeTag(pair) == T_Ident && ((Ident *) pair)->isRel)		{			/*			 * a relation			 */			refname = ((Ident *) pair)->name;			rte = refnameRangeTableEntry(pstate, refname);			if (rte == NULL)				rte = addRangeTableEntry(pstate, refname, refname,										 FALSE, FALSE);			relname = rte->relname;			vnum = refnameRangeTablePosn(pstate, rte->refname, NULL);			/*			 * for func(relname), the param to the function is the tuple			 * under consideration.  we build a special VarNode to reflect			 * this -- it has varno set to the correct range table entry,			 * but has varattno == 0 to signal that the whole tuple is the			 * argument.			 */			toid = typeTypeId(typenameType(relname));			/* replace it in the arg list */			lfirst(fargs) = makeVar(vnum, 0, toid, -1, 0, vnum, 0);		}		else if (!attisset)		{						/* set functions don't have parameters */			/*			 * any functiona args which are typed "unknown", but aren't			 * constants, we don't know what to do with, because we can't			 * cast them	- jolly			 */			if (exprType(pair) == UNKNOWNOID && !IsA(pair, Const))				elog(ERROR, "There is no function '%s'"					 " with argument #%d of type UNKNOWN",					 funcname, nargs);			else				toid = exprType(pair);		}		/* Most of the rest of the parser just assumes that functions do not		 * have more than MAXFARGS parameters.  We have to test here to protect		 * against array overruns, etc.		 */		if (nargs >= MAXFARGS)			elog(ERROR, "Cannot pass more than %d arguments to a function",				 MAXFARGS);		oid_array[nargs++] = toid;	}	/*	 * func_get_detail looks up the function in the catalogs, does	 * disambiguation for polymorphic functions, handles inheritance, and	 * returns the funcid and type and set or singleton status of the	 * function's return value.  it also returns the true argument types	 * to the function.  if func_get_detail returns true, the function	 * exists.	otherwise, there was an error.	 */	if (attisset)	{							/* we know all of these fields already */		/*		 * We create a funcnode with a placeholder function SetEval.		 * SetEval() never actually gets executed.	When the function		 * evaluation routines see it, they use the funcid projected out		 * from the relation as the actual function to call. Example:		 * retrieve (emp.mgr.name) The plan for this will scan the emp		 * relation, projecting out the mgr attribute, which is a funcid.		 * This function is then called (instead of SetEval) and "name" is		 * projected from its result.		 */		funcid = F_SETEVAL;		rettype = toid;		retset = true;		true_oid_array = oid_array;	}	else	{		bool		exists;		exists = func_get_detail(funcname, nargs, oid_array, &funcid,								 &rettype, &retset, &true_oid_array);		if (!exists)			elog(ERROR, "No such function '%s' with the specified attributes",				 funcname);

⌨️ 快捷键说明

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