1use rupg_common::SqlState;
6
7use crate::array::{Array, ArrayDim, MAX_ARRAY_SIZE, MAXDIM, item_count};
8use crate::error::TypeError;
9
10fn subscript_error(message: &str) -> TypeError {
11 TypeError::new(SqlState::ARRAY_SUBSCRIPT_ERROR, message.to_string())
12}
13
14fn too_large() -> TypeError {
15 TypeError::new(
16 SqlState::PROGRAM_LIMIT_EXCEEDED,
17 format!("array size exceeds the maximum allowed ({MAX_ARRAY_SIZE})"),
18 )
19}
20
21fn check_bounds(dims: &[ArrayDim]) -> Result<(), TypeError> {
23 for dim in dims {
24 if dim.len.checked_add(dim.lower).is_none() {
25 return Err(TypeError::new(
26 SqlState::PROGRAM_LIMIT_EXCEEDED,
27 format!("array lower bound is too large: {}", dim.lower),
28 ));
29 }
30 }
31 Ok(())
32}
33
34fn dim_between(lower: i64, end: i64) -> Result<ArrayDim, TypeError> {
36 let len = end - lower;
37 if len > MAX_ARRAY_SIZE as i64 {
38 return Err(too_large());
39 }
40 let (Ok(len), Ok(lower)) = (i32::try_from(len), i32::try_from(lower)) else {
41 return Err(too_large());
42 };
43 Ok(ArrayDim { len, lower })
44}
45
46fn offset(dims: &[ArrayDim], at: &[usize]) -> usize {
48 dims.iter().zip(at).fold(0, |offset, (dim, &i)| offset * dim.len as usize + i)
49}
50
51impl<T> Array<T> {
52 pub fn set_element(self, subscripts: &[i32], value: Option<T>) -> Result<Array<T>, TypeError> {
58 let n = subscripts.len();
59 if n == 0 || n > MAXDIM {
60 return Err(subscript_error("wrong number of array subscripts"));
61 }
62 let Array { mut dims, mut values } = self;
63 if dims.is_empty() {
64 let dims: Vec<_> = subscripts.iter().map(|&lower| ArrayDim { len: 1, lower }).collect();
66 check_bounds(&dims)?;
67 return Ok(Array { dims, values: vec![value] });
68 }
69 if dims.len() != n {
70 return Err(subscript_error("wrong number of array subscripts"));
71 }
72 if n == 1 {
73 let dim = dims[0];
74 let (lower, end) = (i64::from(dim.lower), i64::from(dim.lower) + i64::from(dim.len));
75 let at = i64::from(subscripts[0]);
76 let grown = dim_between(lower.min(at), end.max(at + 1))?;
77 check_bounds(&[grown])?;
78 let before = (lower - i64::from(grown.lower)) as usize;
79 let after = grown.len as usize - before - dim.len as usize;
80 values.splice(0..0, std::iter::repeat_with(|| None).take(before));
81 values.extend(std::iter::repeat_with(|| None).take(after));
82 dims[0] = grown;
83 values[(at - i64::from(grown.lower)) as usize] = value;
84 return Ok(Array { dims, values });
85 }
86 let mut at = Vec::with_capacity(n);
87 for (dim, &i) in dims.iter().zip(subscripts) {
88 let step = i64::from(i) - i64::from(dim.lower);
89 if step < 0 || step >= i64::from(dim.len) {
90 return Err(subscript_error("array subscript out of range"));
91 }
92 at.push(step as usize);
93 }
94 let place = offset(&dims, &at);
95 values[place] = value;
96 Ok(Array { dims, values })
97 }
98
99 pub fn set_slice(
105 self,
106 lower: &[Option<i32>],
107 upper: &[Option<i32>],
108 source: Array<T>,
109 ) -> Result<Array<T>, TypeError> {
110 let n = upper.len();
111 let Array { mut dims, mut values } = self;
112 let source = source.values;
113 if dims.is_empty() {
114 let mut dims = Vec::with_capacity(n);
115 for (lo, up) in lower.iter().zip(upper) {
116 let (Some(lo), Some(up)) = (lo, up) else {
117 let mut error =
118 subscript_error("array slice subscript must provide both boundaries");
119 error.detail = Some(
120 "When assigning to a slice of an empty array value, slice boundaries must be fully specified."
121 .to_string(),
122 );
123 return Err(error);
124 };
125 let len = i64::from(*up) - i64::from(*lo) + 1;
126 let len = i32::try_from(len).map_err(|_| too_large())?;
127 dims.push(ArrayDim { len, lower: *lo });
128 }
129 let count = item_count(&dims)?;
130 if source.len() < count {
131 return Err(subscript_error("source array too small"));
132 }
133 check_bounds(&dims)?;
134 if count == 0 {
135 return Ok(Array::empty());
136 }
137 return Ok(Array { dims, values: source.into_iter().take(count).collect() });
138 }
139 if dims.len() < n {
140 return Err(subscript_error("wrong number of array subscripts"));
141 }
142 let mut ranges = Vec::with_capacity(dims.len());
143 for (i, dim) in dims.iter().enumerate() {
144 let (first, end) = (i64::from(dim.lower), i64::from(dim.lower) + i64::from(dim.len));
145 let lo = lower.get(i).copied().flatten().map_or(first, i64::from);
146 let up = upper.get(i).copied().flatten().map_or(end - 1, i64::from);
147 if lo > up {
148 return Err(subscript_error("upper bound cannot be less than lower bound"));
149 }
150 if dims.len() > 1 && (lo < first || up >= end) {
151 return Err(subscript_error("array subscript out of range"));
152 }
153 ranges.push((lo, up));
154 }
155 if dims.len() == 1 {
156 let dim = dims[0];
157 let (lo, up) = ranges[0];
158 let (lower, end) = (i64::from(dim.lower), i64::from(dim.lower) + i64::from(dim.len));
159 let grown = dim_between(lower.min(lo), end.max(up + 1))?;
160 check_bounds(&[grown])?;
161 let span = (up - lo + 1) as usize;
162 if source.len() < span {
163 return Err(subscript_error("source array too small"));
164 }
165 let before = (lower - i64::from(grown.lower)) as usize;
166 let after = grown.len as usize - before - dim.len as usize;
167 values.splice(0..0, std::iter::repeat_with(|| None).take(before));
168 values.extend(std::iter::repeat_with(|| None).take(after));
169 dims[0] = grown;
170 let start = (lo - i64::from(grown.lower)) as usize;
171 values.splice(start..start + span, source.into_iter().take(span));
172 return Ok(Array { dims, values });
173 }
174 let span: usize = ranges.iter().map(|&(lo, up)| (up - lo + 1) as usize).product();
175 if source.len() < span {
176 return Err(subscript_error("source array too small"));
177 }
178 let mut at: Vec<usize> = ranges
180 .iter()
181 .zip(&dims)
182 .map(|(&(lo, _), dim)| (lo - i64::from(dim.lower)) as usize)
183 .collect();
184 for item in source.into_iter().take(span) {
185 let place = offset(&dims, &at);
186 values[place] = item;
187 for level in (0..at.len()).rev() {
188 let (lo, up) = ranges[level];
189 let first = (lo - i64::from(dims[level].lower)) as usize;
190 if at[level] < (up - i64::from(dims[level].lower)) as usize {
191 at[level] += 1;
192 break;
193 }
194 at[level] = first;
195 }
196 }
197 Ok(Array { dims, values })
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 fn one(values: &[i32]) -> Array<i32> {
206 Array::one(values.iter().copied().map(Some).collect())
207 }
208
209 fn grid(rows: &[&[i32]]) -> Array<i32> {
210 let len = rows[0].len() as i32;
211 let dims = vec![ArrayDim { len: rows.len() as i32, lower: 1 }, ArrayDim { len, lower: 1 }];
212 Array { dims, values: rows.iter().flat_map(|r| r.iter().copied().map(Some)).collect() }
213 }
214
215 fn values(array: &Array<i32>) -> Vec<Option<i32>> {
216 array.values.clone()
217 }
218
219 #[test]
220 fn element() {
221 let a = one(&[1, 2, 3]).set_element(&[5], Some(5)).unwrap();
222 assert_eq!(a.dims, vec![ArrayDim { len: 5, lower: 1 }]);
223 assert_eq!(values(&a), vec![Some(1), Some(2), Some(3), None, Some(5)]);
224 let a = one(&[1]).set_element(&[-1], Some(9)).unwrap();
225 assert_eq!(a.dims, vec![ArrayDim { len: 3, lower: -1 }]);
226 assert_eq!(values(&a), vec![Some(9), None, Some(1)]);
227 let a = Array::empty().set_element(&[2, 3], Some(7)).unwrap();
228 let dims = vec![ArrayDim { len: 1, lower: 2 }, ArrayDim { len: 1, lower: 3 }];
229 assert_eq!(a.dims, dims);
230 let a = grid(&[&[1, 2], &[3, 4]]).set_element(&[2, 1], Some(30)).unwrap();
231 assert_eq!(values(&a), vec![Some(1), Some(2), Some(30), Some(4)]);
232 let out = grid(&[&[1, 2], &[3, 4]]).set_element(&[3, 1], Some(5)).unwrap_err();
233 assert_eq!(out.message, "array subscript out of range");
234 let out = one(&[1, 2]).set_element(&[1, 1], Some(5)).unwrap_err();
235 assert_eq!(out.message, "wrong number of array subscripts");
236 let out = one(&[1, 2, 3]).set_element(&[i32::MAX], Some(1)).unwrap_err();
237 assert_eq!(out.sqlstate, SqlState::PROGRAM_LIMIT_EXCEEDED);
238 let out = Array::empty().set_element(&[i32::MAX], Some(1)).unwrap_err();
239 assert_eq!(out.message, "array lower bound is too large: 2147483647");
240 }
241
242 #[test]
243 fn slice() {
244 let a = one(&[1, 2, 3]).set_slice(&[Some(5)], &[Some(6)], one(&[50, 60])).unwrap();
245 assert_eq!(values(&a), vec![Some(1), Some(2), Some(3), None, Some(50), Some(60)]);
246 let a = one(&[1, 2, 3]).set_slice(&[None], &[Some(2)], one(&[7, 8, 9])).unwrap();
247 assert_eq!(values(&a), vec![Some(7), Some(8), Some(3)]);
248 let a = Array::empty().set_slice(&[Some(2)], &[Some(3)], one(&[1, 2])).unwrap();
249 assert_eq!(a.dims, vec![ArrayDim { len: 2, lower: 2 }]);
250 let a = Array::empty().set_slice(&[Some(3)], &[Some(2)], one(&[1, 2])).unwrap();
251 assert!(a.dims.is_empty());
252 let out = Array::empty().set_slice(&[None], &[Some(3)], one(&[1])).unwrap_err();
253 assert_eq!(out.message, "array slice subscript must provide both boundaries");
254 let out = one(&[1, 2, 3]).set_slice(&[Some(1)], &[Some(3)], one(&[1, 2])).unwrap_err();
255 assert_eq!(out.message, "source array too small");
256 let out = one(&[1, 2, 3]).set_slice(&[Some(3)], &[Some(1)], one(&[1, 2])).unwrap_err();
257 assert_eq!(out.message, "upper bound cannot be less than lower bound");
258 let a = grid(&[&[1, 2, 3], &[4, 5, 6]]);
259 let a = a.set_slice(&[Some(1), Some(2)], &[Some(2), Some(3)], one(&[20, 30, 50, 60]));
260 let a = a.unwrap();
261 let expect = [1, 20, 30, 4, 50, 60].map(Some).to_vec();
262 assert_eq!(values(&a), expect);
263 let a = a.set_slice(&[Some(2)], &[Some(2)], one(&[-1, -2, -3])).unwrap();
264 assert_eq!(values(&a), [1, 20, 30, -1, -2, -3].map(Some).to_vec());
265 let out = a.set_slice(&[Some(1), Some(1)], &[Some(3), Some(1)], one(&[1, 2, 3]));
266 assert_eq!(out.unwrap_err().message, "array subscript out of range");
267 }
268}