Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions | Variables

array.h File Reference

#include "fmgr.h"
Include dependency graph for array.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ArrayType
struct  ArrayBuildState
struct  ArrayMetaState
struct  ArrayMapState

Defines

#define DatumGetArrayTypeP(X)   ((ArrayType *) PG_DETOAST_DATUM(X))
#define DatumGetArrayTypePCopy(X)   ((ArrayType *) PG_DETOAST_DATUM_COPY(X))
#define PG_GETARG_ARRAYTYPE_P(n)   DatumGetArrayTypeP(PG_GETARG_DATUM(n))
#define PG_GETARG_ARRAYTYPE_P_COPY(n)   DatumGetArrayTypePCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_ARRAYTYPE_P(x)   PG_RETURN_POINTER(x)
#define ARR_SIZE(a)   VARSIZE(a)
#define ARR_NDIM(a)   ((a)->ndim)
#define ARR_HASNULL(a)   ((a)->dataoffset != 0)
#define ARR_ELEMTYPE(a)   ((a)->elemtype)
#define ARR_DIMS(a)   ((int *) (((char *) (a)) + sizeof(ArrayType)))
#define ARR_LBOUND(a)
#define ARR_NULLBITMAP(a)
#define ARR_OVERHEAD_NONULLS(ndims)   MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims))
#define ARR_OVERHEAD_WITHNULLS(ndims, nitems)
#define ARR_DATA_OFFSET(a)   (ARR_HASNULL(a) ? (a)->dataoffset : ARR_OVERHEAD_NONULLS(ARR_NDIM(a)))
#define ARR_DATA_PTR(a)   (((char *) (a)) + ARR_DATA_OFFSET(a))

Typedefs

typedef struct ArrayBuildState ArrayBuildState
typedef struct ArrayMetaState ArrayMetaState
typedef struct ArrayMapState ArrayMapState
typedef struct ArrayIteratorDataArrayIterator

Functions

Datum array_in (PG_FUNCTION_ARGS)
Datum array_out (PG_FUNCTION_ARGS)
Datum array_recv (PG_FUNCTION_ARGS)
Datum array_send (PG_FUNCTION_ARGS)
Datum array_eq (PG_FUNCTION_ARGS)
Datum array_ne (PG_FUNCTION_ARGS)
Datum array_lt (PG_FUNCTION_ARGS)
Datum array_gt (PG_FUNCTION_ARGS)
Datum array_le (PG_FUNCTION_ARGS)
Datum array_ge (PG_FUNCTION_ARGS)
Datum btarraycmp (PG_FUNCTION_ARGS)
Datum hash_array (PG_FUNCTION_ARGS)
Datum arrayoverlap (PG_FUNCTION_ARGS)
Datum arraycontains (PG_FUNCTION_ARGS)
Datum arraycontained (PG_FUNCTION_ARGS)
Datum array_ndims (PG_FUNCTION_ARGS)
Datum array_dims (PG_FUNCTION_ARGS)
Datum array_lower (PG_FUNCTION_ARGS)
Datum array_upper (PG_FUNCTION_ARGS)
Datum array_length (PG_FUNCTION_ARGS)
Datum array_larger (PG_FUNCTION_ARGS)
Datum array_smaller (PG_FUNCTION_ARGS)
Datum generate_subscripts (PG_FUNCTION_ARGS)
Datum generate_subscripts_nodir (PG_FUNCTION_ARGS)
Datum array_fill (PG_FUNCTION_ARGS)
Datum array_fill_with_lower_bounds (PG_FUNCTION_ARGS)
Datum array_unnest (PG_FUNCTION_ARGS)
Datum array_remove (PG_FUNCTION_ARGS)
Datum array_replace (PG_FUNCTION_ARGS)
Datum array_ref (ArrayType *array, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
ArrayTypearray_set (ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
ArrayTypearray_get_slice (ArrayType *array, int nSubscripts, int *upperIndx, int *lowerIndx, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
ArrayTypearray_set_slice (ArrayType *array, int nSubscripts, int *upperIndx, int *lowerIndx, ArrayType *srcArray, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Datum array_map (FunctionCallInfo fcinfo, Oid inpType, Oid retType, ArrayMapState *amstate)
void array_bitmap_copy (bits8 *destbitmap, int destoffset, const bits8 *srcbitmap, int srcoffset, int nitems)
ArrayTypeconstruct_array (Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
ArrayTypeconstruct_md_array (Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
ArrayTypeconstruct_empty_array (Oid elmtype)
void deconstruct_array (ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
bool array_contains_nulls (ArrayType *array)
ArrayBuildStateaccumArrayResult (ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Datum makeArrayResult (ArrayBuildState *astate, MemoryContext rcontext)
Datum makeMdArrayResult (ArrayBuildState *astate, int ndims, int *dims, int *lbs, MemoryContext rcontext, bool release)
ArrayIterator array_create_iterator (ArrayType *arr, int slice_ndim)
bool array_iterate (ArrayIterator iterator, Datum *value, bool *isnull)
void array_free_iterator (ArrayIterator iterator)
int ArrayGetOffset (int n, const int *dim, const int *lb, const int *indx)
int ArrayGetOffset0 (int n, const int *tup, const int *scale)
int ArrayGetNItems (int ndim, const int *dims)
void mda_get_range (int n, int *span, const int *st, const int *endp)
void mda_get_prod (int n, const int *range, int *prod)
void mda_get_offset_values (int n, int *dist, const int *prod, const int *span)
int mda_next_tuple (int n, int *curr, const int *span)
int32ArrayGetIntegerTypmods (ArrayType *arr, int *n)
Datum array_push (PG_FUNCTION_ARGS)
Datum array_cat (PG_FUNCTION_ARGS)
ArrayTypecreate_singleton_array (FunctionCallInfo fcinfo, Oid element_type, Datum element, bool isNull, int ndims)
Datum array_agg_transfn (PG_FUNCTION_ARGS)
Datum array_agg_finalfn (PG_FUNCTION_ARGS)
Datum array_typanalyze (PG_FUNCTION_ARGS)

Variables

bool Array_nulls

Define Documentation

#define ARR_DATA_OFFSET (   a  )     (ARR_HASNULL(a) ? (a)->dataoffset : ARR_OVERHEAD_NONULLS(ARR_NDIM(a)))

Definition at line 169 of file array.h.

Referenced by array_cat(), array_set(), array_set_slice(), ExecEvalArray(), and resize_intArrayType().

#define ARR_DATA_PTR (   a  )     (((char *) (a)) + ARR_DATA_OFFSET(a))
#define ARR_DIMS (   a  )     ((int *) (((char *) (a)) + sizeof(ArrayType)))

Definition at line 147 of file array.h.

Referenced by _arrq_cons(), _lca(), _lt_q_regex(), _ltree_compress(), aclnewowner(), aclupdate(), allocacl(), array_cat(), array_cmp(), array_contain_compare(), array_contains_nulls(), array_create_iterator(), array_dims(), array_eq(), array_fill_internal(), array_get_slice(), array_in(), array_insert_slice(), array_iterator(), array_length(), array_map(), array_out(), array_push(), array_recv(), array_ref(), array_replace_internal(), array_send(), array_set(), array_set_slice(), array_to_json_internal(), array_to_text_internal(), array_unnest(), array_upper(), arrq_cons(), build_function_result_tupdesc_d(), check_float8_array(), check_functional_grouping(), construct_md_array(), create_array_envelope(), deconstruct_array(), estimate_array_length(), ExecEvalArray(), ExecEvalScalarArrayOp(), extension_config_remove(), generate_subscripts(), get_attstatsslot(), get_func_arg_info(), get_func_input_arg_names(), get_func_result_name(), get_text_array_contents(), getWeights(), GUCArrayAdd(), GUCArrayDelete(), GUCArrayReset(), hash_array(), hstore_from_array(), hstore_from_arrays(), hstore_slice_to_array(), int2vectorrecv(), is_strict_saop(), lt_q_regex(), new_intArrayType(), oidvectorrecv(), pg_extension_config_dump(), pg_get_functiondef(), plperl_ref_from_pg_array(), PLyList_FromArray(), predicate_classify(), ProcedureCreate(), ProcessGUCArray(), RelationGetExclusionInfo(), resize_intArrayType(), ri_LoadConstraintInfo(), TryReuseForeignKey(), and tsa_rewrite_accum().

#define ARR_ELEMTYPE (   a  )     ((a)->elemtype)
#define ARR_HASNULL (   a  )     ((a)->dataoffset != 0)
#define ARR_LBOUND (   a  ) 
#define ARR_NDIM (   a  )     ((a)->ndim)
#define ARR_NULLBITMAP (   a  ) 
#define ARR_OVERHEAD_NONULLS (   ndims  )     MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims))
#define ARR_OVERHEAD_WITHNULLS (   ndims,
  nitems 
)
Value:
MAXALIGN(sizeof(ArrayType) + 2 * sizeof(int) * (ndims) + \
                 ((nitems) + 7) / 8)

Definition at line 165 of file array.h.

Referenced by array_cat(), array_fill_internal(), array_get_slice(), array_in(), array_map(), array_recv(), array_replace_internal(), array_set(), array_set_slice(), construct_md_array(), and ExecEvalArray().

#define ARR_SIZE (   a  )     VARSIZE(a)
#define DatumGetArrayTypeP (   X  )     ((ArrayType *) PG_DETOAST_DATUM(X))
#define DatumGetArrayTypePCopy (   X  )     ((ArrayType *) PG_DETOAST_DATUM_COPY(X))
#define PG_GETARG_ARRAYTYPE_P (   n  )     DatumGetArrayTypeP(PG_GETARG_DATUM(n))

Definition at line 125 of file array.h.

Referenced by _lca(), _lt_q_regex(), _ltq_extract_regex(), _ltq_regex(), _ltree_extract_isparent(), _ltree_extract_risparent(), _ltree_isparent(), _ltree_risparent(), _ltxtq_exec(), _ltxtq_extract_exec(), array_cat(), array_cmp(), array_dims(), array_eq(), array_fill(), array_fill_with_lower_bounds(), array_larger(), array_length(), array_lower(), array_map(), array_ndims(), array_out(), array_push(), array_remove(), array_replace(), array_send(), array_smaller(), array_to_text(), array_to_text_null(), array_unnest(), array_upper(), arraycontained(), arraycontains(), arrayoverlap(), bittypmodin(), bpchartypmodin(), concat_internal(), create_empty_extension(), cube_a_f8(), cube_a_f8_f8(), cube_subset(), dblink_build_sql_delete(), dblink_build_sql_insert(), dblink_build_sql_update(), float4_accum(), float8_accum(), float8_avg(), float8_corr(), float8_covar_pop(), float8_covar_samp(), float8_regr_accum(), float8_regr_avgx(), float8_regr_avgy(), float8_regr_intercept(), float8_regr_r2(), float8_regr_slope(), float8_regr_sxx(), float8_regr_sxy(), float8_regr_syy(), float8_stddev_pop(), float8_stddev_samp(), float8_var_pop(), float8_var_samp(), g_int_same(), g_intbig_consistent(), generate_subscripts(), get_path_all(), ghstore_consistent(), gin_extract_hstore_query(), ginint4_queryextract(), hash_array(), hstore_delete_array(), hstore_exists_all(), hstore_exists_any(), hstore_from_array(), hstore_from_arrays(), hstore_slice_to_array(), hstore_slice_to_hstore(), icount(), idx(), int2_accum(), int2_avg_accum(), int4_accum(), int4_avg_accum(), int8_accum(), int8_avg(), int8_avg_accum(), intarray_push_array(), intarray_push_elem(), interval_accum(), interval_avg(), intervaltypmodin(), intset_union_elem(), lt_q_regex(), numeric_accum(), numeric_avg(), numeric_avg_accum(), numeric_stddev_pop(), numeric_stddev_samp(), numeric_var_pop(), numeric_var_samp(), numerictypmodin(), subarray(), text_format(), timestamptypmodin(), timestamptztypmodin(), timetypmodin(), timetztypmodin(), varbittypmodin(), varchartypmodin(), xpath(), and xpath_exists().

#define PG_GETARG_ARRAYTYPE_P_COPY (   n  )     DatumGetArrayTypePCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_ARRAYTYPE_P (   x  )     PG_RETURN_POINTER(x)

Typedef Documentation

Definition at line 118 of file array.h.

typedef struct ArrayMapState ArrayMapState

Function Documentation

ArrayBuildState* accumArrayResult ( ArrayBuildState astate,
Datum  dvalue,
bool  disnull,
Oid  element_type,
MemoryContext  rcontext 
)

Definition at line 4556 of file arrayfuncs.c.

References ArrayBuildState::alen, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, datumCopy(), ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, get_typlenbyvalalign(), ArrayBuildState::mcontext, MemoryContextSwitchTo(), ArrayBuildState::nelems, NULL, palloc(), PG_DETOAST_DATUM_COPY, PointerGetDatum, repalloc(), ArrayBuildState::typalign, ArrayBuildState::typbyval, and ArrayBuildState::typlen.

Referenced by array_agg_transfn(), array_to_datum_internal(), dblink_get_connections(), ExecScanSubPlan(), ExecSetParamPlan(), optionListToArray(), regexp_split_to_array(), text_to_array_internal(), and transformRelOptions().

{
    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->alen = 64;      /* arbitrary starting array size */
        astate->dvalues = (Datum *) palloc(astate->alen * sizeof(Datum));
        astate->dnulls = (bool *) palloc(astate->alen * sizeof(bool));
        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[]/dnulls[] if needed */
        if (astate->nelems >= astate->alen)
        {
            astate->alen *= 2;
            astate->dvalues = (Datum *)
                repalloc(astate->dvalues, astate->alen * sizeof(Datum));
            astate->dnulls = (bool *)
                repalloc(astate->dnulls, astate->alen * sizeof(bool));
        }
    }

    /*
     * Ensure pass-by-ref stuff is copied into mcontext; and detoast it too if
     * it's varlena.  (You might think that detoasting is not needed here
     * because construct_md_array can detoast the array elements later.
     * However, we must not let construct_md_array modify the ArrayBuildState
     * because that would mean array_agg_finalfn damages its input, which is
     * verboten.  Also, this way frequently saves one copying step.)
     */
    if (!disnull && !astate->typbyval)
    {
        if (astate->typlen == -1)
            dvalue = PointerGetDatum(PG_DETOAST_DATUM_COPY(dvalue));
        else
            dvalue = datumCopy(dvalue, astate->typbyval, astate->typlen);
    }

    astate->dvalues[astate->nelems] = dvalue;
    astate->dnulls[astate->nelems] = disnull;
    astate->nelems++;

    MemoryContextSwitchTo(oldcontext);

    return astate;
}

Datum array_agg_finalfn ( PG_FUNCTION_ARGS   ) 

Definition at line 512 of file array_userfuncs.c.

References AggCheckCallContext(), Assert, CurrentMemoryContext, makeMdArrayResult(), ArrayBuildState::nelems, NULL, PG_ARGISNULL, PG_GETARG_POINTER, PG_RETURN_DATUM, and PG_RETURN_NULL.

{
    Datum       result;
    ArrayBuildState *state;
    int         dims[1];
    int         lbs[1];

    /*
     * Test for null before Asserting we are in right context.  This is to
     * avoid possible Assert failure in 8.4beta installations, where it is
     * possible for users to create NULL constants of type internal.
     */
    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();       /* returns null iff no input values */

    /* cannot be called directly because of internal-type argument */
    Assert(AggCheckCallContext(fcinfo, NULL));

    state = (ArrayBuildState *) PG_GETARG_POINTER(0);

    dims[0] = state->nelems;
    lbs[0] = 1;

    /*
     * Make the result.  We cannot release the ArrayBuildState because
     * sometimes aggregate final functions are re-executed.  Rather, it is
     * nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
     * so.
     */
    result = makeMdArrayResult(state, 1, dims, lbs,
                               CurrentMemoryContext,
                               false);

    PG_RETURN_DATUM(result);
}

Datum array_agg_transfn ( PG_FUNCTION_ARGS   ) 

Definition at line 477 of file array_userfuncs.c.

References accumArrayResult(), AggCheckCallContext(), elog, ereport, errcode(), errmsg(), ERROR, get_fn_expr_argtype(), InvalidOid, NULL, PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_POINTER, and PG_RETURN_POINTER.

{
    Oid         arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
    MemoryContext aggcontext;
    ArrayBuildState *state;
    Datum       elem;

    if (arg1_typeid == InvalidOid)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("could not determine input data type")));

    if (!AggCheckCallContext(fcinfo, &aggcontext))
    {
        /* cannot be called directly because of internal-type argument */
        elog(ERROR, "array_agg_transfn called in non-aggregate context");
    }

    state = PG_ARGISNULL(0) ? NULL : (ArrayBuildState *) PG_GETARG_POINTER(0);
    elem = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
    state = accumArrayResult(state,
                             elem,
                             PG_ARGISNULL(1),
                             arg1_typeid,
                             aggcontext);

    /*
     * The transition type for array_agg() is declared to be "internal", which
     * is a pass-by-value type the same size as a pointer.  So we can safely
     * pass the ArrayBuildState pointer through nodeAgg.c's machinations.
     */
    PG_RETURN_POINTER(state);
}

void array_bitmap_copy ( bits8 destbitmap,
int  destoffset,
const bits8 srcbitmap,
int  srcoffset,
int  nitems 
)

Definition at line 4252 of file arrayfuncs.c.

References Assert.

Referenced by array_cat(), array_extract_slice(), array_insert_slice(), array_set(), array_set_slice(), and ExecEvalArray().

{
    int         destbitmask,
                destbitval,
                srcbitmask,
                srcbitval;

    Assert(destbitmap);
    if (nitems <= 0)
        return;                 /* don't risk fetch off end of memory */
    destbitmap += destoffset / 8;
    destbitmask = 1 << (destoffset % 8);
    destbitval = *destbitmap;
    if (srcbitmap)
    {
        srcbitmap += srcoffset / 8;
        srcbitmask = 1 << (srcoffset % 8);
        srcbitval = *srcbitmap;
        while (nitems-- > 0)
        {
            if (srcbitval & srcbitmask)
                destbitval |= destbitmask;
            else
                destbitval &= ~destbitmask;
            destbitmask <<= 1;
            if (destbitmask == 0x100)
            {
                *destbitmap++ = destbitval;
                destbitmask = 1;
                if (nitems > 0)
                    destbitval = *destbitmap;
            }
            srcbitmask <<= 1;
            if (srcbitmask == 0x100)
            {
                srcbitmap++;
                srcbitmask = 1;
                if (nitems > 0)
                    srcbitval = *srcbitmap;
            }
        }
        if (destbitmask != 1)
            *destbitmap = destbitval;
    }
    else
    {
        while (nitems-- > 0)
        {
            destbitval |= destbitmask;
            destbitmask <<= 1;
            if (destbitmask == 0x100)
            {
                *destbitmap++ = destbitval;
                destbitmask = 1;
                if (nitems > 0)
                    destbitval = *destbitmap;
            }
        }
        if (destbitmask != 1)
            *destbitmap = destbitval;
    }
}

Datum array_cat ( PG_FUNCTION_ARGS   ) 

Definition at line 169 of file array_userfuncs.c.

References ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ARR_SIZE, array_bitmap_copy(), ArrayGetNItems(), ArrayType::dataoffset, ArrayType::elemtype, ereport, errcode(), errdetail(), errmsg(), ERROR, format_type_be(), i, ArrayType::ndim, palloc(), palloc0(), PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, PG_RETURN_NULL, and SET_VARSIZE.

{
    ArrayType  *v1,
               *v2;
    ArrayType  *result;
    int        *dims,
               *lbs,
                ndims,
                nitems,
                ndatabytes,
                nbytes;
    int        *dims1,
               *lbs1,
                ndims1,
                nitems1,
                ndatabytes1;
    int        *dims2,
               *lbs2,
                ndims2,
                nitems2,
                ndatabytes2;
    int         i;
    char       *dat1,
               *dat2;
    bits8      *bitmap1,
               *bitmap2;
    Oid         element_type;
    Oid         element_type1;
    Oid         element_type2;
    int32       dataoffset;

    /* Concatenating a null array is a no-op, just return the other input */
    if (PG_ARGISNULL(0))
    {
        if (PG_ARGISNULL(1))
            PG_RETURN_NULL();
        result = PG_GETARG_ARRAYTYPE_P(1);
        PG_RETURN_ARRAYTYPE_P(result);
    }
    if (PG_ARGISNULL(1))
    {
        result = PG_GETARG_ARRAYTYPE_P(0);
        PG_RETURN_ARRAYTYPE_P(result);
    }

    v1 = PG_GETARG_ARRAYTYPE_P(0);
    v2 = PG_GETARG_ARRAYTYPE_P(1);

    element_type1 = ARR_ELEMTYPE(v1);
    element_type2 = ARR_ELEMTYPE(v2);

    /* Check we have matching element types */
    if (element_type1 != element_type2)
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("cannot concatenate incompatible arrays"),
                 errdetail("Arrays with element types %s and %s are not "
                           "compatible for concatenation.",
                           format_type_be(element_type1),
                           format_type_be(element_type2))));

    /* OK, use it */
    element_type = element_type1;

    /*----------
     * 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
     *----------
     */
    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 under rule 3, 4, or 5 */
    if (ndims1 != ndims2 &&
        ndims1 != ndims2 - 1 &&
        ndims1 != ndims2 + 1)
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                 errmsg("cannot concatenate incompatible arrays"),
                 errdetail("Arrays of %d and %d dimensions are not "
                           "compatible for concatenation.",
                           ndims1, ndims2)));

    /* get argument array details */
    lbs1 = ARR_LBOUND(v1);
    lbs2 = ARR_LBOUND(v2);
    dims1 = ARR_DIMS(v1);
    dims2 = ARR_DIMS(v2);
    dat1 = ARR_DATA_PTR(v1);
    dat2 = ARR_DATA_PTR(v2);
    bitmap1 = ARR_NULLBITMAP(v1);
    bitmap2 = ARR_NULLBITMAP(v2);
    nitems1 = ArrayGetNItems(ndims1, dims1);
    nitems2 = ArrayGetNItems(ndims2, dims2);
    ndatabytes1 = ARR_SIZE(v1) - ARR_DATA_OFFSET(v1);
    ndatabytes2 = ARR_SIZE(v2) - ARR_DATA_OFFSET(v2);

    if (ndims1 == ndims2)
    {
        /*
         * resulting array is made up of the elements (possibly arrays
         * themselves) of the input argument arrays
         */
        ndims = ndims1;
        dims = (int *) palloc(ndims * sizeof(int));
        lbs = (int *) palloc(ndims * sizeof(int));

        dims[0] = dims1[0] + dims2[0];
        lbs[0] = lbs1[0];

        for (i = 1; i < ndims; i++)
        {
            if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i])
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                         errmsg("cannot concatenate incompatible arrays"),
                    errdetail("Arrays with differing element dimensions are "
                              "not compatible for concatenation.")));

            dims[i] = dims1[i];
            lbs[i] = lbs1[i];
        }
    }
    else if (ndims1 == ndims2 - 1)
    {
        /*
         * resulting array has the second argument as the outer array, with
         * the first argument inserted at the front of the outer dimension
         */
        ndims = ndims2;
        dims = (int *) palloc(ndims * sizeof(int));
        lbs = (int *) palloc(ndims * sizeof(int));
        memcpy(dims, dims2, ndims * sizeof(int));
        memcpy(lbs, lbs2, ndims * sizeof(int));

        /* increment number of elements in outer array */
        dims[0] += 1;

        /* make sure the added element matches our existing elements */
        for (i = 0; i < ndims1; i++)
        {
            if (dims1[i] != dims[i + 1] || lbs1[i] != lbs[i + 1])
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                         errmsg("cannot concatenate incompatible arrays"),
                         errdetail("Arrays with differing dimensions are not "
                                   "compatible for concatenation.")));
        }
    }
    else
    {
        /*
         * (ndims1 == ndims2 + 1)
         *
         * resulting array has the first argument as the outer array, with the
         * second argument appended to the end of the outer dimension
         */
        ndims = ndims1;
        dims = (int *) palloc(ndims * sizeof(int));
        lbs = (int *) palloc(ndims * sizeof(int));
        memcpy(dims, dims1, ndims * sizeof(int));
        memcpy(lbs, lbs1, ndims * sizeof(int));

        /* increment number of elements in outer array */
        dims[0] += 1;

        /* make sure the added element matches our existing elements */
        for (i = 0; i < ndims2; i++)
        {
            if (dims2[i] != dims[i + 1] || lbs2[i] != lbs[i + 1])
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                         errmsg("cannot concatenate incompatible arrays"),
                         errdetail("Arrays with differing dimensions are not "
                                   "compatible for concatenation.")));
        }
    }

    /* Do this mainly for overflow checking */
    nitems = ArrayGetNItems(ndims, dims);

    /* build the result array */
    ndatabytes = ndatabytes1 + ndatabytes2;
    if (ARR_HASNULL(v1) || ARR_HASNULL(v2))
    {
        dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
        nbytes = ndatabytes + dataoffset;
    }
    else
    {
        dataoffset = 0;         /* marker for no null bitmap */
        nbytes = ndatabytes + ARR_OVERHEAD_NONULLS(ndims);
    }
    result = (ArrayType *) palloc0(nbytes);
    SET_VARSIZE(result, nbytes);
    result->ndim = ndims;
    result->dataoffset = dataoffset;
    result->elemtype = element_type;
    memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
    memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
    /* data area is arg1 then arg2 */
    memcpy(ARR_DATA_PTR(result), dat1, ndatabytes1);
    memcpy(ARR_DATA_PTR(result) + ndatabytes1, dat2, ndatabytes2);
    /* handle the null bitmap if needed */
    if (ARR_HASNULL(result))
    {
        array_bitmap_copy(ARR_NULLBITMAP(result), 0,
                          bitmap1, 0,
                          nitems1);
        array_bitmap_copy(ARR_NULLBITMAP(result), nitems1,
                          bitmap2, 0,
                          nitems2);
    }

    PG_RETURN_ARRAYTYPE_P(result);
}

