diff options
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r-- | src/backend/utils/adt/acl.c | 11 | ||||
-rw-r--r-- | src/backend/utils/adt/array_userfuncs.c | 289 | ||||
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 824 | ||||
-rw-r--r-- | src/backend/utils/adt/varlena.c | 196 |
4 files changed, 286 insertions, 1034 deletions
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index cfef2db349d..415a086b7dd 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.89 2003/06/24 23:14:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.90 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -427,15 +427,6 @@ aclitemeq(const AclItem *a1, const AclItem *a2) a1->ai_grantor == a2->ai_grantor; } -/* - * user-facing version of aclitemeq() for use as the - * aclitem equality operator - */ -Datum -aclitem_eq(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(aclitemeq(PG_GETARG_ACLITEM_P(0), PG_GETARG_ACLITEM_P(1))); -} /* * acldefault() --- create an ACL describing default access permissions diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index f5e50771b13..519ac8d1885 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -6,7 +6,7 @@ * Copyright (c) 2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.2 2003/06/24 23:14:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.3 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,35 @@ #include "utils/lsyscache.h" #include "utils/syscache.h" + +/*----------------------------------------------------------------------------- + * singleton_array : + * Form a multi-dimensional array given one starting element. + * + * - first argument is the datum with which to build the array + * - second argument is the number of dimensions the array should have; + * defaults to 1 if no second argument is provided + *---------------------------------------------------------------------------- + */ +Datum +singleton_array(PG_FUNCTION_ARGS) +{ + Oid elem_type = get_fn_expr_argtype(fcinfo, 0); + int ndims; + + if (elem_type == InvalidOid) + elog(ERROR, "Cannot determine input datatype"); + + if (PG_NARGS() == 2) + ndims = PG_GETARG_INT32(1); + else + ndims = 1; + + PG_RETURN_ARRAYTYPE_P(create_singleton_array(elem_type, + PG_GETARG_DATUM(0), + ndims)); +} + /*----------------------------------------------------------------------------- * array_push : * push an element onto either end of a one-dimensional array @@ -41,7 +70,6 @@ array_push(PG_FUNCTION_ARGS) Oid arg1_typeid = get_fn_expr_argtype(fcinfo, 1); Oid arg0_elemid; Oid arg1_elemid; - ArrayMetaState *my_extra; if (arg0_typeid == InvalidOid || arg1_typeid == InvalidOid) elog(ERROR, "array_push: cannot determine input data types"); @@ -67,61 +95,28 @@ array_push(PG_FUNCTION_ARGS) PG_RETURN_NULL(); /* keep compiler quiet */ } - if (ARR_NDIM(v) == 1) - { - lb = ARR_LBOUND(v); - dimv = ARR_DIMS(v); - - if (arg0_elemid != InvalidOid) - { - /* append newelem */ - int ub = dimv[0] + lb[0] - 1; - indx = ub + 1; - } - else - { - /* prepend newelem */ - indx = lb[0] - 1; - } - } - else if (ARR_NDIM(v) == 0) - indx = 1; - else - elog(ERROR, "only empty and one-dimensional arrays are supported"); - - - /* - * We arrange to look up info about element type only once per series - * of calls, assuming the element type doesn't change underneath us. - */ - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; - } + /* Sanity check: do we have a one-dimensional array */ + if (ARR_NDIM(v) != 1) + elog(ERROR, "Arrays greater than one-dimension are not supported"); - if (my_extra->element_type != element_type) + lb = ARR_LBOUND(v); + dimv = ARR_DIMS(v); + if (arg0_elemid != InvalidOid) { - /* Get info about element type */ - get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typalign = typalign; + /* append newelem */ + int ub = dimv[0] + lb[0] - 1; + indx = ub + 1; } else { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typalign = my_extra->typalign; + /* prepend newelem */ + indx = lb[0] - 1; } - result = array_set(v, 1, &indx, newelem, -1, typlen, typbyval, - typalign, &isNull); + get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); + + result = array_set(v, 1, &indx, newelem, -1, + typlen, typbyval, typalign, &isNull); PG_RETURN_ARRAYTYPE_P(result); } @@ -150,28 +145,13 @@ array_cat(PG_FUNCTION_ARGS) /* * We must have one of the following combinations of inputs: - * 1) one empty array, and one non-empty array - * 2) both arrays empty - * 3) two arrays with ndims1 == ndims2 - * 4) ndims1 == ndims2 - 1 - * 5) ndims1 == ndims2 + 1 + * 1) two arrays with ndims1 == ndims2 + * 2) ndims1 == ndims2 - 1 + * 3) ndims1 == ndims2 + 1 */ ndims1 = ARR_NDIM(v1); ndims2 = ARR_NDIM(v2); - /* - * short circuit - if one input array is empty, and the other is not, - * we return the non-empty one as the result - * - * if both are empty, return the first one - */ - if (ndims1 == 0 && ndims2 > 0) - PG_RETURN_ARRAYTYPE_P(v2); - - if (ndims2 == 0) - PG_RETURN_ARRAYTYPE_P(v1); - - /* the rest fall into combo 2, 3, or 4 */ if (ndims1 != ndims2 && ndims1 != ndims2 - 1 && ndims1 != ndims2 + 1) elog(ERROR, "Cannot concatenate incompatible arrays of %d and " "%d dimensions", ndims1, ndims2); @@ -286,15 +266,147 @@ array_cat(PG_FUNCTION_ARGS) PG_RETURN_ARRAYTYPE_P(result); } +/*---------------------------------------------------------------------------- + * array_accum : + * accumulator to build a 1-D array from input values -- this can be used + * to create custom aggregates. + * + * This function is not marked strict, so we have to be careful about nulls. + *---------------------------------------------------------------------------- + */ +Datum +array_accum(PG_FUNCTION_ARGS) +{ + /* return NULL if both arguments are NULL */ + if (PG_ARGISNULL(0) && PG_ARGISNULL(1)) + PG_RETURN_NULL(); + + /* create a new 1-D array from the new element if the array is NULL */ + if (PG_ARGISNULL(0)) + { + Oid tgt_type = get_fn_expr_rettype(fcinfo); + Oid tgt_elem_type; + + if (tgt_type == InvalidOid) + elog(ERROR, "Cannot determine target array type"); + tgt_elem_type = get_element_type(tgt_type); + if (tgt_elem_type == InvalidOid) + elog(ERROR, "Target type is not an array"); + + PG_RETURN_ARRAYTYPE_P(create_singleton_array(tgt_elem_type, + PG_GETARG_DATUM(1), + 1)); + } + + /* return the array if the new element is NULL */ + if (PG_ARGISNULL(1)) + PG_RETURN_ARRAYTYPE_P(PG_GETARG_ARRAYTYPE_P_COPY(0)); + + /* + * Otherwise this is equivalent to array_push. We hack the call a little + * so that array_push can see the fn_expr information. + */ + return array_push(fcinfo); +} + +/*----------------------------------------------------------------------------- + * array_assign : + * assign an element of an array to a new value and return the + * redefined array + *---------------------------------------------------------------------------- + */ +Datum +array_assign(PG_FUNCTION_ARGS) +{ + ArrayType *v; + int idx_to_chg; + Datum newelem; + int *dimv, + *lb, ub; + ArrayType *result; + bool isNull; + Oid element_type; + int16 typlen; + bool typbyval; + char typalign; + + v = PG_GETARG_ARRAYTYPE_P(0); + idx_to_chg = PG_GETARG_INT32(1); + newelem = PG_GETARG_DATUM(2); + + /* Sanity check: do we have a one-dimensional array */ + if (ARR_NDIM(v) != 1) + elog(ERROR, "Arrays greater than one-dimension are not supported"); + + lb = ARR_LBOUND(v); + dimv = ARR_DIMS(v); + ub = dimv[0] + lb[0] - 1; + if (idx_to_chg < lb[0] || idx_to_chg > ub) + elog(ERROR, "Cannot alter nonexistent array element: %d", idx_to_chg); + + element_type = ARR_ELEMTYPE(v); + /* Sanity check: do we have a non-zero element type */ + if (element_type == 0) + elog(ERROR, "Invalid array element type: %u", element_type); + + get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); + + result = array_set(v, 1, &idx_to_chg, newelem, -1, + typlen, typbyval, typalign, &isNull); + + PG_RETURN_ARRAYTYPE_P(result); +} + +/*----------------------------------------------------------------------------- + * array_subscript : + * return specific element of an array + *---------------------------------------------------------------------------- + */ +Datum +array_subscript(PG_FUNCTION_ARGS) +{ + ArrayType *v; + int idx; + int *dimv, + *lb, ub; + Datum result; + bool isNull; + Oid element_type; + int16 typlen; + bool typbyval; + char typalign; + + v = PG_GETARG_ARRAYTYPE_P(0); + idx = PG_GETARG_INT32(1); + + /* Sanity check: do we have a one-dimensional array */ + if (ARR_NDIM(v) != 1) + elog(ERROR, "Arrays greater than one-dimension are not supported"); + + lb = ARR_LBOUND(v); + dimv = ARR_DIMS(v); + ub = dimv[0] + lb[0] - 1; + if (idx < lb[0] || idx > ub) + elog(ERROR, "Cannot return nonexistent array element: %d", idx); + + element_type = ARR_ELEMTYPE(v); + /* Sanity check: do we have a non-zero element type */ + if (element_type == 0) + elog(ERROR, "Invalid array element type: %u", element_type); + + get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); + + result = array_ref(v, 1, &idx, -1, typlen, typbyval, typalign, &isNull); + + PG_RETURN_DATUM(result); +} /* - * used by text_to_array() in varlena.c + * actually does the work for singleton_array(), and array_accum() if it is + * given a null input array. */ ArrayType * -create_singleton_array(FunctionCallInfo fcinfo, - Oid element_type, - Datum element, - int ndims) +create_singleton_array(Oid element_type, Datum element, int ndims) { Datum dvalues[1]; int16 typlen; @@ -303,7 +415,6 @@ create_singleton_array(FunctionCallInfo fcinfo, int dims[MAXDIM]; int lbs[MAXDIM]; int i; - ArrayMetaState *my_extra; if (element_type == 0) elog(ERROR, "Invalid array element type: %u", element_type); @@ -318,35 +429,7 @@ create_singleton_array(FunctionCallInfo fcinfo, lbs[i] = 1; } - /* - * We arrange to look up info about element type only once per series - * of calls, assuming the element type doesn't change underneath us. - */ - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; - } - - if (my_extra->element_type != element_type) - { - /* Get info about element type */ - get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typalign = typalign; - } - else - { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typalign = my_extra->typalign; - } + get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); return construct_md_array(dvalues, ndims, dims, lbs, element_type, typlen, typbyval, typalign); diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 27a805d9b28..c03d8c861d1 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.90 2003/06/24 23:14:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.91 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,10 +21,8 @@ #include "catalog/pg_type.h" #include "libpq/pqformat.h" #include "parser/parse_coerce.h" -#include "parser/parse_oper.h" #include "utils/array.h" #include "utils/builtins.h" -#include "utils/datum.h" #include "utils/memutils.h" #include "utils/lsyscache.h" #include "utils/syscache.h" @@ -72,6 +70,16 @@ #define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0) +/* I/O function selector for system_cache_lookup */ +typedef enum IOFuncSelector +{ + IOFunc_input, + IOFunc_output, + IOFunc_receive, + IOFunc_send +} IOFuncSelector; + + static int ArrayCount(char *str, int *dim, char typdelim); static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim, FmgrInfo *inputproc, Oid typelem, int32 typmod, @@ -85,6 +93,10 @@ static Datum *ReadArrayBinary(StringInfo buf, int nitems, static void CopyArrayEls(char *p, Datum *values, int nitems, int typlen, bool typbyval, char typalign, bool freedata); +static void system_cache_lookup(Oid element_type, IOFuncSelector which_func, + int *typlen, bool *typbyval, + char *typdelim, Oid *typelem, + Oid *proc, char *typalign); static Datum ArrayCast(char *value, bool byval, int len); static int ArrayCastAndSet(Datum src, int typlen, bool typbyval, char typalign, @@ -107,7 +119,7 @@ static void array_insert_slice(int ndim, int *dim, int *lb, char *destPtr, int *st, int *endp, char *srcPtr, int typlen, bool typbyval, char typalign); -static int array_cmp(FunctionCallInfo fcinfo); + /*--------------------------------------------------------------------- * array_in : @@ -142,49 +154,12 @@ array_in(PG_FUNCTION_ARGS) dim[MAXDIM], lBound[MAXDIM]; char typalign; - ArrayMetaState *my_extra; - - /* - * We arrange to look up info about element type, including its input - * conversion proc only once per series of calls, assuming the element - * type doesn't change underneath us. - */ - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; - } - if (my_extra->element_type != element_type) - { - /* Get info about element type, including its input conversion proc */ - get_type_metadata(element_type, IOFunc_input, - &typlen, &typbyval, &typdelim, - &typelem, &typinput, &typalign); - fmgr_info(typinput, &inputproc); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typdelim = typdelim; - my_extra->typelem = typelem; - my_extra->typiofunc = typinput; - my_extra->typalign = typalign; - my_extra->proc = inputproc; - } - else - { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typdelim = my_extra->typdelim; - typelem = my_extra->typelem; - typinput = my_extra->typiofunc; - typalign = my_extra->typalign; - inputproc = my_extra->proc; - } + /* Get info about element type, including its input conversion proc */ + system_cache_lookup(element_type, IOFunc_input, + &typlen, &typbyval, &typdelim, + &typelem, &typinput, &typalign); + fmgr_info(typinput, &inputproc); /* Make a modifiable copy of the input */ /* XXX why are we allocating an extra 2 bytes here? */ @@ -661,51 +636,12 @@ array_out(PG_FUNCTION_ARGS) indx[MAXDIM]; int ndim, *dim; - ArrayMetaState *my_extra; element_type = ARR_ELEMTYPE(v); - - /* - * We arrange to look up info about element type, including its input - * conversion proc only once per series of calls, assuming the element - * type doesn't change underneath us. - */ - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; - } - - if (my_extra->element_type != element_type) - { - /* Get info about element type, including its output conversion proc */ - get_type_metadata(element_type, IOFunc_output, - &typlen, &typbyval, &typdelim, - &typelem, &typoutput, &typalign); - fmgr_info(typoutput, &outputproc); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typdelim = typdelim; - my_extra->typelem = typelem; - my_extra->typiofunc = typoutput; - my_extra->typalign = typalign; - my_extra->proc = outputproc; - } - else - { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typdelim = my_extra->typdelim; - typelem = my_extra->typelem; - typoutput = my_extra->typiofunc; - typalign = my_extra->typalign; - outputproc = my_extra->proc; - } + system_cache_lookup(element_type, IOFunc_output, + &typlen, &typbyval, &typdelim, + &typelem, &typoutput, &typalign); + fmgr_info(typoutput, &outputproc); ndim = ARR_NDIM(v); dim = ARR_DIMS(v); @@ -864,7 +800,6 @@ array_recv(PG_FUNCTION_ARGS) dim[MAXDIM], lBound[MAXDIM]; char typalign; - ArrayMetaState *my_extra; /* Get the array header information */ ndim = pq_getmsgint(buf, 4); @@ -896,50 +831,14 @@ array_recv(PG_FUNCTION_ARGS) PG_RETURN_ARRAYTYPE_P(retval); } - /* - * We arrange to look up info about element type, including its receive - * conversion proc only once per series of calls, assuming the element - * type doesn't change underneath us. - */ - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; - } - - if (my_extra->element_type != element_type) - { - /* Get info about element type, including its receive conversion proc */ - get_type_metadata(element_type, IOFunc_receive, - &typlen, &typbyval, &typdelim, - &typelem, &typreceive, &typalign); - if (!OidIsValid(typreceive)) - elog(ERROR, "No binary input function available for type %s", - format_type_be(element_type)); - fmgr_info(typreceive, &receiveproc); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typdelim = typdelim; - my_extra->typelem = typelem; - my_extra->typiofunc = typreceive; - my_extra->typalign = typalign; - my_extra->proc = receiveproc; - } - else - { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typdelim = my_extra->typdelim; - typelem = my_extra->typelem; - typreceive = my_extra->typiofunc; - typalign = my_extra->typalign; - receiveproc = my_extra->proc; - } + /* Get info about element type, including its receive conversion proc */ + system_cache_lookup(element_type, IOFunc_receive, + &typlen, &typbyval, &typdelim, + &typelem, &typreceive, &typalign); + if (!OidIsValid(typreceive)) + elog(ERROR, "No binary input function available for type %s", + format_type_be(element_type)); + fmgr_info(typreceive, &receiveproc); dataPtr = ReadArrayBinary(buf, nitems, &receiveproc, typelem, typlen, typbyval, typalign, @@ -1077,54 +976,15 @@ array_send(PG_FUNCTION_ARGS) int ndim, *dim; StringInfoData buf; - ArrayMetaState *my_extra; /* Get information about the element type and the array dimensions */ element_type = ARR_ELEMTYPE(v); - - /* - * We arrange to look up info about element type, including its send - * proc only once per series of calls, assuming the element - * type doesn't change underneath us. - */ - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; - } - - if (my_extra->element_type != element_type) - { - /* Get info about element type, including its send proc */ - get_type_metadata(element_type, IOFunc_send, &typlen, &typbyval, - &typdelim, &typelem, &typsend, &typalign); - if (!OidIsValid(typsend)) - elog(ERROR, "No binary output function available for type %s", - format_type_be(element_type)); - fmgr_info(typsend, &sendproc); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typdelim = typdelim; - my_extra->typelem = typelem; - my_extra->typiofunc = typsend; - my_extra->typalign = typalign; - my_extra->proc = sendproc; - } - else - { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typdelim = my_extra->typdelim; - typelem = my_extra->typelem; - typsend = my_extra->typiofunc; - typalign = my_extra->typalign; - sendproc = my_extra->proc; - } + system_cache_lookup(element_type, IOFunc_send, &typlen, &typbyval, + &typdelim, &typelem, &typsend, &typalign); + if (!OidIsValid(typsend)) + elog(ERROR, "No binary output function available for type %s", + format_type_be(element_type)); + fmgr_info(typsend, &sendproc); ndim = ARR_NDIM(v); dim = ARR_DIMS(v); @@ -1616,26 +1476,6 @@ array_set(ArrayType *array, array = DatumGetArrayTypeP(PointerGetDatum(array)); ndim = ARR_NDIM(array); - - /* - * if number of dims is zero, i.e. an empty array, create an array - * with nSubscripts dimensions, and set the lower bounds to the supplied - * subscripts - */ - if (ndim == 0) - { - Oid elmtype = ARR_ELEMTYPE(array); - - for (i = 0; i < nSubscripts; i++) - { - dim[i] = 1; - lb[i] = indx[i]; - } - - return construct_md_array(&dataValue, nSubscripts, dim, lb, elmtype, - elmlen, elmbyval, elmalign); - } - if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM) elog(ERROR, "Invalid array subscripts"); @@ -1792,31 +1632,6 @@ array_set_slice(ArrayType *array, /* note: we assume srcArray contains no toasted elements */ ndim = ARR_NDIM(array); - - /* - * if number of dims is zero, i.e. an empty array, create an array - * with nSubscripts dimensions, and set the upper and lower bounds - * to the supplied subscripts - */ - if (ndim == 0) - { - Datum *dvalues; - int nelems; - Oid elmtype = ARR_ELEMTYPE(array); - - deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign, - &dvalues, &nelems); - - for (i = 0; i < nSubscripts; i++) - { - dim[i] = 1 + upperIndx[i] - lowerIndx[i]; - lb[i] = lowerIndx[i]; - } - - return construct_md_array(dvalues, nSubscripts, dim, lb, elmtype, - elmlen, elmbyval, elmalign); - } - if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM) elog(ERROR, "Invalid array subscripts"); @@ -1996,13 +1811,6 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) Oid typelem; Oid proc; char *s; - typedef struct { - ArrayMetaState *inp_extra; - ArrayMetaState *ret_extra; - } am_extra; - am_extra *my_extra; - ArrayMetaState *inp_extra; - ArrayMetaState *ret_extra; /* Get input array */ if (fcinfo->nargs < 1) @@ -2021,81 +1829,11 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType) if (nitems <= 0) PG_RETURN_ARRAYTYPE_P(v); - /* - * We arrange to look up info about input and return element types only - * once per series of calls, assuming the element type doesn't change - * underneath us. - */ - my_extra = (am_extra *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(am_extra)); - my_extra = (am_extra *) fcinfo->flinfo->fn_extra; - - my_extra->inp_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - inp_extra = my_extra->inp_extra; - inp_extra->element_type = InvalidOid; - - my_extra->ret_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - ret_extra = my_extra->ret_extra; - ret_extra->element_type = InvalidOid; - } - else - { - inp_extra = my_extra->inp_extra; - ret_extra = my_extra->ret_extra; - } - - if (inp_extra->element_type != inpType) - { - /* Lookup source and result types. Unneeded variables are reused. */ - get_type_metadata(inpType, IOFunc_input, &inp_typlen, &inp_typbyval, - &typdelim, &typelem, &proc, &inp_typalign); - - inp_extra->element_type = inpType; - inp_extra->typlen = inp_typlen; - inp_extra->typbyval = inp_typbyval; - inp_extra->typdelim = typdelim; - inp_extra->typelem = typelem; - inp_extra->typiofunc = proc; - inp_extra->typalign = inp_typalign; - } - else - { - inp_typlen = inp_extra->typlen; - inp_typbyval = inp_extra->typbyval; - typdelim = inp_extra->typdelim; - typelem = inp_extra->typelem; - proc = inp_extra->typiofunc; - inp_typalign = inp_extra->typalign; - } - - if (ret_extra->element_type != retType) - { - /* Lookup source and result types. Unneeded variables are reused. */ - get_type_metadata(retType, IOFunc_input, &typlen, &typbyval, - &typdelim, &typelem, &proc, &typalign); - - ret_extra->element_type = retType; - ret_extra->typlen = typlen; - ret_extra->typbyval = typbyval; - ret_extra->typdelim = typdelim; - ret_extra->typelem = typelem; - ret_extra->typiofunc = proc; - ret_extra->typalign = typalign; - } - else - { - typlen = ret_extra->typlen; - typbyval = ret_extra->typbyval; - typdelim = ret_extra->typdelim; - typelem = ret_extra->typelem; - proc = ret_extra->typiofunc; - typalign = ret_extra->typalign; - } + /* Lookup source and result types. Unneeded variables are reused. */ + system_cache_lookup(inpType, IOFunc_input, &inp_typlen, &inp_typbyval, + &typdelim, &typelem, &proc, &inp_typalign); + system_cache_lookup(retType, IOFunc_input, &typlen, &typbyval, + &typdelim, &typelem, &proc, &typalign); /* Allocate temporary array for new values */ values = (Datum *) palloc(nitems * sizeof(Datum)); @@ -2311,6 +2049,8 @@ deconstruct_array(ArrayType *array, * compares two arrays for equality * result : * returns true if the arrays are equal, false otherwise. + * + * XXX bitwise equality is pretty bogus ... *----------------------------------------------------------------------------- */ Datum @@ -2318,118 +2058,12 @@ array_eq(PG_FUNCTION_ARGS) { ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0); ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1); - char *p1 = (char *) ARR_DATA_PTR(array1); - char *p2 = (char *) ARR_DATA_PTR(array2); - int ndims1 = ARR_NDIM(array1); - int ndims2 = ARR_NDIM(array2); - int *dims1 = ARR_DIMS(array1); - int *dims2 = ARR_DIMS(array2); - 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; - int typlen; - bool typbyval; - char typdelim; - Oid typelem; - char typalign; - Oid typiofunc; - int i; - ArrayMetaState *my_extra; - FunctionCallInfoData locfcinfo; - /* fast path if the arrays do not have the same number of elements */ - if (nitems1 != nitems2) + if (ARR_SIZE(array1) != ARR_SIZE(array2)) + result = false; + else if (memcmp(array1, array2, ARR_SIZE(array1)) != 0) result = false; - else - { - /* - * We arrange to look up the equality function only once per series of - * calls, assuming the element type doesn't change underneath us. - */ - my_extra = (ArrayMetaState *) ae_fmgr_info->fn_extra; - if (my_extra == NULL) - { - 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); - - if (OidIsValid(opfuncid)) - fmgr_info_cxt(opfuncid, &my_extra->proc, ae_fmgr_info->fn_mcxt); - else - elog(ERROR, - "array_eq: cannot find equality operator for type: %u", - element_type); - - get_type_metadata(element_type, IOFunc_output, - &typlen, &typbyval, &typdelim, - &typelem, &typiofunc, &typalign); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typdelim = typdelim; - my_extra->typelem = typelem; - my_extra->typiofunc = typiofunc; - my_extra->typalign = typalign; - } - else - { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typdelim = my_extra->typdelim; - typelem = my_extra->typelem; - typiofunc = my_extra->typiofunc; - typalign = my_extra->typalign; - } - - /* - * apply the operator to each pair of array elements. - */ - MemSet(&locfcinfo, 0, sizeof(locfcinfo)); - locfcinfo.flinfo = &my_extra->proc; - locfcinfo.nargs = 2; - - /* Loop over source data */ - for (i = 0; i < nitems1; i++) - { - Datum elt1; - Datum elt2; - bool oprresult; - - /* Get element pair */ - elt1 = fetch_att(p1, typbyval, typlen); - elt2 = fetch_att(p2, typbyval, typlen); - - p1 = att_addlength(p1, typlen, PointerGetDatum(p1)); - p1 = (char *) att_align(p1, typalign); - - p2 = att_addlength(p2, typlen, PointerGetDatum(p2)); - p2 = (char *) att_align(p2, typalign); - - /* - * Apply the operator to the element pair - */ - locfcinfo.arg[0] = elt1; - locfcinfo.arg[1] = elt2; - locfcinfo.argnull[0] = false; - locfcinfo.argnull[1] = false; - locfcinfo.isnull = false; - oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo)); - if (!oprresult) - { - result = false; - break; - } - } - } /* Avoid leaking memory when handed toasted input. */ PG_FREE_IF_COPY(array1, 0); @@ -2439,190 +2073,53 @@ array_eq(PG_FUNCTION_ARGS) } -/*----------------------------------------------------------------------------- - * array-array bool operators: - * Given two arrays, iterate comparison operators - * over the array. Uses logic similar to text comparison - * functions, except element-by-element instead of - * character-by-character. - *---------------------------------------------------------------------------- - */ -Datum -array_ne(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(!DatumGetBool(array_eq(fcinfo))); -} - -Datum -array_lt(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(array_cmp(fcinfo) < 0); -} - -Datum -array_gt(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(array_cmp(fcinfo) > 0); -} - -Datum -array_le(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(array_cmp(fcinfo) <= 0); -} - -Datum -array_ge(PG_FUNCTION_ARGS) -{ - PG_RETURN_BOOL(array_cmp(fcinfo) >= 0); -} - -Datum -btarraycmp(PG_FUNCTION_ARGS) -{ - PG_RETURN_INT32(array_cmp(fcinfo)); -} - -/* - * array_cmp() - * Internal comparison function for arrays. - * - * Returns -1, 0 or 1 - */ -static int -array_cmp(FunctionCallInfo fcinfo) -{ - ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0); - ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1); - FmgrInfo *ac_fmgr_info = fcinfo->flinfo; - Datum opresult; - int result = 0; - Oid element_type = InvalidOid; - int typlen; - bool typbyval; - char typdelim; - Oid typelem; - char typalign; - Oid typiofunc; - Datum *dvalues1; - int nelems1; - Datum *dvalues2; - int nelems2; - int min_nelems; - int i; - typedef struct - { - Oid element_type; - int typlen; - bool typbyval; - char typdelim; - Oid typelem; - Oid typiofunc; - char typalign; - FmgrInfo eqproc; - FmgrInfo ordproc; - } ac_extra; - ac_extra *my_extra; - - element_type = ARR_ELEMTYPE(array1); - - /* - * We arrange to look up the element type operator function only once - * per series of calls, assuming the element type and opname don't - * change underneath us. - */ - my_extra = (ac_extra *) ac_fmgr_info->fn_extra; - if (my_extra == NULL) - { - 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; - } - - if (my_extra->element_type != element_type) - { - Oid eqfuncid = equality_oper_funcid(element_type); - Oid ordfuncid = ordering_oper_funcid(element_type); - - fmgr_info_cxt(eqfuncid, &my_extra->eqproc, ac_fmgr_info->fn_mcxt); - fmgr_info_cxt(ordfuncid, &my_extra->ordproc, ac_fmgr_info->fn_mcxt); - - if (my_extra->eqproc.fn_nargs != 2) - elog(ERROR, "Equality operator does not take 2 arguments: %u", - eqfuncid); - if (my_extra->ordproc.fn_nargs != 2) - elog(ERROR, "Ordering operator does not take 2 arguments: %u", - ordfuncid); - - get_type_metadata(element_type, IOFunc_output, - &typlen, &typbyval, &typdelim, - &typelem, &typiofunc, &typalign); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typdelim = typdelim; - my_extra->typelem = typelem; - my_extra->typiofunc = InvalidOid; - my_extra->typalign = typalign; - } - else - { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typalign = my_extra->typalign; - } - - /* extract a C array of arg array datums */ - deconstruct_array(array1, element_type, typlen, typbyval, typalign, - &dvalues1, &nelems1); - - deconstruct_array(array2, element_type, typlen, typbyval, typalign, - &dvalues2, &nelems2); - - min_nelems = Min(nelems1, nelems2); - for (i = 0; i < min_nelems; i++) - { - /* are they equal */ - opresult = FunctionCall2(&my_extra->eqproc, - dvalues1[i], dvalues2[i]); - - if (!DatumGetBool(opresult)) - { - /* nope, see if arg1 is less than arg2 */ - opresult = FunctionCall2(&my_extra->ordproc, - dvalues1[i], dvalues2[i]); - if (DatumGetBool(opresult)) - { - /* arg1 is less than arg2 */ - result = -1; - break; - } - else - { - /* arg1 is greater than arg2 */ - result = 1; - break; - } - } - } - - if ((result == 0) && (nelems1 != nelems2)) - result = (nelems1 < nelems2) ? -1 : 1; - - /* Avoid leaking memory when handed toasted input. */ - PG_FREE_IF_COPY(array1, 0); - PG_FREE_IF_COPY(array2, 1); - - return result; -} - - /***************************************************************************/ /******************| Support Routines |*****************/ /***************************************************************************/ +static void +system_cache_lookup(Oid element_type, + IOFuncSelector which_func, + int *typlen, + bool *typbyval, + char *typdelim, + Oid *typelem, + Oid *proc, + char *typalign) +{ + HeapTuple typeTuple; + Form_pg_type typeStruct; + + typeTuple = SearchSysCache(TYPEOID, + ObjectIdGetDatum(element_type), + 0, 0, 0); + if (!HeapTupleIsValid(typeTuple)) + elog(ERROR, "cache lookup failed for type %u", element_type); + typeStruct = (Form_pg_type) GETSTRUCT(typeTuple); + + *typlen = typeStruct->typlen; + *typbyval = typeStruct->typbyval; + *typdelim = typeStruct->typdelim; + *typelem = typeStruct->typelem; + *typalign = typeStruct->typalign; + switch (which_func) + { + case IOFunc_input: + *proc = typeStruct->typinput; + break; + case IOFunc_output: + *proc = typeStruct->typoutput; + break; + case IOFunc_receive: + *proc = typeStruct->typreceive; + break; + case IOFunc_send: + *proc = typeStruct->typsend; + break; + } + ReleaseSysCache(typeTuple); +} + /* * Fetch array element at pointer, converted correctly to a Datum */ @@ -2926,18 +2423,6 @@ array_type_coerce(PG_FUNCTION_ARGS) if (tgt_elem_type == InvalidOid) elog(ERROR, "Target type is not an array"); - /* - * We don't deal with domain constraints yet, so bail out. - * This isn't currently a problem, because we also don't - * support arrays of domain type elements either. But in the - * future we might. At that point consideration should be given - * to removing the check below and adding a domain constraints - * check to the coercion. - */ - if (getBaseType(tgt_elem_type) != tgt_elem_type) - elog(ERROR, "array coercion to domain type elements not " \ - "currently supported"); - if (!find_coercion_pathway(tgt_elem_type, src_elem_type, COERCION_EXPLICIT, &funcId)) { @@ -2954,16 +2439,10 @@ array_type_coerce(PG_FUNCTION_ARGS) } /* - * If it's binary-compatible, modify the element type in the array header, - * but otherwise leave the array as we received it. + * If it's binary-compatible, return the array unmodified. */ if (my_extra->coerce_finfo.fn_oid == InvalidOid) - { - ArrayType *result = DatumGetArrayTypePCopy(PG_GETARG_DATUM(0)); - - ARR_ELEMTYPE(result) = my_extra->desttype; - PG_RETURN_ARRAYTYPE_P(result); - } + PG_RETURN_ARRAYTYPE_P(src); /* * Use array_map to apply the function to each array element. @@ -2975,118 +2454,3 @@ array_type_coerce(PG_FUNCTION_ARGS) return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype); } - -/* - * accumArrayResult - accumulate one (more) Datum for an ARRAY_SUBLINK - * - * astate is working state (NULL on first call) - * rcontext is where to keep working state - */ -ArrayBuildState * -accumArrayResult(ArrayBuildState *astate, - Datum dvalue, bool disnull, - Oid element_type, - MemoryContext rcontext) -{ - MemoryContext arr_context, - oldcontext; - - if (astate == NULL) - { - /* First time through --- initialize */ - - /* Make a temporary context to hold all the junk */ - arr_context = AllocSetContextCreate(rcontext, - "accumArrayResult", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); - oldcontext = MemoryContextSwitchTo(arr_context); - astate = (ArrayBuildState *) palloc(sizeof(ArrayBuildState)); - astate->mcontext = arr_context; - astate->dvalues = (Datum *) - palloc(ARRAY_ELEMS_CHUNKSIZE * sizeof(Datum)); - astate->nelems = 0; - astate->element_type = element_type; - get_typlenbyvalalign(element_type, - &astate->typlen, - &astate->typbyval, - &astate->typalign); - } - else - { - oldcontext = MemoryContextSwitchTo(astate->mcontext); - Assert(astate->element_type == element_type); - /* enlarge dvalues[] if needed */ - if ((astate->nelems % ARRAY_ELEMS_CHUNKSIZE) == 0) - astate->dvalues = (Datum *) - repalloc(astate->dvalues, - (astate->nelems + ARRAY_ELEMS_CHUNKSIZE) * sizeof(Datum)); - } - - if (disnull) - elog(ERROR, "NULL elements not allowed in Arrays"); - - /* Use datumCopy to ensure pass-by-ref stuff is copied into mcontext */ - astate->dvalues[astate->nelems++] = - datumCopy(dvalue, astate->typbyval, astate->typlen); - - MemoryContextSwitchTo(oldcontext); - - return astate; -} - -/* - * makeArrayResult - produce final result of accumArrayResult - * - * astate is working state (not NULL) - * rcontext is where to construct result - */ -Datum -makeArrayResult(ArrayBuildState *astate, - MemoryContext rcontext) -{ - int dims[1]; - int lbs[1]; - - dims[0] = astate->nelems; - lbs[0] = 1; - - return makeMdArrayResult(astate, 1, dims, lbs, rcontext); -} - -/* - * makeMdArrayResult - produce md final result of accumArrayResult - * - * astate is working state (not NULL) - * rcontext is where to construct result - */ -Datum -makeMdArrayResult(ArrayBuildState *astate, - int ndims, - int *dims, - int *lbs, - MemoryContext rcontext) -{ - ArrayType *result; - MemoryContext oldcontext; - - /* Build the final array result in rcontext */ - oldcontext = MemoryContextSwitchTo(rcontext); - - result = construct_md_array(astate->dvalues, - ndims, - dims, - lbs, - astate->element_type, - astate->typlen, - astate->typbyval, - astate->typalign); - - MemoryContextSwitchTo(oldcontext); - - /* Clean up all the junk */ - MemoryContextDelete(astate->mcontext); - - return PointerGetDatum(result); -} diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index aca19d17e89..ce6443647e2 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.99 2003/06/24 23:14:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.100 2003/06/25 21:30:32 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -19,14 +19,11 @@ #include "mb/pg_wchar.h" #include "miscadmin.h" #include "access/tuptoaster.h" -#include "catalog/pg_type.h" #include "lib/stringinfo.h" #include "libpq/crypt.h" #include "libpq/pqformat.h" -#include "utils/array.h" #include "utils/builtins.h" #include "utils/pg_locale.h" -#include "utils/lsyscache.h" typedef struct varlena unknown; @@ -1986,7 +1983,8 @@ split_text(PG_FUNCTION_ARGS) if (fldnum == 1) /* first field - just return the input * string */ PG_RETURN_TEXT_P(inputstring); - else /* otherwise return an empty string */ + else +/* otherwise return an empty string */ PG_RETURN_TEXT_P(PG_STR_GET_TEXT("")); } @@ -2006,7 +2004,8 @@ split_text(PG_FUNCTION_ARGS) if (fldnum == 1) /* first field - just return the input * string */ PG_RETURN_TEXT_P(inputstring); - else /* otherwise return an empty string */ + else +/* otherwise return an empty string */ PG_RETURN_TEXT_P(PG_STR_GET_TEXT("")); } else if ((start_posn != 0) && (end_posn == 0)) @@ -2029,191 +2028,6 @@ split_text(PG_FUNCTION_ARGS) } } -/* - * text_to_array - * parse input string - * return text array of elements - * based on provided field separator - */ -Datum -text_to_array(PG_FUNCTION_ARGS) -{ - text *inputstring = PG_GETARG_TEXT_P(0); - int inputstring_len = TEXTLEN(inputstring); - text *fldsep = PG_GETARG_TEXT_P(1); - int fldsep_len = TEXTLEN(fldsep); - int fldnum; - int start_posn = 0; - int end_posn = 0; - text *result_text = NULL; - ArrayBuildState *astate = NULL; - MemoryContext oldcontext = CurrentMemoryContext; - - /* return NULL for empty input string */ - if (inputstring_len < 1) - PG_RETURN_NULL(); - - /* empty field separator - * return one element, 1D, array using the input string */ - if (fldsep_len < 1) - PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID, - CStringGetDatum(inputstring), 1)); - - /* start with end position holding the initial start position */ - end_posn = 0; - for (fldnum=1;;fldnum++) /* field number is 1 based */ - { - Datum dvalue; - bool disnull = false; - - start_posn = end_posn; - end_posn = text_position(PointerGetDatum(inputstring), - PointerGetDatum(fldsep), - fldnum); - - if ((start_posn == 0) && (end_posn == 0)) /* fldsep not found */ - { - if (fldnum == 1) - { - /* first element - * return one element, 1D, array using the input string */ - PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID, - CStringGetDatum(inputstring), 1)); - } - else - { - /* otherwise create array and exit */ - PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, oldcontext)); - } - } - else if ((start_posn != 0) && (end_posn == 0)) - { - /* last field requested */ - result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, -1, true); - } - else if ((start_posn == 0) && (end_posn != 0)) - { - /* first field requested */ - result_text = LEFT(inputstring, fldsep); - } - else - { - /* prior to last field requested */ - result_text = text_substring(PointerGetDatum(inputstring), start_posn + fldsep_len, end_posn - start_posn - fldsep_len, false); - } - - /* stash away current value */ - dvalue = PointerGetDatum(result_text); - astate = accumArrayResult(astate, dvalue, - disnull, TEXTOID, oldcontext); - - } - - /* never reached -- keep compiler quiet */ - PG_RETURN_NULL(); -} - -/* - * array_to_text - * concatenate Cstring representation of input array elements - * using provided field separator - */ -Datum -array_to_text(PG_FUNCTION_ARGS) -{ - ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); - char *fldsep = PG_TEXTARG_GET_STR(1); - int nitems, *dims, ndims; - char *p; - Oid element_type; - int typlen; - bool typbyval; - char typdelim; - Oid typoutput, - typelem; - FmgrInfo outputproc; - char typalign; - StringInfo result_str = makeStringInfo(); - int i; - ArrayMetaState *my_extra; - - p = ARR_DATA_PTR(v); - ndims = ARR_NDIM(v); - dims = ARR_DIMS(v); - nitems = ArrayGetNItems(ndims, dims); - - /* if there are no elements, return an empty string */ - if (nitems == 0) - PG_RETURN_TEXT_P(PG_STR_GET_TEXT("")); - - element_type = ARR_ELEMTYPE(v); - - /* - * We arrange to look up info about element type, including its output - * conversion proc only once per series of calls, assuming the element - * type doesn't change underneath us. - */ - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - if (my_extra == NULL) - { - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - sizeof(ArrayMetaState)); - my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; - my_extra->element_type = InvalidOid; - } - - if (my_extra->element_type != element_type) - { - /* Get info about element type, including its output conversion proc */ - get_type_metadata(element_type, IOFunc_output, - &typlen, &typbyval, &typdelim, - &typelem, &typoutput, &typalign); - fmgr_info(typoutput, &outputproc); - - my_extra->element_type = element_type; - my_extra->typlen = typlen; - my_extra->typbyval = typbyval; - my_extra->typdelim = typdelim; - my_extra->typelem = typelem; - my_extra->typiofunc = typoutput; - my_extra->typalign = typalign; - my_extra->proc = outputproc; - } - else - { - typlen = my_extra->typlen; - typbyval = my_extra->typbyval; - typdelim = my_extra->typdelim; - typelem = my_extra->typelem; - typoutput = my_extra->typiofunc; - typalign = my_extra->typalign; - outputproc = my_extra->proc; - } - - for (i = 0; i < nitems; i++) - { - Datum itemvalue; - char *value; - - itemvalue = fetch_att(p, typbyval, typlen); - - value = DatumGetCString(FunctionCall3(&outputproc, - itemvalue, - ObjectIdGetDatum(typelem), - Int32GetDatum(-1))); - - if (i > 0) - appendStringInfo(result_str, "%s%s", fldsep, value); - else - appendStringInfo(result_str, "%s", value); - - p = att_addlength(p, typlen, PointerGetDatum(p)); - p = (char *) att_align(p, typalign); - } - - PG_RETURN_TEXT_P(PG_STR_GET_TEXT(result_str->data)); -} - #define HEXBASE 16 /* * Convert a int32 to a string containing a base 16 (hex) representation of |