Patch applied, with minor adjustments in error message wording, with
documntation added;  committed patch attached.

---------------------------------------------------------------------------

Pavel Stehule wrote:
> Hello
> 
> Proposal: http://archives.postgresql.org/pgsql-hackers/2008-06/msg00057.php
> 
> I changed name to array_fill and order of arguments.
> 
> postgres=# SELECT array_fill(0, ARRAY[2,3]);
>     array_fill
> -------------------
>  {{0,0,0},{0,0,0}}
> (1 row)
> 
> postgres=# SELECT array_fill(0, ARRAY[2,3], ARRAY[1,2]);
>           array_fill
> ------------------------------
>  [1:2][2:4]={{0,0,0},{0,0,0}}
> (1 row)
> 
> postgres=# SELECT array_fill(0, ARRAY[4], ARRAY[2]);
>    array_fill
> -----------------
>  [2:5]={0,0,0,0}
> (1 row)
> 
> postgres=# SELECT array_fill(NULL::int, ARRAY[4]);
>       array_fill
> -----------------------
>  {NULL,NULL,NULL,NULL}
> (1 row)
> 
> Regards
> Pavel Stehule

[ Attachment, skipping... ]

> 
> -- 
> Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-patches

-- 
  Bruce Momjian  <[EMAIL PROTECTED]>        http://momjian.us
  EnterpriseDB                             http://enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/func.sgml,v
retrieving revision 1.440
diff -c -c -r1.440 func.sgml
*** doc/src/sgml/func.sgml	15 Jul 2008 18:24:59 -0000	1.440
--- doc/src/sgml/func.sgml	16 Jul 2008 00:42:25 -0000
***************
*** 9374,9379 ****
--- 9374,9392 ----
         <row>
          <entry>
           <literal>
+           <function>array_fill</function>(<type>anyelement</type>, <type>anyarray</type>,
+           <optional>, <type>anyarray</type></optional>)
+          </literal>
+         </entry>
+         <entry><type>anyarray</type></entry>
+         <entry>returns an array initialized with supplied value,
+         dimensions, and lower bounds</entry>
+         <entry><literal>array_fill(7, ARRAY[3], ARRAY[2])</literal></entry>
+         <entry><literal>[2:4]={7,7,7}</literal></entry>
+        </row>
+        <row>
+         <entry>
+          <literal>
            <function>array_lower</function>(<type>anyarray</type>, <type>int</type>)
           </literal>
          </entry>
Index: src/backend/utils/adt/arrayfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v
retrieving revision 1.145
diff -c -c -r1.145 arrayfuncs.c
*** src/backend/utils/adt/arrayfuncs.c	12 May 2008 00:00:51 -0000	1.145
--- src/backend/utils/adt/arrayfuncs.c	16 Jul 2008 00:42:26 -0000
***************
*** 95,100 ****
--- 95,105 ----
  				   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 *lbv, int nbytes,
+ 			    Oid elmtype, int dataoffset);
+ static ArrayType *array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value, 
+ 					    Oid elmtype, bool isnull, 
+ 					    FunctionCallInfo fcinfo);
  
  
  /*
***************
*** 4314,4316 ****
--- 4319,4590 ----
  	/* just call the other one -- it can handle both cases */
  	return generate_subscripts(fcinfo);
  }