bool array_contains_nulls ( ArrayType array  ) 

Definition at line 3084 of file arrayfuncs.c.

References ARR_DIMS, ARR_HASNULL, ARR_NDIM, ARR_NULLBITMAP, and ArrayGetNItems().

Referenced by _arrq_cons(), _lca(), _lt_q_regex(), _ltree_compress(), array_fill_internal(), array_iterator(), ArrayGetIntegerTypmods(), arrq_cons(), cube_a_f8(), cube_a_f8_f8(), cube_subset(), get_path_all(), getWeights(), and lt_q_regex().

{
    int         nelems;
    bits8      *bitmap;
    int         bitmask;

    /* Easy answer if there's no null bitmap */
    if (!ARR_HASNULL(array))
        return false;

    nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));

    bitmap = ARR_NULLBITMAP(array);

    /* check whole bytes of the bitmap byte-at-a-time */
    while (nelems >= 8)
    {
        if (*bitmap != 0xFF)
            return true;
        bitmap++;
        nelems -= 8;
    }

    /* check last partial byte */
    bitmask = 1;
    while (nelems > 0)
    {
        if ((*bitmap & bitmask) == 0)
            return true;
        bitmask <<= 1;
        nelems--;
    }

    return false;
}

ArrayIterator array_create_iterator ( ArrayType arr,
int  slice_ndim 
)

Definition at line 3893 of file arrayfuncs.c.

References ArrayIteratorData::arr, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), Assert, ArrayIteratorData::current_item, ArrayIteratorData::data_ptr, elog, ERROR, get_typlenbyvalalign(), ArrayIteratorData::nitems, ArrayIteratorData::nullbitmap, palloc(), palloc0(), PointerIsValid, ArrayIteratorData::slice_dims, ArrayIteratorData::slice_lbound, ArrayIteratorData::slice_len, ArrayIteratorData::slice_ndim, ArrayIteratorData::slice_nulls, ArrayIteratorData::slice_values, ArrayIteratorData::typalign, ArrayIteratorData::typbyval, and ArrayIteratorData::typlen.

Referenced by exec_stmt_foreach_a().

{
    ArrayIterator iterator = palloc0(sizeof(ArrayIteratorData));

    /*
     * Sanity-check inputs --- caller should have got this right already
     */
    Assert(PointerIsValid(arr));
    if (slice_ndim < 0 || slice_ndim > ARR_NDIM(arr))
        elog(ERROR, "invalid arguments to array_create_iterator");

    /*
     * Remember basic info about the array and its element type
     */
    iterator->arr = arr;
    iterator->nullbitmap = ARR_NULLBITMAP(arr);
    iterator->nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
    get_typlenbyvalalign(ARR_ELEMTYPE(arr),
                         &iterator->typlen,
                         &iterator->typbyval,
                         &iterator->typalign);

    /*
     * Remember the slicing parameters.
     */
    iterator->slice_ndim = slice_ndim;

    if (slice_ndim > 0)
    {
        /*
         * Get pointers into the array's dims and lbound arrays to represent
         * the dims/lbound arrays of a slice.  These are the same as the
         * rightmost N dimensions of the array.
         */
        iterator->slice_dims = ARR_DIMS(arr) + ARR_NDIM(arr) - slice_ndim;
        iterator->slice_lbound = ARR_LBOUND(arr) + ARR_NDIM(arr) - slice_ndim;

        /*
         * Compute number of elements in a slice.
         */
        iterator->slice_len = ArrayGetNItems(slice_ndim,
                                             iterator->slice_dims);

        /*
         * Create workspace for building sub-arrays.
         */
        iterator->slice_values = (Datum *)
            palloc(iterator->slice_len * sizeof(Datum));
        iterator->slice_nulls = (bool *)
            palloc(iterator->slice_len * sizeof(bool));
    }

    /*
     * Initialize our data pointer and linear element number.  These will
     * advance through the array during array_iterate().
     */
    iterator->data_ptr = ARR_DATA_PTR(arr);
    iterator->current_item = 0;

    return iterator;
}

Datum array_dims ( PG_FUNCTION_ARGS   ) 

Definition at line 1625 of file arrayfuncs.c.

References ARR_DIMS, ARR_LBOUND, ARR_NDIM, buf, cstring_to_text(), i, MAXDIM, PG_GETARG_ARRAYTYPE_P, PG_RETURN_NULL, and PG_RETURN_TEXT_P.

{
    ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
    char       *p;
    int         i;
    int        *dimv,
               *lb;

    /*
     * 33 since we assume 15 digits per number + ':' +'[]'
     *
     * +1 for trailing null
     */
    char        buf[MAXDIM * 33 + 1];

    /* Sanity check: does it look like an array at all? */
    if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
        PG_RETURN_NULL();

    dimv = ARR_DIMS(v);
    lb = ARR_LBOUND(v);

    p = buf;
    for (i = 0; i < ARR_NDIM(v); i++)
    {
        sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
        p += strlen(p);
    }

    PG_RETURN_TEXT_P(cstring_to_text(buf));
}

Datum array_eq ( PG_FUNCTION_ARGS   ) 

Definition at line 3131 of file arrayfuncs.c.

References FunctionCallInfoData::arg, FunctionCallInfoData::argnull, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), att_addlength_pointer, att_align_nominal, DatumGetBool, TypeCacheEntry::eq_opr_finfo, ereport, errcode(), errmsg(), ERROR, fetch_att, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, i, InitFunctionCallInfoData, FunctionCallInfoData::isnull, lookup_type_cache(), memcmp(), NULL, OidIsValid, PG_FREE_IF_COPY, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_RETURN_BOOL, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_EQ_OPR_FINFO, and TypeCacheEntry::typlen.

Referenced by array_ne().

