typedefstruct polymorphic_actuals
{
Oid anyelement_type; /* anyelement mapping, if known */
Oid anyarray_type; /* anyarray mapping, if known */
Oid anyrange_type; /* anyrange mapping, if known */
Oid anymultirange_type; /* anymultirange mapping, if known */
} polymorphic_actuals;
/* check to see if caller supports returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize) ||
((flags & MAT_SRF_USE_EXPECTED_DESC) != 0 && rsinfo->expectedDesc == NULL))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not allowed in this context")));
/* build a tuple descriptor for our result type */ if ((flags & MAT_SRF_USE_EXPECTED_DESC) != 0)
stored_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); else
{ if (get_call_result_type(fcinfo, NULL, &stored_tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
}
/* If requested, bless the tuple descriptor */ if ((flags & MAT_SRF_BLESS) != 0)
BlessTupleDesc(stored_tupdesc);
/* *Bailifwe'recalledinthewrongcontext
*/ if (fcinfo->resultinfo == NULL || !IsA(fcinfo->resultinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
/* *Ensurewewillgetshutdowncleanlyiftheexprcontextisnotrun *tocompletion.
*/
RegisterExprContextCallback(rsi->econtext,
shutdown_MultiFuncCall,
PointerGetDatum(fcinfo->flinfo));
} else
{ /* second and subsequent calls */
elog(ERROR, "init_MultiFuncCall cannot be called more than once");
/* never reached, but keep compiler happy */
retval = NULL;
}
rec = DatumGetHeapTupleHeader(((Const *) expr)->constvalue);
tupType = HeapTupleHeaderGetTypeId(rec);
tupTypmod = HeapTupleHeaderGetTypMod(rec); if (resultTypeId)
*resultTypeId = tupType; if (tupType != RECORDOID || tupTypmod >= 0)
{ /* Should be able to look it up */ if (resultTupleDesc)
*resultTupleDesc = lookup_rowtype_tupdesc_copy(tupType,
tupTypmod); return TYPEFUNC_COMPOSITE;
} else
{ /* This shouldn't really happen ... */ if (resultTupleDesc)
*resultTupleDesc = NULL; return TYPEFUNC_RECORD;
}
} else
{ /* handle as a generic expression; no chance to resolve RECORD */
Oid typid = exprType(expr);
Oid base_typid;
if (resultTypeId)
*resultTypeId = typid; if (resultTupleDesc)
*resultTupleDesc = NULL;
result = get_type_func_class(typid, &base_typid); if ((result == TYPEFUNC_COMPOSITE ||
result == TYPEFUNC_COMPOSITE_DOMAIN) &&
resultTupleDesc)
*resultTupleDesc = lookup_rowtype_tupdesc_copy(base_typid, -1);
}
/* First fetch the function's pg_proc row to inspect its rettype */
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
procform = (Form_pg_proc) GETSTRUCT(tp);
rettype = procform->prorettype;
/* Check for OUT parameters defining a RECORD result */
tupdesc = build_function_result_tupdesc_t(tp); if (tupdesc)
{ /* *IthasOUTparameters,soit'sbasicallylikearegularcomposite *type,exceptwehavetobeabletoresolveanypolymorphicOUT *parameters.
*/ if (resultTypeId)
*resultTypeId = rettype;
if (resolve_polymorphic_tupdesc(tupdesc,
&procform->proargtypes,
call_expr))
{ if (tupdesc->tdtypeid == RECORDOID &&
tupdesc->tdtypmod < 0)
assign_record_type_typmod(tupdesc); if (resultTupleDesc)
*resultTupleDesc = tupdesc;
result = TYPEFUNC_COMPOSITE;
} else
{ if (resultTupleDesc)
*resultTupleDesc = NULL;
result = TYPEFUNC_RECORD;
}
ReleaseSysCache(tp);
return result;
}
/* *Ifscalarpolymorphicresult,trytoresolveit.
*/ if (IsPolymorphicType(rettype))
{
Oid newrettype = exprType(call_expr);
if (newrettype == InvalidOid) /* this probably should not happen */
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not determine actual result type for function \"%s\" declared to return type %s",
NameStr(procform->proname),
format_type_be(rettype))));
rettype = newrettype;
}
if (resultTypeId)
*resultTypeId = rettype; if (resultTupleDesc)
*resultTupleDesc = NULL; /* default result */
/* Classify the result type */
result = get_type_func_class(rettype, &base_rettype); switch (result)
{ case TYPEFUNC_COMPOSITE: case TYPEFUNC_COMPOSITE_DOMAIN: if (resultTupleDesc)
*resultTupleDesc = lookup_rowtype_tupdesc_copy(base_rettype, -1); /* Named composite types can't have any polymorphic columns */ break; case TYPEFUNC_SCALAR: break; case TYPEFUNC_RECORD: /* We must get the tupledesc from call context */ if (rsinfo && IsA(rsinfo, ReturnSetInfo) &&
rsinfo->expectedDesc != NULL)
{
result = TYPEFUNC_COMPOSITE; if (resultTupleDesc)
*resultTupleDesc = rsinfo->expectedDesc; /* Assume no polymorphic columns here, either */
} break; default: break;
}
if (functypclass == TYPEFUNC_COMPOSITE ||
functypclass == TYPEFUNC_COMPOSITE_DOMAIN) return tupleDesc;
if (!noError)
{
Oid exprTypeId = exprType(expr);
if (exprTypeId != RECORDOID)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("type %s is not composite",
format_type_be(exprTypeId)))); else
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("record type has not been registered")));
}
return NULL;
}
/* *ResolveactualtypeofANYELEMENTfromotherpolymorphicinputs * *Note:theerrorcaseshereandinthesiblingfunctionsbelowarenot *reallyuser-facing;theycouldonlyoccurifthefunctionsignatureis *incorrectortheparserfailedtoenforceconsistencyoftheactual *argumenttypes.Hence,wedon'tsweattoomuchovertheerrormessages.
*/ staticvoid
resolve_anyelement_from_others(polymorphic_actuals *actuals)
{ if (OidIsValid(actuals->anyarray_type))
{ /* Use the element type corresponding to actual type */
Oid array_base_type = getBaseType(actuals->anyarray_type);
Oid array_typelem = get_element_type(array_base_type);
if (!OidIsValid(array_typelem))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared %s is not an array but type %s", "anyarray",
format_type_be(array_base_type))));
actuals->anyelement_type = array_typelem;
} elseif (OidIsValid(actuals->anyrange_type))
{ /* Use the element type corresponding to actual type */
Oid range_base_type = getBaseType(actuals->anyrange_type);
Oid range_typelem = get_range_subtype(range_base_type);
if (!OidIsValid(range_typelem))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared %s is not a range type but type %s", "anyrange",
format_type_be(range_base_type))));
actuals->anyelement_type = range_typelem;
} elseif (OidIsValid(actuals->anymultirange_type))
{ /* Use the element type based on the multirange type */
Oid multirange_base_type;
Oid multirange_typelem;
Oid range_base_type;
Oid range_typelem;
multirange_base_type = getBaseType(actuals->anymultirange_type);
multirange_typelem = get_multirange_range(multirange_base_type); if (!OidIsValid(multirange_typelem))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared %s is not a multirange type but type %s", "anymultirange",
format_type_be(multirange_base_type))));
if (!OidIsValid(range_typelem))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared %s does not contain a range type but type %s", "anymultirange",
format_type_be(range_base_type))));
actuals->anyelement_type = range_typelem;
} else
elog(ERROR, "could not determine polymorphic type");
}
/* *ResolveactualtypeofANYARRAYfromotherpolymorphicinputs
*/ staticvoid
resolve_anyarray_from_others(polymorphic_actuals *actuals)
{ /* If we don't know ANYELEMENT, resolve that first */ if (!OidIsValid(actuals->anyelement_type))
resolve_anyelement_from_others(actuals);
if (OidIsValid(actuals->anyelement_type))
{ /* Use the array type corresponding to actual type */
Oid array_typeid = get_array_type(actuals->anyelement_type);
if (!OidIsValid(array_typeid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find array type for data type %s",
format_type_be(actuals->anyelement_type))));
actuals->anyarray_type = array_typeid;
} else
elog(ERROR, "could not determine polymorphic type");
}
/* *ResolveactualtypeofANYRANGEfromotherpolymorphicinputs
*/ staticvoid
resolve_anyrange_from_others(polymorphic_actuals *actuals)
{ /* *Wecan'tdeducearangetypefromotherpolymorphicarrayorbase *types,becausetheremaybemultiplerangetypeswiththesamesubtype, *butwecandeduceitfromapolymorphicmultirangetype.
*/ if (OidIsValid(actuals->anymultirange_type))
{ /* Use the element type based on the multirange type */
Oid multirange_base_type = getBaseType(actuals->anymultirange_type);
Oid multirange_typelem = get_multirange_range(multirange_base_type);
if (!OidIsValid(multirange_typelem))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("argument declared %s is not a multirange type but type %s", "anymultirange",
format_type_be(multirange_base_type))));
actuals->anyrange_type = multirange_typelem;
} else
elog(ERROR, "could not determine polymorphic type");
}
/* *ResolveactualtypeofANYMULTIRANGEfromotherpolymorphicinputs
*/ staticvoid
resolve_anymultirange_from_others(polymorphic_actuals *actuals)
{ /* *Wecan'tdeduceamultirangetypefrompolymorphicarrayorbasetypes, *becausetheremaybemultiplerangetypeswiththesamesubtype,butwe *candeduceitfromapolymorphicrangetype.
*/ if (OidIsValid(actuals->anyrange_type))
{
Oid range_base_type = getBaseType(actuals->anyrange_type);
Oid multirange_typeid = get_range_multirange(range_base_type);
if (!OidIsValid(multirange_typeid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("could not find multirange type for data type %s",
format_type_be(actuals->anyrange_type))));
actuals->anymultirange_type = multirange_typeid;
} else
elog(ERROR, "could not determine polymorphic type");
}
/* See if there are any polymorphic outputs; quick out if not */ for (i = 0; i < natts; i++)
{ switch (TupleDescAttr(tupdesc, i)->atttypid)
{ case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID:
have_polymorphic_result = true;
have_anyelement_result = true; break; case ANYARRAYOID:
have_polymorphic_result = true;
have_anyarray_result = true; break; case ANYRANGEOID:
have_polymorphic_result = true;
have_anyrange_result = true; break; case ANYMULTIRANGEOID:
have_polymorphic_result = true;
have_anymultirange_result = true; break; case ANYCOMPATIBLEOID: case ANYCOMPATIBLENONARRAYOID:
have_polymorphic_result = true;
have_anycompatible_result = true; break; case ANYCOMPATIBLEARRAYOID:
have_polymorphic_result = true;
have_anycompatible_array_result = true; break; case ANYCOMPATIBLERANGEOID:
have_polymorphic_result = true;
have_anycompatible_range_result = true; break; case ANYCOMPATIBLEMULTIRANGEOID:
have_polymorphic_result = true;
have_anycompatible_multirange_result = true; break; default: break;
}
} if (!have_polymorphic_result) returntrue;
/* *Otherwise,extractactualdatatype(s)frominputarguments.(Weassume *theparseralreadyvalidatedconsistencyofthearguments.Also,for *theANYCOMPATIBLEpseudotypefamily,weexpectthatallmatching *argumentswerecoercedtotheselectedcommonsupertype,sothatit *doesn'tmatterwhichone'sexposedtypewelookat.)
*/ if (!call_expr) returnfalse; /* no hope */
for (i = 0; i < nargs; i++)
{ switch (declared_args->values[i])
{ case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: if (!OidIsValid(poly_actuals.anyelement_type))
{
poly_actuals.anyelement_type =
get_call_expr_argtype(call_expr, i); if (!OidIsValid(poly_actuals.anyelement_type)) returnfalse;
} break; case ANYARRAYOID: if (!OidIsValid(poly_actuals.anyarray_type))
{
poly_actuals.anyarray_type =
get_call_expr_argtype(call_expr, i); if (!OidIsValid(poly_actuals.anyarray_type)) returnfalse;
} break; case ANYRANGEOID: if (!OidIsValid(poly_actuals.anyrange_type))
{
poly_actuals.anyrange_type =
get_call_expr_argtype(call_expr, i); if (!OidIsValid(poly_actuals.anyrange_type)) returnfalse;
} break; case ANYMULTIRANGEOID: if (!OidIsValid(poly_actuals.anymultirange_type))
{
poly_actuals.anymultirange_type =
get_call_expr_argtype(call_expr, i); if (!OidIsValid(poly_actuals.anymultirange_type)) returnfalse;
} break; case ANYCOMPATIBLEOID: case ANYCOMPATIBLENONARRAYOID: if (!OidIsValid(anyc_actuals.anyelement_type))
{
anyc_actuals.anyelement_type =
get_call_expr_argtype(call_expr, i); if (!OidIsValid(anyc_actuals.anyelement_type)) returnfalse;
} break; case ANYCOMPATIBLEARRAYOID: if (!OidIsValid(anyc_actuals.anyarray_type))
{
anyc_actuals.anyarray_type =
get_call_expr_argtype(call_expr, i); if (!OidIsValid(anyc_actuals.anyarray_type)) returnfalse;
} break; case ANYCOMPATIBLERANGEOID: if (!OidIsValid(anyc_actuals.anyrange_type))
{
anyc_actuals.anyrange_type =
get_call_expr_argtype(call_expr, i); if (!OidIsValid(anyc_actuals.anyrange_type)) returnfalse;
} break; case ANYCOMPATIBLEMULTIRANGEOID: if (!OidIsValid(anyc_actuals.anymultirange_type))
{
anyc_actuals.anymultirange_type =
get_call_expr_argtype(call_expr, i); if (!OidIsValid(anyc_actuals.anymultirange_type)) returnfalse;
} break; default: break;
}
}
/* If needed, deduce one polymorphic type from others */ if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
resolve_anyelement_from_others(&poly_actuals);
if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
resolve_anyarray_from_others(&poly_actuals);
if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
resolve_anyrange_from_others(&poly_actuals);
if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
resolve_anymultirange_from_others(&poly_actuals);
if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
resolve_anyelement_from_others(&anyc_actuals);
if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
resolve_anyarray_from_others(&anyc_actuals);
if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
resolve_anyrange_from_others(&anyc_actuals);
if (have_anycompatible_multirange_result && !OidIsValid(anyc_actuals.anymultirange_type))
resolve_anymultirange_from_others(&anyc_actuals);
if (OidIsValid(anyc_actuals.anyelement_type))
anycompatcollation = get_typcollation(anyc_actuals.anyelement_type); elseif (OidIsValid(anyc_actuals.anyarray_type))
anycompatcollation = get_typcollation(anyc_actuals.anyarray_type);
if (OidIsValid(anycollation) || OidIsValid(anycompatcollation))
{ /* *Thetypesarecollatable,soconsiderwhethertouseanondefault *collation.Wedosoifwecanidentifytheinputcollationused *forthefunction.
*/
Oid inputcollation = exprInputCollation(call_expr);
if (OidIsValid(inputcollation))
{ if (OidIsValid(anycollation))
anycollation = inputcollation; if (OidIsValid(anycompatcollation))
anycompatcollation = inputcollation;
}
}
/* And finally replace the tuple column types as needed */ for (i = 0; i < natts; i++)
{
Form_pg_attribute att = TupleDescAttr(tupdesc, i);
switch (att->atttypid)
{ case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(att->attname),
poly_actuals.anyelement_type,
-1, 0);
TupleDescInitEntryCollation(tupdesc, i + 1, anycollation); break; case ANYARRAYOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(att->attname),
poly_actuals.anyarray_type,
-1, 0);
TupleDescInitEntryCollation(tupdesc, i + 1, anycollation); break; case ANYRANGEOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(att->attname),
poly_actuals.anyrange_type,
-1, 0); /* no collation should be attached to a range type */ break; case ANYMULTIRANGEOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(att->attname),
poly_actuals.anymultirange_type,
-1, 0); /* no collation should be attached to a multirange type */ break; case ANYCOMPATIBLEOID: case ANYCOMPATIBLENONARRAYOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(att->attname),
anyc_actuals.anyelement_type,
-1, 0);
TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation); break; case ANYCOMPATIBLEARRAYOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(att->attname),
anyc_actuals.anyarray_type,
-1, 0);
TupleDescInitEntryCollation(tupdesc, i + 1, anycompatcollation); break; case ANYCOMPATIBLERANGEOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(att->attname),
anyc_actuals.anyrange_type,
-1, 0); /* no collation should be attached to a range type */ break; case ANYCOMPATIBLEMULTIRANGEOID:
TupleDescInitEntry(tupdesc, i + 1,
NameStr(att->attname),
anyc_actuals.anymultirange_type,
-1, 0); /* no collation should be attached to a multirange type */ break; default: break;
}
}
switch (argtypes[i])
{ case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
{
have_polymorphic_result = true;
have_anyelement_result = true;
} else
{ if (!OidIsValid(poly_actuals.anyelement_type))
{
poly_actuals.anyelement_type =
get_call_expr_argtype(call_expr, inargno); if (!OidIsValid(poly_actuals.anyelement_type)) returnfalse;
}
argtypes[i] = poly_actuals.anyelement_type;
} break; case ANYARRAYOID: if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
{
have_polymorphic_result = true;
have_anyarray_result = true;
} else
{ if (!OidIsValid(poly_actuals.anyarray_type))
{
poly_actuals.anyarray_type =
get_call_expr_argtype(call_expr, inargno); if (!OidIsValid(poly_actuals.anyarray_type)) returnfalse;
}
argtypes[i] = poly_actuals.anyarray_type;
} break; case ANYRANGEOID: if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
{
have_polymorphic_result = true;
have_anyrange_result = true;
} else
{ if (!OidIsValid(poly_actuals.anyrange_type))
{
poly_actuals.anyrange_type =
get_call_expr_argtype(call_expr, inargno); if (!OidIsValid(poly_actuals.anyrange_type)) returnfalse;
}
argtypes[i] = poly_actuals.anyrange_type;
} break; case ANYMULTIRANGEOID: if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
{
have_polymorphic_result = true;
have_anymultirange_result = true;
} else
{ if (!OidIsValid(poly_actuals.anymultirange_type))
{
poly_actuals.anymultirange_type =
get_call_expr_argtype(call_expr, inargno); if (!OidIsValid(poly_actuals.anymultirange_type)) returnfalse;
}
argtypes[i] = poly_actuals.anymultirange_type;
} break; case ANYCOMPATIBLEOID: case ANYCOMPATIBLENONARRAYOID: if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
{
have_polymorphic_result = true;
have_anycompatible_result = true;
} else
{ if (!OidIsValid(anyc_actuals.anyelement_type))
{
anyc_actuals.anyelement_type =
get_call_expr_argtype(call_expr, inargno); if (!OidIsValid(anyc_actuals.anyelement_type)) returnfalse;
}
argtypes[i] = anyc_actuals.anyelement_type;
} break; case ANYCOMPATIBLEARRAYOID: if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
{
have_polymorphic_result = true;
have_anycompatible_array_result = true;
} else
{ if (!OidIsValid(anyc_actuals.anyarray_type))
{
anyc_actuals.anyarray_type =
get_call_expr_argtype(call_expr, inargno); if (!OidIsValid(anyc_actuals.anyarray_type)) returnfalse;
}
argtypes[i] = anyc_actuals.anyarray_type;
} break; case ANYCOMPATIBLERANGEOID: if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
{
have_polymorphic_result = true;
have_anycompatible_range_result = true;
} else
{ if (!OidIsValid(anyc_actuals.anyrange_type))
{
anyc_actuals.anyrange_type =
get_call_expr_argtype(call_expr, inargno); if (!OidIsValid(anyc_actuals.anyrange_type)) returnfalse;
}
argtypes[i] = anyc_actuals.anyrange_type;
} break; case ANYCOMPATIBLEMULTIRANGEOID: if (argmode == PROARGMODE_OUT || argmode == PROARGMODE_TABLE)
{
have_polymorphic_result = true;
have_anycompatible_multirange_result = true;
} else
{ if (!OidIsValid(anyc_actuals.anymultirange_type))
{
anyc_actuals.anymultirange_type =
get_call_expr_argtype(call_expr, inargno); if (!OidIsValid(anyc_actuals.anymultirange_type)) returnfalse;
}
argtypes[i] = anyc_actuals.anymultirange_type;
} break; default: break;
} if (argmode != PROARGMODE_OUT && argmode != PROARGMODE_TABLE)
inargno++;
}
/* Done? */ if (!have_polymorphic_result) returntrue;
/* If needed, deduce one polymorphic type from others */ if (have_anyelement_result && !OidIsValid(poly_actuals.anyelement_type))
resolve_anyelement_from_others(&poly_actuals);
if (have_anyarray_result && !OidIsValid(poly_actuals.anyarray_type))
resolve_anyarray_from_others(&poly_actuals);
if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type))
resolve_anyrange_from_others(&poly_actuals);
if (have_anymultirange_result && !OidIsValid(poly_actuals.anymultirange_type))
resolve_anymultirange_from_others(&poly_actuals);
if (have_anycompatible_result && !OidIsValid(anyc_actuals.anyelement_type))
resolve_anyelement_from_others(&anyc_actuals);
if (have_anycompatible_array_result && !OidIsValid(anyc_actuals.anyarray_type))
resolve_anyarray_from_others(&anyc_actuals);
if (have_anycompatible_range_result && !OidIsValid(anyc_actuals.anyrange_type))
resolve_anyrange_from_others(&anyc_actuals);
if (have_anycompatible_multirange_result && !OidIsValid(anyc_actuals.anymultirange_type))
resolve_anymultirange_from_others(&anyc_actuals);
/* 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] = poly_actuals.anyelement_type; break; case ANYARRAYOID:
argtypes[i] = poly_actuals.anyarray_type; break; case ANYRANGEOID:
argtypes[i] = poly_actuals.anyrange_type; break; case ANYMULTIRANGEOID:
argtypes[i] = poly_actuals.anymultirange_type; break; case ANYCOMPATIBLEOID: case ANYCOMPATIBLENONARRAYOID:
argtypes[i] = anyc_actuals.anyelement_type; break; case ANYCOMPATIBLEARRAYOID:
argtypes[i] = anyc_actuals.anyarray_type; break; case ANYCOMPATIBLERANGEOID:
argtypes[i] = anyc_actuals.anyrange_type; break; case ANYCOMPATIBLEMULTIRANGEOID:
argtypes[i] = anyc_actuals.anymultirange_type; break; default: break;
}
}
switch (get_typtype(typid))
{ case TYPTYPE_COMPOSITE: return TYPEFUNC_COMPOSITE; case TYPTYPE_BASE: case TYPTYPE_ENUM: case TYPTYPE_RANGE: case TYPTYPE_MULTIRANGE: return TYPEFUNC_SCALAR; case TYPTYPE_DOMAIN:
*base_typeid = typid = getBaseType(typid); if (get_typtype(typid) == TYPTYPE_COMPOSITE) return TYPEFUNC_COMPOSITE_DOMAIN; else/* domain base type can't be a pseudotype */ return TYPEFUNC_SCALAR; case TYPTYPE_PSEUDO: if (typid == RECORDOID) return TYPEFUNC_RECORD;
/* *get_func_arg_info * *Fetchinfoabouttheargumenttypes,names,andIN/OUTmodesfromthe *pg_proctuple.Returnvalueisthetotalnumberofarguments. *Otherresultsarepalloc'd.*p_argtypesisalwaysfilledin,but **p_argnamesand*p_argmodeswillbesetNULLinthedefaultcases *(nonames,andallINarguments,respectively). * *Notethatthisfunctionsimplyfetcheswhatisinthepg_proctuple; *itdoesn'tdoanyinterpretationofpolymorphictypes.
*/ int
get_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)
{ /* *Weexpectthearraystobe1-Darraysoftherighttypes;verify *that.FortheOIDandchararrays,wedon'tneedtouse *deconstruct_array()sincethearraydataisjustgoingtolooklike *aCarrayofvalues.
*/
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 or it contains nulls");
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_builtin(DatumGetArrayTypeP(proargnames), TEXTOID,
&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] = TextDatumGetCString(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 of length %d or it contains nulls",
numargs);
*p_argmodes = (char *) palloc(numargs * sizeof(char));
memcpy(*p_argmodes, ARR_DATA_PTR(arr),
numargs * sizeof(char));
}
return numargs;
}
/* *get_func_trftypes * *Returnsthenumberoftransformedtypesusedbythefunction. *Ifthereareany,apalloc'darrayofthetypeOIDsisreturned *into*p_trftypes.
*/ int
get_func_trftypes(HeapTuple procTup,
Oid **p_trftypes)
{
Datum protrftypes;
ArrayType *arr; int nelems; bool isNull;
protrftypes = SysCacheGetAttr(PROCOID, procTup,
Anum_pg_proc_protrftypes,
&isNull); if (!isNull)
{ /* *Weexpectthearraystobe1-Darraysoftherighttypes;verify *that.FortheOIDandchararrays,wedon'tneedtouse *deconstruct_array()sincethearraydataisjustgoingtolooklike *aCarrayofvalues.
*/
arr = DatumGetArrayTypeP(protrftypes); /* ensure not toasted */
nelems = ARR_DIMS(arr)[0]; if (ARR_NDIM(arr) != 1 ||
nelems < 0 ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != OIDOID)
elog(ERROR, "protrftypes is not a 1-D Oid array or it contains nulls");
*p_trftypes = (Oid *) palloc(nelems * sizeof(Oid));
memcpy(*p_trftypes, ARR_DATA_PTR(arr),
nelems * sizeof(Oid));
return nelems;
} else return0;
}
/* *get_func_input_arg_names * *Extractthenamesofinputargumentsonly,givenafunction's *proargnamesandproargmodesentriesinDatumform. * *Returnsthenumberofinputarguments,whichisthelengthofthe *palloc'darrayreturnedto*arg_names.Entriesforunnamedargs *aresettoNULL.Youdon'tgetanythingifproargnamesisNULL.
*/ int
get_func_input_arg_names(Datum proargnames, Datum proargmodes, char ***arg_names)
{
ArrayType *arr; int numargs;
Datum *argnames; char *argmodes; char **inargnames; int numinargs; int i;
/* Do nothing if null proargnames */ if (proargnames == PointerGetDatum(NULL))
{
*arg_names = NULL; return0;
}
/* *Weexpectthearraystobe1-Darraysoftherighttypes;verifythat. *Forproargmodes,wedon'tneedtousedeconstruct_array()sincethe *arraydataisjustgoingtolooklikeaCarrayofvalues.
*/
arr = DatumGetArrayTypeP(proargnames); /* ensure not toasted */ if (ARR_NDIM(arr) != 1 ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != TEXTOID)
elog(ERROR, "proargnames is not a 1-D text array or it contains nulls");
deconstruct_array_builtin(arr, TEXTOID, &argnames, NULL, &numargs); if (proargmodes != PointerGetDatum(NULL))
{
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 of length %d or it contains nulls",
numargs);
argmodes = (char *) ARR_DATA_PTR(arr);
} else
argmodes = NULL;
/* zero elements probably shouldn't happen, but handle it gracefully */ if (numargs <= 0)
{
*arg_names = NULL; return0;
}
/* *get_func_result_name * *Ifthefunctionhasexactlyoneoutputparameter,andthatparameter *isnamed,returnthename(asapalloc'dstring).ElsereturnNULL. * *Thisisusedtodeterminethedefaultoutputcolumnnameforfunctions *returningscalartypes.
*/ char *
get_func_result_name(Oid functionId)
{ char *result;
HeapTuple procTuple;
Datum proargmodes;
Datum proargnames;
ArrayType *arr; int numargs; char *argmodes;
Datum *argnames; int numoutargs; int nargnames; int i;
/* First fetch the function's pg_proc row */
procTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId)); 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, NULL) ||
heap_attisnull(procTuple, Anum_pg_proc_proargnames, NULL))
result = NULL; else
{ /* Get the data out of the tuple */
proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
Anum_pg_proc_proargmodes);
proargnames = SysCacheGetAttrNotNull(PROCOID, procTuple,
Anum_pg_proc_proargnames);
/* *Weexpectthearraystobe1-Darraysoftherighttypes;verify *that.Forthechararray,wedon'tneedtousedeconstruct_array() *sincethearraydataisjustgoingtolooklikeaCarrayof *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 or it contains nulls");
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 of length %d or it contains nulls",
numargs);
deconstruct_array_builtin(arr, TEXTOID, &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 ||
argmodes[i] == PROARGMODE_VARIADIC) continue;
Assert(argmodes[i] == PROARGMODE_OUT ||
argmodes[i] == PROARGMODE_INOUT ||
argmodes[i] == PROARGMODE_TABLE); if (++numoutargs > 1)
{ /* multiple out args, so forget it */
result = NULL; break;
}
result = TextDatumGetCString(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 * *Givenapg_procrowforafunction,returnatupledescriptorforthe *resultrowtype,orNULLifthefunctiondoesnothaveOUTparameters. * *Notethatthisdoesnothandleresolutionofpolymorphictypes; *thatisdeliberate.
*/
TupleDesc
build_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, NULL) ||
heap_attisnull(procTuple, Anum_pg_proc_proargmodes, NULL)) return NULL;
/* Get the data out of the tuple */
proallargtypes = SysCacheGetAttrNotNull(PROCOID, procTuple,
Anum_pg_proc_proallargtypes);
proargmodes = SysCacheGetAttrNotNull(PROCOID, procTuple,
Anum_pg_proc_proargmodes);
proargnames = SysCacheGetAttr(PROCOID, procTuple,
Anum_pg_proc_proargnames,
&isnull); if (isnull)
proargnames = PointerGetDatum(NULL); /* just to be sure */
/* *build_function_result_tupdesc_d * *BuildaRECORDfunction'stupledescfromthepg_procproallargtypes, *proargmodes,andproargnamesarrays.Thisissplitoutforthe *convenienceofProcedureCreate,whichneedstobeabletocomputethe *tupledescbeforeactuallycreatingthefunction. * *Forfunctions(butnotforprocedures),returnsNULLiftherearenotat *leasttwoOUTorINOUTarguments.
*/
TupleDesc
build_function_result_tupdesc_d(char prokind,
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;
/* *Weexpectthearraystobe1-Darraysoftherighttypes;verifythat. *FortheOIDandchararrays,wedon'tneedtousedeconstruct_array() *sincethearraydataisjustgoingtolooklikeaCarrayofvalues.
*/
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 or it contains nulls");
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 of length %d or it contains nulls",
numargs);
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 of length %d or it contains nulls",
numargs);
deconstruct_array_builtin(arr, TEXTOID, &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 ||
argmodes[i] == PROARGMODE_VARIADIC) continue;
Assert(argmodes[i] == PROARGMODE_OUT ||
argmodes[i] == PROARGMODE_INOUT ||
argmodes[i] == PROARGMODE_TABLE);
outargtypes[numoutargs] = argtypes[i]; if (argnames)
pname = TextDatumGetCString(argnames[i]); else
pname = NULL; if (pname == NULL || pname[0] == '\0')
{ /* Parameter is not named, so gin up a column name */
pname = psprintf("column%d", numoutargs + 1);
}
outargnames[numoutargs] = pname;
numoutargs++;
}
/* *Buildasuitabletupledescrepresentingtheoutputrows.We *intentionallydonotsupportTYPEFUNC_COMPOSITE_DOMAINhere,asit's *unlikelythatlegacycallersofthisobsoletefunctionwouldbe *preparedtoapplydomainconstraints.
*/ if (functypclass == TYPEFUNC_COMPOSITE)
{ /* Composite data type, e.g. a table's row type */
tupdesc = lookup_rowtype_tupdesc_copy(base_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));
Form_pg_attribute attr = TupleDescAttr(tupdesc, varattno);
if (label != NULL)
namestrcpy(&(attr->attname), label);
}
/* The tuple type is now an anonymous record type */
tupdesc->tdtypeid = RECORDOID;
tupdesc->tdtypmod = -1;
}
} elseif (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);
TupleDescInitEntry(tupdesc,
(AttrNumber) 1,
attname,
typeoid,
-1, 0);
} elseif (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;
}
/* *extract_variadic_args * *Extractasetofargumentvalues,typesandNULLmarkersforagiven *inputfunctionwhichmakesuseofaVARIADICinputwhoseargumentlist *dependsonthecallercontext.WhendoingaVARIADICcall,thecaller *hasprovidedoneargumentmadeofanarrayofvalues,sodeconstructthe *arraydatabeforeusingitforthenextprocessing.IfnoVARIADICcall *isused,justfillinthestatusdatabasedonalltheargumentsgiven *bythecaller. * *Thisfunctionreturnsthenumberofargumentsgenerated,or-1inthe *caseof"VARIADICNULL".
*/ int
extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, bool convert_unknown, Datum **args, Oid **types, bool **nulls)
{ bool variadic = get_fn_expr_variadic(fcinfo->flinfo);
Datum *args_res; bool *nulls_res;
Oid *types_res; int nargs,
i;
*args = NULL;
*types = NULL;
*nulls = NULL;
if (variadic)
{
ArrayType *array_in;
Oid element_type; bool typbyval; char typalign;
int16 typlen;
if (PG_ARGISNULL(i + variadic_start))
args_res[i] = (Datum) 0; else
args_res[i] =
CStringGetTextDatum(PG_GETARG_POINTER(i + variadic_start));
} else
{ /* no conversion needed, just take the datum as given */
args_res[i] = PG_GETARG_DATUM(i + variadic_start);
}
if (!OidIsValid(types_res[i]) ||
(convert_unknown && types_res[i] == UNKNOWNOID))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not determine data type for argument %d",
i + 1)));
}
}
/* Fill in results */
*args = args_res;
*nulls = nulls_res;
*types = types_res;
return nargs;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.