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

📄 funcapi.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
	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:				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);	/* And finally replace the output column types as needed */	for (i = 0; i < numargs; i++)	{		switch (argtypes[i])		{			case ANYELEMENTOID:				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 'c':			return TYPEFUNC_COMPOSITE;		case 'b':		case 'd':			return TYPEFUNC_SCALAR;		case 'p':			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_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. * * This is used to determine the default output column name for functions * returning scalar types. */char *get_func_result_name(Oid functionId){	char	   *result;	HeapTuple	procTuple;	Datum		proargmodes;	Datum		proargnames;	bool		isnull;	ArrayType  *arr;	int			numargs;	char	   *argmodes;	Datum	   *argnames;	int			numoutargs;	int			nargnames;	int			i;	/* First fetch the function's pg_proc row */	procTuple = SearchSysCache(PROCOID,							   ObjectIdGetDatum(functionId),							   0, 0, 0);	if (!HeapTupleIsValid(procTuple))		elog(ERROR, "cache lookup failed for function %u", functionId);	/* If there are no named OUT parameters, return NULL */	if (heap_attisnull(procTuple, Anum_pg_proc_proargmodes) ||		heap_attisnull(procTuple, Anum_pg_proc_proargnames))		result = NULL;	else	{		/* Get the data out of the tuple */		proargmodes = SysCacheGetAttr(PROCOID, procTuple,									  Anum_pg_proc_proargmodes,									  &isnull);		Assert(!isnull);		proargnames = SysCacheGetAttr(PROCOID, procTuple,									  Anum_pg_proc_proargnames,									  &isnull);		Assert(!isnull);		/*		 * We expect the arrays to be 1-D arrays of the right types; verify		 * that.  For the char array, 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(proargmodes);	/* ensure not toasted */		numargs = ARR_DIMS(arr)[0];		if (ARR_NDIM(arr) != 1 ||			numargs < 0 ||			ARR_ELEMTYPE(arr) != CHAROID)			elog(ERROR, "proargmodes is not a 1-D char array");		argmodes = (char *) ARR_DATA_PTR(arr);		arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */		if (ARR_NDIM(arr) != 1 ||			ARR_DIMS(arr)[0] != numargs ||			ARR_ELEMTYPE(arr) != TEXTOID)			elog(ERROR, "proargnames is not a 1-D text array");		deconstruct_array(arr, TEXTOID, -1, false, 'i',						  &argnames, &nargnames);		Assert(nargnames == numargs);		/* scan for output argument(s) */		result = NULL;		numoutargs = 0;		for (i = 0; i < numargs; i++)		{			if (argmodes[i] == PROARGMODE_IN)				continue;			Assert(argmodes[i] == PROARGMODE_OUT ||				   argmodes[i] == PROARGMODE_INOUT);			if (++numoutargs > 1)			{				/* multiple out args, so forget it */				result = NULL;				break;			}			result = DatumGetCString(DirectFunctionCall1(textout,														 argnames[i]));			if (result == NULL || result[0] == '\0')			{				/* Parameter is not named, so forget it */				result = NULL;				break;			}		}	}	ReleaseSysCache(procTuple);	return result;}/* * build_function_result_tupdesc_t * * Given a pg_proc row for a function, return a tuple descriptor for the * result rowtype, or NULL if the function does not have OUT parameters. * * Note that this does not handle resolution of ANYELEMENT/ANYARRAY types; * that is deliberate. */TupleDescbuild_function_result_tupdesc_t(HeapTuple procTuple){	Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(procTuple);	Datum		proallargtypes;	Datum		proargmodes;	Datum		proargnames;	bool		isnull;	/* Return NULL if the function isn't declared to return RECORD */	if (procform->prorettype != RECORDOID)		return NULL;	/* If there are no OUT parameters, return NULL */	if (heap_attisnull(procTuple, Anum_pg_proc_proallargtypes) ||		heap_attisnull(procTuple, Anum_pg_proc_proargmodes))		return NULL;	/* Get the data out of the tuple */	proallargtypes = SysCacheGetAttr(PROCOID, procTuple,									 Anum_pg_proc_proallargtypes,									 &isnull);	Assert(!isnull);	proargmodes = SysCacheGetAttr(PROCOID, procTuple,								  Anum_pg_proc_proargmodes,								  &isnull);	Assert(!isnull);	proargnames = SysCacheGetAttr(PROCOID, procTuple,								  Anum_pg_proc_proargnames,								  &isnull);	if (isnull)		proargnames = PointerGetDatum(NULL);	/* just to be sure */	return build_function_result_tupdesc_d(proallargtypes,										   proargmodes,										   proargnames);}/* * build_function_result_tupdesc_d * * Build a RECORD function's tupledesc from the pg_proc proallargtypes, * proargmodes, and proargnames arrays.  This is split out for the * convenience of ProcedureCreate, which needs to be able to compute the * tupledesc before actually creating the function. * * Returns NULL if there are not at least two OUT or INOUT arguments. */TupleDescbuild_function_result_tupdesc_d(Datum proallargtypes,								Datum proargmodes,								Datum proargnames){	TupleDesc	desc;	ArrayType  *arr;	int			numargs;	Oid		   *argtypes;	char	   *argmodes;	Datum	   *argnames = NULL;	Oid		   *outargtypes;	char	  **outargnames;	int			numoutargs;	int			nargnames;	int			i;	/* Can't have output args if columns are null */	if (proallargtypes == PointerGetDatum(NULL) ||		proargmodes == PointerGetDatum(NULL))		return NULL;	/*	 * 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_ELEMTYPE(arr) != OIDOID)		elog(ERROR, "proallargtypes is not a 1-D Oid array");	argtypes = (Oid *) ARR_DATA_PTR(arr);	arr = DatumGetArrayTypeP(proargmodes);		/* ensure not toasted */	if (ARR_NDIM(arr) != 1 ||		ARR_DIMS(arr)[0] != numargs ||		ARR_ELEMTYPE(arr) != CHAROID)		elog(ERROR, "proargmodes is not a 1-D char array");	argmodes = (char *) ARR_DATA_PTR(arr);	if (proargnames != PointerGetDatum(NULL))	{		arr = DatumGetArrayTypeP(proargnames);	/* ensure not toasted */		if (ARR_NDIM(arr) != 1 ||			ARR_DIMS(arr)[0] != numargs ||			ARR_ELEMTYPE(arr) != TEXTOID)			elog(ERROR, "proargnames is not a 1-D text array");		deconstruct_array(arr, TEXTOID, -1, false, 'i',						  &argnames, &nargnames);		Assert(nargnames == numargs);	}	/* zero elements probably shouldn't happen, but handle it gracefully */	if (numargs <= 0)		return NULL;	/* extract output-argument types and names */	outargtypes = (Oid *) palloc(numargs * sizeof(Oid));	outargnames = (char **) palloc(numargs * sizeof(char *));	numoutargs = 0;	for (i = 0; i < numargs; i++)	{		char	   *pname;		if (argmodes[i] == PROARGMODE_IN)			continue;		Assert(argmodes[i] == PROARGMODE_OUT ||			   argmodes[i] == PROARGMODE_INOUT);		outargtypes[numoutargs] = argtypes[i];		if (argnames)			pname = DatumGetCString(DirectFunctionCall1(textout, argnames[i]));		else			pname = NULL;		if (pname == NULL || pname[0] == '\0')		{			/* Parameter is not named, so gin up a column name */			pname = (char *) palloc(32);			snprintf(pname, 32, "column%d", numoutargs + 1);		}		outargnames[numoutargs] = pname;		numoutargs++;	}	/*	 * If there is no output argument, or only one, the function does not	 * return tuples.	 */	if (numoutargs < 2)		return NULL;	desc = CreateTemplateTupleDesc(numoutargs, false);	for (i = 0; i < numoutargs; i++)	{		TupleDescInitEntry(desc, i + 1,						   outargnames[i],						   outargtypes[i],						   -1,						   0);	}	return desc;}/* * RelationNameGetTupleDesc * * Given a (possibly qualified) relation name, build a TupleDesc. * * Note: while this works as advertised, it's seldom the best way to * build a tupdesc for a function's result type.  It's kept around * only for backwards compatibility with existing user-written code. */TupleDescRelationNameGetTupleDesc(const char *relname){	RangeVar   *relvar;	Relation	rel;	TupleDesc	tupdesc;	List	   *relname_list;	/* Open relation and copy the tuple description */	relname_list = stringToQualifiedNameList(relname, "RelationNameGetTupleDesc");	relvar = makeRangeVarFromNameList(relname_list);	rel = relation_openrv(relvar, AccessShareLock);	tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));	relation_close(rel, AccessShareLock);	return tupdesc;}/* * TypeGetTupleDesc * * Given a type Oid, build a TupleDesc.  (In most cases you should be * using get_call_result_type or one of its siblings instead of this * routine, so that you can handle OUT parameters, RECORD result type, * and polymorphic results.) * * If the type is composite, *and* a colaliases List is provided, *and* * the List is of natts length, use the aliases instead of the relation * attnames.  (NB: this usage is deprecated since it may result in * creation of unnecessary transient record types.) * * If the type is a base type, a single item alias List is required. */TupleDescTypeGetTupleDesc(Oid typeoid, List *colaliases){	TypeFuncClass functypclass = get_type_func_class(typeoid);	TupleDesc	tupdesc = NULL;	/*	 * Build a suitable tupledesc representing the output rows	 */	if (functypclass == TYPEFUNC_COMPOSITE)	{		/* Composite data type, e.g. a table's row type */		tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(typeoid, -1));		if (colaliases != NIL)		{			int			natts = tupdesc->natts;			int			varattno;			/* does the list length match the number of attributes? */			if (list_length(colaliases) != natts)				ereport(ERROR,						(errcode(ERRCODE_DATATYPE_MISMATCH),						 errmsg("number of aliases does not match number of columns")));			/* OK, use the aliases instead */			for (varattno = 0; varattno < natts; varattno++)			{				char	   *label = strVal(list_nth(colaliases, varattno));				if (label != NULL)					namestrcpy(&(tupdesc->attrs[varattno]->attname), label);			}			/* The tuple type is now an anonymous record type */			tupdesc->tdtypeid = RECORDOID;			tupdesc->tdtypmod = -1;		}	}	else if (functypclass == TYPEFUNC_SCALAR)	{		/* Base data type, i.e. scalar */		char	   *attname;		/* the alias list is required for base types */		if (colaliases == NIL)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),					 errmsg("no column alias was provided")));		/* the alias list length must be 1 */		if (list_length(colaliases) != 1)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),			  errmsg("number of aliases does not match number of columns")));		/* OK, get the column alias */		attname = strVal(linitial(colaliases));		tupdesc = CreateTemplateTupleDesc(1, false);		TupleDescInitEntry(tupdesc,						   (AttrNumber) 1,						   attname,						   typeoid,						   -1,						   0);	}	else if (functypclass == TYPEFUNC_RECORD)	{		/* XXX can't support this because typmod wasn't passed in ... */		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("could not determine row description for function returning record")));	}	else	{		/* crummy error message, but parser should have caught this */		elog(ERROR, "function in FROM has unsupported return type");	}	return tupdesc;}

⌨️ 快捷键说明

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