+ 
+ /*
+  * array_fill_with_lower_bounds
+  *		Create and fill array with defined lower bounds.
+  */
+ Datum
+ array_fill_with_lower_bounds(PG_FUNCTION_ARGS)
+ {
+ 	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, elmtype, isnull, fcinfo);
+ 	PG_RETURN_ARRAYTYPE_P(result);
+ }
+ 
+ /*
+  * array_fill
+  *		Create and fill array with default lower bounds.
+  */
+ Datum
+ array_fill(PG_FUNCTION_ARGS)
+ {
+ 	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, elmtype, isnull, fcinfo);
+ 	PG_RETURN_ARRAYTYPE_P(result);
+ }
+ 
+ static ArrayType *
+ create_array_envelope(int ndims, int *dimv, int *lbsv, int nbytes,
+ 			    Oid elmtype, int dataoffset)
+ {
+ 	ArrayType *result;
+ 
+ 	result = (ArrayType *) palloc0(nbytes);
+ 	SET_VARSIZE(result, nbytes);
+ 	result->ndim = ndims;
+ 	result->dataoffset = dataoffset;
+ 	result->elemtype = elmtype;
+ 	memcpy(ARR_DIMS(result), dimv, ndims * sizeof(int));
+ 	memcpy(ARR_LBOUND(result), lbsv, ndims * sizeof(int));
+ 
+ 	return result;
+ }
+ 
+ static ArrayType *
+ array_fill_internal(ArrayType *dims, ArrayType *lbs, Datum value, 
+ 					    Oid elmtype, bool isnull,
+ 					    FunctionCallInfo fcinfo)
+ {
+ 	ArrayType	*result;
+ 	int	*dimv;
+ 	int	*lbsv;
+ 	int	ndims;
+ 	int	nitems;
+ 	int 		deflbs[MAXDIM];
+ 	int16 elmlen; 
+ 	bool elmbyval; 
+ 	char elmalign;
+ 	ArrayMetaState 		*my_extra;
+ 
+ 	/* 
+ 	 * Params checks
+ 	 */
+ 	if (ARR_NDIM(dims) != 1)
+ 		ereport(ERROR,
+ 			    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ 			     errmsg("wrong number of array subscripts"),
+ 			     errhint("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"),
+ 			     errhint("Lower bound of dimension array must be one.")));
+ 	
+ 	if (ARR_HASNULL(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];
+ 	
+ 	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)));
+ 	
+ 	if (lbs != NULL)
+ 	{
+ 		if (ARR_NDIM(lbs) != 1)
+ 			ereport(ERROR,
+ 				    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ 			    	     errmsg("wrong number of array subscripts"),
+ 			    	     errhint("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"),
+ 			    	 errhint("Lower bound of dimension array must be one.")));
+ 	
+ 		if (ARR_HASNULL(lbs))
+ 			ereport(ERROR, 
+ 				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+ 				 errmsg("dimension values cannot be null")));
+ 
+ 		if (ARR_DIMS(lbs)[0] != ndims)
+ 			ereport(ERROR,
+ 				    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ 				     errmsg("wrong number of array_subscripts"),
+ 				     errhint("Low bound array has different size than dimensions array.")));
+ 				     
+ 		lbsv = (int *) ARR_DATA_PTR(lbs);
+ 	}
+ 	else	
+ 	{
+ 		int	i;
+ 	
+ 		for (i = 0; i < MAXDIM; i++)
+ 			deflbs[i] = 1;
+ 
+ 		lbsv = deflbs;
+ 	}
+ 
+ 	/* fast track for empty array */
+ 	if (ndims == 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.
+ 	 */
+ 	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 = InvalidOid;
+ 	}
+ 
+ 	if (my_extra->element_type != elmtype)
+ 	{
+ 		/* Get info about element type */
+ 		get_typlenbyvalalign(elmtype,
+ 							 &my_extra->typlen,
+ 							 &my_extra->typbyval,
+ 							 &my_extra->typalign);
+ 		my_extra->element_type = elmtype;
+ 	}
+ 
+ 	elmlen = my_extra->typlen;
+ 	elmbyval = my_extra->typbyval;
+ 	elmalign = my_extra->typalign;
+ 
+ 	/* compute required space */
+ 	if (!isnull)
+ 	{
+ 		int 	i;
+ 		char		*p;
+ 		int			nbytes;
+ 		Datum	aux_value = value;
+ 
+ 		/* make sure data is not toasted */
+ 		if (elmlen == -1)
+ 			value = PointerGetDatum(PG_DETOAST_DATUM(value));
+ 
+ 		nbytes = att_addlength_datum(0, elmlen, value);
+ 		nbytes = att_align_nominal(nbytes, elmalign);
+ 
+ 		nbytes *= nitems;
+ 		/* 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)));
+ 
+ 		nbytes += ARR_OVERHEAD_NONULLS(ndims);
+ 		result = create_array_envelope(ndims, dimv, lbsv, nbytes,
+ 							elmtype, 0);
+ 		p = ARR_DATA_PTR(result);
+ 		for (i = 0; i < nitems; i++)
+ 			p += ArrayCastAndSet(value, elmlen, elmbyval, elmalign, p);
+ 
+ 		/* cleaning up detoasted copies of datum */
+ 		if (aux_value != value)
+ 			pfree((Pointer) value);
+ 	}
+ 	else
+ 	{
+ 		int	nbytes;
+ 		int	dataoffset;
+ 		bits8	*bitmap;
+ 
+ 		dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
+ 		nbytes = dataoffset;
+ 
+ 		result = create_array_envelope(ndims, dimv, lbsv, nbytes,
+ 							elmtype, dataoffset);
+ 		bitmap = ARR_NULLBITMAP(result);
+ 		MemSet(bitmap, 0, (nitems + 7) / 8);
+ 	}
+ 		
+ 	return result;
+ }
Index: src/include/catalog/catversion.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/catversion.h,v
retrieving revision 1.467
diff -c -c -r1.467 catversion.h
*** src/include/catalog/catversion.h	14 Jul 2008 00:51:45 -0000	1.467
--- src/include/catalog/catversion.h	16 Jul 2008 00:42:27 -0000
***************
*** 53,58 ****
   */
  
  /*							yyyymmddN */