{
    ArrayType  *array1 = PG_GETARG_ARRAYTYPE_P(0);
    ArrayType  *array2 = PG_GETARG_ARRAYTYPE_P(1);
    Oid         collation = PG_GET_COLLATION();
    int         ndims1 = ARR_NDIM(array1);
    int         ndims2 = ARR_NDIM(array2);
    int        *dims1 = ARR_DIMS(array1);
    int        *dims2 = ARR_DIMS(array2);
    Oid         element_type = ARR_ELEMTYPE(array1);
    bool        result = true;
    int         nitems;
    TypeCacheEntry *typentry;
    int         typlen;
    bool        typbyval;
    char        typalign;
    char       *ptr1;
    char       *ptr2;
    bits8      *bitmap1;
    bits8      *bitmap2;
    int         bitmask;
    int         i;
    FunctionCallInfoData locfcinfo;

    if (element_type != ARR_ELEMTYPE(array2))
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("cannot compare arrays of different element types")));

    /* fast path if the arrays do not have the same dimensionality */
    if (ndims1 != ndims2 ||
        memcmp(dims1, dims2, 2 * ndims1 * sizeof(int)) != 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.  The
         * typcache is used so that we have no memory leakage when being used
         * as an index support function.
         */
        typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
        if (typentry == NULL ||
            typentry->type_id != 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 = typentry->typlen;
        typbyval = typentry->typbyval;
        typalign = typentry->typalign;

        /*
         * apply the operator to each pair of array elements.
         */
        InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
                                 collation, NULL, NULL);

        /* Loop over source data */
        nitems = ArrayGetNItems(ndims1, dims1);
        ptr1 = ARR_DATA_PTR(array1);
        ptr2 = ARR_DATA_PTR(array2);
        bitmap1 = ARR_NULLBITMAP(array1);
        bitmap2 = ARR_NULLBITMAP(array2);
        bitmask = 1;            /* use same bitmask for both arrays */

        for (i = 0; i < nitems; i++)
        {
            Datum       elt1;
            Datum       elt2;
            bool        isnull1;
            bool        isnull2;
            bool        oprresult;

            /* Get elements, checking for NULL */
            if (bitmap1 && (*bitmap1 & bitmask) == 0)
            {
                isnull1 = true;
                elt1 = (Datum) 0;
            }
            else
            {
                isnull1 = false;
                elt1 = fetch_att(ptr1, typbyval, typlen);
                ptr1 = att_addlength_pointer(ptr1, typlen, ptr1);
                ptr1 = (char *) att_align_nominal(ptr1, typalign);
            }

            if (bitmap2 && (*bitmap2 & bitmask) == 0)
            {
                isnull2 = true;
                elt2 = (Datum) 0;
            }
            else
            {
                isnull2 = false;
                elt2 = fetch_att(ptr2, typbyval, typlen);
                ptr2 = att_addlength_pointer(ptr2, typlen, ptr2);
                ptr2 = (char *) att_align_nominal(ptr2, typalign);
            }

            /* advance bitmap pointers if any */
            bitmask <<= 1;
            if (bitmask == 0x100)
            {
                if (bitmap1)
                    bitmap1++;
                if (bitmap2)
                    bitmap2++;
                bitmask = 1;
            }

            /*
             * We consider two NULLs equal; NULL and not-NULL are unequal.
             */
            if (isnull1 && isnull2)
                continue;
            if (isnull1 || isnull2)
            {
                result = false;
                break;
            }

            /*
             * 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);
    PG_FREE_IF_COPY(array2, 1);

    PG_RETURN_BOOL(result);
}

Datum array_fill ( PG_FUNCTION_ARGS   ) 

Definition at line 4848 of file arrayfuncs.c.

References array_fill_internal(), elog, ereport, errcode(), errmsg(), ERROR, get_fn_expr_argtype(), NULL, OidIsValid, PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, and value.

{
    ArrayType  *dims;
    ArrayType  *result;
    Oid         elmtype;
    Datum       value;
    bool        isnull;

    if (PG_ARGISNULL(1))
        ereport(ERROR,
                (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
               errmsg("dimension array or low bound array cannot be null")));

    dims = PG_GETARG_ARRAYTYPE_P(1);

    if (!PG_ARGISNULL(0))
    {
        value = PG_GETARG_DATUM(0);
        isnull = false;
    }
    else
    {
        value = 0;
        isnull = true;
    }

    elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
    if (!OidIsValid(elmtype))
        elog(ERROR, "could not determine data type of input");

    result = array_fill_internal(dims, NULL, value, isnull, elmtype, fcinfo);
    PG_RETURN_ARRAYTYPE_P(result);
}

Datum array_fill_with_lower_bounds ( PG_FUNCTION_ARGS   ) 

Definition at line 4807 of file arrayfuncs.c.

References array_fill_internal(), elog, ereport, errcode(), errmsg(), ERROR, get_fn_expr_argtype(), OidIsValid, PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, and value.

{
    ArrayType  *dims;
    ArrayType  *lbs;
    ArrayType  *result;
    Oid         elmtype;
    Datum       value;
    bool        isnull;

    if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
        ereport(ERROR,
                (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
               errmsg("dimension array or low bound array cannot be null")));

    dims = PG_GETARG_ARRAYTYPE_P(1);
    lbs = PG_GETARG_ARRAYTYPE_P(2);

    if (!PG_ARGISNULL(0))
    {
        value = PG_GETARG_DATUM(0);
        isnull = false;
    }
    else
    {
        value = 0;
        isnull = true;
    }

    elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
    if (!OidIsValid(elmtype))
        elog(ERROR, "could not determine data type of input");

    result = array_fill_internal(dims, lbs, value, isnull, elmtype, fcinfo);
    PG_RETURN_ARRAYTYPE_P(result);
}

void array_free_iterator ( ArrayIterator  iterator  ) 

Definition at line 4045 of file arrayfuncs.c.

References pfree(), ArrayIteratorData::slice_ndim, ArrayIteratorData::slice_nulls, and ArrayIteratorData::slice_values.

Referenced by exec_stmt_foreach_a().

{
    if (iterator->slice_ndim > 0)
    {
        pfree(iterator->slice_values);
        pfree(iterator->slice_nulls);
    }
    pfree(iterator);
}

Datum array_ge ( PG_FUNCTION_ARGS   ) 

Definition at line 3319 of file arrayfuncs.c.

References array_cmp(), and PG_RETURN_BOOL.

{
    PG_RETURN_BOOL(array_cmp(fcinfo) >= 0);
}

ArrayType* array_get_slice ( ArrayType array,
int  nSubscripts,
int *  upperIndx,
int *  lowerIndx,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 1874 of file arrayfuncs.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_extract_slice(), array_slice_size(), ArrayGetNItems(), construct_empty_array(), ArrayType::dataoffset, DatumGetArrayTypeP, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, MAXDIM, mda_get_range(), ArrayType::ndim, palloc0(), PointerGetDatum, and SET_VARSIZE.

Referenced by ExecEvalArrayRef().

{
    ArrayType  *newarray;
    int         i,
                ndim,
               *dim,
               *lb,
               *newlb;
    int         fixedDim[1],
                fixedLb[1];
    Oid         elemtype;
    char       *arraydataptr;
    bits8      *arraynullsptr;
    int32       dataoffset;
    int         bytes,
                span[MAXDIM];

    if (arraytyplen > 0)
    {
        /*
         * fixed-length arrays -- currently, cannot slice these because parser
         * labels output as being of the fixed-length array type! Code below
         * shows how we could support it if the parser were changed to label
         * output as a suitable varlena array type.
         */
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("slices of fixed-length arrays not implemented")));

        /*
         * fixed-length arrays -- these are assumed to be 1-d, 0-based
         *
         * XXX where would we get the correct ELEMTYPE from?
         */
        ndim = 1;
        fixedDim[0] = arraytyplen / elmlen;
        fixedLb[0] = 0;
        dim = fixedDim;
        lb = fixedLb;
        elemtype = InvalidOid;  /* XXX */
        arraydataptr = (char *) array;
        arraynullsptr = NULL;
    }
    else
    {
        /* detoast input array if necessary */
        array = DatumGetArrayTypeP(PointerGetDatum(array));

        ndim = ARR_NDIM(array);
        dim = ARR_DIMS(array);
        lb = ARR_LBOUND(array);
        elemtype = ARR_ELEMTYPE(array);
        arraydataptr = ARR_DATA_PTR(array);
        arraynullsptr = ARR_NULLBITMAP(array);
    }

    /*
     * Check provided subscripts.  A slice exceeding the current array limits
     * is silently truncated to the array limits.  If we end up with an empty
     * slice, return an empty array.
     */
    if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
        return construct_empty_array(elemtype);

    for (i = 0; i < nSubscripts; i++)
    {
        if (lowerIndx[i] < lb[i])
            lowerIndx[i] = lb[i];
        if (upperIndx[i] >= (dim[i] + lb[i]))
            upperIndx[i] = dim[i] + lb[i] - 1;
        if (lowerIndx[i] > upperIndx[i])
            return construct_empty_array(elemtype);
    }
    /* fill any missing subscript positions with full array range */
    for (; i < ndim; i++)
    {
        lowerIndx[i] = lb[i];
        upperIndx[i] = dim[i] + lb[i] - 1;
        if (lowerIndx[i] > upperIndx[i])
            return construct_empty_array(elemtype);
    }

    mda_get_range(ndim, span, lowerIndx, upperIndx);

    bytes = array_slice_size(arraydataptr, arraynullsptr,
                             ndim, dim, lb,
                             lowerIndx, upperIndx,
                             elmlen, elmbyval, elmalign);

    /*
     * Currently, we put a null bitmap in the result if the source has one;
     * could be smarter ...
     */
    if (arraynullsptr)
    {
        dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, ArrayGetNItems(ndim, span));
        bytes += dataoffset;
    }
    else
    {
        dataoffset = 0;         /* marker for no null bitmap */
        bytes += ARR_OVERHEAD_NONULLS(ndim);
    }

    newarray = (ArrayType *) palloc0(bytes);
    SET_VARSIZE(newarray, bytes);
    newarray->ndim = ndim;
    newarray->dataoffset = dataoffset;
    newarray->elemtype = elemtype;
    memcpy(ARR_DIMS(newarray), span, ndim * sizeof(int));

    /*
     * Lower bounds of the new array are set to 1.  Formerly (before 7.3) we
     * copied the given lowerIndx values ... but that seems confusing.
     */
    newlb = ARR_LBOUND(newarray);
    for (i = 0; i < ndim; i++)
        newlb[i] = 1;

    array_extract_slice(newarray,
                        ndim, dim, lb,
                        arraydataptr, arraynullsptr,
                        lowerIndx, upperIndx,
                        elmlen, elmbyval, elmalign);

    return newarray;
}

Datum array_gt ( PG_FUNCTION_ARGS   ) 

Definition at line 3307 of file arrayfuncs.c.

References array_cmp(), and PG_RETURN_BOOL.

{
    PG_RETURN_BOOL(array_cmp(fcinfo) > 0);
}

Datum array_in ( PG_FUNCTION_ARGS   ) 

Definition at line 144 of file arrayfuncs.c.

References ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, array_isspace(), ArrayCount(), ArrayGetNItems(), ASSGN, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayMetaState::element_type, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_type_io_data(), i, IOFunc_input, MAXDIM, MemoryContextAlloc(), ArrayType::ndim, NULL, palloc(), palloc0(), pfree(), PG_GETARG_CSTRING, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_ARRAYTYPE_P, ArrayMetaState::proc, pstrdup(), ReadArrayStr(), SET_VARSIZE, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, and ArrayMetaState::typlen.

{
    char       *string = PG_GETARG_CSTRING(0);  /* external form */
    Oid         element_type = PG_GETARG_OID(1);        /* type of an array
                                                         * element */
    int32       typmod = PG_GETARG_INT32(2);    /* typmod for array elements */
    int         typlen;
    bool        typbyval;
    char        typalign;
    char        typdelim;
    Oid         typioparam;
    char       *string_save,
               *p;
    int         i,
                nitems;
    Datum      *dataPtr;
    bool       *nullsPtr;
    bool        hasnulls;
    int32       nbytes;
    int32       dataoffset;
    ArrayType  *retval;
    int         ndim,
                dim[MAXDIM],
                lBound[MAXDIM];
    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 = ~element_type;
    }

    if (my_extra->element_type != element_type)
    {
        /*
         * Get info about element type, including its input conversion proc
         */
        get_type_io_data(element_type, IOFunc_input,
                         &my_extra->typlen, &my_extra->typbyval,
                         &my_extra->typalign, &my_extra->typdelim,
                         &my_extra->typioparam, &my_extra->typiofunc);
        fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
                      fcinfo->flinfo->fn_mcxt);
        my_extra->element_type = element_type;
    }
    typlen = my_extra->typlen;
    typbyval = my_extra->typbyval;
    typalign = my_extra->typalign;
    typdelim = my_extra->typdelim;
    typioparam = my_extra->typioparam;

    /* Make a modifiable copy of the input */
    string_save = pstrdup(string);

    /*
     * If the input string starts with dimension info, read and use that.
     * Otherwise, we require the input to be in curly-brace style, and we
     * prescan the input to determine dimensions.
     *
     * Dimension info takes the form of one or more [n] or [m:n] items. The
     * outer loop iterates once per dimension item.
     */
    p = string_save;
    ndim = 0;
    for (;;)
    {
        char       *q;
        int         ub;

        /*
         * Note: we currently allow whitespace between, but not within,
         * dimension items.
         */
        while (array_isspace(*p))
            p++;
        if (*p != '[')
            break;              /* no more dimension items */
        p++;
        if (ndim >= MAXDIM)
            ereport(ERROR,
                    (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                     errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
                            ndim + 1, MAXDIM)));

        for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);
        if (q == p)             /* no digits? */
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                     errmsg("missing dimension value")));

        if (*q == ':')
        {
            /* [m:n] format */
            *q = '\0';
            lBound[ndim] = atoi(p);
            p = q + 1;
            for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++);
            if (q == p)         /* no digits? */
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                         errmsg("missing dimension value")));
        }
        else
        {
            /* [n] format */
            lBound[ndim] = 1;
        }
        if (*q != ']')
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                     errmsg("missing \"]\" in array dimensions")));

        *q = '\0';
        ub = atoi(p);
        p = q + 1;
        if (ub < lBound[ndim])
            ereport(ERROR,
                    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("upper bound cannot be less than lower bound")));

        dim[ndim] = ub - lBound[ndim] + 1;
        ndim++;
    }

    if (ndim == 0)
    {
        /* No array dimensions, so intuit dimensions from brace structure */
        if (*p != '{')
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                     errmsg("array value must start with \"{\" or dimension information")));
        ndim = ArrayCount(p, dim, typdelim);
        for (i = 0; i < ndim; i++)
            lBound[i] = 1;
    }
    else
    {
        int         ndim_braces,
                    dim_braces[MAXDIM];

        /* If array dimensions are given, expect '=' operator */
        if (strncmp(p, ASSGN, strlen(ASSGN)) != 0)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                     errmsg("missing assignment operator")));
        p += strlen(ASSGN);
        while (array_isspace(*p))
            p++;

        /*
         * intuit dimensions from brace structure -- it better match what we
         * were given
         */
        if (*p != '{')
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                     errmsg("array value must start with \"{\" or dimension information")));
        ndim_braces = ArrayCount(p, dim_braces, typdelim);
        if (ndim_braces != ndim)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                errmsg("array dimensions incompatible with array literal")));
        for (i = 0; i < ndim; ++i)
        {
            if (dim[i] != dim_braces[i])
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                errmsg("array dimensions incompatible with array literal")));
        }
    }

#ifdef ARRAYDEBUG
    printf("array_in- ndim %d (", ndim);
    for (i = 0; i < ndim; i++)
    {
        printf(" %d", dim[i]);
    };
    printf(") for %s\n", string);
#endif

    /* This checks for overflow of the array dimensions */
    nitems = ArrayGetNItems(ndim, dim);
    /* Empty array? */
    if (nitems == 0)
        PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));

    dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
    nullsPtr = (bool *) palloc(nitems * sizeof(bool));
    ReadArrayStr(p, string,
                 nitems, ndim, dim,
                 &my_extra->proc, typioparam, typmod,
                 typdelim,
                 typlen, typbyval, typalign,
                 dataPtr, nullsPtr,
                 &hasnulls, &nbytes);
    if (hasnulls)
    {
        dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
        nbytes += dataoffset;
    }
    else
    {
        dataoffset = 0;         /* marker for no null bitmap */
        nbytes += ARR_OVERHEAD_NONULLS(ndim);
    }
    retval = (ArrayType *) palloc0(nbytes);
    SET_VARSIZE(retval, nbytes);
    retval->ndim = ndim;
    retval->dataoffset = dataoffset;

    /*
     * This comes from the array's pg_type.typelem (which points to the base
     * data type's pg_type.oid) and stores system oids in user tables. This
     * oid must be preserved by binary upgrades.
     */
    retval->elemtype = element_type;
    memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
    memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));

    CopyArrayEls(retval,
                 dataPtr, nullsPtr, nitems,
                 typlen, typbyval, typalign,
                 true);

    pfree(dataPtr);
    pfree(nullsPtr);
    pfree(string_save);

    PG_RETURN_ARRAYTYPE_P(retval);
}

bool array_iterate ( ArrayIterator  iterator,
Datum value,
bool isnull 
)

Definition at line 3962 of file arrayfuncs.c.

References ArrayIteratorData::arr, ARR_ELEMTYPE, array_get_isnull(), att_addlength_pointer, att_align_nominal, construct_md_array(), ArrayIteratorData::current_item, ArrayIteratorData::data_ptr, fetch_att, i, ArrayIteratorData::nitems, ArrayIteratorData::nullbitmap, PointerGetDatum, ArrayIteratorData::slice_dims, ArrayIteratorData::slice_lbound, ArrayIteratorData::slice_len, ArrayIteratorData::slice_ndim, ArrayIteratorData::slice_nulls, ArrayIteratorData::slice_values, ArrayIteratorData::typalign, ArrayIteratorData::typbyval, ArrayIteratorData::typlen, and values.

Referenced by exec_stmt_foreach_a().

{
    /* Done if we have reached the end of the array */
    if (iterator->current_item >= iterator->nitems)
        return false;

    if (iterator->slice_ndim == 0)
    {
        /*
         * Scalar case: return one element.
         */
        if (array_get_isnull(iterator->nullbitmap, iterator->current_item++))
        {
            *isnull = true;
            *value = (Datum) 0;
        }
        else
        {
            /* non-NULL, so fetch the individual Datum to return */
            char       *p = iterator->data_ptr;

            *isnull = false;
            *value = fetch_att(p, iterator->typbyval, iterator->typlen);

            /* Move our data pointer forward to the next element */
            p = att_addlength_pointer(p, iterator->typlen, p);
            p = (char *) att_align_nominal(p, iterator->typalign);
            iterator->data_ptr = p;
        }
    }
    else
    {
        /*
         * Slice case: build and return an array of the requested size.
         */
        ArrayType  *result;
        Datum      *values = iterator->slice_values;
        bool       *nulls = iterator->slice_nulls;
        char       *p = iterator->data_ptr;
        int         i;

        for (i = 0; i < iterator->slice_len; i++)
        {
            if (array_get_isnull(iterator->nullbitmap,
                                 iterator->current_item++))
            {
                nulls[i] = true;
                values[i] = (Datum) 0;
            }
            else
            {
                nulls[i] = false;
                values[i] = fetch_att(p, iterator->typbyval, iterator->typlen);

                /* Move our data pointer forward to the next element */
                p = att_addlength_pointer(p, iterator->typlen, p);
                p = (char *) att_align_nominal(p, iterator->typalign);
            }
        }

        iterator->data_ptr = p;

        result = construct_md_array(values,
                                    nulls,
                                    iterator->slice_ndim,
                                    iterator->slice_dims,
                                    iterator->slice_lbound,
                                    ARR_ELEMTYPE(iterator->arr),
                                    iterator->typlen,
                                    iterator->typbyval,
                                    iterator->typalign);

        *isnull = false;
        *value = PointerGetDatum(result);
    }

    return true;
}

Datum array_larger ( PG_FUNCTION_ARGS   ) 

Definition at line 4690 of file arrayfuncs.c.

References array_cmp(), PG_GETARG_ARRAYTYPE_P, and PG_RETURN_ARRAYTYPE_P.

{
    ArrayType  *v1,
               *v2,
               *result;

    v1 = PG_GETARG_ARRAYTYPE_P(0);
    v2 = PG_GETARG_ARRAYTYPE_P(1);

    result = ((array_cmp(fcinfo) > 0) ? v1 : v2);

    PG_RETURN_ARRAYTYPE_P(result);
}

Datum array_le ( PG_FUNCTION_ARGS   ) 

Definition at line 3313 of file arrayfuncs.c.

References array_cmp(), and PG_RETURN_BOOL.

{
    PG_RETURN_BOOL(array_cmp(fcinfo) <= 0);
}

Datum array_length ( PG_FUNCTION_ARGS   ) 

Definition at line 1720 of file arrayfuncs.c.

References ARR_DIMS, ARR_NDIM, MAXDIM, PG_GETARG_ARRAYTYPE_P, PG_GETARG_INT32, PG_RETURN_INT32, and PG_RETURN_NULL.

{
    ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
    int         reqdim = PG_GETARG_INT32(1);
    int        *dimv;
    int         result;

    /* Sanity check: does it look like an array at all? */
    if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
        PG_RETURN_NULL();

    /* Sanity check: was the requested dim valid */
    if (reqdim <= 0 || reqdim > ARR_NDIM(v))
        PG_RETURN_NULL();

    dimv = ARR_DIMS(v);

    result = dimv[reqdim - 1];

    PG_RETURN_INT32(result);
}

Datum array_lower ( PG_FUNCTION_ARGS   ) 

Definition at line 1663 of file arrayfuncs.c.

References ARR_LBOUND, ARR_NDIM, MAXDIM, PG_GETARG_ARRAYTYPE_P, PG_GETARG_INT32, PG_RETURN_INT32, and PG_RETURN_NULL.

{
    ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
    int         reqdim = PG_GETARG_INT32(1);
    int        *lb;
    int         result;

    /* Sanity check: does it look like an array at all? */
    if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
        PG_RETURN_NULL();

    /* Sanity check: was the requested dim valid */
    if (reqdim <= 0 || reqdim > ARR_NDIM(v))
        PG_RETURN_NULL();

    lb = ARR_LBOUND(v);
    result = lb[reqdim - 1];

    PG_RETURN_INT32(result);
}

Datum array_lt ( PG_FUNCTION_ARGS   ) 

Definition at line 3301 of file arrayfuncs.c.

References array_cmp(), and PG_RETURN_BOOL.

{
    PG_RETURN_BOOL(array_cmp(fcinfo) < 0);
}

Datum array_map ( FunctionCallInfo  fcinfo,
Oid  inpType,
Oid  retType,
ArrayMapState amstate 
)

Definition at line 2653 of file arrayfuncs.c.

References AllocSizeIsValid, FunctionCallInfoData::arg, FunctionCallInfoData::argnull, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayGetNItems(), Assert, att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayMetaState::element_type, ArrayType::elemtype, elog, ereport, errcode(), errmsg(), ERROR, fetch_att, FunctionCallInfoData::flinfo, FmgrInfo::fn_strict, FunctionCallInvoke, get_typlenbyvalalign(), i, ArrayMapState::inp_extra, FunctionCallInfoData::isnull, MaxAllocSize, FunctionCallInfoData::nargs, ArrayType::ndim, palloc(), palloc0(), pfree(), PG_ARGISNULL, PG_DETOAST_DATUM, PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, PointerGetDatum, ArrayMapState::ret_extra, SET_VARSIZE, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typlen, and values.

Referenced by ExecEvalArrayCoerceExpr().

{
    ArrayType  *v;
    ArrayType  *result;
    Datum      *values;
    bool       *nulls;
    Datum       elt;
    int        *dim;
    int         ndim;
    int         nitems;
    int         i;
    int32       nbytes = 0;
    int32       dataoffset;
    bool        hasnulls;
    int         inp_typlen;
    bool        inp_typbyval;
    char        inp_typalign;
    int         typlen;
    bool        typbyval;
    char        typalign;
    char       *s;
    bits8      *bitmap;
    int         bitmask;
    ArrayMetaState *inp_extra;
    ArrayMetaState *ret_extra;

    /* Get input array */
    if (fcinfo->nargs < 1)
        elog(ERROR, "invalid nargs: %d", fcinfo->nargs);
    if (PG_ARGISNULL(0))
        elog(ERROR, "null input array");
    v = PG_GETARG_ARRAYTYPE_P(0);

    Assert(ARR_ELEMTYPE(v) == inpType);

    ndim = ARR_NDIM(v);
    dim = ARR_DIMS(v);
    nitems = ArrayGetNItems(ndim, dim);

    /* Check for empty array */
    if (nitems <= 0)
    {
        /* Return empty array */
        PG_RETURN_ARRAYTYPE_P(construct_empty_array(retType));
    }

    /*
     * 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.
     */
    inp_extra = &amstate->inp_extra;
    ret_extra = &amstate->ret_extra;

    if (inp_extra->element_type != inpType)
    {
        get_typlenbyvalalign(inpType,
                             &inp_extra->typlen,
                             &inp_extra->typbyval,
                             &inp_extra->typalign);
        inp_extra->element_type = inpType;
    }
    inp_typlen = inp_extra->typlen;
    inp_typbyval = inp_extra->typbyval;
    inp_typalign = inp_extra->typalign;

    if (ret_extra->element_type != retType)
    {
        get_typlenbyvalalign(retType,
                             &ret_extra->typlen,
                             &ret_extra->typbyval,
                             &ret_extra->typalign);
        ret_extra->element_type = retType;
    }
    typlen = ret_extra->typlen;
    typbyval = ret_extra->typbyval;
    typalign = ret_extra->typalign;

    /* Allocate temporary arrays for new values */
    values = (Datum *) palloc(nitems * sizeof(Datum));
    nulls = (bool *) palloc(nitems * sizeof(bool));

    /* Loop over source data */
    s = ARR_DATA_PTR(v);
    bitmap = ARR_NULLBITMAP(v);
    bitmask = 1;
    hasnulls = false;

    for (i = 0; i < nitems; i++)
    {
        bool        callit = true;

        /* Get source element, checking for NULL */
        if (bitmap && (*bitmap & bitmask) == 0)
        {
            fcinfo->argnull[0] = true;
        }
        else
        {
            elt = fetch_att(s, inp_typbyval, inp_typlen);
            s = att_addlength_datum(s, inp_typlen, elt);
            s = (char *) att_align_nominal(s, inp_typalign);
            fcinfo->arg[0] = elt;
            fcinfo->argnull[0] = false;
        }

        /*
         * Apply the given function to source elt and extra args.
         */
        if (fcinfo->flinfo->fn_strict)
        {
            int         j;

            for (j = 0; j < fcinfo->nargs; j++)
            {
                if (fcinfo->argnull[j])
                {
                    callit = false;
                    break;
                }
            }
        }

        if (callit)
        {
            fcinfo->isnull = false;
            values[i] = FunctionCallInvoke(fcinfo);
        }
        else
            fcinfo->isnull = true;

        nulls[i] = fcinfo->isnull;
        if (fcinfo->isnull)
            hasnulls = true;
        else
        {
            /* Ensure data is not toasted */
            if (typlen == -1)
                values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
            /* Update total result size */
            nbytes = att_addlength_datum(nbytes, typlen, values[i]);
            nbytes = att_align_nominal(nbytes, typalign);
            /* check for overflow of total request */
            if (!AllocSizeIsValid(nbytes))
                ereport(ERROR,
                        (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                         errmsg("array size exceeds the maximum allowed (%d)",
                                (int) MaxAllocSize)));
        }

        /* advance bitmap pointer if any */
        if (bitmap)
        {
            bitmask <<= 1;
            if (bitmask == 0x100)
            {
                bitmap++;
                bitmask = 1;
            }
        }
    }

    /* Allocate and initialize the result array */
    if (hasnulls)
    {
        dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
        nbytes += dataoffset;
    }
    else
    {
        dataoffset = 0;         /* marker for no null bitmap */
        nbytes += ARR_OVERHEAD_NONULLS(ndim);
    }
    result = (ArrayType *) palloc0(nbytes);
    SET_VARSIZE(result, nbytes);
    result->ndim = ndim;
    result->dataoffset = dataoffset;
    result->elemtype = retType;
    memcpy(ARR_DIMS(result), ARR_DIMS(v), 2 * ndim * sizeof(int));

    /*
     * Note: do not risk trying to pfree the results of the called function
     */
    CopyArrayEls(result,
                 values, nulls, nitems,
                 typlen, typbyval, typalign,
                 false);

    pfree(values);
    pfree(nulls);

    PG_RETURN_ARRAYTYPE_P(result);
}

Datum array_ndims ( PG_FUNCTION_ARGS   ) 

Definition at line 1609 of file arrayfuncs.c.

References ARR_NDIM, MAXDIM, PG_GETARG_ARRAYTYPE_P, PG_RETURN_INT32, and PG_RETURN_NULL.

{
    ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);

    /* Sanity check: does it look like an array at all? */
    if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
        PG_RETURN_NULL();

    PG_RETURN_INT32(ARR_NDIM(v));
}

Datum array_ne ( PG_FUNCTION_ARGS   ) 

Definition at line 3295 of file arrayfuncs.c.

References array_eq(), DatumGetBool, and PG_RETURN_BOOL.

Datum array_out ( PG_FUNCTION_ARGS   ) 

Definition at line 956 of file arrayfuncs.c.

References APPENDCHAR, APPENDSTR, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, array_isspace(), ArrayGetNItems(), att_addlength_pointer, att_align_nominal, ArrayMetaState::element_type, fetch_att, fmgr_info_cxt(), FmgrInfo::fn_mcxt, get_type_io_data(), i, IOFunc_output, MAXDIM, MemoryContextAlloc(), NULL, OutputFunctionCall(), palloc(), pfree(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_CSTRING, pg_strcasecmp(), ArrayMetaState::proc, pstrdup(), ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, ArrayMetaState::typlen, and values.

Referenced by anyarray_out().

{
    ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
    Oid         element_type = ARR_ELEMTYPE(v);
    int         typlen;
    bool        typbyval;
    char        typalign;
    char        typdelim;
    char       *p,
               *tmp,
               *retval,
              **values,
                dims_str[(MAXDIM * 33) + 2];

    /*
     * 33 per dim since we assume 15 digits per number + ':' +'[]'
     *
     * +2 allows for assignment operator + trailing null
     */
    bits8      *bitmap;
    int         bitmask;
    bool       *needquotes,
                needdims = false;
    int         nitems,
                overall_length,
                i,
                j,
                k,
                indx[MAXDIM];
    int         ndim,
               *dims,
               *lb;
    ArrayMetaState *my_extra;

    /*
     * 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 = ~element_type;
    }

    if (my_extra->element_type != element_type)
    {
        /*
         * Get info about element type, including its output conversion proc
         */
        get_type_io_data(element_type, IOFunc_output,
                         &my_extra->typlen, &my_extra->typbyval,
                         &my_extra->typalign, &my_extra->typdelim,
                         &my_extra->typioparam, &my_extra->typiofunc);
        fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
                      fcinfo->flinfo->fn_mcxt);
        my_extra->element_type = element_type;
    }
    typlen = my_extra->typlen;
    typbyval = my_extra->typbyval;
    typalign = my_extra->typalign;
    typdelim = my_extra->typdelim;

    ndim = ARR_NDIM(v);
    dims = ARR_DIMS(v);
    lb = ARR_LBOUND(v);
    nitems = ArrayGetNItems(ndim, dims);

    if (nitems == 0)
    {
        retval = pstrdup("{}");
        PG_RETURN_CSTRING(retval);
    }

    /*
     * we will need to add explicit dimensions if any dimension has a lower
     * bound other than one
     */
    for (i = 0; i < ndim; i++)
    {
        if (lb[i] != 1)
        {
            needdims = true;
            break;
        }
    }

    /*
     * Convert all values to string form, count total space needed (including
     * any overhead such as escaping backslashes), and detect whether each
     * item needs double quotes.
     */
    values = (char **) palloc(nitems * sizeof(char *));
    needquotes = (bool *) palloc(nitems * sizeof(bool));
    overall_length = 1;         /* don't forget to count \0 at end. */

    p = ARR_DATA_PTR(v);
    bitmap = ARR_NULLBITMAP(v);
    bitmask = 1;

    for (i = 0; i < nitems; i++)
    {
        bool        needquote;

        /* Get source element, checking for NULL */
        if (bitmap && (*bitmap & bitmask) == 0)
        {
            values[i] = pstrdup("NULL");
            overall_length += 4;
            needquote = false;
        }
        else
        {
            Datum       itemvalue;

            itemvalue = fetch_att(p, typbyval, typlen);
            values[i] = OutputFunctionCall(&my_extra->proc, itemvalue);
            p = att_addlength_pointer(p, typlen, p);
            p = (char *) att_align_nominal(p, typalign);

            /* count data plus backslashes; detect chars needing quotes */
            if (values[i][0] == '\0')
                needquote = true;       /* force quotes for empty string */
            else if (pg_strcasecmp(values[i], "NULL") == 0)
                needquote = true;       /* force quotes for literal NULL */
            else
                needquote = false;

            for (tmp = values[i]; *tmp != '\0'; tmp++)
            {
                char        ch = *tmp;

                overall_length += 1;
                if (ch == '"' || ch == '\\')
                {
                    needquote = true;
                    overall_length += 1;
                }
                else if (ch == '{' || ch == '}' || ch == typdelim ||
                         array_isspace(ch))
                    needquote = true;
            }
        }

        needquotes[i] = needquote;

        /* Count the pair of double quotes, if needed */
        if (needquote)
            overall_length += 2;
        /* and the comma */
        overall_length += 1;

        /* advance bitmap pointer if any */
        if (bitmap)
        {
            bitmask <<= 1;
            if (bitmask == 0x100)
            {
                bitmap++;
                bitmask = 1;
            }
        }
    }

    /*
     * count total number of curly braces in output string
     */
    for (i = j = 0, k = 1; i < ndim; i++)
        k *= dims[i], j += k;

    dims_str[0] = '\0';

    /* add explicit dimensions if required */
    if (needdims)
    {
        char       *ptr = dims_str;

        for (i = 0; i < ndim; i++)
        {
            sprintf(ptr, "[%d:%d]", lb[i], lb[i] + dims[i] - 1);
            ptr += strlen(ptr);
        }
        *ptr++ = *ASSGN;
        *ptr = '\0';
    }

    retval = (char *) palloc(strlen(dims_str) + overall_length + 2 * j);
    p = retval;

#define APPENDSTR(str)  (strcpy(p, (str)), p += strlen(p))
#define APPENDCHAR(ch)  (*p++ = (ch), *p = '\0')

    if (needdims)
        APPENDSTR(dims_str);
    APPENDCHAR('{');
    for (i = 0; i < ndim; i++)
        indx[i] = 0;
    j = 0;
    k = 0;
    do
    {
        for (i = j; i < ndim - 1; i++)
            APPENDCHAR('{');

        if (needquotes[k])
        {
            APPENDCHAR('"');
            for (tmp = values[k]; *tmp; tmp++)
            {
                char        ch = *tmp;

                if (ch == '"' || ch == '\\')
                    *p++ = '\\';
                *p++ = ch;
            }
            *p = '\0';
            APPENDCHAR('"');
        }
        else
            APPENDSTR(values[k]);
        pfree(values[k++]);

        for (i = ndim - 1; i >= 0; i--)
        {
            indx[i] = (indx[i] + 1) % dims[i];
            if (indx[i])
            {
                APPENDCHAR(typdelim);
                break;
            }
            else
                APPENDCHAR('}');
        }
        j = i;
    } while (j != -1);

#undef APPENDSTR
#undef APPENDCHAR

    pfree(values);
    pfree(needquotes);

    PG_RETURN_CSTRING(retval);
}

Datum array_push ( PG_FUNCTION_ARGS   ) 

Definition at line 26 of file array_userfuncs.c.

References ARR_DIMS, ARR_ELEMTYPE, ARR_LBOUND, ARR_NDIM, array_set(), construct_empty_array(), ArrayMetaState::element_type, ereport, errcode(), errmsg(), ERROR, get_element_type(), get_fn_expr_argtype(), get_typlenbyvalalign(), InvalidOid, MemoryContextAlloc(), NULL, PG_ARGISNULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, PG_RETURN_NULL, ArrayMetaState::typalign, ArrayMetaState::typbyval, and ArrayMetaState::typlen.

{
    ArrayType  *v;
    Datum       newelem;
    bool        isNull;
    int        *dimv,
               *lb;
    ArrayType  *result;
    int         indx;
    Oid         element_type;
    int16       typlen;
    bool        typbyval;
    char        typalign;
    Oid         arg0_typeid = get_fn_expr_argtype(fcinfo->flinfo, 0);
    Oid         arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1);
    Oid         arg0_elemid;
    Oid         arg1_elemid;
    ArrayMetaState *my_extra;

    if (arg0_typeid == InvalidOid || arg1_typeid == InvalidOid)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("could not determine input data types")));

    arg0_elemid = get_element_type(arg0_typeid);
    arg1_elemid = get_element_type(arg1_typeid);

    if (arg0_elemid != InvalidOid)
    {
        if (PG_ARGISNULL(0))
            v = construct_empty_array(arg0_elemid);
        else
            v = PG_GETARG_ARRAYTYPE_P(0);
        isNull = PG_ARGISNULL(1);
        if (isNull)
            newelem = (Datum) 0;
        else
            newelem = PG_GETARG_DATUM(1);
    }
    else if (arg1_elemid != InvalidOid)
    {
        if (PG_ARGISNULL(1))
            v = construct_empty_array(arg1_elemid);
        else
            v = PG_GETARG_ARRAYTYPE_P(1);
        isNull = PG_ARGISNULL(0);
        if (isNull)
            newelem = (Datum) 0;
        else
            newelem = PG_GETARG_DATUM(0);
    }
    else
    {
        /* Shouldn't get here given proper type checking in parser */
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("neither input type is an array")));
        PG_RETURN_NULL();       /* keep compiler quiet */
    }

    element_type = ARR_ELEMTYPE(v);

    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;
            /* overflow? */
            if (indx < ub)
                ereport(ERROR,
                        (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                         errmsg("integer out of range")));
        }
        else
        {
            /* prepend newelem */
            indx = lb[0] - 1;
            /* overflow? */
            if (indx > lb[0])
                ereport(ERROR,
                        (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                         errmsg("integer out of range")));
        }
    }
    else if (ARR_NDIM(v) == 0)
        indx = 1;
    else
        ereport(ERROR,
                (errcode(ERRCODE_DATA_EXCEPTION),
                 errmsg("argument must be empty or one-dimensional array")));

    /*
     * 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 = ~element_type;
    }

    if (my_extra->element_type != element_type)
    {
        /* Get info about element type */
        get_typlenbyvalalign(element_type,
                             &my_extra->typlen,
                             &my_extra->typbyval,
                             &my_extra->typalign);
        my_extra->element_type = element_type;
    }
    typlen = my_extra->typlen;
    typbyval = my_extra->typbyval;
    typalign = my_extra->typalign;

    result = array_set(v, 1, &indx, newelem, isNull,
                       -1, typlen, typbyval, typalign);

    /*
     * Readjust result's LB to match the input's.  This does nothing in the
     * append case, but it's the simplest way to implement the prepend case.
     */
    if (ARR_NDIM(v) == 1)
        ARR_LBOUND(result)[0] = ARR_LBOUND(v)[0];

    PG_RETURN_ARRAYTYPE_P(result);
}

Datum array_recv ( PG_FUNCTION_ARGS   ) 

Definition at line 1213 of file arrayfuncs.c.

References ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayGetNItems(), buf, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayMetaState::element_type, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, fmgr_info_cxt(), FmgrInfo::fn_mcxt, format_type_be(), get_type_io_data(), i, IOFunc_receive, MAXDIM, MemoryContextAlloc(), ArrayType::ndim, NULL, OidIsValid, palloc(), palloc0(), pfree(), PG_GETARG_INT32, PG_GETARG_OID, PG_GETARG_POINTER, PG_RETURN_ARRAYTYPE_P, pq_getmsgint(), ArrayMetaState::proc, ReadArrayBinary(), SET_VARSIZE, ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, and ArrayMetaState::typlen.

Referenced by int2vectorrecv(), and oidvectorrecv().

{
    StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
    Oid         spec_element_type = PG_GETARG_OID(1);   /* type of an array
                                                         * element */
    int32       typmod = PG_GETARG_INT32(2);    /* typmod for array elements */
    Oid         element_type;
    int         typlen;
    bool        typbyval;
    char        typalign;
    Oid         typioparam;
    int         i,
                nitems;
    Datum      *dataPtr;
    bool       *nullsPtr;
    bool        hasnulls;
    int32       nbytes;
    int32       dataoffset;
    ArrayType  *retval;
    int         ndim,
                flags,
                dim[MAXDIM],
                lBound[MAXDIM];
    ArrayMetaState *my_extra;

    /* Get the array header information */
    ndim = pq_getmsgint(buf, 4);
    if (ndim < 0)               /* we do allow zero-dimension arrays */
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                 errmsg("invalid number of dimensions: %d", ndim)));
    if (ndim > MAXDIM)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
                        ndim, MAXDIM)));

    flags = pq_getmsgint(buf, 4);
    if (flags != 0 && flags != 1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                 errmsg("invalid array flags")));

    element_type = pq_getmsgint(buf, sizeof(Oid));
    if (element_type != spec_element_type)
    {
        /* XXX Can we allow taking the input element type in any cases? */
        ereport(ERROR,
                (errcode(ERRCODE_DATATYPE_MISMATCH),
                 errmsg("wrong element type")));
    }

    for (i = 0; i < ndim; i++)
    {
        dim[i] = pq_getmsgint(buf, 4);
        lBound[i] = pq_getmsgint(buf, 4);

        /*
         * Check overflow of upper bound. (ArrayNItems() below checks that
         * dim[i] >= 0)
         */
        if (dim[i] != 0)
        {
            int         ub = lBound[i] + dim[i] - 1;

            if (lBound[i] > ub)
                ereport(ERROR,
                        (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
                         errmsg("integer out of range")));
        }
    }

    /* This checks for overflow of array dimensions */
    nitems = ArrayGetNItems(ndim, dim);

    /*
     * 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 = ~element_type;
    }

    if (my_extra->element_type != element_type)
    {
        /* Get info about element type, including its receive proc */
        get_type_io_data(element_type, IOFunc_receive,
                         &my_extra->typlen, &my_extra->typbyval,
                         &my_extra->typalign, &my_extra->typdelim,
                         &my_extra->typioparam, &my_extra->typiofunc);
        if (!OidIsValid(my_extra->typiofunc))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_FUNCTION),
                     errmsg("no binary input function available for type %s",
                            format_type_be(element_type))));
        fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
                      fcinfo->flinfo->fn_mcxt);
        my_extra->element_type = element_type;
    }

    if (nitems == 0)
    {
        /* Return empty array ... but not till we've validated element_type */
        PG_RETURN_ARRAYTYPE_P(construct_empty_array(element_type));
    }

    typlen = my_extra->typlen;
    typbyval = my_extra->typbyval;
    typalign = my_extra->typalign;
    typioparam = my_extra->typioparam;

    dataPtr = (Datum *) palloc(nitems * sizeof(Datum));
    nullsPtr = (bool *) palloc(nitems * sizeof(bool));
    ReadArrayBinary(buf, nitems,
                    &my_extra->proc, typioparam, typmod,
                    typlen, typbyval, typalign,
                    dataPtr, nullsPtr,
                    &hasnulls, &nbytes);
    if (hasnulls)
    {
        dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
        nbytes += dataoffset;
    }
    else
    {
        dataoffset = 0;         /* marker for no null bitmap */
        nbytes += ARR_OVERHEAD_NONULLS(ndim);
    }
    retval = (ArrayType *) palloc0(nbytes);
    SET_VARSIZE(retval, nbytes);
    retval->ndim = ndim;
    retval->dataoffset = dataoffset;
    retval->elemtype = element_type;
    memcpy(ARR_DIMS(retval), dim, ndim * sizeof(int));
    memcpy(ARR_LBOUND(retval), lBound, ndim * sizeof(int));

    CopyArrayEls(retval,
                 dataPtr, nullsPtr, nitems,
                 typlen, typbyval, typalign,
                 true);

    pfree(dataPtr);
    pfree(nullsPtr);

    PG_RETURN_ARRAYTYPE_P(retval);
}

Datum array_ref ( ArrayType array,
int  nSubscripts,
int *  indx,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign,
bool isNull 
)

Definition at line 1764 of file arrayfuncs.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, array_get_isnull(), array_seek(), ArrayCast(), ArrayGetOffset(), DatumGetArrayTypeP, i, MAXDIM, and PointerGetDatum.

Referenced by ExecEvalArrayRef(), GUCArrayAdd(), GUCArrayDelete(), GUCArrayReset(), pg_get_functiondef(), PLyList_FromArray(), and ProcessGUCArray().

{
    int         i,
                ndim,
               *dim,
               *lb,
                offset,
                fixedDim[1],
                fixedLb[1];
    char       *arraydataptr,
               *retptr;
    bits8      *arraynullsptr;

    if (arraytyplen > 0)
    {
        /*
         * fixed-length arrays -- these are assumed to be 1-d, 0-based
         */
        ndim = 1;
        fixedDim[0] = arraytyplen / elmlen;
        fixedLb[0] = 0;
        dim = fixedDim;
        lb = fixedLb;
        arraydataptr = (char *) array;
        arraynullsptr = NULL;
    }
    else
    {
        /* detoast input array if necessary */
        array = DatumGetArrayTypeP(PointerGetDatum(array));

        ndim = ARR_NDIM(array);
        dim = ARR_DIMS(array);
        lb = ARR_LBOUND(array);
        arraydataptr = ARR_DATA_PTR(array);
        arraynullsptr = ARR_NULLBITMAP(array);
    }

    /*
     * Return NULL for invalid subscript
     */
    if (ndim != nSubscripts || ndim <= 0 || ndim > MAXDIM)
    {
        *isNull = true;
        return (Datum) 0;
    }
    for (i = 0; i < ndim; i++)
    {
        if (indx[i] < lb[i] || indx[i] >= (dim[i] + lb[i]))
        {
            *isNull = true;
            return (Datum) 0;
        }
    }

    /*
     * Calculate the element number
     */
    offset = ArrayGetOffset(nSubscripts, dim, lb, indx);

    /*
     * Check for NULL array element
     */
    if (array_get_isnull(arraynullsptr, offset))
    {
        *isNull = true;
        return (Datum) 0;
    }

    /*
     * OK, get the element
     */
    *isNull = false;
    retptr = array_seek(arraydataptr, 0, arraynullsptr, offset,
                        elmlen, elmbyval, elmalign);
    return ArrayCast(retptr, elmbyval, elmlen);
}

Datum array_remove ( PG_FUNCTION_ARGS   ) 

Definition at line 5443 of file arrayfuncs.c.

References array_replace_internal(), PG_ARGISNULL, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, and PG_RETURN_NULL.

{
    ArrayType  *array;
    Datum       search = PG_GETARG_DATUM(1);
    bool        search_isnull = PG_ARGISNULL(1);

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();
    array = PG_GETARG_ARRAYTYPE_P(0);

    array = array_replace_internal(array,
                                   search, search_isnull,
                                   (Datum) 0, true,
                                   true, PG_GET_COLLATION(),
                                   fcinfo);
    PG_RETURN_ARRAYTYPE_P(array);
}

Datum array_replace ( PG_FUNCTION_ARGS   ) 

Definition at line 5465 of file arrayfuncs.c.

References array_replace_internal(), PG_ARGISNULL, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, PG_RETURN_ARRAYTYPE_P, and PG_RETURN_NULL.

{
    ArrayType  *array;
    Datum       search = PG_GETARG_DATUM(1);
    bool        search_isnull = PG_ARGISNULL(1);
    Datum       replace = PG_GETARG_DATUM(2);
    bool        replace_isnull = PG_ARGISNULL(2);

    if (PG_ARGISNULL(0))
        PG_RETURN_NULL();
    array = PG_GETARG_ARRAYTYPE_P(0);

    array = array_replace_internal(array,
                                   search, search_isnull,
                                   replace, replace_isnull,
                                   false, PG_GET_COLLATION(),
                                   fcinfo);
    PG_RETURN_ARRAYTYPE_P(array);
}

Datum array_send ( PG_FUNCTION_ARGS   ) 

Definition at line 1493 of file arrayfuncs.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), att_addlength_pointer, att_align_nominal, buf, ArrayMetaState::element_type, ereport, errcode(), errmsg(), ERROR, fetch_att, fmgr_info_cxt(), FmgrInfo::fn_mcxt, format_type_be(), get_type_io_data(), i, IOFunc_send, MemoryContextAlloc(), NULL, OidIsValid, pfree(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendbytes(), pq_sendint(), ArrayMetaState::proc, SendFunctionCall(), ArrayMetaState::typalign, ArrayMetaState::typbyval, ArrayMetaState::typdelim, ArrayMetaState::typiofunc, ArrayMetaState::typioparam, ArrayMetaState::typlen, VARDATA, VARHDRSZ, and VARSIZE.

Referenced by anyarray_send(), int2vectorsend(), and oidvectorsend().

{
    ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
    Oid         element_type = ARR_ELEMTYPE(v);
    int         typlen;
    bool        typbyval;
    char        typalign;
    char       *p;
    bits8      *bitmap;
    int         bitmask;
    int         nitems,
                i;
    int         ndim,
               *dim;
    StringInfoData buf;
    ArrayMetaState *my_extra;

    /*
     * We arrange to look up info about element type, including its send
     * 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 = ~element_type;
    }

    if (my_extra->element_type != element_type)
    {
        /* Get info about element type, including its send proc */
        get_type_io_data(element_type, IOFunc_send,
                         &my_extra->typlen, &my_extra->typbyval,
                         &my_extra->typalign, &my_extra->typdelim,
                         &my_extra->typioparam, &my_extra->typiofunc);
        if (!OidIsValid(my_extra->typiofunc))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_FUNCTION),
                     errmsg("no binary output function available for type %s",
                            format_type_be(element_type))));
        fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
                      fcinfo->flinfo->fn_mcxt);
        my_extra->element_type = element_type;
    }
    typlen = my_extra->typlen;
    typbyval = my_extra->typbyval;
    typalign = my_extra->typalign;

    ndim = ARR_NDIM(v);
    dim = ARR_DIMS(v);
    nitems = ArrayGetNItems(ndim, dim);

    pq_begintypsend(&buf);

    /* Send the array header information */
    pq_sendint(&buf, ndim, 4);
    pq_sendint(&buf, ARR_HASNULL(v) ? 1 : 0, 4);
    pq_sendint(&buf, element_type, sizeof(Oid));
    for (i = 0; i < ndim; i++)
    {
        pq_sendint(&buf, ARR_DIMS(v)[i], 4);
        pq_sendint(&buf, ARR_LBOUND(v)[i], 4);
    }

    /* Send the array elements using the element's own sendproc */
    p = ARR_DATA_PTR(v);
    bitmap = ARR_NULLBITMAP(v);
    bitmask = 1;

    for (i = 0; i < nitems; i++)
    {
        /* Get source element, checking for NULL */
        if (bitmap && (*bitmap & bitmask) == 0)
        {
            /* -1 length means a NULL */
            pq_sendint(&buf, -1, 4);
        }
        else
        {
            Datum       itemvalue;
            bytea      *outputbytes;

            itemvalue = fetch_att(p, typbyval, typlen);
            outputbytes = SendFunctionCall(&my_extra->proc, itemvalue);
            pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
            pq_sendbytes(&buf, VARDATA(outputbytes),
                         VARSIZE(outputbytes) - VARHDRSZ);
            pfree(outputbytes);

            p = att_addlength_pointer(p, typlen, p);
            p = (char *) att_align_nominal(p, typalign);
        }

        /* advance bitmap pointer if any */
        if (bitmap)
        {
            bitmask <<= 1;
            if (bitmask == 0x100)
            {
                bitmap++;
                bitmask = 1;
            }
        }
    }

    PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

