funcapi.c

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

C
1,163
字号
 * 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_HASNULL(arr) ||			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_HASNULL(arr) ||			ARR_ELEMTYPE(arr) != TEXTOID)			elog(ERROR, "proargnames is not a 1-D text array");		deconstruct_array(arr, TEXTOID, -1, false, 'i',						  &argnames, NULL, &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 polymorphic 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_HASNULL(arr) ||		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_HASNULL(arr) ||		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_HASNULL(arr) ||			ARR_ELEMTYPE(arr) != TEXTOID)			elog(ERROR, "proargnames is not a 1-D text array");		deconstruct_array(arr, TEXTOID, -1, false, 'i',						  &argnames, NULL, &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);	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 = lookup_rowtype_tupdesc_copy(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 + =
减小字号Ctrl + -
显示快捷键?