! #define CATALOG_VERSION_NO	200807131
  
  #endif
--- 53,58 ----
   */
  
  /*							yyyymmddN */
! #define CATALOG_VERSION_NO	200807151
  
  #endif
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.505
diff -c -c -r1.505 pg_proc.h
*** src/include/catalog/pg_proc.h	14 Jul 2008 00:51:45 -0000	1.505
--- src/include/catalog/pg_proc.h	16 Jul 2008 00:42:27 -0000
***************
*** 1010,1017 ****
  DESCR("array subscripts generator");
  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_ ));
  DESCR("array subscripts generator");
! 
! 
  DATA(insert OID = 760 (  smgrin			   PGNSP PGUID 12 1 0 f f t f s 1 210 "2275" _null_ _null_ _null_  smgrin - _null_ _null_ ));
  DESCR("I/O");
  DATA(insert OID = 761 (  smgrout		   PGNSP PGUID 12 1 0 f f t f s 1 2275 "210" _null_ _null_ _null_  smgrout - _null_ _null_ ));
--- 1010,1019 ----
  DESCR("array subscripts generator");
  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_ ));
  DESCR("array subscripts generator");
! 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_ ));
! DESCR("array constructor with value");
! 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_ ));
! DESCR("array constructor with value");
  DATA(insert OID = 760 (  smgrin			   PGNSP PGUID 12 1 0 f f t f s 1 210 "2275" _null_ _null_ _null_  smgrin - _null_ _null_ ));
  DESCR("I/O");
  DATA(insert OID = 761 (  smgrout		   PGNSP PGUID 12 1 0 f f t f s 1 2275 "210" _null_ _null_ _null_  smgrout - _null_ _null_ ));
Index: src/include/utils/array.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/utils/array.h,v
retrieving revision 1.67
diff -c -c -r1.67 array.h
*** src/include/utils/array.h	28 Apr 2008 14:48:57 -0000	1.67
--- src/include/utils/array.h	16 Jul 2008 00:42:28 -0000
***************
*** 202,207 ****
--- 202,209 ----
  extern Datum array_smaller(PG_FUNCTION_ARGS);
  extern Datum generate_subscripts(PG_FUNCTION_ARGS);
  extern Datum generate_subscripts_nodir(PG_FUNCTION_ARGS);