ArrayType* array_set ( ArrayType array,
int  nSubscripts,
int *  indx,
Datum  dataValue,
bool  isNull,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 2040 of file arrayfuncs.c.

References ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ARR_SIZE, array_bitmap_copy(), array_get_isnull(), array_seek(), array_set_isnull(), ArrayCastAndSet(), ArrayGetNItems(), ArrayGetOffset(), att_addlength_datum, att_addlength_pointer, att_align_nominal, construct_md_array(), ArrayType::dataoffset, DatumGetArrayTypeP, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, MAXDIM, MemSet, ArrayType::ndim, palloc(), palloc0(), PG_DETOAST_DATUM, PointerGetDatum, and SET_VARSIZE.

Referenced by array_push(), exec_assign_value(), ExecEvalArrayRef(), GUCArrayAdd(), GUCArrayDelete(), GUCArrayReset(), and pg_extension_config_dump().

{
    ArrayType  *newarray;
    int         i,
                ndim,
                dim[MAXDIM],
                lb[MAXDIM],
                offset;
    char       *elt_ptr;
    bool        newhasnulls;
    bits8      *oldnullbitmap;
    int         oldnitems,
                newnitems,
                olddatasize,
                newsize,
                olditemlen,
                newitemlen,
                overheadlen,
                oldoverheadlen,
                addedbefore,
                addedafter,
                lenbefore,
                lenafter;

    if (arraytyplen > 0)
    {
        /*
         * fixed-length arrays -- these are assumed to be 1-d, 0-based. We
         * cannot extend them, either.
         */
        if (nSubscripts != 1)
            ereport(ERROR,
                    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("wrong number of array subscripts")));

        if (indx[0] < 0 || indx[0] * elmlen >= arraytyplen)
            ereport(ERROR,
                    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("array subscript out of range")));

        if (isNull)
            ereport(ERROR,
                    (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                     errmsg("cannot assign null value to an element of a fixed-length array")));

        newarray = (ArrayType *) palloc(arraytyplen);
        memcpy(newarray, array, arraytyplen);
        elt_ptr = (char *) newarray + indx[0] * elmlen;
        ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr);
        return newarray;
    }

    if (nSubscripts <= 0 || nSubscripts > MAXDIM)
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                 errmsg("wrong number of array subscripts")));

    /* make sure item to be inserted is not toasted */
    if (elmlen == -1 && !isNull)
        dataValue = PointerGetDatum(PG_DETOAST_DATUM(dataValue));

    /* detoast input array if necessary */
    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, &isNull, nSubscripts,
                                  dim, lb, elmtype,
                                  elmlen, elmbyval, elmalign);
    }

    if (ndim != nSubscripts)
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                 errmsg("wrong number of array subscripts")));

    /* copy dim/lb since we may modify them */
    memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
    memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));

    newhasnulls = (ARR_HASNULL(array) || isNull);
    addedbefore = addedafter = 0;

    /*
     * Check subscripts
     */
    if (ndim == 1)
    {
        if (indx[0] < lb[0])
        {
            addedbefore = lb[0] - indx[0];
            dim[0] += addedbefore;
            lb[0] = indx[0];
            if (addedbefore > 1)
                newhasnulls = true;     /* will insert nulls */
        }
        if (indx[0] >= (dim[0] + lb[0]))
        {
            addedafter = indx[0] - (dim[0] + lb[0]) + 1;
            dim[0] += addedafter;
            if (addedafter > 1)
                newhasnulls = true;     /* will insert nulls */
        }
    }
    else
    {
        /*
         * XXX currently we do not support extending multi-dimensional arrays
         * during assignment
         */
        for (i = 0; i < ndim; i++)
        {
            if (indx[i] < lb[i] ||
                indx[i] >= (dim[i] + lb[i]))
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                         errmsg("array subscript out of range")));
        }
    }

    /*
     * Compute sizes of items and areas to copy
     */
    newnitems = ArrayGetNItems(ndim, dim);
    if (newhasnulls)
        overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems);
    else
        overheadlen = ARR_OVERHEAD_NONULLS(ndim);
    oldnitems = ArrayGetNItems(ndim, ARR_DIMS(array));
    oldnullbitmap = ARR_NULLBITMAP(array);
    oldoverheadlen = ARR_DATA_OFFSET(array);
    olddatasize = ARR_SIZE(array) - oldoverheadlen;
    if (addedbefore)
    {
        offset = 0;
        lenbefore = 0;
        olditemlen = 0;
        lenafter = olddatasize;
    }
    else if (addedafter)
    {
        offset = oldnitems;
        lenbefore = olddatasize;
        olditemlen = 0;
        lenafter = 0;
    }
    else
    {
        offset = ArrayGetOffset(nSubscripts, dim, lb, indx);
        elt_ptr = array_seek(ARR_DATA_PTR(array), 0, oldnullbitmap, offset,
                             elmlen, elmbyval, elmalign);
        lenbefore = (int) (elt_ptr - ARR_DATA_PTR(array));
        if (array_get_isnull(oldnullbitmap, offset))
            olditemlen = 0;
        else
        {
            olditemlen = att_addlength_pointer(0, elmlen, elt_ptr);
            olditemlen = att_align_nominal(olditemlen, elmalign);
        }
        lenafter = (int) (olddatasize - lenbefore - olditemlen);
    }

    if (isNull)
        newitemlen = 0;
    else
    {
        newitemlen = att_addlength_datum(0, elmlen, dataValue);
        newitemlen = att_align_nominal(newitemlen, elmalign);
    }

    newsize = overheadlen + lenbefore + newitemlen + lenafter;

    /*
     * OK, create the new array and fill in header/dimensions
     */
    newarray = (ArrayType *) palloc0(newsize);
    SET_VARSIZE(newarray, newsize);
    newarray->ndim = ndim;
    newarray->dataoffset = newhasnulls ? overheadlen : 0;
    newarray->elemtype = ARR_ELEMTYPE(array);
    memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
    memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));

    /*
     * Fill in data
     */
    memcpy((char *) newarray + overheadlen,
           (char *) array + oldoverheadlen,
           lenbefore);
    if (!isNull)
        ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign,
                        (char *) newarray + overheadlen + lenbefore);
    memcpy((char *) newarray + overheadlen + lenbefore + newitemlen,
           (char *) array + oldoverheadlen + lenbefore + olditemlen,
           lenafter);

    /*
     * Fill in nulls bitmap if needed
     *
     * Note: it's possible we just replaced the last NULL with a non-NULL, and
     * could get rid of the bitmap.  Seems not worth testing for though.
     */
    if (newhasnulls)
    {
        bits8      *newnullbitmap = ARR_NULLBITMAP(newarray);

        /* Zero the bitmap to take care of marking inserted positions null */
        MemSet(newnullbitmap, 0, (newnitems + 7) / 8);
        /* Fix the inserted value */
        if (addedafter)
            array_set_isnull(newnullbitmap, newnitems - 1, isNull);
        else
            array_set_isnull(newnullbitmap, offset, isNull);
        /* Fix the copied range(s) */
        if (addedbefore)
            array_bitmap_copy(newnullbitmap, addedbefore,
                              oldnullbitmap, 0,
                              oldnitems);
        else
        {
            array_bitmap_copy(newnullbitmap, 0,
                              oldnullbitmap, 0,
                              offset);
            if (addedafter == 0)
                array_bitmap_copy(newnullbitmap, offset + 1,
                                  oldnullbitmap, offset + 1,
                                  oldnitems - offset - 1);
        }
    }

    return newarray;
}

ArrayType* array_set_slice ( ArrayType array,
int  nSubscripts,
int *  upperIndx,
int *  lowerIndx,
ArrayType srcArray,
bool  isNull,
int  arraytyplen,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 2332 of file arrayfuncs.c.

References ARR_DATA_OFFSET, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, ARR_NULLBITMAP, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ARR_SIZE, array_bitmap_copy(), array_insert_slice(), array_nelems_size(), array_slice_size(), ArrayGetNItems(), Assert, construct_md_array(), ArrayType::dataoffset, DatumGetArrayTypeP, deconstruct_array(), ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, Max, MAXDIM, mda_get_range(), MemSet, Min, ArrayType::ndim, palloc0(), PointerGetDatum, and SET_VARSIZE.

Referenced by ExecEvalArrayRef().

{
    ArrayType  *newarray;
    int         i,
                ndim,
                dim[MAXDIM],
                lb[MAXDIM],
                span[MAXDIM];
    bool        newhasnulls;
    int         nitems,
                nsrcitems,
                olddatasize,
                newsize,
                olditemsize,
                newitemsize,
                overheadlen,
                oldoverheadlen,
                addedbefore,
                addedafter,
                lenbefore,
                lenafter,
                itemsbefore,
                itemsafter,
                nolditems;

    /* Currently, assignment from a NULL source array is a no-op */
    if (isNull)
        return array;

    if (arraytyplen > 0)
    {
        /*
         * fixed-length arrays -- not got round to doing this...
         */
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
        errmsg("updates on slices of fixed-length arrays not implemented")));
    }

    /* detoast arrays if necessary */
    array = DatumGetArrayTypeP(PointerGetDatum(array));
    srcArray = DatumGetArrayTypeP(PointerGetDatum(srcArray));

    /* 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;
        bool       *dnulls;
        int         nelems;
        Oid         elmtype = ARR_ELEMTYPE(array);

        deconstruct_array(srcArray, elmtype, elmlen, elmbyval, elmalign,
                          &dvalues, &dnulls, &nelems);

        for (i = 0; i < nSubscripts; i++)
        {
            dim[i] = 1 + upperIndx[i] - lowerIndx[i];
            lb[i] = lowerIndx[i];
        }

        /* complain if too few source items; we ignore extras, however */
        if (nelems < ArrayGetNItems(nSubscripts, dim))
            ereport(ERROR,
                    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("source array too small")));

        return construct_md_array(dvalues, dnulls, nSubscripts,
                                  dim, lb, elmtype,
                                  elmlen, elmbyval, elmalign);
    }

    if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                 errmsg("wrong number of array subscripts")));

    /* copy dim/lb since we may modify them */
    memcpy(dim, ARR_DIMS(array), ndim * sizeof(int));
    memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int));

    newhasnulls = (ARR_HASNULL(array) || ARR_HASNULL(srcArray));
    addedbefore = addedafter = 0;

    /*
     * Check subscripts
     */
    if (ndim == 1)
    {
        Assert(nSubscripts == 1);
        if (lowerIndx[0] > upperIndx[0])
            ereport(ERROR,
                    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("upper bound cannot be less than lower bound")));
        if (lowerIndx[0] < lb[0])
        {
            if (upperIndx[0] < lb[0] - 1)
                newhasnulls = true;     /* will insert nulls */
            addedbefore = lb[0] - lowerIndx[0];
            dim[0] += addedbefore;
            lb[0] = lowerIndx[0];
        }
        if (upperIndx[0] >= (dim[0] + lb[0]))
        {
            if (lowerIndx[0] > (dim[0] + lb[0]))
                newhasnulls = true;     /* will insert nulls */
            addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1;
            dim[0] += addedafter;
        }
    }
    else
    {
        /*
         * XXX currently we do not support extending multi-dimensional arrays
         * during assignment
         */
        for (i = 0; i < nSubscripts; i++)
        {
            if (lowerIndx[i] > upperIndx[i])
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("upper bound cannot be less than lower bound")));
            if (lowerIndx[i] < lb[i] ||
                upperIndx[i] >= (dim[i] + lb[i]))
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                         errmsg("array subscript out of range")));
        }
        /* fill any missing subscript positions with full array range */
        for (; i < ndim; i++)
        {
            lowerIndx[i] = lb[i];
            upperIndx[i] = dim[i] + lb[i] - 1;
            if (lowerIndx[i] > upperIndx[i])
                ereport(ERROR,
                        (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                     errmsg("upper bound cannot be less than lower bound")));
        }
    }

    /* Do this mainly to check for overflow */
    nitems = ArrayGetNItems(ndim, dim);

    /*
     * Make sure source array has enough entries.  Note we ignore the shape of
     * the source array and just read entries serially.
     */
    mda_get_range(ndim, span, lowerIndx, upperIndx);
    nsrcitems = ArrayGetNItems(ndim, span);
    if (nsrcitems > ArrayGetNItems(ARR_NDIM(srcArray), ARR_DIMS(srcArray)))
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                 errmsg("source array too small")));

    /*
     * Compute space occupied by new entries, space occupied by replaced
     * entries, and required space for new array.
     */
    if (newhasnulls)
        overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, nitems);
    else
        overheadlen = ARR_OVERHEAD_NONULLS(ndim);
    newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), 0,
                                    ARR_NULLBITMAP(srcArray), nsrcitems,
                                    elmlen, elmbyval, elmalign);
    oldoverheadlen = ARR_DATA_OFFSET(array);
    olddatasize = ARR_SIZE(array) - oldoverheadlen;
    if (ndim > 1)
    {
        /*
         * here we do not need to cope with extension of the array; it would
         * be a lot more complicated if we had to do so...
         */
        olditemsize = array_slice_size(ARR_DATA_PTR(array),
                                       ARR_NULLBITMAP(array),
                                       ndim, dim, lb,
                                       lowerIndx, upperIndx,
                                       elmlen, elmbyval, elmalign);
        lenbefore = lenafter = 0;       /* keep compiler quiet */
        itemsbefore = itemsafter = nolditems = 0;
    }
    else
    {
        /*
         * here we must allow for possibility of slice larger than orig array
         * and/or not adjacent to orig array subscripts
         */
        int         oldlb = ARR_LBOUND(array)[0];
        int         oldub = oldlb + ARR_DIMS(array)[0] - 1;
        int         slicelb = Max(oldlb, lowerIndx[0]);
        int         sliceub = Min(oldub, upperIndx[0]);
        char       *oldarraydata = ARR_DATA_PTR(array);
        bits8      *oldarraybitmap = ARR_NULLBITMAP(array);

        /* count/size of old array entries that will go before the slice */
        itemsbefore = Min(slicelb, oldub + 1) - oldlb;
        lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap,
                                      itemsbefore,
                                      elmlen, elmbyval, elmalign);
        /* count/size of old array entries that will be replaced by slice */
        if (slicelb > sliceub)
        {
            nolditems = 0;
            olditemsize = 0;
        }
        else
        {
            nolditems = sliceub - slicelb + 1;
            olditemsize = array_nelems_size(oldarraydata + lenbefore,
                                            itemsbefore, oldarraybitmap,
                                            nolditems,
                                            elmlen, elmbyval, elmalign);
        }
        /* count/size of old array entries that will go after the slice */
        itemsafter = oldub + 1 - Max(sliceub + 1, oldlb);
        lenafter = olddatasize - lenbefore - olditemsize;
    }

    newsize = overheadlen + olddatasize - olditemsize + newitemsize;

    newarray = (ArrayType *) palloc0(newsize);
    SET_VARSIZE(newarray, newsize);
    newarray->ndim = ndim;
    newarray->dataoffset = newhasnulls ? overheadlen : 0;
    newarray->elemtype = ARR_ELEMTYPE(array);
    memcpy(ARR_DIMS(newarray), dim, ndim * sizeof(int));
    memcpy(ARR_LBOUND(newarray), lb, ndim * sizeof(int));

    if (ndim > 1)
    {
        /*
         * here we do not need to cope with extension of the array; it would
         * be a lot more complicated if we had to do so...
         */
        array_insert_slice(newarray, array, srcArray,
                           ndim, dim, lb,
                           lowerIndx, upperIndx,
                           elmlen, elmbyval, elmalign);
    }
    else
    {
        /* fill in data */
        memcpy((char *) newarray + overheadlen,
               (char *) array + oldoverheadlen,
               lenbefore);
        memcpy((char *) newarray + overheadlen + lenbefore,
               ARR_DATA_PTR(srcArray),
               newitemsize);
        memcpy((char *) newarray + overheadlen + lenbefore + newitemsize,
               (char *) array + oldoverheadlen + lenbefore + olditemsize,
               lenafter);
        /* fill in nulls bitmap if needed */
        if (newhasnulls)
        {
            bits8      *newnullbitmap = ARR_NULLBITMAP(newarray);
            bits8      *oldnullbitmap = ARR_NULLBITMAP(array);

            /* Zero the bitmap to handle marking inserted positions null */
            MemSet(newnullbitmap, 0, (nitems + 7) / 8);
            array_bitmap_copy(newnullbitmap, addedbefore,
                              oldnullbitmap, 0,
                              itemsbefore);
            array_bitmap_copy(newnullbitmap, lowerIndx[0] - lb[0],
                              ARR_NULLBITMAP(srcArray), 0,
                              nsrcitems);
            array_bitmap_copy(newnullbitmap, addedbefore + itemsbefore + nolditems,
                              oldnullbitmap, itemsbefore + nolditems,
                              itemsafter);
        }
    }

    return newarray;
}

