Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2c77329

Browse files
committed
Add array_fill() to create arrays initialized with a value.
Pavel Stehule
1 parent 2fa42cc commit 2c77329

File tree

7 files changed

+371
-8
lines changed

7 files changed

+371
-8
lines changed

doc/src/sgml/func.sgml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.440 2008/07/15 18:24:59 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.441 2008/07/16 00:48:53 momjian Exp $ -->
22

33
<chapter id="functions">
44
<title>Functions and Operators</title>
@@ -9371,6 +9371,19 @@ SELECT NULLIF(value, '(none)') ...
93719371
<entry><literal>array_dims(ARRAY[[1,2,3], [4,5,6]])</literal></entry>
93729372
<entry><literal>[1:2][1:3]</literal></entry>
93739373
</row>
9374+
<row>
9375+
<entry>
9376+
<literal>
9377+
<function>array_fill</function>(<type>anyelement</type>, <type>anyarray</type>,
9378+
<optional>, <type>anyarray</type></optional>)
9379+
</literal>
9380+
</entry>
9381+
<entry><type>anyarray</type></entry>
9382+
<entry>returns an array initialized with supplied value,
9383+
dimensions, and lower bounds</entry>
9384+
<entry><literal>array_fill(7, ARRAY[3], ARRAY[2])</literal></entry>
9385+
<entry><literal>[2:4]={7,7,7}</literal></entry>
9386+
</row>
93749387
<row>
93759388
<entry>
93769389
<literal>

src/backend/utils/adt/arrayfuncs.c

Lines changed: 275 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.145 2008/05/12 00:00:51 alvherre Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.146 2008/07/16 00:48:53 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -95,6 +95,11 @@ static void array_insert_slice(ArrayType *destArray, ArrayType *origArray,
9595
int *st, int *endp,
9696
int typlen, bool typbyval, char typalign);
9797
static int array_cmp(FunctionCallInfo fcinfo);
98+
static ArrayType *create_array_envelope(int ndims, int *dimv, int *lbv, int nbytes,
99+
Oid elmtype, int dataoffset);
100+
static ArrayType *array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value,
101+
Oid elmtype, bool isnull,
102+
FunctionCallInfo fcinfo);
98103

99104

