in src/backend/utils/adt/arrayfuncs.c [97:428]
static void ReadArrayStr(char *arrayStr, const char *origStr,
int nitems, int ndim, int *dim,
FmgrInfo *inputproc, Oid typioparam, int32 typmod,
char typdelim,
int typlen, bool typbyval, char typalign,
Datum *values, bool *nulls,
bool *hasnulls, int32 *nbytes);
static void ReadArrayBinary(StringInfo buf, int nitems,
FmgrInfo *receiveproc, Oid typioparam, int32 typmod,
int typlen, bool typbyval, char typalign,
Datum *values, bool *nulls,
bool *hasnulls, int32 *nbytes);
static Datum array_get_element_expanded(Datum arraydatum,
int nSubscripts, int *indx,
int arraytyplen,
int elmlen, bool elmbyval, char elmalign,
bool *isNull);
static Datum array_set_element_expanded(Datum arraydatum,
int nSubscripts, int *indx,
Datum dataValue, bool isNull,
int arraytyplen,
int elmlen, bool elmbyval, char elmalign);
static bool array_get_isnull(const bits8 *nullbitmap, int offset);
static void array_set_isnull(bits8 *nullbitmap, int offset, bool isNull);
static Datum ArrayCast(char *value, bool byval, int len);
static int ArrayCastAndSet(Datum src,
int typlen, bool typbyval, char typalign,
char *dest);
static char *array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems,
int typlen, bool typbyval, char typalign);
static int array_nelems_size(char *ptr, int offset, bits8 *nullbitmap,
int nitems, int typlen, bool typbyval, char typalign);
static int array_copy(char *destptr, int nitems,
char *srcptr, int offset, bits8 *nullbitmap,
int typlen, bool typbyval, char typalign);
static int array_slice_size(char *arraydataptr, bits8 *arraynullsptr,
int ndim, int *dim, int *lb,
int *st, int *endp,
int typlen, bool typbyval, char typalign);
static void array_extract_slice(ArrayType *newarray,
int ndim, int *dim, int *lb,
char *arraydataptr, bits8 *arraynullsptr,
int *st, int *endp,
int typlen, bool typbyval, char typalign);
static void array_insert_slice(ArrayType *destArray, ArrayType *origArray,
ArrayType *srcArray,
int ndim, int *dim, int *lb,
int *st, int *endp,
int typlen, bool typbyval, char typalign);
static int array_cmp(FunctionCallInfo fcinfo);
static ArrayType *create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes,
Oid elmtype, int dataoffset);
static ArrayType *array_fill_internal(ArrayType *dims, ArrayType *lbs,
Datum value, bool isnull, Oid elmtype,
FunctionCallInfo fcinfo);
static ArrayType *array_replace_internal(ArrayType *array,
Datum search, bool search_isnull,
Datum replace, bool replace_isnull,
bool remove, Oid collation,
FunctionCallInfo fcinfo);
static int width_bucket_array_float8(Datum operand, ArrayType *thresholds);
static int width_bucket_array_fixed(Datum operand,
ArrayType *thresholds,
Oid collation,
TypeCacheEntry *typentry);
static int width_bucket_array_variable(Datum operand,
ArrayType *thresholds,
Oid collation,
TypeCacheEntry *typentry);
/*
* array_in :
* converts an array from the external format in "string" to
* its internal format.
*
* return value :
* the internal representation of the input array
*/
Datum
array_in(PG_FUNCTION_ARGS)
{
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++)
/* skip */ ;
if (q == p) /* no digits? */
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", string),
errdetail("\"[\" must introduce explicitly-specified array dimensions.")));
if (*q == ':')
{
/* [m:n] format */
*q = '\0';
lBound[ndim] = atoi(p);
p = q + 1;
for (q = p; isdigit((unsigned char) *q) || (*q == '-') || (*q == '+'); q++)
/* skip */ ;
if (q == p) /* no digits? */
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", string),
errdetail("Missing array dimension value.")));
}
else
{
/* [n] format */
lBound[ndim] = 1;
}
if (*q != ']')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", string),
errdetail("Missing \"%s\" after 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("malformed array literal: \"%s\"", string),
errdetail("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("malformed array literal: \"%s\"", string),
errdetail("Missing \"%s\" after array dimensions.",
ASSGN)));
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("malformed array literal: \"%s\"", string),
errdetail("Array contents must start with \"{\".")));
ndim_braces = ArrayCount(p, dim_braces, typdelim);
if (ndim_braces != ndim)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", string),
errdetail("Specified array dimensions do not match array contents.")));
for (i = 0; i < ndim; ++i)
{
if (dim[i] != dim_braces[i])
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed array literal: \"%s\"", string),
errdetail("Specified array dimensions do not match array contents.")));
}
}
#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);
ArrayCheckBounds(ndim, dim, lBound);
/* 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);
}