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 + -
显示快捷键?