aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/array_userfuncs.c
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2003-06-25 21:30:34 +0000
committerBruce Momjian <bruce@momjian.us>2003-06-25 21:30:34 +0000
commit111d8e522b61169393e2698924db07586fdd847f (patch)
treea62b7f9640246a64003131f472793a295417051f /src/backend/utils/adt/array_userfuncs.c
parent621691d816c45396ab9f8f9486ee9eb2a037795c (diff)
downloadpostgresql-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.c289
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);