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