100105
/*
@@ -4314,3 +4319,272 @@ generate_subscripts_nodir(PG_FUNCTION_ARGS)
43144319
/* just call the other one -- it can handle both cases */
43154320
return generate_subscripts(fcinfo);
43164321
}
4322+
4323+
/*
4324+
* array_fill_with_lower_bounds
4325+
* Create and fill array with defined lower bounds.
4326+
*/
4327+
Datum
4328+
array_fill_with_lower_bounds(PG_FUNCTION_ARGS)
4329+
{
4330+
ArrayType *dims;
4331+
ArrayType *lbs;
4332+
ArrayType *result;
4333+
Oid elmtype;
4334+
Datum value;
4335+
bool isnull;
4336+
4337+
if (PG_ARGISNULL(1) || PG_ARGISNULL(2))
4338+
ereport(ERROR,
4339+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4340+
errmsg("dimension array or low bound array cannot be NULL")));
4341+
4342+
dims = PG_GETARG_ARRAYTYPE_P(1);
4343+
lbs = PG_GETARG_ARRAYTYPE_P(2);
4344+
4345+
if (!PG_ARGISNULL(0))
4346+
{
4347+
value = PG_GETARG_DATUM(0);
4348+
isnull = false;
4349+
}
4350+
else
4351+
{
4352+
value = 0;
4353+
isnull = true;
4354+
}
4355+
4356+
elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
4357+
if (!OidIsValid(elmtype))
4358+
elog(ERROR, "could not determine data type of input");
4359+
4360+
result = array_fill_internal(dims, lbs, value, elmtype, isnull, fcinfo);
4361+
PG_RETURN_ARRAYTYPE_P(result);
4362+
}
4363+
4364+
/*
4365+
* array_fill
4366+
* Create and fill array with default lower bounds.
4367+
*/
4368+
Datum
4369+
array_fill(PG_FUNCTION_ARGS)
4370+
{
4371+
ArrayType *dims;
4372+
ArrayType *result;
4373+
Oid elmtype;
4374+
Datum value;
4375+
bool isnull;
4376+
4377+
if (PG_ARGISNULL(1))
4378+
ereport(ERROR,
4379+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4380+
errmsg("dimension array or low bound array cannot be NULL")));
4381+
4382+
dims = PG_GETARG_ARRAYTYPE_P(1);
4383+
4384+
if (!PG_ARGISNULL(0))
4385+
{
4386+
value = PG_GETARG_DATUM(0);
4387+
isnull = false;
4388+
}
4389+
else
4390+
{
4391+
value = 0;
4392+
isnull = true;
4393+
}
4394+
4395+
elmtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
4396+
if (!OidIsValid(elmtype))
4397+
elog(ERROR, "could not determine data type of input");
4398+
4399+
result = array_fill_internal(dims, NULL, value, elmtype, isnull, fcinfo);
4400+
PG_RETURN_ARRAYTYPE_P(result);
4401+
}
4402+
4403+
static ArrayType *
4404+
create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes,
4405+
Oid elmtype, int dataoffset)
4406+
{
4407+
ArrayType *result;
4408+
4409+
result = (ArrayType *) palloc0(nbytes);
4410+
SET_VARSIZE(result, nbytes);
4411+
result->ndim = ndims;
4412+
result->dataoffset = dataoffset;
4413+
result->elemtype = elmtype;
4414+
memcpy(ARR_DIMS(result), dimv, ndims * sizeof(int));
4415+
memcpy(ARR_LBOUND(result), lbsv, ndims * sizeof(int));
4416+
4417+
return result;
4418+
}
4419+
4420+
static ArrayType *
4421+
array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value,
4422+
Oid elmtype, bool isnull,
4423+
FunctionCallInfo fcinfo)
4424+
{
4425+
ArrayType *result;
4426+
int *dimv;
4427+
int *lbsv;
4428+
int ndims;
4429+
int nitems;
4430+
int deflbs[MAXDIM];
4431+
int16 elmlen;
4432+
bool elmbyval;
4433+
char elmalign;
4434+
ArrayMetaState *my_extra;
4435+
4436+
/*
4437+
* Params checks
4438+
*/
4439+
if (ARR_NDIM(dims) != 1)
4440+
ereport(ERROR,
4441+
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4442+
errmsg("wrong number of array subscripts"),
4443+
errhint("Dimension array must be one dimensional.")));
4444+
4445+
if (ARR_LBOUND(dims)[0] != 1)
4446+
ereport(ERROR,
4447+
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4448+
errmsg("wrong range of array_subscripts"),
4449+
errhint("Lower bound of dimension array must be one.")));
4450+
4451+
if (ARR_HASNULL(dims))
4452+
ereport(ERROR,
4453+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4454+
errmsg("dimension values cannot be null")));
4455+
4456+
dimv = (int *) ARR_DATA_PTR(dims);
4457+
ndims = ARR_DIMS(dims)[0];
4458+
4459+
if (ndims < 0) /* we do allow zero-dimension arrays */
4460+
ereport(ERROR,
4461+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4462+
errmsg("invalid number of dimensions: %d", ndims)));
4463+
if (ndims > MAXDIM)
4464+
ereport(ERROR,
4465+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
4466+
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
4467+
ndims, MAXDIM)));
4468+
4469+
if (lbs != NULL)
4470+
{
4471+
if (ARR_NDIM(lbs) != 1)
4472+
ereport(ERROR,
4473+
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4474+
errmsg("wrong number of array subscripts"),
4475+
errhint("Dimension array must be one dimensional.")));
4476+
4477+
if (ARR_LBOUND(lbs)[0] != 1)
4478+
ereport(ERROR,
4479+
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4480+
errmsg("wrong range of array_subscripts"),
4481+
errhint("Lower bound of dimension array must be one.")));
4482+
4483+
if (ARR_HASNULL(lbs))
4484+
ereport(ERROR,
4485+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
4486+
errmsg("dimension values cannot be null")));
4487+
4488+
if (ARR_DIMS(lbs)[0] != ndims)
4489+
ereport(ERROR,
4490+
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
4491+
errmsg("wrong number of array_subscripts"),
4492+
errhint("Low bound array has different size than dimensions array.")));
4493+
4494+
lbsv = (int *) ARR_DATA_PTR(lbs);
4495+
}
4496+
else
4497+
{
4498+
int i;
4499+
4500+
for (i = 0; i < MAXDIM; i++)
4501+
deflbs[i] = 1;
4502+
4503+
lbsv = deflbs;
4504+
}
4505+
4506+
/* fast track for empty array */
4507+
if (ndims == 0)
4508+
return construct_empty_array(elmtype);
4509+
4510+
nitems = ArrayGetNItems(ndims, dimv);
4511+
4512+
4513+
/*
4514+
* We arrange to look up info about element type only once per series of
4515+
* calls, assuming the element type doesn't change underneath us.
4516+
*/
4517+
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
4518+
if (my_extra == NULL)
4519+
{
4520+
fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
4521+
sizeof(ArrayMetaState));
4522+
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
4523+
my_extra->element_type = InvalidOid;
4524+
}
4525+
4526+
if (my_extra->element_type != elmtype)
4527+
{
4528+
/* Get info about element type */
4529+
get_typlenbyvalalign(elmtype,
4530+
&my_extra->typlen,
4531+
&my_extra->typbyval,
4532+
&my_extra->typalign);
4533+
my_extra->element_type = elmtype;
4534+
}
4535+
4536+
elmlen = my_extra->typlen;
4537+
elmbyval = my_extra->typbyval;
4538+
elmalign = my_extra->typalign;
4539+
4540+
/* compute required space */
4541+
if (!isnull)
4542+
{
4543+
int i;
4544+
char *p;
4545+
int nbytes;
4546+
Datum aux_value = value;
4547+
4548+
/* make sure data is not toasted */
4549+
if (elmlen == -1)
4550+
value = PointerGetDatum(PG_DETOAST_DATUM(value));
4551+
4552+
nbytes = att_addlength_datum(0, elmlen, value);
4553+
nbytes = att_align_nominal(nbytes, elmalign);
4554+
4555+
nbytes *= nitems;
4556+
/* check for overflow of total request */
4557+
if (!AllocSizeIsValid(nbytes))
4558+
ereport(ERROR,
4559+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
4560+
errmsg("array size exceeds the maximum allowed (%d)",
4561+
(int) MaxAllocSize)));
4562+
4563+
nbytes += ARR_OVERHEAD_NONULLS(ndims);
4564+
result = create_array_envelope(ndims, dimv, lbsv, nbytes,
4565+
elmtype, 0);
4566+
p = ARR_DATA_PTR(result);
4567+
for (i = 0; i < nitems; i++)
4568+
p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p);
4569+
4570+
/* cleaning up detoasted copies of datum */
4571+
if (aux_value != value)
4572+
pfree((Pointer) value);
4573+
}
4574+
else
4575+
{
4576+
int nbytes;
4577+
int dataoffset;
4578+
bits8 *bitmap;
4579+
4580+
dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
4581+
nbytes = dataoffset;
4582+
4583+
result = create_array_envelope(ndims, dimv, lbsv, nbytes,
4584+
elmtype, dataoffset);
4585+
bitmap = ARR_NULLBITMAP(result);
4586+
MemSet(bitmap, 0, (nitems + 7) / 8);
4587+
}
4588+
4589+
return result;
4590+
}

