diff options
Diffstat (limited to 'src/backend/utils/adt/arrayfuncs.c')
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 132 |
1 files changed, 59 insertions, 73 deletions
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 37504718ad5..46f7881d648 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.98 2003/08/15 00:22:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.99 2003/08/17 19:58:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,6 +28,7 @@ #include "utils/memutils.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +#include "utils/typcache.h" /*---------- @@ -2341,6 +2342,9 @@ deconstruct_array(ArrayType *array, * compares two arrays for equality * result : * returns true if the arrays are equal, false otherwise. + * + * Note: we do not use array_cmp here, since equality may be meaningful in + * datatypes that don't have a total ordering (and hence no btree support). *----------------------------------------------------------------------------- */ Datum @@ -2357,13 +2361,12 @@ array_eq(PG_FUNCTION_ARGS) int nitems1 = ArrayGetNItems(ndims1, dims1); int nitems2 = ArrayGetNItems(ndims2, dims2); Oid element_type = ARR_ELEMTYPE(array1); - FmgrInfo *ae_fmgr_info = fcinfo->flinfo; bool result = true; + TypeCacheEntry *typentry; int typlen; bool typbyval; char typalign; int i; - ArrayMetaState *my_extra; FunctionCallInfoData locfcinfo; if (element_type != ARR_ELEMTYPE(array2)) @@ -2379,38 +2382,31 @@ array_eq(PG_FUNCTION_ARGS) /* * We arrange to look up the equality function only once per * series of calls, assuming the element type doesn't change - * underneath us. + * underneath us. The typcache is used so that we have no + * memory leakage when being used as an index support function. */ - my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra; - if (my_extra == NULL) + typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra; + if (typentry == NULL || + typentry->type_id != element_type) { - ae_fmgr_info->fn_extra = MemoryContextAlloc(ae_fmgr_info->fn_mcxt, - sizeof(ArrayMetaState)); - my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra; - my_extra->element_type = InvalidOid; - } - - if (my_extra->element_type != element_type) - { - Oid opfuncid = equality_oper_funcid(element_type); - - get_typlenbyvalalign(element_type, - &my_extra->typlen, - &my_extra->typbyval, - &my_extra->typalign); - fmgr_info_cxt(opfuncid, &my_extra->proc, - ae_fmgr_info->fn_mcxt); - my_extra->element_type = element_type; + typentry = lookup_type_cache(element_type, + TYPECACHE_EQ_OPR_FINFO); + if (!OidIsValid(typentry->eq_opr_finfo.fn_oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("could not identify an equality operator for type %s", + format_type_be(element_type)))); + fcinfo->flinfo->fn_extra = (void *) typentry; } - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typalign = my_extra->typalign; + typlen = typentry->typlen; + typbyval = typentry->typbyval; + typalign = typentry->typalign; /* * apply the operator to each pair of array elements. */ MemSet(&locfcinfo, 0, sizeof(locfcinfo)); - locfcinfo.flinfo = &my_extra->proc; + locfcinfo.flinfo = &typentry->eq_opr_finfo; locfcinfo.nargs = 2; /* Loop over source data */ @@ -2519,23 +2515,14 @@ array_cmp(FunctionCallInfo fcinfo) int nitems1 = ArrayGetNItems(ndims1, dims1); int nitems2 = ArrayGetNItems(ndims2, dims2); Oid element_type = ARR_ELEMTYPE(array1); - FmgrInfo *ac_fmgr_info = fcinfo->flinfo; int result = 0; + TypeCacheEntry *typentry; int typlen; bool typbyval; char typalign; int min_nitems; int i; - typedef struct - { - Oid element_type; - int16 typlen; - bool typbyval; - char typalign; - FmgrInfo eqproc; - FmgrInfo ordproc; - } ac_extra; - ac_extra *my_extra; + FunctionCallInfoData locfcinfo; if (element_type != ARR_ELEMTYPE(array2)) ereport(ERROR, @@ -2543,37 +2530,34 @@ array_cmp(FunctionCallInfo fcinfo) errmsg("cannot compare arrays of different element types"))); /* - * We arrange to look up the element type info and related functions - * only once per series of calls, assuming the element type doesn't - * change underneath us. + * We arrange to look up the comparison function only once per series of + * calls, assuming the element type doesn't change underneath us. + * The typcache is used so that we have no memory leakage when being used + * as an index support function. */ - my_extra = (ac_extra *) ac_fmgr_info->fn_extra; - if (my_extra == NULL) + typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra; + if (typentry == NULL || + typentry->type_id != element_type) { - ac_fmgr_info->fn_extra = MemoryContextAlloc(ac_fmgr_info->fn_mcxt, - sizeof(ac_extra)); - my_extra = (ac_extra *) ac_fmgr_info->fn_extra; - my_extra->element_type = InvalidOid; + typentry = lookup_type_cache(element_type, + TYPECACHE_CMP_PROC_FINFO); + if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("could not identify a comparison function for type %s", + format_type_be(element_type)))); + fcinfo->flinfo->fn_extra = (void *) typentry; } + typlen = typentry->typlen; + typbyval = typentry->typbyval; + typalign = typentry->typalign; - if (my_extra->element_type != element_type) - { - Oid eqfuncid = equality_oper_funcid(element_type); - Oid ordfuncid = ordering_oper_funcid(element_type); - - get_typlenbyvalalign(element_type, - &my_extra->typlen, - &my_extra->typbyval, - &my_extra->typalign); - fmgr_info_cxt(eqfuncid, &my_extra->eqproc, - ac_fmgr_info->fn_mcxt); - fmgr_info_cxt(ordfuncid, &my_extra->ordproc, - ac_fmgr_info->fn_mcxt); - my_extra->element_type = element_type; - } - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typalign = my_extra->typalign; + /* + * apply the operator to each pair of array elements. + */ + MemSet(&locfcinfo, 0, sizeof(locfcinfo)); + locfcinfo.flinfo = &typentry->cmp_proc_finfo; + locfcinfo.nargs = 2; /* Loop over source data */ min_nitems = Min(nitems1, nitems2); @@ -2581,7 +2565,7 @@ array_cmp(FunctionCallInfo fcinfo) { Datum elt1; Datum elt2; - Datum opresult; + int32 cmpresult; /* Get element pair */ elt1 = fetch_att(p1, typbyval, typlen); @@ -2594,15 +2578,17 @@ array_cmp(FunctionCallInfo fcinfo) p2 = (char *) att_align(p2, typalign); /* Compare the pair of elements */ + locfcinfo.arg[0] = elt1; + locfcinfo.arg[1] = elt2; + locfcinfo.argnull[0] = false; + locfcinfo.argnull[1] = false; + locfcinfo.isnull = false; + cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo)); - /* are they equal */ - opresult = FunctionCall2(&my_extra->eqproc, elt1, elt2); - if (DatumGetBool(opresult)) - continue; + if (cmpresult == 0) + continue; /* equal */ - /* nope, see if arg1 is less than arg2 */ - opresult = FunctionCall2(&my_extra->ordproc, elt1, elt2); - if (DatumGetBool(opresult)) + if (cmpresult < 0) { /* arg1 is less than arg2 */ result = -1; |