Datum array_smaller ( PG_FUNCTION_ARGS   ) 

Definition at line 4705 of file arrayfuncs.c.

References array_cmp(), PG_GETARG_ARRAYTYPE_P, and PG_RETURN_ARRAYTYPE_P.

{
    ArrayType  *v1,
               *v2,
               *result;

    v1 = PG_GETARG_ARRAYTYPE_P(0);
    v2 = PG_GETARG_ARRAYTYPE_P(1);

    result = ((array_cmp(fcinfo) < 0) ? v1 : v2);

    PG_RETURN_ARRAYTYPE_P(result);
}

Datum array_typanalyze ( PG_FUNCTION_ARGS   ) 

Definition at line 97 of file array_typanalyze.c.

References VacAttrStats::attrtypid, ArrayAnalyzeExtraData::cmp, TypeCacheEntry::cmp_proc_finfo, VacAttrStats::compute_stats, elog, ArrayAnalyzeExtraData::eq_opr, TypeCacheEntry::eq_opr, ERROR, VacAttrStats::extra_data, FmgrInfo::fn_oid, get_base_element_type(), ArrayAnalyzeExtraData::hash, TypeCacheEntry::hash_proc_finfo, lookup_type_cache(), OidIsValid, palloc(), PG_GETARG_POINTER, PG_RETURN_BOOL, ArrayAnalyzeExtraData::std_compute_stats, ArrayAnalyzeExtraData::std_extra_data, std_typanalyze(), TypeCacheEntry::typalign, ArrayAnalyzeExtraData::typalign, TypeCacheEntry::typbyval, ArrayAnalyzeExtraData::typbyval, TypeCacheEntry::type_id, ArrayAnalyzeExtraData::type_id, TYPECACHE_CMP_PROC_FINFO, TYPECACHE_EQ_OPR, TYPECACHE_HASH_PROC_FINFO, TypeCacheEntry::typlen, and ArrayAnalyzeExtraData::typlen.

{
    VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0);
    Oid         element_typeid;
    TypeCacheEntry *typentry;
    ArrayAnalyzeExtraData *extra_data;

    /*
     * Call the standard typanalyze function.  It may fail to find needed
     * operators, in which case we also can't do anything, so just fail.
     */
    if (!std_typanalyze(stats))
        PG_RETURN_BOOL(false);

    /*
     * Check attribute data type is a varlena array (or a domain over one).
     */
    element_typeid = get_base_element_type(stats->attrtypid);
    if (!OidIsValid(element_typeid))
        elog(ERROR, "array_typanalyze was invoked for non-array type %u",
             stats->attrtypid);

    /*
     * Gather information about the element type.  If we fail to find
     * something, return leaving the state from std_typanalyze() in place.
     */
    typentry = lookup_type_cache(element_typeid,
                                 TYPECACHE_EQ_OPR |
                                 TYPECACHE_CMP_PROC_FINFO |
                                 TYPECACHE_HASH_PROC_FINFO);

    if (!OidIsValid(typentry->eq_opr) ||
        !OidIsValid(typentry->cmp_proc_finfo.fn_oid) ||
        !OidIsValid(typentry->hash_proc_finfo.fn_oid))
        PG_RETURN_BOOL(true);

    /* Store our findings for use by compute_array_stats() */
    extra_data = (ArrayAnalyzeExtraData *) palloc(sizeof(ArrayAnalyzeExtraData));
    extra_data->type_id = typentry->type_id;
    extra_data->eq_opr = typentry->eq_opr;
    extra_data->typbyval = typentry->typbyval;
    extra_data->typlen = typentry->typlen;
    extra_data->typalign = typentry->typalign;
    extra_data->cmp = &typentry->cmp_proc_finfo;
    extra_data->hash = &typentry->hash_proc_finfo;

    /* Save old compute_stats and extra_data for scalar statistics ... */
    extra_data->std_compute_stats = stats->compute_stats;
    extra_data->std_extra_data = stats->extra_data;

    /* ... and replace with our info */
    stats->compute_stats = compute_array_stats;
    stats->extra_data = extra_data;

    /*
     * Note we leave stats->minrows set as std_typanalyze set it.  Should it
     * be increased for array analysis purposes?
     */

    PG_RETURN_BOOL(true);
}

Datum array_unnest ( PG_FUNCTION_ARGS   ) 

Definition at line 5079 of file arrayfuncs.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, ARR_NULLBITMAP, array_get_isnull(), ArrayCast(), ArrayGetNItems(), att_addlength_pointer, att_align_nominal, get_typlenbyvalalign(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc(), PG_GETARG_ARRAYTYPE_P, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and FuncCallContext::user_fctx.

{
    typedef struct
    {
        ArrayType  *arr;
        int         nextelem;
        int         numelems;
        char       *elemdataptr;    /* this moves with nextelem */
        bits8      *arraynullsptr;      /* this does not */
        int16       elmlen;
        bool        elmbyval;
        char        elmalign;
    } array_unnest_fctx;

    FuncCallContext *funcctx;
    array_unnest_fctx *fctx;
    MemoryContext oldcontext;

    /* stuff done only on the first call of the function */
    if (SRF_IS_FIRSTCALL())
    {
        ArrayType  *arr;

        /* create a function context for cross-call persistence */
        funcctx = SRF_FIRSTCALL_INIT();

        /*
         * switch to memory context appropriate for multiple function calls
         */
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        /*
         * Get the array value and detoast if needed.  We can't do this
         * earlier because if we have to detoast, we want the detoasted copy
         * to be in multi_call_memory_ctx, so it will go away when we're done
         * and not before.  (If no detoast happens, we assume the originally
         * passed array will stick around till then.)
         */
        arr = PG_GETARG_ARRAYTYPE_P(0);

        /* allocate memory for user context */
        fctx = (array_unnest_fctx *) palloc(sizeof(array_unnest_fctx));

        /* initialize state */
        fctx->arr = arr;
        fctx->nextelem = 0;
        fctx->numelems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));

        fctx->elemdataptr = ARR_DATA_PTR(arr);
        fctx->arraynullsptr = ARR_NULLBITMAP(arr);

        get_typlenbyvalalign(ARR_ELEMTYPE(arr),
                             &fctx->elmlen,
                             &fctx->elmbyval,
                             &fctx->elmalign);

        funcctx->user_fctx = fctx;
        MemoryContextSwitchTo(oldcontext);
    }

    /* stuff done on every call of the function */
    funcctx = SRF_PERCALL_SETUP();
    fctx = funcctx->user_fctx;

    if (fctx->nextelem < fctx->numelems)
    {
        int         offset = fctx->nextelem++;
        Datum       elem;

        /*
         * Check for NULL array element
         */
        if (array_get_isnull(fctx->arraynullsptr, offset))
        {
            fcinfo->isnull = true;
            elem = (Datum) 0;
            /* elemdataptr does not move */
        }
        else
        {
            /*
             * OK, get the element
             */
            char       *ptr = fctx->elemdataptr;

            fcinfo->isnull = false;
            elem = ArrayCast(ptr, fctx->elmbyval, fctx->elmlen);

            /*
             * Advance elemdataptr over it
             */
            ptr = att_addlength_pointer(ptr, fctx->elmlen, ptr);
            ptr = (char *) att_align_nominal(ptr, fctx->elmalign);
            fctx->elemdataptr = ptr;
        }

        SRF_RETURN_NEXT(funcctx, elem);
    }
    else
    {
        /* do when there is no more left */
        SRF_RETURN_DONE(funcctx);
    }
}

Datum array_upper ( PG_FUNCTION_ARGS   ) 

Definition at line 1690 of file arrayfuncs.c.

References ARR_DIMS, ARR_LBOUND, ARR_NDIM, MAXDIM, PG_GETARG_ARRAYTYPE_P, PG_GETARG_INT32, PG_RETURN_INT32, and PG_RETURN_NULL.

{
    ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
    int         reqdim = PG_GETARG_INT32(1);
    int        *dimv,
               *lb;
    int         result;

    /* Sanity check: does it look like an array at all? */
    if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
        PG_RETURN_NULL();

    /* Sanity check: was the requested dim valid */
    if (reqdim <= 0 || reqdim > ARR_NDIM(v))
        PG_RETURN_NULL();

    lb = ARR_LBOUND(v);
    dimv = ARR_DIMS(v);

    result = dimv[reqdim - 1] + lb[reqdim - 1] - 1;

    PG_RETURN_INT32(result);
}

Datum arraycontained ( PG_FUNCTION_ARGS   ) 

Definition at line 3856 of file arrayfuncs.c.

References array_contain_compare(), PG_FREE_IF_COPY, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, and PG_RETURN_BOOL.

{
    ArrayType  *array1 = PG_GETARG_ARRAYTYPE_P(0);
    ArrayType  *array2 = PG_GETARG_ARRAYTYPE_P(1);
    Oid         collation = PG_GET_COLLATION();
    bool        result;

    result = array_contain_compare(array1, array2, collation, true,
                                   &fcinfo->flinfo->fn_extra);

    /* Avoid leaking memory when handed toasted input. */
    PG_FREE_IF_COPY(array1, 0);
    PG_FREE_IF_COPY(array2, 1);

    PG_RETURN_BOOL(result);
}

Datum arraycontains ( PG_FUNCTION_ARGS   ) 

Definition at line 3838 of file arrayfuncs.c.

References array_contain_compare(), PG_FREE_IF_COPY, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, and PG_RETURN_BOOL.

{
    ArrayType  *array1 = PG_GETARG_ARRAYTYPE_P(0);
    ArrayType  *array2 = PG_GETARG_ARRAYTYPE_P(1);
    Oid         collation = PG_GET_COLLATION();
    bool        result;

    result = array_contain_compare(array2, array1, collation, true,
                                   &fcinfo->flinfo->fn_extra);

    /* Avoid leaking memory when handed toasted input. */
    PG_FREE_IF_COPY(array1, 0);
    PG_FREE_IF_COPY(array2, 1);

    PG_RETURN_BOOL(result);
}

int32* ArrayGetIntegerTypmods ( ArrayType arr,
int *  n 
)

Definition at line 200 of file arrayutils.c.

References ARR_ELEMTYPE, ARR_NDIM, array_contains_nulls(), CSTRINGOID, DatumGetCString, deconstruct_array(), ereport, errcode(), errmsg(), ERROR, i, NULL, palloc(), pfree(), and pg_atoi().

Referenced by anybit_typmodin(), anychar_typmodin(), anytime_typmodin(), anytimestamp_typmodin(), intervaltypmodin(), and numerictypmodin().

{
    int32      *result;
    Datum      *elem_values;
    int         i;

    if (ARR_ELEMTYPE(arr) != CSTRINGOID)
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
                 errmsg("typmod array must be type cstring[]")));

    if (ARR_NDIM(arr) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                 errmsg("typmod array must be one-dimensional")));

    if (array_contains_nulls(arr))
        ereport(ERROR,
                (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                 errmsg("typmod array must not contain nulls")));

    /* hardwired knowledge about cstring's representation details here */
    deconstruct_array(arr, CSTRINGOID,
                      -2, false, 'c',
                      &elem_values, NULL, n);

    result = (int32 *) palloc(*n * sizeof(int32));

    for (i = 0; i < *n; i++)
        result[i] = pg_atoi(DatumGetCString(elem_values[i]),
                            sizeof(int32), '\0');

    pfree(elem_values);

    return result;
}

int ArrayGetNItems ( int  ndim,
const int *  dims 
)

Definition at line 75 of file arrayutils.c.

References Assert, ereport, errcode(), errmsg(), ERROR, i, and MaxArraySize.

Referenced by _arrq_cons(), _lca(), _lt_q_regex(), _ltree_compress(), array_cat(), array_cmp(), array_contain_compare(), array_contains_nulls(), array_create_iterator(), array_eq(), array_fill_internal(), array_get_slice(), array_in(), array_insert_slice(), array_iterator(), array_map(), array_out(), array_recv(), array_replace_internal(), array_send(), array_set(), array_set_slice(), array_slice_size(), array_to_json_internal(), array_to_text_internal(), array_unnest(), arrq_cons(), construct_md_array(), deconstruct_array(), estimate_array_length(), ExecEvalArray(), ExecEvalScalarArrayOp(), get_text_array_contents(), getWeights(), hash_array(), is_strict_saop(), lt_q_regex(), predicate_classify(), and tsa_rewrite_accum().

{
    int32       ret;
    int         i;

#define MaxArraySize ((Size) (MaxAllocSize / sizeof(Datum)))

    if (ndim <= 0)
        return 0;
    ret = 1;
    for (i = 0; i < ndim; i++)
    {
        int64       prod;

        /* A negative dimension implies that UB-LB overflowed ... */
        if (dims[i] < 0)
            ereport(ERROR,
                    (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                     errmsg("array size exceeds the maximum allowed (%d)",
                            (int) MaxArraySize)));

        prod = (int64) ret *(int64) dims[i];

        ret = (int32) prod;
        if ((int64) ret != prod)
            ereport(ERROR,
                    (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                     errmsg("array size exceeds the maximum allowed (%d)",
                            (int) MaxArraySize)));
    }
    Assert(ret >= 0);
    if ((Size) ret > MaxArraySize)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("array size exceeds the maximum allowed (%d)",
                        (int) MaxArraySize)));
    return (int) ret;
}

int ArrayGetOffset ( int  n,
const int *  dim,
const int *  lb,
const int *  indx 
)

Definition at line 31 of file arrayutils.c.

References i, and scale.

Referenced by array_extract_slice(), array_insert_slice(), array_ref(), array_set(), and array_slice_size().

{
    int         i,
                scale = 1,
                offset = 0;

    for (i = n - 1; i >= 0; i--)
    {
        offset += (indx[i] - lb[i]) * scale;
        scale *= dim[i];
    }
    return offset;
}

int ArrayGetOffset0 ( int  n,
const int *  tup,
const int *  scale 
)

Definition at line 50 of file arrayutils.c.

References i.

Referenced by ReadArrayStr().

{
    int         i,
                lin = 0;

    for (i = 0; i < n; i++)
        lin += tup[i] * scale[i];
    return lin;
}

Datum arrayoverlap ( PG_FUNCTION_ARGS   ) 

Definition at line 3820 of file arrayfuncs.c.

References array_contain_compare(), PG_FREE_IF_COPY, PG_GET_COLLATION, PG_GETARG_ARRAYTYPE_P, and PG_RETURN_BOOL.

{
    ArrayType  *array1 = PG_GETARG_ARRAYTYPE_P(0);
    ArrayType  *array2 = PG_GETARG_ARRAYTYPE_P(1);
    Oid         collation = PG_GET_COLLATION();
    bool        result;

    result = array_contain_compare(array1, array2, collation, false,
                                   &fcinfo->flinfo->fn_extra);

    /* Avoid leaking memory when handed toasted input. */
    PG_FREE_IF_COPY(array1, 0);
    PG_FREE_IF_COPY(array2, 1);

    PG_RETURN_BOOL(result);
}

Datum btarraycmp ( PG_FUNCTION_ARGS   ) 

Definition at line 3325 of file arrayfuncs.c.

References array_cmp(), and PG_RETURN_INT32.

{
    PG_RETURN_INT32(array_cmp(fcinfo));
}

ArrayType* construct_array ( Datum elems,
int  nelems,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign 
)
ArrayType* construct_empty_array ( Oid  elmtype  ) 
ArrayType* construct_md_array ( Datum elems,
bool nulls,
int  ndims,
int *  dims,
int *  lbs,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign 
)

Definition at line 2899 of file arrayfuncs.c.

References AllocSizeIsValid, ARR_DIMS, ARR_LBOUND, ARR_OVERHEAD_NONULLS, ARR_OVERHEAD_WITHNULLS, ArrayGetNItems(), att_addlength_datum, att_align_nominal, construct_empty_array(), CopyArrayEls(), ArrayType::dataoffset, ArrayType::elemtype, ereport, errcode(), errmsg(), ERROR, i, MaxAllocSize, MAXDIM, ArrayType::ndim, palloc0(), PG_DETOAST_DATUM, PointerGetDatum, and SET_VARSIZE.

Referenced by array_iterate(), array_set(), array_set_slice(), build_regexp_matches_result(), construct_array(), create_singleton_array(), ExecEvalArray(), hstore_avals(), hstore_slice_to_array(), hstore_to_array_internal(), makeMdArrayResult(), plpgsql_exec_trigger(), and PLySequence_ToArray().

