postgres.git / summary / log / commit / refs

commit    e0d59c6ef57bad6f9a4f1de0c5635be2eb7fea5a
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Thu Jan 05 16:33:51 2017 +0000
First released in: 10.0, 9.2.20, 9.3.16, 9.4.11, 9.5.6, 9.6.2

    Fix handling of empty arrays in array_fill().
    
    array_fill(..., array[0]) produced an empty array, which is probably
    what users expect, but it was a one-dimensional zero-length array
    which is not our standard representation of empty arrays.  Also, for
    no very good reason, it rejected empty input arrays; that case should
    be allowed and produce an empty output array.
    
    In passing, remove the restriction that the input array(s) have lower
    bound 1.  That seems rather pointless, and it would have needed extra
    complexity to make the check deal with empty input arrays.
    
    Per bug #14487 from Andrew Gierth.  It's been broken all along, so
    back-patch to all supported branches.
    
    Discussion: https://postgr.es/m/20170105152156.10135.64195@wrigleys.postgresql.org


src/backend/utils/adt/arrayfuncs.c | 26 +++++++------------------- src/test/regress/expected/arrays.out | 27 +++++++++++++++++++++++++++ src/test/regress/sql/arrays.sql | 8 ++++++++ 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 8ded5179cd3..f07009cda1d 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -4909,25 +4909,19 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, /* * Params checks */ - if (ARR_NDIM(dims) != 1) + if (ARR_NDIM(dims) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"), errdetail("Dimension array must be one dimensional."))); - if (ARR_LBOUND(dims)[0] != 1) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("wrong range of array subscripts"), - errdetail("Lower bound of dimension array must be one."))); - if (array_contains_nulls(dims)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("dimension values cannot be null"))); dimv = (int *) ARR_DATA_PTR(dims); - ndims = ARR_DIMS(dims)[0]; + ndims = (ARR_NDIM(dims) > 0) ? ARR_DIMS(dims)[0] : 0; if (ndims < 0) /* we do allow zero-dimension arrays */ ereport(ERROR, @@ -4941,24 +4935,18 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, if (lbs != NULL) { - if (ARR_NDIM(lbs) != 1) + if (ARR_NDIM(lbs) > 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"), errdetail("Dimension array must be one dimensional."))); - if (ARR_LBOUND(lbs)[0] != 1) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("wrong range of array subscripts"), - errdetail("Lower bound of dimension array must be one."))); - if (array_contains_nulls(lbs)) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("dimension values cannot be null"))); - if (ARR_DIMS(lbs)[0] != ndims) + if (ndims != ((ARR_NDIM(lbs) > 0) ? ARR_DIMS(lbs)[0] : 0)) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("wrong number of array subscripts"), @@ -4976,12 +4964,12 @@ array_fill_internal(ArrayType *dims, ArrayType *lbs, lbsv = deflbs; } + nitems = ArrayGetNItems(ndims, dimv); + /* fast track for empty array */ - if (ndims == 0) + if (nitems <= 0) return construct_empty_array(elmtype); - nitems = ArrayGetNItems(ndims, dimv); - /* * We arrange to look up info about element type only once per series of * calls, assuming the element type doesn't change underneath us. diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index d0df67d9ae2..481f3196f84 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -1290,16 +1290,43 @@ select array_fill('juhu'::text, array[3,3]); {{juhu,juhu,juhu},{juhu,juhu,juhu},{juhu,juhu,juhu}} (1 row) +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, array[0]) as a) ss; + a | is_eq | array_dims +----+-------+------------ + {} | t | +(1 row) + +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, '{}') as a) ss; + a | is_eq | array_dims +----+-------+------------ + {} | t | +(1 row) + +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, '{}', '{}') as a) ss; + a | is_eq | array_dims +----+-------+------------ + {} | t | +(1 row) + -- raise exception select array_fill(1, null, array[2,2]); ERROR: dimension array or low bound array cannot be null select array_fill(1, array[2,2], null); ERROR: dimension array or low bound array cannot be null +select array_fill(1, array[2,2], '{}'); +ERROR: wrong number of array subscripts +DETAIL: Low bound array has different size than dimensions array. select array_fill(1, array[3,3], array[1,1,1]); ERROR: wrong number of array subscripts DETAIL: Low bound array has different size than dimensions array. select array_fill(1, array[1,2,null]); ERROR: dimension values cannot be null +select array_fill(1, array[[1,2],[3,4]]); +ERROR: wrong number of array subscripts +DETAIL: Dimension array must be one dimensional. select string_to_array('1|2|3', '|'); string_to_array ----------------- diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql index 101822f574a..bda584bae20 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -383,11 +383,19 @@ select array_fill(7, array[3,3],array[2,2]); select array_fill(7, array[3,3]); select array_fill('juhu'::text, array[3,3],array[2,2]); select array_fill('juhu'::text, array[3,3]); +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, array[0]) as a) ss; +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, '{}') as a) ss; +select a, a = '{}' as is_eq, array_dims(a) + from (select array_fill(42, '{}', '{}') as a) ss; -- raise exception select array_fill(1, null, array[2,2]); select array_fill(1, array[2,2], null); +select array_fill(1, array[2,2], '{}'); select array_fill(1, array[3,3], array[1,1,1]); select array_fill(1, array[1,2,null]); +select array_fill(1, array[[1,2],[3,4]]); select string_to_array('1|2|3', '|'); select string_to_array('1|2|3|', '|'); [parent: 6c4cf2be81e4]