funcapi.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,163 行 · 第 1/3 页

C
1,163
字号
			break;		default:			break;	}	ReleaseSysCache(tp);	return result;}/* * Given the result tuple descriptor for a function with OUT parameters, * replace any polymorphic columns (ANYELEMENT etc) with correct data types * deduced from the input arguments. Returns TRUE if able to deduce all types, * FALSE if not. */static boolresolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,							Node *call_expr){	int			natts = tupdesc->natts;	int			nargs = declared_args->dim1;	bool		have_anyelement_result = false;	bool		have_anyarray_result = false;	bool		have_anynonarray = false;	bool		have_anyenum = false;	Oid			anyelement_type = InvalidOid;	Oid			anyarray_type = InvalidOid;	int			i;	/* See if there are any polymorphic outputs; quick out if not */	for (i = 0; i < natts; i++)	{		switch (tupdesc->attrs[i]->atttypid)		{			case ANYELEMENTOID:				have_anyelement_result = true;				break;			case ANYARRAYOID:				have_anyarray_result = true;				break;			case ANYNONARRAYOID:				have_anyelement_result = true;				have_anynonarray = true;				break;			case ANYENUMOID:				have_anyelement_result = true;				have_anyenum = true;				break;			default:				break;		}	}	if (!have_anyelement_result && !have_anyarray_result)		return true;	/*	 * Otherwise, extract actual datatype(s) from input arguments.	(We assume	 * the parser already validated consistency of the arguments.)	 */	if (!call_expr)		return false;			/* no hope */	for (i = 0; i < nargs; i++)	{		switch (declared_args->values[i])		{			case ANYELEMENTOID:			case ANYNONARRAYOID:			case ANYENUMOID:				if (!OidIsValid(anyelement_type))					anyelement_type = get_call_expr_argtype(call_expr, i);				break;			case ANYARRAYOID:				if (!OidIsValid(anyarray_type))					anyarray_type = get_call_expr_argtype(call_expr, i);				break;			default:				break;		}	}	/* If nothing found, parser messed up */	if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type))		return false;	/* If needed, deduce one polymorphic type from the other */	if (have_anyelement_result && !OidIsValid(anyelement_type))		anyelement_type = resolve_generic_type(ANYELEMENTOID,											   anyarray_type,											   ANYARRAYOID);	if (have_anyarray_result && !OidIsValid(anyarray_type))		anyarray_type = resolve_generic_type(ANYARRAYOID,											 anyelement_type,											 ANYELEMENTOID);	/* Enforce ANYNONARRAY if needed */	if (have_anynonarray && type_is_array(anyelement_type))		return false;	/* Enforce ANYENUM if needed */	if (have_anyenum && !type_is_enum(anyelement_type))		return false;	/* And finally replace the tuple column types as needed */	for (i = 0; i < natts; i++)	{		switch (tupdesc->attrs[i]->atttypid)		{			case ANYELEMENTOID:			case ANYNONARRAYOID:			case ANYENUMOID:				TupleDescInitEntry(tupdesc, i + 1,								   NameStr(tupdesc->attrs[i]->attname),								   anyelement_type,								   -1,								   0);				break;			case ANYARRAYOID:				TupleDescInitEntry(tupdesc, i + 1,								   NameStr(tupdesc->attrs[i]->attname),								   anyarray_type,								   -1,								   0);				break;			default:				break;		}	}	return true;}/* * Given the declared argument types and modes for a function, replace any * polymorphic types (ANYELEMENT etc) with correct data types deduced from the * input arguments.  Returns TRUE if able to deduce all types, FALSE if not. * This is the same logic as resolve_polymorphic_tupdesc, but with a different * argument representation. * * argmodes may be NULL, in which case all arguments are assumed to be IN mode. */boolresolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,							 Node *call_expr){	bool		have_anyelement_result = false;	bool		have_anyarray_result = false;	Oid			anyelement_type = InvalidOid;	Oid			anyarray_type = InvalidOid;	int			inargno;	int			i;	/* First pass: resolve polymorphic inputs, check for outputs */	inargno = 0;	for (i = 0; i < numargs; i++)	{		char		argmode = argmodes ? argmodes[i] : PROARGMODE_IN;		switch (argtypes[i])		{			case ANYELEMENTOID:			case ANYNONARRAYOID:			case ANYENUMOID:				if (argmode == PROARGMODE_OUT)					have_anyelement_result = true;				else				{					if (!OidIsValid(anyelement_type))					{						anyelement_type = get_call_expr_argtype(call_expr,																inargno);						if (!OidIsValid(anyelement_type))							return false;					}					argtypes[i] = anyelement_type;				}				break;			case ANYARRAYOID:				if (argmode == PROARGMODE_OUT)					have_anyarray_result = true;				else				{					if (!OidIsValid(anyarray_type))					{						anyarray_type = get_call_expr_argtype(call_expr,															  inargno);						if (!OidIsValid(anyarray_type))							return false;					}					argtypes[i] = anyarray_type;				}				break;			default:				break;		}		if (argmode != PROARGMODE_OUT)			inargno++;	}	/* Done? */	if (!have_anyelement_result && !have_anyarray_result)		return true;	/* If no input polymorphics, parser messed up */	if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type))		return false;	/* If needed, deduce one polymorphic type from the other */	if (have_anyelement_result && !OidIsValid(anyelement_type))		anyelement_type = resolve_generic_type(ANYELEMENTOID,											   anyarray_type,											   ANYARRAYOID);	if (have_anyarray_result && !OidIsValid(anyarray_type))		anyarray_type = resolve_generic_type(ANYARRAYOID,											 anyelement_type,											 ANYELEMENTOID);	/* XXX do we need to enforce ANYNONARRAY or ANYENUM here?  I think not */	/* And finally replace the output column types as needed */	for (i = 0; i < numargs; i++)	{		switch (argtypes[i])		{			case ANYELEMENTOID:			case ANYNONARRAYOID:			case ANYENUMOID:				argtypes[i] = anyelement_type;				break;			case ANYARRAYOID:				argtypes[i] = anyarray_type;				break;			default:				break;		}	}	return true;}/* * get_type_func_class *		Given the type OID, obtain its TYPEFUNC classification. * * This is intended to centralize a bunch of formerly ad-hoc code for * classifying types.  The categories used here are useful for deciding * how to handle functions returning the datatype. */static TypeFuncClassget_type_func_class(Oid typid){	switch (get_typtype(typid))	{		case TYPTYPE_COMPOSITE:			return TYPEFUNC_COMPOSITE;		case TYPTYPE_BASE:		case TYPTYPE_DOMAIN:		case TYPTYPE_ENUM:			return TYPEFUNC_SCALAR;		case TYPTYPE_PSEUDO:			if (typid == RECORDOID)				return TYPEFUNC_RECORD;			/*			 * We treat VOID and CSTRING as legitimate scalar datatypes,			 * mostly for the convenience of the JDBC driver (which wants to			 * be able to do "SELECT * FROM foo()" for all legitimately			 * user-callable functions).			 */			if (typid == VOIDOID || typid == CSTRINGOID)				return TYPEFUNC_SCALAR;			return TYPEFUNC_OTHER;	}	/* shouldn't get here, probably */	return TYPEFUNC_OTHER;}/* * get_func_arg_info * * Fetch info about the argument types, names, and IN/OUT modes from the * pg_proc tuple.  Return value is the total number of arguments. * Other results are palloc'd.  *p_argtypes is always filled in, but * *p_argnames and *p_argmodes will be set NULL in the default cases * (no names, and all IN arguments, respectively). * * Note that this function simply fetches what is in the pg_proc tuple; * it doesn't do any interpretation of polymorphic types. */intget_func_arg_info(HeapTuple procTup,				  Oid **p_argtypes, char ***p_argnames, char **p_argmodes){	Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);	Datum		proallargtypes;	Datum		proargmodes;	Datum		proargnames;	bool		isNull;	ArrayType  *arr;	int			numargs;	Datum	   *elems;	int			nelems;	int			i;	/* First discover the total number of parameters and get their types */	proallargtypes = SysCacheGetAttr(PROCOID, procTup,									 Anum_pg_proc_proallargtypes,									 &isNull);	if (!isNull)	{		/*		 * We expect the arrays to be 1-D arrays of the right types; verify		 * that.  For the OID and char arrays, we don't need to use		 * deconstruct_array() since the array data is just going to look like		 * a C array of values.		 */		arr = DatumGetArrayTypeP(proallargtypes);		/* ensure not toasted */		numargs = ARR_DIMS(arr)[0];		if (ARR_NDIM(arr) != 1 ||			numargs < 0 ||			ARR_HASNULL(arr) ||			ARR_ELEMTYPE(arr) != OIDOID)			elog(ERROR, "proallargtypes is not a 1-D Oid array");		Assert(numargs >= procStruct->pronargs);		*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));		memcpy(*p_argtypes, ARR_DATA_PTR(arr),			   numargs * sizeof(Oid));	}	else	{		/* If no proallargtypes, use proargtypes */		numargs = procStruct->proargtypes.dim1;		Assert(numargs == procStruct->pronargs);		*p_argtypes = (Oid *) palloc(numargs * sizeof(Oid));		memcpy(*p_argtypes, procStruct->proargtypes.values,			   numargs * sizeof(Oid));	}	/* Get argument names, if available */	proargnames = SysCacheGetAttr(PROCOID, procTup,								  Anum_pg_proc_proargnames,								  &isNull);	if (isNull)		*p_argnames = NULL;	else	{		deconstruct_array(DatumGetArrayTypeP(proargnames),						  TEXTOID, -1, false, 'i',						  &elems, NULL, &nelems);		if (nelems != numargs)	/* should not happen */			elog(ERROR, "proargnames must have the same number of elements as the function has arguments");		*p_argnames = (char **) palloc(sizeof(char *) * numargs);		for (i = 0; i < numargs; i++)			(*p_argnames)[i] = DatumGetCString(DirectFunctionCall1(textout,																   elems[i]));	}	/* Get argument modes, if available */	proargmodes = SysCacheGetAttr(PROCOID, procTup,								  Anum_pg_proc_proargmodes,								  &isNull);	if (isNull)		*p_argmodes = NULL;	else	{		arr = DatumGetArrayTypeP(proargmodes);	/* ensure not toasted */		if (ARR_NDIM(arr) != 1 ||			ARR_DIMS(arr)[0] != numargs ||			ARR_HASNULL(arr) ||			ARR_ELEMTYPE(arr) != CHAROID)			elog(ERROR, "proargmodes is not a 1-D char array");		*p_argmodes = (char *) palloc(numargs * sizeof(char));		memcpy(*p_argmodes, ARR_DATA_PTR(arr),			   numargs * sizeof(char));	}	return numargs;}/* * get_func_result_name * * If the function has exactly one output parameter, and that parameter * is named, return the name (as a palloc'd string).  Else return NULL. *

⌨️ 快捷键说明

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