@@ -50,6 +50,30 @@ typedef enum
50
50
ARRAY_LEVEL_DELIMITED
51
51
}ArrayParseState ;
52
52
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
+
53
77
static bool array_isspace (char ch );
54
78
static int ArrayCount (const char * str ,int * dim ,char typdelim );
55
79
static void ReadArrayStr (char * arrayStr ,const char * origStr ,
@@ -3833,6 +3857,188 @@ arraycontained(PG_FUNCTION_ARGS)
3833
3857
}
3834
3858
3835
3859
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
+
3836
4042
/***************************************************************************/
3837
4043
/******************| Support Routines |*****************/
3838
4044
/***************************************************************************/