+ extern Datum array_fill(PG_FUNCTION_ARGS);
+ extern Datum array_fill_with_lower_bounds(PG_FUNCTION_ARGS);
  
  extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
  		  int arraytyplen, int elmlen, bool elmbyval, char elmalign,
Index: src/test/regress/expected/arrays.out
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/expected/arrays.out,v
retrieving revision 1.36
diff -c -c -r1.36 arrays.out
*** src/test/regress/expected/arrays.out	28 Apr 2008 14:48:57 -0000	1.36
--- src/test/regress/expected/arrays.out	16 Jul 2008 00:42:28 -0000
***************
*** 933,935 ****
--- 933,993 ----
  
  drop function unnest1(anyarray);
  drop function unnest2(anyarray);
+ select array_fill(null::integer, array[3,3],array[2,2]);
+                            array_fill                            
+ -----------------------------------------------------------------
+  [2:4][2:4]={{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,NULL}}
+ (1 row)
+ 
+ select array_fill(null::integer, array[3,3]);
+                       array_fill                      
+ ------------------------------------------------------
+  {{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,NULL}}
+ (1 row)
+ 
+ select array_fill(null::text, array[3,3],array[2,2]);
+                            array_fill                            
+ -----------------------------------------------------------------
+  [2:4][2:4]={{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,NULL}}
+ (1 row)
+ 
+ select array_fill(null::text, array[3,3]);
+                       array_fill                      
+ ------------------------------------------------------
+  {{NULL,NULL,NULL},{NULL,NULL,NULL},{NULL,NULL,NULL}}
+ (1 row)
+ 
+ select array_fill(7, array[3,3],array[2,2]);
+               array_fill              
+ --------------------------------------
+  [2:4][2:4]={{7,7,7},{7,7,7},{7,7,7}}
+ (1 row)
+ 
+ select array_fill(7, array[3,3]);
+         array_fill         
+ ---------------------------
+  {{7,7,7},{7,7,7},{7,7,7}}
+ (1 row)
+ 
+ select array_fill('juhu'::text, array[3,3],array[2,2]);
+                            array_fill                            
+ -----------------------------------------------------------------
+  [2:4][2:4]={{juhu,juhu,juhu},{juhu,juhu,juhu},{juhu,juhu,juhu}}
+ (1 row)
+ 
+ select array_fill('juhu'::text, array[3,3]);
+                       array_fill                      
+ ------------------------------------------------------
+  {{juhu,juhu,juhu},{juhu,juhu,juhu},{juhu,juhu,juhu}}
+ (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[3,3], array[1,1,1]);
+ ERROR:  wrong number of array_subscripts
+ HINT:  Low bound array has different size than dimensions array.
+ select array_fill(1, array[1,2,null]);
+ ERROR:  dimension values cannot be null
Index: src/test/regress/sql/arrays.sql
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/sql/arrays.sql,v
retrieving revision 1.28
diff -c -c -r1.28 arrays.sql
*** src/test/regress/sql/arrays.sql	28 Apr 2008 14:48:58 -0000	1.28
--- src/test/regress/sql/arrays.sql	16 Jul 2008 00:42:28 -0000
***************
*** 357,359 ****
--- 357,373 ----
  
  drop function unnest1(anyarray);
  drop function unnest2(anyarray);
+ 
+ select array_fill(null::integer, array[3,3],array[2,2]);
+ select array_fill(null::integer, array[3,3]);
+ select array_fill(null::text, array[3,3],array[2,2]);
+ select array_fill(null::text, array[3,3]);
+ 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]);
+ -- raise exception
+ select array_fill(1, null, array[2,2]);
+ select array_fill(1, array[2,2], null);
+ select array_fill(1, array[3,3], array[1,1,1]);
+ select array_fill(1, array[1,2,null]);
-- 
Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches

Reply via email to