diff options
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 197 |
1 files changed, 116 insertions, 81 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 62361932f98..e9951d839a3 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.104 2004/06/08 20:28:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.105 2004/06/16 01:26:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -109,6 +109,11 @@ static void array_insert_slice(int ndim, int *dim, int *lb, int *st, int *endp, char *srcPtr, int typlen, bool typbyval, char typalign); static int array_cmp(FunctionCallInfo fcinfo); +static Datum array_type_length_coerce_internal(ArrayType *src, + int32 desttypmod, + bool isExplicit, + FmgrInfo *fmgr_info); + /*--------------------------------------------------------------------- * array_in : @@ -1174,82 +1179,6 @@ array_send(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } -/*------------------------------------------------------------------------- - * array_length_coerce : - * Apply the element type's length-coercion routine to each element - * of the given array. - *------------------------------------------------------------------------- - */ -Datum -array_length_coerce(PG_FUNCTION_ARGS) -{ - ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); - int32 len = PG_GETARG_INT32(1); - bool isExplicit = PG_GETARG_BOOL(2); - FmgrInfo *fmgr_info = fcinfo->flinfo; - typedef struct - { - Oid elemtype; - FmgrInfo coerce_finfo; - } alc_extra; - alc_extra *my_extra; - FunctionCallInfoData locfcinfo; - - /* If no typmod is provided, shortcircuit the whole thing */ - if (len < 0) - PG_RETURN_ARRAYTYPE_P(v); - - /* - * We arrange to look up the element type's coercion function only - * once per series of calls, assuming the element type doesn't change - * underneath us. - */ - my_extra = (alc_extra *) fmgr_info->fn_extra; - if (my_extra == NULL) - { - fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt, - sizeof(alc_extra)); - my_extra = (alc_extra *) fmgr_info->fn_extra; - my_extra->elemtype = InvalidOid; - } - - if (my_extra->elemtype != ARR_ELEMTYPE(v)) - { - Oid funcId; - int nargs; - - funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v), &nargs); - - if (OidIsValid(funcId)) - fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt); - else - my_extra->coerce_finfo.fn_oid = InvalidOid; - my_extra->elemtype = ARR_ELEMTYPE(v); - } - - /* - * If we didn't find a coercion function, return the array unmodified - * (this should not happen in the normal course of things, but might - * happen if this function is called manually). - */ - if (my_extra->coerce_finfo.fn_oid == InvalidOid) - PG_RETURN_ARRAYTYPE_P(v); - - /* - * Use array_map to apply the function to each array element. - * - * Note: we pass isExplicit whether or not the function wants it ... - */ - MemSet(&locfcinfo, 0, sizeof(locfcinfo)); - locfcinfo.flinfo = &my_extra->coerce_finfo; - locfcinfo.nargs = 3; - locfcinfo.arg[0] = PointerGetDatum(v); - locfcinfo.arg[1] = Int32GetDatum(len); - locfcinfo.arg[2] = BoolGetDatum(isExplicit); - - return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v)); -} - /*----------------------------------------------------------------------------- * array_dims : * returns the dimensions of the array pointed to by "v", as a "text" @@ -2879,6 +2808,9 @@ array_insert_slice(int ndim, * array_type_coerce -- allow explicit or assignment coercion from * one array type to another. * + * array_type_length_coerce -- the same, for cases where both type and length + * coercion are done by a single function on the element type. + * * Caller should have already verified that the source element type can be * coerced into the target element type. */ @@ -2886,8 +2818,30 @@ Datum array_type_coerce(PG_FUNCTION_ARGS) { ArrayType *src = PG_GETARG_ARRAYTYPE_P(0); - Oid src_elem_type = ARR_ELEMTYPE(src); FmgrInfo *fmgr_info = fcinfo->flinfo; + + return array_type_length_coerce_internal(src, -1, false, fmgr_info); +} + +Datum +array_type_length_coerce(PG_FUNCTION_ARGS) +{ + ArrayType *src = PG_GETARG_ARRAYTYPE_P(0); + int32 desttypmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + FmgrInfo *fmgr_info = fcinfo->flinfo; + + return array_type_length_coerce_internal(src, desttypmod, + isExplicit, fmgr_info); +} + +static Datum +array_type_length_coerce_internal(ArrayType *src, + int32 desttypmod, + bool isExplicit, + FmgrInfo *fmgr_info) +{ + Oid src_elem_type = ARR_ELEMTYPE(src); typedef struct { Oid srctype; @@ -2946,7 +2900,8 @@ array_type_coerce(PG_FUNCTION_ARGS) { /* should never happen, but check anyway */ elog(ERROR, "no conversion function from %s to %s", - format_type_be(src_elem_type), format_type_be(tgt_elem_type)); + format_type_be(src_elem_type), + format_type_be(tgt_elem_type)); } if (OidIsValid(funcId)) fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt); @@ -2962,24 +2917,104 @@ array_type_coerce(PG_FUNCTION_ARGS) */ if (my_extra->coerce_finfo.fn_oid == InvalidOid) { - ArrayType *result = DatumGetArrayTypePCopy(PG_GETARG_DATUM(0)); + ArrayType *result; + result = (ArrayType *) DatumGetPointer(datumCopy(PointerGetDatum(src), + false, -1)); ARR_ELEMTYPE(result) = my_extra->desttype; PG_RETURN_ARRAYTYPE_P(result); } /* * Use array_map to apply the function to each array element. + * + * We pass on the desttypmod and isExplicit flags whether or not the + * function wants them. */ MemSet(&locfcinfo, 0, sizeof(locfcinfo)); locfcinfo.flinfo = &my_extra->coerce_finfo; - locfcinfo.nargs = 1; + locfcinfo.nargs = 3; locfcinfo.arg[0] = PointerGetDatum(src); + locfcinfo.arg[1] = Int32GetDatum(desttypmod); + locfcinfo.arg[2] = BoolGetDatum(isExplicit); return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype); } /* + * array_length_coerce -- apply the element type's length-coercion routine + * to each element of the given array. + */ +Datum +array_length_coerce(PG_FUNCTION_ARGS) +{ + ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); + int32 desttypmod = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + FmgrInfo *fmgr_info = fcinfo->flinfo; + typedef struct + { + Oid elemtype; + FmgrInfo coerce_finfo; + } alc_extra; + alc_extra *my_extra; + FunctionCallInfoData locfcinfo; + + /* If no typmod is provided, shortcircuit the whole thing */ + if (desttypmod < 0) + PG_RETURN_ARRAYTYPE_P(v); + + /* + * We arrange to look up the element type's coercion function only + * once per series of calls, assuming the element type doesn't change + * underneath us. + */ + my_extra = (alc_extra *) fmgr_info->fn_extra; + if (my_extra == NULL) + { + fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt, + sizeof(alc_extra)); + my_extra = (alc_extra *) fmgr_info->fn_extra; + my_extra->elemtype = InvalidOid; + } + + if (my_extra->elemtype != ARR_ELEMTYPE(v)) + { + Oid funcId; + + funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v)); + + if (OidIsValid(funcId)) + fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt); + else + my_extra->coerce_finfo.fn_oid = InvalidOid; + my_extra->elemtype = ARR_ELEMTYPE(v); + } + + /* + * If we didn't find a coercion function, return the array unmodified + * (this should not happen in the normal course of things, but might + * happen if this function is called manually). + */ + if (my_extra->coerce_finfo.fn_oid == InvalidOid) + PG_RETURN_ARRAYTYPE_P(v); + + /* + * Use array_map to apply the function to each array element. + * + * Note: we pass isExplicit whether or not the function wants it ... + */ + MemSet(&locfcinfo, 0, sizeof(locfcinfo)); + locfcinfo.flinfo = &my_extra->coerce_finfo; + locfcinfo.nargs = 3; + locfcinfo.arg[0] = PointerGetDatum(v); + locfcinfo.arg[1] = Int32GetDatum(desttypmod); + locfcinfo.arg[2] = BoolGetDatum(isExplicit); + + return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v)); +} + +/* * accumArrayResult - accumulate one (more) Datum for an array result * * astate is working state (NULL on first call) |