@@ -50,6 +50,30 @@ typedef enum
5050ARRAY_LEVEL_DELIMITED
5151}ArrayParseState ;
5252
53+ /* Working state for array_iterate() */
54+ typedef struct ArrayIteratorData
55+ {
56+ /* basic info about the array, set up during array_create_iterator() */
57+ ArrayType * arr ;/* array we're iterating through */
58+ bits8 * nullbitmap ;/* its null bitmap, if any */
59+ int nitems ;/* total number of elements in array */
60+ int16 typlen ;/* element type's length */
61+ bool typbyval ;/* element type's byval property */
62+ char typalign ;/* element type's align property */
63+
64+ /* information about the requested slice size */
65+ int slice_ndim ;/* slice dimension, or 0 if not slicing */
66+ int slice_len ;/* number of elements per slice */
67+ int * slice_dims ;/* slice dims array */
68+ int * slice_lbound ;/* slice lbound array */
69+ Datum * slice_values ;/* workspace of length slice_len */
70+ bool * slice_nulls ;/* workspace of length slice_len */
71+
72+ /* current position information, updated on each iteration */
73+ char * data_ptr ;/* our current position in the array */
74+ int current_item ;/* the item # we're at in the array */
75+ }ArrayIteratorData ;
76+
5377static bool array_isspace (char ch );
5478static int ArrayCount (const char * str ,int * dim ,char typdelim );
5579static void ReadArrayStr (char * arrayStr ,const char * origStr ,
@@ -3833,6 +3857,188 @@ arraycontained(PG_FUNCTION_ARGS)
38333857}
38343858
38353859
3860+ /*-----------------------------------------------------------------------------
3861+ * Array iteration functions
3862+ *These functions are used to iterate efficiently through arrays
3863+ *-----------------------------------------------------------------------------
3864+ */
3865+
3866+ /*
3867+ * array_create_iterator --- set up to iterate through an array
3868+ *
3869+ * If slice_ndim is zero, we will iterate element-by-element; the returned
3870+ * datums are of the array's element type.
3871+ *
3872+ * If slice_ndim is 1..ARR_NDIM(arr), we will iterate by slices: the
3873+ * returned datums are of the same array type as 'arr', but of size
3874+ * equal to the rightmost N dimensions of 'arr'.
3875+ *
3876+ * The passed-in array must remain valid for the lifetime of the iterator.
3877+ */
3878+ ArrayIterator
3879+ array_create_iterator (ArrayType * arr ,int slice_ndim )
3880+ {
3881+ ArrayIterator iterator = palloc0 (sizeof (ArrayIteratorData ));
3882+
3883+ /*
3884+ * Sanity-check inputs --- caller should have got this right already
3885+ */
3886+ Assert (PointerIsValid (arr ));
3887+ if (slice_ndim < 0 || slice_ndim > ARR_NDIM (arr ))
3888+ elog (ERROR ,"invalid arguments to array_create_iterator" );
3889+
3890+ /*
3891+ * Remember basic info about the array and its element type
3892+ */
3893+ iterator -> arr = arr ;
3894+ iterator -> nullbitmap = ARR_NULLBITMAP (arr );
3895+ iterator -> nitems = ArrayGetNItems (ARR_NDIM (arr ),ARR_DIMS (arr ));
3896+ get_typlenbyvalalign (ARR_ELEMTYPE (arr ),
3897+ & iterator -> typlen ,
3898+ & iterator -> typbyval ,
3899+ & iterator -> typalign );
3900+
3901+ /*
3902+ * Remember the slicing parameters.
3903+ */
3904+ iterator -> slice_ndim = slice_ndim ;
3905+
3906+ if (slice_ndim > 0 )
3907+ {
3908+ /*
3909+ * Get pointers into the array's dims and lbound arrays to represent
3910+ * the dims/lbound arrays of a slice. These are the same as the
3911+ * rightmost N dimensions of the array.
3912+ */
3913+ iterator -> slice_dims = ARR_DIMS (arr )+ ARR_NDIM (arr )- slice_ndim ;
3914+ iterator -> slice_lbound = ARR_LBOUND (arr )+ ARR_NDIM (arr )- slice_ndim ;
3915+
3916+ /*
3917+ * Compute number of elements in a slice.
3918+ */
3919+ iterator -> slice_len = ArrayGetNItems (slice_ndim ,
3920+ iterator -> slice_dims );
3921+
3922+ /*
3923+ * Create workspace for building sub-arrays.
3924+ */
3925+ iterator -> slice_values = (Datum * )
3926+ palloc (iterator -> slice_len * sizeof (Datum ));
3927+ iterator -> slice_nulls = (bool * )
3928+ palloc (iterator -> slice_len * sizeof (bool ));
3929+ }
3930+
3931+ /*
3932+ * Initialize our data pointer and linear element number. These will
3933+ * advance through the array during array_iterate().
3934+ */
3935+ iterator -> data_ptr = ARR_DATA_PTR (arr );
3936+ iterator -> current_item = 0 ;
3937+
3938+ return iterator ;
3939+ }
3940+
3941+ /*
3942+ * Iterate through the array referenced by 'iterator'.
3943+ *
3944+ * As long as there is another element (or slice), return it into
3945+ * *value / *isnull, and return true. Return false when no more data.
3946+ */
3947+ bool
3948+ array_iterate (ArrayIterator iterator ,Datum * value ,bool * isnull )
3949+ {
3950+ /* Done if we have reached the end of the array */
3951+ if (iterator -> current_item >=iterator -> nitems )
3952+ return false;
3953+
3954+ if (iterator -> slice_ndim == 0 )
3955+ {
3956+ /*
3957+ * Scalar case: return one element.
3958+ */
3959+ if (array_get_isnull (iterator -> nullbitmap ,iterator -> current_item ++ ))
3960+ {
3961+ * isnull = true;
3962+ * value = (Datum )0 ;
3963+ }
3964+ else
3965+ {
3966+ /* non-NULL, so fetch the individual Datum to return */
3967+ char * p = iterator -> data_ptr ;
3968+
3969+ * isnull = false;
3970+ * value = fetch_att (p ,iterator -> typbyval ,iterator -> typlen );
3971+
3972+ /* Move our data pointer forward to the next element */
3973+ p = att_addlength_pointer (p ,iterator -> typlen ,p );
3974+ p = (char * )att_align_nominal (p ,iterator -> typalign );
3975+ iterator -> data_ptr = p ;
3976+ }
3977+ }
3978+ else
3979+ {
3980+ /*
3981+ * Slice case: build and return an array of the requested size.
3982+ */
3983+ ArrayType * result ;
3984+ Datum * values = iterator -> slice_values ;
3985+ bool * nulls = iterator -> slice_nulls ;
3986+ char * p = iterator -> data_ptr ;
3987+ int i ;
3988+
3989+ for (i = 0 ;i < iterator -> slice_len ;i ++ )
3990+ {
3991+ if (array_get_isnull (iterator -> nullbitmap ,
3992+ iterator -> current_item ++ ))
3993+ {
3994+ nulls [i ]= true;
3995+ values [i ]= (Datum )0 ;
3996+ }
3997+ else
3998+ {
3999+ nulls [i ]= false;
4000+ values [i ]= fetch_att (p ,iterator -> typbyval ,iterator -> typlen );
4001+
4002+ /* Move our data pointer forward to the next element */
4003+ p = att_addlength_pointer (p ,iterator -> typlen ,p );
4004+ p = (char * )att_align_nominal (p ,iterator -> typalign );
4005+ }
4006+ }
4007+
4008+ iterator -> data_ptr = p ;
4009+
4010+ result = construct_md_array (values ,
4011+ nulls ,
4012+ iterator -> slice_ndim ,
4013+ iterator -> slice_dims ,
4014+ iterator -> slice_lbound ,
4015+ ARR_ELEMTYPE (iterator -> arr ),
4016+ iterator -> typlen ,
4017+ iterator -> typbyval ,
4018+ iterator -> typalign );
4019+
4020+ * isnull = false;
4021+ * value = PointerGetDatum (result );
4022+ }
4023+
4024+ return true;
4025+ }
4026+
4027+ /*
4028+ * Release an ArrayIterator data structure
4029+ */
4030+ void
4031+ array_free_iterator (ArrayIterator iterator )
4032+ {
4033+ if (iterator -> slice_ndim > 0 )
4034+ {
4035+ pfree (iterator -> slice_values );
4036+ pfree (iterator -> slice_nulls );
4037+ }
4038+ pfree (iterator );
4039+ }
4040+
4041+
38364042/***************************************************************************/
38374043/******************| Support Routines |*****************/
38384044/***************************************************************************/