src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.467 2008/07/14 00:51:45 tgl Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.468 2008/07/16 00:48:53 momjian Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 200807131
56+
#define CATALOG_VERSION_NO 200807151
5757

5858
#endif

src/include/catalog/pg_proc.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.505 2008/07/14 00:51:45 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.506 2008/07/16 00:48:53 momjian Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.sh reads this file and generates .bki
@@ -1010,8 +1010,10 @@ DATA(insert OID = 1191 ( generate_subscripts PGNSP PGUID 12 1 1000 f f t t i 3
10101010
DESCR("array subscripts generator");
10111011
DATA(insert OID = 1192 ( generate_subscripts PGNSP PGUID 12 1 1000 f f t t i 2 23 "2277 23" _null_ _null_ _null_ generate_subscripts_nodir - _null_ _null_ ));
10121012
DESCR("array subscripts generator");
1013-
1014-
1013+
DATA(insert OID = 1193 ( array_fill PGNSP PGUID 12 1 0 f f f f i 2 2277 "2283 1007" _null_ _null_ _null_ array_fill - _null_ _null_ ));
1014+
DESCR("array constructor with value");
1015+
DATA(insert OID = 1286 ( array_fill PGNSP PGUID 12 1 0 f f f f i 3 2277 "2283 1007 1007" _null_ _null_ _null_ array_fill_with_lower_bounds - _null_ _null_ ));
1016+
DESCR("array constructor with value");
10151017
DATA(insert OID = 760 ( smgrin PGNSP PGUID 12 1 0 f f t f s 1 210 "2275" _null_ _null_ _null_ smgrin - _null_ _null_ ));
10161018
DESCR("I/O");
10171019
DATA(insert OID = 761 ( smgrout PGNSP PGUID 12 1 0 f f t f s 1 2275 "210" _null_ _null_ _null_ smgrout - _null_ _null_ ));

src/include/utils/array.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
5050
* Portions Copyright (c) 1994, Regents of the University of California
5151
*
52-
* $PostgreSQL: pgsql/src/include/utils/array.h,v 1.67 2008/04/28 14:48:57 alvherre Exp $
52+
* $PostgreSQL: pgsql/src/include/utils/array.h,v 1.68 2008/07/16 00:48:54 momjian Exp $
5353
*
5454
*-------------------------------------------------------------------------
5555
*/
@@ -202,6 +202,8 @@ extern Datum array_larger(PG_FUNCTION_ARGS);
202202
extern Datum array_smaller(PG_FUNCTION_ARGS);
203203
extern Datum generate_subscripts(PG_FUNCTION_ARGS);
204204
extern Datum generate_subscripts_nodir(PG_FUNCTION_ARGS);
205+
extern Datum array_fill(PG_FUNCTION_ARGS);
206+
extern Datum array_fill_with_lower_bounds(PG_FUNCTION_ARGS);
205207

206208
extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
207209
int arraytyplen, int elmlen, bool elmbyval, char elmalign,

0 commit comments

Comments
 (0)