@@ -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
/***************************************************************************/
0 commit comments