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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy