diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/json.c | 2 | ||||
-rw-r--r-- | src/backend/utils/adt/jsonb.c | 2 | ||||
-rw-r--r-- | src/backend/utils/adt/pseudotypes.c | 35 | ||||
-rw-r--r-- | src/backend/utils/fmgr/funcapi.c | 196 |
4 files changed, 224 insertions, 11 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index f78420e22dc..8bb00abb6b3 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -195,7 +195,7 @@ json_categorize_type(Oid typoid, default: /* Check for arrays and composites */ if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID - || typoid == RECORDARRAYOID) + || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID) *tcategory = JSONTYPE_ARRAY; else if (type_is_rowtype(typoid)) /* includes RECORDOID */ *tcategory = JSONTYPE_COMPOSITE; diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index b961d294723..1e9ca046c69 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -677,7 +677,7 @@ jsonb_categorize_type(Oid typoid, default: /* Check for arrays and composites */ if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID - || typoid == RECORDARRAYOID) + || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID) *tcategory = JSONBTYPE_ARRAY; else if (type_is_rowtype(typoid)) /* includes RECORDOID */ *tcategory = JSONBTYPE_COMPOSITE; diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index 9eee03c143a..3d6b2f90935 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -169,6 +169,26 @@ anyarray_send(PG_FUNCTION_ARGS) } /* + * anycompatiblearray + * + * We may as well allow output, since we do for anyarray. + */ +PSEUDOTYPE_DUMMY_INPUT_FUNC(anycompatiblearray); +PSEUDOTYPE_DUMMY_RECEIVE_FUNC(anycompatiblearray); + +Datum +anycompatiblearray_out(PG_FUNCTION_ARGS) +{ + return array_out(fcinfo); +} + +Datum +anycompatiblearray_send(PG_FUNCTION_ARGS) +{ + return array_send(fcinfo); +} + +/* * anyenum * * We may as well allow output, since enum_out will in fact work. @@ -195,6 +215,19 @@ anyrange_out(PG_FUNCTION_ARGS) } /* + * anycompatiblerange + * + * We may as well allow output, since range_out will in fact work. + */ +PSEUDOTYPE_DUMMY_INPUT_FUNC(anycompatiblerange); + +Datum +anycompatiblerange_out(PG_FUNCTION_ARGS) +{ + return range_out(fcinfo); +} + +/* * void * * We support void_in so that PL functions can return VOID without any @@ -316,3 +349,5 @@ PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler); PSEUDOTYPE_DUMMY_IO_FUNCS(internal); PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement); PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray); +PSEUDOTYPE_DUMMY_IO_FUNCS(anycompatible); +PSEUDOTYPE_DUMMY_IO_FUNCS(anycompatiblenonarray); diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 4e9d21bd541..78ed8572038 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -552,7 +552,9 @@ resolve_anyrange_from_others(polymorphic_actuals *actuals) * with concrete data types deduced from the input arguments. * declared_args is an oidvector of the function's declared input arg types * (showing which are polymorphic), and call_expr is the call expression. - * Returns true if able to deduce all types, false if not. + * + * Returns true if able to deduce all types, false if necessary information + * is not provided (call_expr is NULL or arg types aren't identifiable). */ static bool resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, @@ -564,8 +566,13 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, bool have_anyelement_result = false; bool have_anyarray_result = false; bool have_anyrange_result = false; + bool have_anycompatible_result = false; + bool have_anycompatible_array_result = false; + bool have_anycompatible_range_result = false; polymorphic_actuals poly_actuals; + polymorphic_actuals anyc_actuals; Oid anycollation = InvalidOid; + Oid anycompatcollation = InvalidOid; int i; /* See if there are any polymorphic outputs; quick out if not */ @@ -587,6 +594,19 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, have_polymorphic_result = true; have_anyrange_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; default: break; } @@ -596,12 +616,16 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, /* * Otherwise, extract actual datatype(s) from input arguments. (We assume - * the parser already validated consistency of the arguments.) + * the parser already validated consistency of the arguments. Also, for + * the ANYCOMPATIBLE pseudotype family, we expect that all matching + * arguments were coerced to the selected common supertype, so that it + * doesn't matter which one's exposed type we look at.) */ if (!call_expr) return false; /* no hope */ memset(&poly_actuals, 0, sizeof(poly_actuals)); + memset(&anyc_actuals, 0, sizeof(anyc_actuals)); for (i = 0; i < nargs; i++) { @@ -636,6 +660,34 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, return false; } 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)) + return false; + } + 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)) + return false; + } + 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)) + return false; + } + break; default: break; } @@ -651,18 +703,33 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type)) resolve_anyrange_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); + /* * Identify the collation to use for polymorphic OUT parameters. (It'll - * necessarily be the same for both anyelement and anyarray.) Note that - * range types are not collatable, so any possible internal collation of a - * range type is not considered here. + * necessarily be the same for both anyelement and anyarray, likewise for + * anycompatible and anycompatiblearray.) Note that range types are not + * collatable, so any possible internal collation of a range type is not + * considered here. */ if (OidIsValid(poly_actuals.anyelement_type)) anycollation = get_typcollation(poly_actuals.anyelement_type); else if (OidIsValid(poly_actuals.anyarray_type)) anycollation = get_typcollation(poly_actuals.anyarray_type); - if (OidIsValid(anycollation)) + if (OidIsValid(anyc_actuals.anyelement_type)) + anycompatcollation = get_typcollation(anyc_actuals.anyelement_type); + else if (OidIsValid(anyc_actuals.anyarray_type)) + anycompatcollation = get_typcollation(anyc_actuals.anyarray_type); + + if (OidIsValid(anycollation) || OidIsValid(anycompatcollation)) { /* * The types are collatable, so consider whether to use a nondefault @@ -672,7 +739,12 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, Oid inputcollation = exprInputCollation(call_expr); if (OidIsValid(inputcollation)) - anycollation = inputcollation; + { + if (OidIsValid(anycollation)) + anycollation = inputcollation; + if (OidIsValid(anycompatcollation)) + anycompatcollation = inputcollation; + } } /* And finally replace the tuple column types as needed */ @@ -708,6 +780,31 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, 0); /* no collation should be attached to a range 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; default: break; } @@ -720,7 +817,9 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, * Given the declared argument types and modes for a function, replace any * polymorphic types (ANYELEMENT etc) in argtypes[] with concrete data types * deduced from the input arguments found in call_expr. - * Returns true if able to deduce all types, false if not. + * + * Returns true if able to deduce all types, false if necessary information + * is not provided (call_expr is NULL or arg types aren't identifiable). * * This is the same logic as resolve_polymorphic_tupdesc, but with a different * argument representation, and slightly different output responsibilities. @@ -735,16 +834,21 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, bool have_anyelement_result = false; bool have_anyarray_result = false; bool have_anyrange_result = false; + bool have_anycompatible_result = false; + bool have_anycompatible_array_result = false; + bool have_anycompatible_range_result = false; polymorphic_actuals poly_actuals; + polymorphic_actuals anyc_actuals; int inargno; int i; /* * First pass: resolve polymorphic inputs, check for outputs. As in * resolve_polymorphic_tupdesc, we rely on the parser to have enforced - * type consistency. + * type consistency and coerced ANYCOMPATIBLE args to a common supertype. */ memset(&poly_actuals, 0, sizeof(poly_actuals)); + memset(&anyc_actuals, 0, sizeof(anyc_actuals)); inargno = 0; for (i = 0; i < numargs; i++) { @@ -808,6 +912,61 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, argtypes[i] = poly_actuals.anyrange_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)) + return false; + } + 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)) + return false; + } + 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)) + return false; + } + argtypes[i] = anyc_actuals.anyrange_type; + } + break; default: break; } @@ -829,6 +988,15 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, if (have_anyrange_result && !OidIsValid(poly_actuals.anyrange_type)) resolve_anyrange_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); + /* And finally replace the output column types as needed */ for (i = 0; i < numargs; i++) { @@ -845,6 +1013,16 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes, case ANYRANGEOID: argtypes[i] = poly_actuals.anyrange_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; default: break; } |