array_fill function

"Pavel Stehule" <[email protected]>
Newsgroups gmane.comp.db.postgresql.devel.patches
Message-ID <[email protected]>
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


-- 
Sent via pgsql-patches mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches
array_fill.diff (text/x-patch, 13.3 KB)
*** ./src/backend/utils/adt/arrayfuncs.c.orig	2008-06-05 08:16:09.000000000 +0200
--- ./src/backend/utils/adt/arrayfuncs.c	2008-06-06 05:56:56.000000000 +0200
***************
*** 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 should be one dimensional")));
+ 
+ 	if (ARR_LBOUND(dims)[0] != 1)
+ 		ereport(ERROR,
+ 			    (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ 			     errmsg("wrong range of array_subscripts"),
+ 			     errhint("lbound of dimension array is different than 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 should be one dimensional")));
+ 
+ 		if (ARR_LBOUND(lbs)[0] != 1)
+ 			ereport(ERROR,
+ 				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ 			         errmsg("wrong range of array_subscripts"),
+ 			    	 errhint("lbound of dimension array is different than 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;
+ }
*** ./src/include/catalog/pg_proc.h.orig	2008-06-05 08:39:47.000000000 +0200
--- ./src/include/catalog/pg_proc.h	2008-06-06 05:32:06.000000000 +0200
***************
*** 1014,1021 ****
  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_ ));
--- 1014,1023 ----
  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_ ));
*** ./src/include/utils/array.h.orig	2008-06-05 08:33:30.000000000 +0200
--- ./src/include/utils/array.h	2008-06-05 08:34:55.000000000 +0200
***************
*** 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,
*** ./src/test/regress/expected/arrays.out.orig	2008-06-06 06:05:05.000000000 +0200
--- ./src/test/regress/expected/arrays.out	2008-06-06 06:03:32.000000000 +0200
***************
*** 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
*** ./src/test/regress/sql/arrays.sql.orig	2008-06-06 05:59:32.000000000 +0200
--- ./src/test/regress/sql/arrays.sql	2008-06-06 06:02:32.000000000 +0200
***************
*** 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]);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.