parse_func.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,534 行 · 第 1/3 页

C
1,534
字号
	nvisited = 0;	queue = NIL;	visited = NIL;	inhrel = heap_openr(InheritsRelationName, AccessShareLock);	/*	 * Use queue to do a breadth-first traversal of the inheritance graph	 * from the relid supplied up to the root.	At the top of the loop,	 * relid is the OID of the reltype to check next, queue is the list of	 * pending relids to check after this one, and visited is the list of	 * relids we need to output.	 */	do	{		/* find all types this relid inherits from, and add them to queue */		ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrelid,							   F_OIDEQ,							   ObjectIdGetDatum(relid));		inhscan = heap_beginscan(inhrel, SnapshotNow, 1, &skey);		while ((inhtup = heap_getnext(inhscan, ForwardScanDirection)) != NULL)		{			Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(inhtup);			queue = lappendo(queue, inh->inhparent);		}		heap_endscan(inhscan);		/* pull next unvisited relid off the queue */		newrelid = false;		while (queue != NIL)		{			relid = lfirsto(queue);			queue = lnext(queue);			if (!oidMember(relid, visited))			{				newrelid = true;				break;			}		}		if (newrelid)		{			visited = lappendo(visited, relid);			nvisited++;		}	} while (newrelid);	heap_close(inhrel, AccessShareLock);	if (nvisited > 0)	{		relidvec = (Oid *) palloc(nvisited * sizeof(Oid));		*supervec = relidvec;		foreach(elt, visited)		{			/* return the type id, rather than the relation id */			*relidvec++ = get_rel_type_id(lfirsto(elt));		}	}	else		*supervec = (Oid *) NULL;	freeList(visited);	/*	 * there doesn't seem to be any equally easy way to release the queue	 * list cells, but since they're palloc'd space it's not critical.	 */	return nvisited;}/* * Generate the ordered list of substitute argtype vectors to try. * * See comments for argtype_inherit. */static Oid **gen_cross_product(InhPaths *arginh, int nargs){	int			nanswers;	Oid		  **result;	Oid		   *oneres;	int			i,				j;	int			cur[FUNC_MAX_ARGS];	/*	 * At each position we want to try the original datatype, plus each	 * supertype.  So the number of possible combinations is this:	 */	nanswers = 1;	for (i = 0; i < nargs; i++)		nanswers *= (arginh[i].nsupers + 1);	/*	 * We also need an extra slot for the terminating NULL in the result	 * array, but that cancels out with the fact that we don't want to	 * generate the zero-changes case.	So we need exactly nanswers slots.	 */	result = (Oid **) palloc(sizeof(Oid *) * nanswers);	j = 0;	/*	 * Compute the cross product from right to left.  When cur[i] == 0,	 * generate the original input type at position i.	When cur[i] == k	 * for k > 0, generate its k'th supertype.	 */	MemSet(cur, 0, sizeof(cur));	for (;;)	{		/*		 * Find a column we can increment.	All the columns after it get		 * reset to zero.  (Essentially, we're adding one to the multi-		 * digit number represented by cur[].)		 */		for (i = nargs - 1; i >= 0 && cur[i] >= arginh[i].nsupers; i--)			cur[i] = 0;		/* if none, we're done */		if (i < 0)			break;		/* increment this column */		cur[i] += 1;		/* Generate the proper output type-OID vector */		oneres = (Oid *) palloc0(FUNC_MAX_ARGS * sizeof(Oid));		for (i = 0; i < nargs; i++)		{			if (cur[i] == 0)				oneres[i] = arginh[i].self;			else				oneres[i] = arginh[i].supervec[cur[i] - 1];		}		result[j++] = oneres;	}	/* terminate result vector with NULL pointer */	result[j++] = NULL;	Assert(j == nanswers);	return result;}/* * Given two type OIDs, determine whether the first is a complex type * (class type) that inherits from the second. */booltypeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId){	Oid			relid;	Oid		   *supervec;	int			nsupers,				i;	bool		result;	if (!ISCOMPLEX(subclassTypeId) || !ISCOMPLEX(superclassTypeId))		return false;	relid = typeidTypeRelid(subclassTypeId);	if (relid == InvalidOid)		return false;	nsupers = find_inheritors(relid, &supervec);	result = false;	for (i = 0; i < nsupers; i++)	{		if (supervec[i] == superclassTypeId)		{			result = true;			break;		}	}	if (supervec)		pfree(supervec);	return result;}/* * make_fn_arguments() * * Given the actual argument expressions for a function, and the desired * input types for the function, add any necessary typecasting to the * expression tree.  Caller should already have verified that casting is * allowed. * * Caution: given argument list is modified in-place. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */voidmake_fn_arguments(ParseState *pstate,				  List *fargs,				  Oid *actual_arg_types,				  Oid *declared_arg_types){	List	   *current_fargs;	int			i = 0;	foreach(current_fargs, fargs)	{		/* types don't match? then force coercion using a function call... */		if (actual_arg_types[i] != declared_arg_types[i])		{			lfirst(current_fargs) = coerce_type(pstate,												lfirst(current_fargs),												actual_arg_types[i],												declared_arg_types[i],												COERCION_IMPLICIT,												COERCE_IMPLICIT_CAST);		}		i++;	}}/* * setup_field_select *		Build a FieldSelect node that says which attribute to project to. *		This routine is called by ParseFuncOrColumn() when we have found *		a projection on a function result or parameter. */static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid){	FieldSelect *fselect = makeNode(FieldSelect);	AttrNumber	attno;	attno = get_attnum(relid, attname);	if (attno == InvalidAttrNumber)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_COLUMN),			 errmsg("column \"%s\" of relation \"%s\" does not exist",					attname, get_rel_name(relid))));	fselect->arg = (Expr *) input;	fselect->fieldnum = attno;	fselect->resulttype = get_atttype(relid, attno);	fselect->resulttypmod = get_atttypmod(relid, attno);	return fselect;}/* * ParseComplexProjection - *	  handles function calls with a single argument that is of complex type. *	  If the function call is actually a column projection, return a suitably *	  transformed expression tree.	If not, return NULL. * * NB: argument is expected to be transformed already, ie, not a RangeVar. */static Node *ParseComplexProjection(char *funcname, Node *first_arg){	Oid			argtype = exprType(first_arg);	Oid			argrelid;	AttrNumber	attnum;	FieldSelect *fselect;	argrelid = typeidTypeRelid(argtype);	if (!argrelid)		return NULL;			/* probably should not happen */	attnum = get_attnum(argrelid, funcname);	if (attnum == InvalidAttrNumber)		return NULL;			/* funcname does not match any column */	/*	 * Check for special cases where we don't want to return a	 * FieldSelect.	 */	switch (nodeTag(first_arg))	{		case T_Var:			{				Var		   *var = (Var *) first_arg;				/*				 * If the Var is a whole-row tuple, we can just replace it				 * with a simple Var reference.				 */				if (var->varattno == InvalidAttrNumber)				{					Oid			vartype;					int32		vartypmod;					get_atttypetypmod(argrelid, attnum,									  &vartype, &vartypmod);					return (Node *) makeVar(var->varno,											attnum,											vartype,											vartypmod,											var->varlevelsup);				}				break;			}		default:			break;	}	/* Else generate a FieldSelect expression */	fselect = setup_field_select(first_arg, funcname, argrelid);	return (Node *) fselect;}/* * Simple helper routine for delivering "column does not exist" error message */static voidunknown_attribute(const char *schemaname, const char *relname,				  const char *attname){	if (schemaname)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_COLUMN),				 errmsg("column %s.%s.%s does not exist",						schemaname, relname, attname)));	else		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_COLUMN),				 errmsg("column %s.%s does not exist",						relname, attname)));}/* * funcname_signature_string *		Build a string representing a function name, including arg types. *		The result is something like "foo(integer)". * * This is typically used in the construction of function-not-found error * messages. */const char *funcname_signature_string(const char *funcname,						  int nargs, const Oid *argtypes){	StringInfoData argbuf;	int			i;	initStringInfo(&argbuf);	appendStringInfo(&argbuf, "%s(", funcname);	for (i = 0; i < nargs; i++)	{		if (i)			appendStringInfoString(&argbuf, ", ");		appendStringInfoString(&argbuf, format_type_be(argtypes[i]));	}	appendStringInfoChar(&argbuf, ')');	return argbuf.data;			/* return palloc'd string buffer */}/* * func_signature_string *		As above, but function name is passed as a qualified name list. */const char *func_signature_string(List *funcname, int nargs, const Oid *argtypes){	return funcname_signature_string(NameListToString(funcname),									 nargs, argtypes);}/* * find_aggregate_func *		Convenience routine to check that a function exists and is an *		aggregate. * * Note: basetype is ANYOID if we are looking for an aggregate on * all types. */Oidfind_aggregate_func(List *aggname, Oid basetype, bool noError){	Oid			oid;	HeapTuple	ftup;	Form_pg_proc pform;	oid = LookupFuncName(aggname, 1, &basetype, true);	if (!OidIsValid(oid))	{		if (noError)			return InvalidOid;		if (basetype == ANYOID)			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_FUNCTION),					 errmsg("aggregate %s(*) does not exist",							NameListToString(aggname))));		else			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_FUNCTION),					 errmsg("aggregate %s(%s) does not exist",							NameListToString(aggname),							format_type_be(basetype))));	}	/* Make sure it's an aggregate */	ftup = SearchSysCache(PROCOID,						  ObjectIdGetDatum(oid),						  0, 0, 0);	if (!HeapTupleIsValid(ftup))	/* should not happen */		elog(ERROR, "cache lookup failed for function %u", oid);	pform = (Form_pg_proc) GETSTRUCT(ftup);	if (!pform->proisagg)	{		ReleaseSysCache(ftup);		if (noError)			return InvalidOid;		/* we do not use the (*) notation for functions... */		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("function %s(%s) is not an aggregate",				  NameListToString(aggname), format_type_be(basetype))));	}	ReleaseSysCache(ftup);	return oid;}/* * LookupFuncName *		Given a possibly-qualified function name and a set of argument types, *		look up the function. * * If the function name is not schema-qualified, it is sought in the current * namespace search path. * * If the function is not found, we return InvalidOid if noError is true, * else raise an error. */OidLookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError){	FuncCandidateList clist;	clist = FuncnameGetCandidates(funcname, nargs);	while (clist)	{		if (memcmp(argtypes, clist->args, nargs * sizeof(Oid)) == 0)			return clist->oid;		clist = clist->next;	}	if (!noError)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("function %s does not exist",					 func_signature_string(funcname, nargs, argtypes))));	return InvalidOid;}/* * LookupFuncNameTypeNames *		Like LookupFuncName, but the argument types are specified by a *		list of TypeName nodes. */OidLookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError){	Oid			argoids[FUNC_MAX_ARGS];	int			argcount;	int			i;	MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid));	argcount = length(argtypes);	if (argcount > FUNC_MAX_ARGS)		ereport(ERROR,				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),				 errmsg("functions cannot have more than %d arguments",						FUNC_MAX_ARGS)));	for (i = 0; i < argcount; i++)	{		TypeName   *t = (TypeName *) lfirst(argtypes);		argoids[i] = LookupTypeName(t);		if (!OidIsValid(argoids[i]))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("type \"%s\" does not exist",							TypeNameToString(t))));		argtypes = lnext(argtypes);	}	return LookupFuncName(funcname, argcount, argoids, noError);}

⌨️ 快捷键说明

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