{
    ArrayType  *result;
    bool        hasnulls;
    int32       nbytes;
    int32       dataoffset;
    int         i;
    int         nelems;

    if (ndims < 0)              /* we do allow zero-dimension arrays */
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("invalid number of dimensions: %d", ndims)));
    if (ndims > MAXDIM)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
                        ndims, MAXDIM)));

    /* fast track for empty array */
    if (ndims == 0)
        return construct_empty_array(elmtype);

    nelems = ArrayGetNItems(ndims, dims);

    /* compute required space */
    nbytes = 0;
    hasnulls = false;
    for (i = 0; i < nelems; i++)
    {
        if (nulls && nulls[i])
        {
            hasnulls = true;
            continue;
        }
        /* make sure data is not toasted */
        if (elmlen == -1)
            elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i]));
        nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
        nbytes = att_align_nominal(nbytes, elmalign);
        /* check for overflow of total request */
        if (!AllocSizeIsValid(nbytes))
            ereport(ERROR,
                    (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                     errmsg("array size exceeds the maximum allowed (%d)",
                            (int) MaxAllocSize)));
    }

    /* Allocate and initialize result array */
    if (hasnulls)
    {
        dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nelems);
        nbytes += dataoffset;
    }
    else
    {
        dataoffset = 0;         /* marker for no null bitmap */
        nbytes += ARR_OVERHEAD_NONULLS(ndims);
    }
    result = (ArrayType *) palloc0(nbytes);
    SET_VARSIZE(result, nbytes);
    result->ndim = ndims;
    result->dataoffset = dataoffset;
    result->elemtype = elmtype;
    memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
    memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));

    CopyArrayEls(result,
                 elems, nulls, nelems,
                 elmlen, elmbyval, elmalign,
                 false);

    return result;
}

ArrayType* create_singleton_array ( FunctionCallInfo  fcinfo,
Oid  element_type,
Datum  element,
bool  isNull,
int  ndims 
)

Definition at line 407 of file array_userfuncs.c.

References construct_md_array(), ArrayMetaState::element_type, ereport, errcode(), errmsg(), ERROR, FunctionCallInfoData::flinfo, FmgrInfo::fn_extra, FmgrInfo::fn_mcxt, get_typlenbyvalalign(), i, MAXDIM, MemoryContextAlloc(), NULL, ArrayMetaState::typalign, ArrayMetaState::typbyval, and ArrayMetaState::typlen.

Referenced by text_to_array_internal().

{
    Datum       dvalues[1];
    bool        nulls[1];
    int16       typlen;
    bool        typbyval;
    char        typalign;
    int         dims[MAXDIM];
    int         lbs[MAXDIM];
    int         i;
    ArrayMetaState *my_extra;

    if (ndims < 1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("invalid number of dimensions: %d", ndims)));
    if (ndims > MAXDIM)
        ereport(ERROR,
                (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
                        ndims, MAXDIM)));

    dvalues[0] = element;
    nulls[0] = isNull;

    for (i = 0; i < ndims; i++)
    {
        dims[i] = 1;
        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 = ~element_type;
    }

    if (my_extra->element_type != element_type)
    {
        /* Get info about element type */
        get_typlenbyvalalign(element_type,
                             &my_extra->typlen,
                             &my_extra->typbyval,
                             &my_extra->typalign);
        my_extra->element_type = element_type;
    }
    typlen = my_extra->typlen;
    typbyval = my_extra->typbyval;
    typalign = my_extra->typalign;

    return construct_md_array(dvalues, nulls, ndims, dims, lbs, element_type,
                              typlen, typbyval, typalign);
}

void deconstruct_array ( ArrayType array,
Oid  elmtype,
int  elmlen,
bool  elmbyval,
char  elmalign,
Datum **  elemsp,
bool **  nullsp,
int *  nelemsp 
)

Definition at line 3017 of file arrayfuncs.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), Assert, att_addlength_pointer, att_align_nominal, ereport, errcode(), errmsg(), ERROR, fetch_att, i, palloc(), and palloc0().

Referenced by _bt_preprocess_array_keys(), array_contain_compare(), array_set_slice(), array_to_json_internal(), arrayconst_startup_fn(), ArrayGetIntegerTypmods(), build_function_result_tupdesc_d(), compute_array_stats(), create_empty_extension(), DecodeTextArrayToCString(), decompile_column_index_array(), do_numeric_accum(), do_numeric_avg_accum(), ExecIndexEvalArrayKeys(), extension_config_remove(), generateClonedIndexStmt(), get_attstatsslot(), get_func_arg_info(), get_func_input_arg_names(), get_func_result_name(), get_path_all(), ghstore_consistent(), gin_extract_hstore_query(), ginarrayextract(), gincost_scalararrayopexpr(), ginqueryarrayextract(), hstore_from_array(), hstore_from_arrays(), hstore_slice_to_array(), hstoreArrayToPairs(), interval_accum(), interval_avg(), map_sql_value_to_xml_value(), mcelem_array_selec(), numeric_avg(), numeric_stddev_internal(), parseRelOptions(), pg_get_constraintdef_worker(), plperl_ref_from_pg_array(), scalararraysel(), text_format(), TidListCreate(), transformRelOptions(), tsa_rewrite_accum(), and untransformRelOptions().

{
    Datum      *elems;
    bool       *nulls;
    int         nelems;
    char       *p;
    bits8      *bitmap;
    int         bitmask;
    int         i;

    Assert(ARR_ELEMTYPE(array) == elmtype);

    nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
    *elemsp = elems = (Datum *) palloc(nelems * sizeof(Datum));
    if (nullsp)
        *nullsp = nulls = (bool *) palloc0(nelems * sizeof(bool));
    else
        nulls = NULL;
    *nelemsp = nelems;

    p = ARR_DATA_PTR(array);
    bitmap = ARR_NULLBITMAP(array);
    bitmask = 1;

    for (i = 0; i < nelems; i++)
    {
        /* Get source element, checking for NULL */
        if (bitmap && (*bitmap & bitmask) == 0)
        {
            elems[i] = (Datum) 0;
            if (nulls)
                nulls[i] = true;
            else
                ereport(ERROR,
                        (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                  errmsg("null array element not allowed in this context")));
        }
        else
        {
            elems[i] = fetch_att(p, elmbyval, elmlen);
            p = att_addlength_pointer(p, elmlen, p);
            p = (char *) att_align_nominal(p, elmalign);
        }

        /* advance bitmap pointer if any */
        if (bitmap)
        {
            bitmask <<= 1;
            if (bitmask == 0x100)
            {
                bitmap++;
                bitmask = 1;
            }
        }
    }
}

Datum generate_subscripts ( PG_FUNCTION_ARGS   ) 

Definition at line 4732 of file arrayfuncs.c.

References ARR_DIMS, ARR_LBOUND, ARR_NDIM, Int32GetDatum, generate_subscripts_fctx::lower, MAXDIM, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_BOOL, PG_GETARG_INT32, PG_NARGS, generate_subscripts_fctx::reverse, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, generate_subscripts_fctx::upper, and FuncCallContext::user_fctx.

Referenced by generate_subscripts_nodir().

{
    FuncCallContext *funcctx;
    MemoryContext oldcontext;
    generate_subscripts_fctx *fctx;

    /* stuff done only on the first call of the function */
    if (SRF_IS_FIRSTCALL())
    {
        ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
        int         reqdim = PG_GETARG_INT32(1);
        int        *lb,
                   *dimv;

        /* create a function context for cross-call persistence */
        funcctx = SRF_FIRSTCALL_INIT();

        /* Sanity check: does it look like an array at all? */
        if (ARR_NDIM(v) <= 0 || ARR_NDIM(v) > MAXDIM)
            SRF_RETURN_DONE(funcctx);

        /* Sanity check: was the requested dim valid */
        if (reqdim <= 0 || reqdim > ARR_NDIM(v))
            SRF_RETURN_DONE(funcctx);

        /*
         * switch to memory context appropriate for multiple function calls
         */
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        fctx = (generate_subscripts_fctx *) palloc(sizeof(generate_subscripts_fctx));

        lb = ARR_LBOUND(v);
        dimv = ARR_DIMS(v);

        fctx->lower = lb[reqdim - 1];
        fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1;
        fctx->reverse = (PG_NARGS() < 3) ? false : PG_GETARG_BOOL(2);

        funcctx->user_fctx = fctx;

        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();

    fctx = funcctx->user_fctx;

    if (fctx->lower <= fctx->upper)
    {
        if (!fctx->reverse)
            SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->lower++));
        else
            SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->upper--));
    }
    else
        /* done when there are no more elements left */
        SRF_RETURN_DONE(funcctx);
}

Datum generate_subscripts_nodir ( PG_FUNCTION_ARGS   ) 

Definition at line 4796 of file arrayfuncs.c.

References generate_subscripts().

{
    /* just call the other one -- it can handle both cases */
    return generate_subscripts(fcinfo);
}

Datum hash_array ( PG_FUNCTION_ARGS   ) 

Definition at line 3535 of file arrayfuncs.c.

References FunctionCallInfoData::arg, FunctionCallInfoData::argnull, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_NDIM, ARR_NULLBITMAP, ArrayGetNItems(), att_addlength_pointer, att_align_nominal, DatumGetUInt32, ereport, errcode(), errmsg(), ERROR, fetch_att, FmgrInfo::fn_oid, format_type_be(), FunctionCallInvoke, TypeCacheEntry::hash_proc_finfo, i, InitFunctionCallInfoData, InvalidOid, FunctionCallInfoData::isnull, lookup_type_cache(), NULL, OidIsValid, PG_FREE_IF_COPY, PG_GETARG_ARRAYTYPE_P, PG_RETURN_UINT32, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TYPECACHE_HASH_PROC_FINFO, and TypeCacheEntry::typlen.

{
    ArrayType  *array = PG_GETARG_ARRAYTYPE_P(0);
    int         ndims = ARR_NDIM(array);
    int        *dims = ARR_DIMS(array);
    Oid         element_type = ARR_ELEMTYPE(array);
    uint32      result = 1;
    int         nitems;
    TypeCacheEntry *typentry;
    int         typlen;
    bool        typbyval;
    char        typalign;
    char       *ptr;
    bits8      *bitmap;
    int         bitmask;
    int         i;
    FunctionCallInfoData locfcinfo;

    /*
     * We arrange to look up the hash 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.
     */
    typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
    if (typentry == NULL ||
        typentry->type_id != element_type)
    {
        typentry = lookup_type_cache(element_type,
                                     TYPECACHE_HASH_PROC_FINFO);
        if (!OidIsValid(typentry->hash_proc_finfo.fn_oid))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_FUNCTION),
                     errmsg("could not identify a hash function for type %s",
                            format_type_be(element_type))));
        fcinfo->flinfo->fn_extra = (void *) typentry;
    }
    typlen = typentry->typlen;
    typbyval = typentry->typbyval;
    typalign = typentry->typalign;

    /*
     * apply the hash function to each array element.
     */
    InitFunctionCallInfoData(locfcinfo, &typentry->hash_proc_finfo, 1,
                             InvalidOid, NULL, NULL);

    /* Loop over source data */
    nitems = ArrayGetNItems(ndims, dims);
    ptr = ARR_DATA_PTR(array);
    bitmap = ARR_NULLBITMAP(array);
    bitmask = 1;

    for (i = 0; i < nitems; i++)
    {
        uint32      elthash;

        /* Get element, checking for NULL */
        if (bitmap && (*bitmap & bitmask) == 0)
        {
            /* Treat nulls as having hashvalue 0 */
            elthash = 0;
        }
        else
        {
            Datum       elt;

            elt = fetch_att(ptr, typbyval, typlen);
            ptr = att_addlength_pointer(ptr, typlen, ptr);
            ptr = (char *) att_align_nominal(ptr, typalign);

            /* Apply the hash function */
            locfcinfo.arg[0] = elt;
            locfcinfo.argnull[0] = false;
            locfcinfo.isnull = false;
            elthash = DatumGetUInt32(FunctionCallInvoke(&locfcinfo));
        }

        /* advance bitmap pointer if any */
        if (bitmap)
        {
            bitmask <<= 1;
            if (bitmask == 0x100)
            {
                bitmap++;
                bitmask = 1;
            }
        }

        /*
         * Combine hash values of successive elements by multiplying the
         * current value by 31 and adding on the new element's hash value.
         *
         * The result is a sum in which each element's hash value is
         * multiplied by a different power of 31. This is modulo 2^32
         * arithmetic, and the powers of 31 modulo 2^32 form a cyclic group of
         * order 2^27. So for arrays of up to 2^27 elements, each element's
         * hash value is multiplied by a different (odd) number, resulting in
         * a good mixing of all the elements' hash values.
         */
        result = (result << 5) - result + elthash;
    }

    /* Avoid leaking memory when handed toasted input. */
    PG_FREE_IF_COPY(array, 0);

    PG_RETURN_UINT32(result);
}

Datum makeArrayResult ( ArrayBuildState astate,
MemoryContext  rcontext 
)

Definition at line 4634 of file arrayfuncs.c.

References makeMdArrayResult(), and ArrayBuildState::nelems.

Referenced by dblink_get_connections(), ExecScanSubPlan(), ExecSetParamPlan(), optionListToArray(), regexp_split_to_array(), text_to_array_internal(), transformRelOptions(), and xpath().

{
    int         dims[1];
    int         lbs[1];

    dims[0] = astate->nelems;
    lbs[0] = 1;

    return makeMdArrayResult(astate, 1, dims, lbs, rcontext, true);
}

Datum makeMdArrayResult ( ArrayBuildState astate,
int  ndims,
int *  dims,
int *  lbs,
MemoryContext  rcontext,
bool  release 
)

Definition at line 4657 of file arrayfuncs.c.

References construct_md_array(), ArrayBuildState::dnulls, ArrayBuildState::dvalues, ArrayBuildState::element_type, ArrayBuildState::mcontext, MemoryContextDelete(), MemoryContextSwitchTo(), PointerGetDatum, ArrayBuildState::typalign, ArrayBuildState::typbyval, and ArrayBuildState::typlen.

Referenced by array_agg_finalfn(), makeArrayResult(), and plperl_array_to_datum().

{
    ArrayType  *result;
    MemoryContext oldcontext;

    /* Build the final array result in rcontext */
    oldcontext = MemoryContextSwitchTo(rcontext);

    result = construct_md_array(astate->dvalues,
                                astate->dnulls,
                                ndims,
                                dims,
                                lbs,
                                astate->element_type,
                                astate->typlen,
                                astate->typbyval,
                                astate->typalign);

    MemoryContextSwitchTo(oldcontext);

    /* Clean up all the junk */
    if (release)
        MemoryContextDelete(astate->mcontext);

    return PointerGetDatum(result);
}

void mda_get_offset_values ( int  n,
int *  dist,
const int *  prod,
const int *  span 
)

Definition at line 150 of file arrayutils.c.

References i.

Referenced by array_extract_slice(), array_insert_slice(), and array_slice_size().

{
    int         i,
                j;

    dist[n - 1] = 0;
    for (j = n - 2; j >= 0; j--)
    {
        dist[j] = prod[j] - 1;
        for (i = j + 1; i < n; i++)
            dist[j] -= (span[i] - 1) * prod[i];
    }
}

void mda_get_prod ( int  n,
const int *  range,
int *  prod 
)

Definition at line 134 of file arrayutils.c.

References i.

Referenced by array_extract_slice(), array_insert_slice(), array_slice_size(), and ReadArrayStr().

{
    int         i;

    prod[n - 1] = 1;
    for (i = n - 2; i >= 0; i--)
        prod[i] = prod[i + 1] * range[i + 1];
}

void mda_get_range ( int  n,
int *  span,
const int *  st,
const int *  endp 
)

Definition at line 120 of file arrayutils.c.

References i.

Referenced by array_extract_slice(), array_get_slice(), array_insert_slice(), array_set_slice(), and array_slice_size().

{
    int         i;

    for (i = 0; i < n; i++)
        span[i] = endp[i] - st[i] + 1;
}

int mda_next_tuple ( int  n,
int *  curr,
const int *  span 
)

Definition at line 175 of file arrayutils.c.

References i.

Referenced by array_extract_slice(), array_insert_slice(), and array_slice_size().

{
    int         i;

    if (n <= 0)
        return -1;

    curr[n - 1] = (curr[n - 1] + 1) % span[n - 1];
    for (i = n - 1; i && curr[i] == 0; i--)
        curr[i - 1] = (curr[i - 1] + 1) % span[i - 1];

    if (i)
        return i;
    if (curr[0])
        return 0;

    return -1;
}


Variable Documentation

Definition at line 33 of file arrayfuncs.c.

Referenced by ReadArrayStr().