diff options
author | Bruce Momjian <bruce@momjian.us> | 2003-06-25 21:30:34 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 2003-06-25 21:30:34 +0000 |
commit | 111d8e522b61169393e2698924db07586fdd847f (patch) | |
tree | a62b7f9640246a64003131f472793a295417051f /src/backend/utils/adt/array_userfuncs.c | |
parent | 621691d816c45396ab9f8f9486ee9eb2a037795c (diff) | |
download | postgresql-111d8e522b61169393e2698924db07586fdd847f.tar.gz postgresql-111d8e522b61169393e2698924db07586fdd847f.zip |
Back out array mega-patch.
Joe Conway
Diffstat (limited to 'src/backend/utils/adt/array_userfuncs.c')
-rw-r--r-- | src/backend/utils/adt/array_userfuncs.c | 289 |
1 files changed, 186 insertions, 103 deletions
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); |