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

📄 parse_func.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	/* got it */	funcnode = makeNode(Func);	funcnode->funcid = funcid;	funcnode->functype = rettype;	funcnode->funcisindex = false;	funcnode->funcsize = 0;	funcnode->func_fcache = NULL;	funcnode->func_tlist = NIL;	funcnode->func_planlist = NIL;	/* perform the necessary typecasting */	make_arguments(pstate, nargs, fargs, oid_array, true_oid_array);	/*	 * for functions returning base types, we want to project out the	 * return value.  set up a target list to do that.	the executor will	 * ignore these for c functions, and do the right thing for postquel	 * functions.	 */	if (typeidTypeRelid(rettype) == InvalidOid)		funcnode->func_tlist = setup_base_tlist(rettype);	/*	 * For sets, we want to make a targetlist to project out this	 * attribute of the set tuples.	 */	if (attisset)	{		if (!strcmp(funcname, "*"))			funcnode->func_tlist = expandAll(pstate, relname, refname, curr_resno);		else		{			funcnode->func_tlist = setup_tlist(funcname, argrelid);			rettype = get_atttype(argrelid, get_attnum(argrelid, funcname));		}	}	/*	 * Sequence handling.	 */	if (funcid == F_NEXTVAL ||		funcid == F_CURRVAL ||		funcid == F_SETVAL)	{		Const	   *seq;		char	   *seqrel;		text	   *seqname;		int32		aclcheck_result = -1;		Assert(length(fargs) == ((funcid == F_SETVAL) ? 2 : 1));		seq = (Const *) lfirst(fargs);		if (!IsA((Node *) seq, Const))			elog(ERROR, "Only constant sequence names are acceptable for function '%s'", funcname);		seqrel = textout((text *) DatumGetPointer(seq->constvalue));		/* Do we have nextval('"Aa"')? */		if (strlen(seqrel) >= 2 &&			seqrel[0] == '\"' && seqrel[strlen(seqrel) - 1] == '\"')		{			/* strip off quotes, keep case */			seqrel = pstrdup(seqrel + 1);			seqrel[strlen(seqrel) - 1] = '\0';			pfree(DatumGetPointer(seq->constvalue));			seq->constvalue = (Datum) textin(seqrel);		}		else		{			pfree(seqrel);			seqname = lower((text *) DatumGetPointer(seq->constvalue));			pfree(DatumGetPointer(seq->constvalue));			seq->constvalue = PointerGetDatum(seqname);			seqrel = textout(seqname);		}		if ((aclcheck_result = pg_aclcheck(seqrel, GetPgUserName(),					   (((funcid == F_NEXTVAL) || (funcid == F_SETVAL)) ?						ACL_WR : ACL_RD)))			!= ACLCHECK_OK)			elog(ERROR, "%s.%s: %s",			  seqrel, funcname, aclcheck_error_strings[aclcheck_result]);		pfree(seqrel);		if (funcid == F_NEXTVAL && pstate->p_in_where_clause)			elog(ERROR, "Sequence function nextval is not allowed in WHERE clauses");		if (funcid == F_SETVAL && pstate->p_in_where_clause)			elog(ERROR, "Sequence function setval is not allowed in WHERE clauses");	}	expr = makeNode(Expr);	expr->typeOid = rettype;	expr->opType = FUNC_EXPR;	expr->oper = (Node *) funcnode;	expr->args = fargs;	retval = (Node *) expr;	/*	 * if the function returns a set of values, then we need to iterate	 * over all the returned values in the executor, so we stick an iter	 * node here.  if it returns a singleton, then we don't need the iter	 * node.	 */	if (retset)	{		Iter	   *iter = makeNode(Iter);		iter->itertype = rettype;		iter->iterexpr = retval;		retval = (Node *) iter;	}	return retval;}static Oidfuncid_get_rettype(Oid funcid){	HeapTuple	func_tuple = NULL;	Oid			funcrettype = InvalidOid;	func_tuple = SearchSysCacheTuple(PROOID,									 ObjectIdGetDatum(funcid),									 0, 0, 0);	if (!HeapTupleIsValid(func_tuple))		elog(ERROR, "Function OID %u does not exist", funcid);	funcrettype = (Oid)		((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;	return funcrettype;}/* func_get_candidates() * get a list of all argument type vectors for which a function named * funcname taking nargs arguments exists */static CandidateListfunc_get_candidates(char *funcname, int nargs){	Relation	heapRelation;	Relation	idesc;	ScanKeyData skey;	HeapTupleData tuple;	IndexScanDesc sd;	RetrieveIndexResult indexRes;	Form_pg_proc pgProcP;	CandidateList candidates = NULL;	CandidateList current_candidate;	int			i;	heapRelation = heap_openr(ProcedureRelationName);	ScanKeyEntryInitialize(&skey,						   (bits16) 0x0,						   (AttrNumber) 1,						   (RegProcedure) F_NAMEEQ,						   (Datum) funcname);	idesc = index_openr(ProcedureNameIndex);	sd = index_beginscan(idesc, false, 1, &skey);	do	{		indexRes = index_getnext(sd, ForwardScanDirection);		if (indexRes)		{			Buffer		buffer;			tuple.t_self = indexRes->heap_iptr;			heap_fetch(heapRelation, SnapshotNow, &tuple, &buffer);			pfree(indexRes);			if (tuple.t_data != NULL)			{				pgProcP = (Form_pg_proc) GETSTRUCT(&tuple);				if (pgProcP->pronargs == nargs)				{					current_candidate = (CandidateList)						palloc(sizeof(struct _CandidateList));					current_candidate->args = (Oid *)						palloc(MAXFARGS * sizeof(Oid));					MemSet(current_candidate->args, 0, MAXFARGS * sizeof(Oid));					for (i = 0; i < nargs; i++)						current_candidate->args[i] = pgProcP->proargtypes[i];					current_candidate->next = candidates;					candidates = current_candidate;				}				ReleaseBuffer(buffer);			}		}	} while (indexRes);	index_endscan(sd);	index_close(idesc);	heap_close(heapRelation);	return candidates;}/* match_argtypes() * Given a list of possible typeid arrays to a function and an array of * input typeids, produce a shortlist of those function typeid arrays * that match the input typeids (either exactly or by coercion), and * return the number of such arrays */static intmatch_argtypes(int nargs,			   Oid *input_typeids,			   CandidateList function_typeids,			   CandidateList *candidates)		/* return value */{	CandidateList current_candidate;	CandidateList matching_candidate;	Oid		   *current_typeids;	int			ncandidates = 0;	*candidates = NULL;	for (current_candidate = function_typeids;		 current_candidate != NULL;		 current_candidate = current_candidate->next)	{		current_typeids = current_candidate->args;		if (can_coerce_type(nargs, input_typeids, current_typeids))		{			matching_candidate = (CandidateList)				palloc(sizeof(struct _CandidateList));			matching_candidate->args = current_typeids;			matching_candidate->next = *candidates;			*candidates = matching_candidate;			ncandidates++;		}	}	return ncandidates;}	/* match_argtypes() *//* func_select_candidate() * Given the input argtype array and more than one candidate * for the function argtype array, attempt to resolve the conflict. * returns the selected argtype array if the conflict can be resolved, * otherwise returns NULL. * * If all input Oids are UNKNOWNOID, then try matching with TEXTOID. * Otherwise, could return first function arguments on list of candidates. * But for now, return NULL and make the user give a better hint. * - thomas 1998-03-17 */static Oid *func_select_candidate(int nargs,					  Oid *input_typeids,					  CandidateList candidates){	CandidateList current_candidate;	CandidateList last_candidate;	Oid		   *current_typeids;	int			i;	int			ncandidates;	int			nbestMatch,				nmatch,				nident;	CATEGORY	slot_category,				current_category;	Oid			slot_type,				current_type;/* * Run through all candidates and keep those with the most matches *	on explicit types. Keep all candidates if none match. */	ncandidates = 0;	nbestMatch = 0;	last_candidate = NULL;	for (current_candidate = candidates;		 current_candidate != NULL;		 current_candidate = current_candidate->next)	{		current_typeids = current_candidate->args;		nmatch = 0;		nident = 0;		for (i = 0; i < nargs; i++)		{			if ((input_typeids[i] != UNKNOWNOID)				&& (current_typeids[i] == input_typeids[i]))				nmatch++;			else if (IS_BINARY_COMPATIBLE(current_typeids[i], input_typeids[i]))				nident++;		}		if ((nmatch + nident) == nargs)			return current_candidate->args;		if ((nmatch > nbestMatch) || (last_candidate == NULL))		{			nbestMatch = nmatch;			candidates = current_candidate;			last_candidate = current_candidate;			ncandidates = 1;		}		else if (nmatch == nbestMatch)		{			last_candidate->next = current_candidate;			last_candidate = current_candidate;			ncandidates++;		}		else			last_candidate->next = NULL;	}	if (ncandidates == 1)		return candidates->args;/* * Still too many candidates? * Try assigning types for the unknown columns. */	for (i = 0; i < nargs; i++)	{		if (input_typeids[i] == UNKNOWNOID)		{			slot_category = INVALID_TYPE;			slot_type = InvalidOid;			for (current_candidate = candidates;				 current_candidate != NULL;				 current_candidate = current_candidate->next)			{				current_typeids = current_candidate->args;				current_type = current_typeids[i];				current_category = TypeCategory(current_typeids[i]);				if (slot_category == InvalidOid)				{					slot_category = current_category;					slot_type = current_type;				}				else if ((current_category != slot_category)						 && IS_BUILTIN_TYPE(current_type))					return NULL;				else if (current_type != slot_type)				{					if (IsPreferredType(slot_category, current_type))					{						slot_type = current_type;						candidates = current_candidate;					}					else if (IsPreferredType(slot_category, slot_type))						candidates->next = current_candidate->next;				}			}			if (slot_type != InvalidOid)				input_typeids[i] = slot_type;		}		else		{		}	}	ncandidates = 0;	for (current_candidate = candidates;		 current_candidate != NULL;		 current_candidate = current_candidate->next)		ncandidates++;	if (ncandidates == 1)		return candidates->args;	return NULL;}	/* func_select_candidate() *//* func_get_detail() * Find the named function in the system catalogs. * * Attempt to find the named function in the system catalogs with *	arguments exactly as specified, so that the normal case *	(exact match) is as quick as possible. * * If an exact match isn't found: *	1) get a vector of all possible input arg type arrays constructed *	   from the superclasses of the original input arg types *	2) get a list of all possible argument type arrays to the function *	   with given name and number of arguments *	3) for each input arg type array from vector #1: *	 a) find how many of the function arg type arrays from list #2 *		it can be coerced to *	 b) if the answer is one, we have our function *	 c) if the answer is more than one, attempt to resolve the conflict *	 d) if the answer is zero, try the next array from vector #1 */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)		/* return value */{	Oid		  **input_typeid_vector;	Oid		   *current_input_typeids;	CandidateList function_typeids;	CandidateList current_function_typeids;	HeapTuple	ftup;	Form_pg_proc pform;	/* attempt to find with arguments exactly as specified... */	ftup = SearchSysCacheTuple(PRONAME,							   PointerGetDatum(funcname),							   Int32GetDatum(nargs),							   PointerGetDatum(oid_array),							   0);	*true_typeids = oid_array;	/* didn't find an exact match, so now try to match up candidates... */	if (!HeapTupleIsValid(ftup))	{		function_typeids = func_get_candidates(funcname, nargs);		/* found something, so let's look through them... */		if (function_typeids != NULL)		{			int			ncandidates;			input_typeid_vector = argtype_inherit(nargs, oid_array);			current_input_typeids = oid_array;			do			{				ncandidates = match_argtypes(nargs, current_input_typeids,											 function_typeids,											 &current_function_typeids);				/* one match only? then run with it... */				if (ncandidates == 1)				{					*true_typeids = current_function_typeids->args;					ftup = SearchSysCacheTuple(PRONAME,											   PointerGetDatum(funcname),											   Int32GetDatum(nargs),										  PointerGetDatum(*true_typeids),											   0);					Assert(HeapTupleIsValid(ftup));				}				/*				 * multiple candidates? then better decide or throw an				 * error...				 */				else if (ncandidates > 1)				{					*true_typeids = func_select_candidate(nargs,												   current_input_typeids,											   current_function_typeids);					/* couldn't decide, so quit */					if (*true_typeids == NULL)					{						func_error(NULL, funcname, nargs, oid_array,								   "Unable to identify a function which satisfies the given argument types"								   "\n\tYou will have to retype your query using explicit typecasts");					}					/* found something, so use the first one... */					else					{						ftup = SearchSysCacheTuple(PRONAME,											   PointerGetDatum(funcname),												   Int32GetDatum(nargs),										  PointerGetDatum(*true_typeids),												   0);						Assert(HeapTupleIsValid(ftup));					}				}				current_input_typeids = *input_typeid_vector++;			}			while (current_input_typeids != InvalidOid && ncandidates == 0);		}	}	if (!HeapTupleIsValid(ftup))	{		Type		tp;		if (nargs == 1)		{			tp = typeidType(oid_array[0]);			if (typeTypeFlag(tp) == 'c')				elog(ERROR, "No such attribute or function '%s'", funcname);		}	}	else	{		pform = (Form_pg_proc) GETSTRUCT(ftup);		*funcid = ftup->t_data->t_oid;		*rettype = pform->prorettype;		*retset = pform->proretset;		return true;	}	/* shouldn't reach here */	return false;}	/* func_get_detail() *//* *	argtype_inherit() -- Construct an argtype vector reflecting the *						 inheritance properties of the supplied argv. * *		This function is used to disambiguate among functions with the *		same name but different signatures.  It takes an array of eight *		type ids.  For each type id in the array that's a complex type *		(a class), it walks up the inheritance tree, finding all *		superclasses of that type.	A vector of new Oid type arrays

⌨️ 快捷键说明

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