pg_proc.c

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

C
739
字号
					 errmsg("return type mismatch in function declared to return %s",							format_type_be(rettype)),			 errdetail("Function's final statement must be a SELECT.")));		return;	}	/* find the final query */	parse = (Query *) llast(queryTreeList);	cmd = parse->commandType;	tlist = parse->targetList;	/*	 * The last query must be a SELECT if and only if return type isn't	 * VOID.	 */	if (rettype == VOIDOID)	{		if (cmd == CMD_SELECT)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("return type mismatch in function declared to return %s",							format_type_be(rettype)),					 errdetail("Function's final statement must not be a SELECT.")));		return;	}	/* by here, the function is declared to return some type */	if (cmd != CMD_SELECT)		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),		 errmsg("return type mismatch in function declared to return %s",				format_type_be(rettype)),			 errdetail("Function's final statement must be a SELECT.")));	/*	 * Count the non-junk entries in the result targetlist.	 */	tlistlen = ExecCleanTargetListLength(tlist);	typerelid = typeidTypeRelid(rettype);	if (fn_typtype == 'b' || fn_typtype == 'd')	{		/* Shouldn't have a typerelid */		Assert(typerelid == InvalidOid);		/*		 * For base-type returns, the target list should have exactly one		 * entry, and its type should agree with what the user declared.		 * (As of Postgres 7.2, we accept binary-compatible types too.)		 */		if (tlistlen != 1)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("return type mismatch in function declared to return %s",							format_type_be(rettype)),			 errdetail("Final SELECT must return exactly one column.")));		restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;		if (!IsBinaryCoercible(restype, rettype))			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("return type mismatch in function declared to return %s",							format_type_be(rettype)),					 errdetail("Actual return type is %s.",							   format_type_be(restype))));	}	else if (fn_typtype == 'c')	{		/* Must have a typerelid */		Assert(typerelid != InvalidOid);		/*		 * If the target list is of length 1, and the type of the varnode		 * in the target list matches the declared return type, this is		 * okay. This can happen, for example, where the body of the		 * function is 'SELECT func2()', where func2 has the same return		 * type as the function that's calling it.		 */		if (tlistlen == 1)		{			restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;			if (IsBinaryCoercible(restype, rettype))				return;		}		/*		 * Otherwise verify that the targetlist matches the return tuple		 * type. This part of the typechecking is a hack. We look up the		 * relation that is the declared return type, and scan the		 * non-deleted attributes to ensure that they match the datatypes		 * of the non-resjunk columns.		 */		reln = relation_open(typerelid, AccessShareLock);		relnatts = reln->rd_rel->relnatts;		rellogcols = 0;			/* we'll count nondeleted cols as we go */		colindex = 0;		foreach(tlistitem, tlist)		{			TargetEntry *tle = (TargetEntry *) lfirst(tlistitem);			Form_pg_attribute attr;			Oid			tletype;			Oid			atttype;			if (tle->resdom->resjunk)				continue;			do			{				colindex++;				if (colindex > relnatts)					ereport(ERROR,							(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),							 errmsg("return type mismatch in function declared to return %s",									format_type_be(rettype)),					errdetail("Final SELECT returns too many columns.")));				attr = reln->rd_att->attrs[colindex - 1];			} while (attr->attisdropped);			rellogcols++;			tletype = exprType((Node *) tle->expr);			atttype = attr->atttypid;			if (!IsBinaryCoercible(tletype, atttype))				ereport(ERROR,						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),						 errmsg("return type mismatch in function declared to return %s",								format_type_be(rettype)),						 errdetail("Final SELECT returns %s instead of %s at column %d.",								   format_type_be(tletype),								   format_type_be(atttype),								   rellogcols)));		}		for (;;)		{			colindex++;			if (colindex > relnatts)				break;			if (!reln->rd_att->attrs[colindex - 1]->attisdropped)				rellogcols++;		}		if (tlistlen != rellogcols)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("return type mismatch in function declared to return %s",							format_type_be(rettype)),					 errdetail("Final SELECT returns too few columns.")));		relation_close(reln, AccessShareLock);	}	else if (rettype == RECORDOID)	{		/* Shouldn't have a typerelid */		Assert(typerelid == InvalidOid);		/*		 * For RECORD return type, defer this check until we get the first		 * tuple.		 */	}	else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)	{		/* This should already have been caught ... */		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("cannot determine result data type"),				 errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));	}	else		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),			  errmsg("return type %s is not supported for SQL functions",					 format_type_be(rettype))));}/* * Validator for internal functions * * Check that the given internal function name (the "prosrc" value) is * a known builtin function. */Datumfmgr_internal_validator(PG_FUNCTION_ARGS){	Oid			funcoid = PG_GETARG_OID(0);	HeapTuple	tuple;	Form_pg_proc proc;	bool		isnull;	Datum		tmp;	char	   *prosrc;	/*	 * We do not honor check_function_bodies since it's unlikely the	 * function name will be found later if it isn't there now.	 */	tuple = SearchSysCache(PROCOID,						   ObjectIdGetDatum(funcoid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for function %u", funcoid);	proc = (Form_pg_proc) GETSTRUCT(tuple);	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);	if (isnull)		elog(ERROR, "null prosrc");	prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));	if (fmgr_internal_function(prosrc) == InvalidOid)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_FUNCTION),				 errmsg("there is no built-in function named \"%s\"",						prosrc)));	ReleaseSysCache(tuple);	PG_RETURN_VOID();}/* * Validator for C language functions * * Make sure that the library file exists, is loadable, and contains * the specified link symbol. Also check for a valid function * information record. */Datumfmgr_c_validator(PG_FUNCTION_ARGS){	Oid			funcoid = PG_GETARG_OID(0);	void	   *libraryhandle;	HeapTuple	tuple;	Form_pg_proc proc;	bool		isnull;	Datum		tmp;	char	   *prosrc;	char	   *probin;	/*	 * It'd be most consistent to skip the check if !check_function_bodies,	 * but the purpose of that switch is to be helpful for pg_dump loading,	 * and for pg_dump loading it's much better if we *do* check.	 */	tuple = SearchSysCache(PROCOID,						   ObjectIdGetDatum(funcoid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for function %u", funcoid);	proc = (Form_pg_proc) GETSTRUCT(tuple);	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);	if (isnull)		elog(ERROR, "null prosrc");	prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));	tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);	if (isnull)		elog(ERROR, "null probin");	probin = DatumGetCString(DirectFunctionCall1(textout, tmp));	(void) load_external_function(probin, prosrc, true, &libraryhandle);	(void) fetch_finfo_record(libraryhandle, prosrc);	ReleaseSysCache(tuple);	PG_RETURN_VOID();}/* * Validator for SQL language functions * * Parse it here in order to be sure that it contains no syntax errors. */Datumfmgr_sql_validator(PG_FUNCTION_ARGS){	Oid			funcoid = PG_GETARG_OID(0);	HeapTuple	tuple;	Form_pg_proc proc;	List	   *querytree_list;	bool		isnull;	Datum		tmp;	char	   *prosrc;	char		functyptype;	bool		haspolyarg;	int			i;	tuple = SearchSysCache(PROCOID,						   ObjectIdGetDatum(funcoid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for function %u", funcoid);	proc = (Form_pg_proc) GETSTRUCT(tuple);	functyptype = get_typtype(proc->prorettype);	/* Disallow pseudotype result */	/* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */	if (functyptype == 'p' &&		proc->prorettype != RECORDOID &&		proc->prorettype != VOIDOID &&		proc->prorettype != ANYARRAYOID &&		proc->prorettype != ANYELEMENTOID)		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("SQL functions cannot return type %s",						format_type_be(proc->prorettype))));	/* Disallow pseudotypes in arguments */	/* except for ANYARRAY or ANYELEMENT */	haspolyarg = false;	for (i = 0; i < proc->pronargs; i++)	{		if (get_typtype(proc->proargtypes[i]) == 'p')		{			if (proc->proargtypes[i] == ANYARRAYOID ||				proc->proargtypes[i] == ANYELEMENTOID)				haspolyarg = true;			else				ereport(ERROR,						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("SQL functions cannot have arguments of type %s",						format_type_be(proc->proargtypes[i]))));		}	}	/* Postpone body checks if !check_function_bodies */	if (check_function_bodies)	{		tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);		if (isnull)			elog(ERROR, "null prosrc");		prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));		/*		 * We can't do full prechecking of the function definition if there		 * are any polymorphic input types, because actual datatypes of		 * expression results will be unresolvable.  The check will be done		 * at runtime instead.		 *		 * We can run the text through the raw parser though; this will at		 * least catch silly syntactic errors.		 */		if (!haspolyarg)		{			querytree_list = pg_parse_and_rewrite(prosrc,												  proc->proargtypes,												  proc->pronargs);			check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);		}		else			querytree_list = pg_parse_query(prosrc);	}	ReleaseSysCache(tuple);	PG_RETURN_VOID();}

⌨️ 快捷键说明

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